/* ==========================================================================
   Sven Vranjes portfolio
   Thesis: a quiet white field where work arrives out of blur.
   One typeface, one cut (Arteme Display Regular), three sizes.
   ========================================================================== */

@font-face {
  font-family: "Arteme";
  src: url("../fonts/ArtemeDisplay-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

:root {
  /* colour */
  --bg: #f8f8f8;
  --card: #ececee;
  --card-2: #e2e2e5;
  --ink: #111111;
  --ink-2: #8a8a8a;
  --ink-3: #b8b8b8;
  --line: rgba(0, 0, 0, 0.1);
  --glass: rgba(255, 255, 255, 0.42);
  --glass-edge: rgba(255, 255, 255, 0.75);
  --glass-shade: rgba(0, 0, 0, 0.06);
  --chip: rgba(70, 70, 72, 0.38);
  --loader-a: #cbcdd1;
  --loader-b: #f9f8f8;

  /* type: three sizes only */
  --s: 13px;                              /* small: body, ui, captions */
  --m: clamp(22px, 0.85rem + 1.3vw, 36px);  /* middle: page titles, statements, leads */
  --l: clamp(36px, 1rem + 2.9vw, 64px);     /* large: case study statements, card titles */
  --font: "Arteme", "Helvetica Neue", Helvetica, Arial, sans-serif;

  /* geometry */
  --pad: 16px;                 /* page margin, Holographik */
  --gap: 16px;                 /* grid gutter */
  --cols: 12;
  --radius: clamp(20px, 2.2vw, 36px);
  --header-h: 56px;

  /* motion */
  --ease: cubic-bezier(0.2, 0.8, 0.2, 1);
  --ease-io: cubic-bezier(0.65, 0, 0.35, 1);
  --t-fast: 240ms;
  --t: 520ms;
  --t-slow: 900ms;
}

:root[data-theme="dark"] {
  --bg: #0d0d0e;
  --card: #1a1a1c;
  --card-2: #232326;
  --ink: #f1f1f1;
  --ink-2: #8d8d8f;
  --ink-3: #555557;
  --line: rgba(255, 255, 255, 0.12);
  --glass: rgba(40, 40, 42, 0.42);
  --glass-edge: rgba(255, 255, 255, 0.16);
  --glass-shade: rgba(0, 0, 0, 0.3);
  --chip: rgba(30, 30, 32, 0.45);
  --loader-a: #2a2b2e;
  --loader-b: #0d0d0e;
  color-scheme: dark;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: auto; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-weight: 400;
  font-size: var(--s);
  line-height: 1.32;
  letter-spacing: 0;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-feature-settings: "kern" 1;
  font-synthesis: none;
  transition: background-color var(--t) var(--ease), color var(--t) var(--ease);
  overflow-x: hidden;
}
body.is-loading { overflow: hidden; }
img, video { display: block; max-width: 100%; }
figure { margin: 0; }
h1, h2, h3, h4, h5, h6, p { font-weight: 400; margin: 0; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; border-radius: 6px; }
::selection { background: var(--ink); color: var(--bg); }

/* ---- type tiers ------------------------------------------------------- */
.t-s { font-size: var(--s); line-height: 1.32; letter-spacing: 0; }
.t-m { font-size: var(--m); line-height: 1.1; letter-spacing: -0.015em; text-wrap: pretty; }
.t-l { font-size: var(--l); line-height: 1; letter-spacing: -0.028em; text-wrap: balance; }
.t-l p, .t-m p { margin: 0; }
.indent { text-indent: 4.6em; }            /* Holographik paragraph indent */
.grey { color: var(--ink-2); }
.num { font-variant-numeric: tabular-nums; }
.caption { color: var(--ink-2); }
.u { text-decoration: underline; text-underline-offset: 0.14em; text-decoration-thickness: 0.06em; }
@media (hover: hover) { a.u:hover, .hover-ink:hover { color: var(--ink); } }

/* ---- grid -------------------------------------------------------------- */
.wrap { padding-inline: max(var(--pad), env(safe-area-inset-left)) max(var(--pad), env(safe-area-inset-right)); }
.grid { display: grid; grid-template-columns: repeat(var(--cols), minmax(0, 1fr)); column-gap: var(--gap); }
.span-2 { grid-column: span 2; } .span-3 { grid-column: span 3; } .span-4 { grid-column: span 4; }
.span-5 { grid-column: span 5; } .span-6 { grid-column: span 6; } .span-8 { grid-column: span 8; }
.span-9 { grid-column: span 9; } .span-10 { grid-column: span 10; } .span-12 { grid-column: 1 / -1; }
.start-4 { grid-column-start: 4; } .start-5 { grid-column-start: 5; } .start-7 { grid-column-start: 7; } .start-10 { grid-column-start: 10; }

/* vertical rhythm: few big jumps */
.sp-1 { margin-top: 16px; } .sp-2 { margin-top: 48px; } .sp-3 { margin-top: 96px; } .sp-4 { margin-top: 192px; }

.rule { border: 0; border-top: 1px solid var(--line); margin: 0; }
.label-row { display: flex; justify-content: space-between; gap: var(--gap); padding-bottom: 8px; border-bottom: 1px solid var(--line); }

/* ---- glass ------------------------------------------------------------- */
.glass {
  background: var(--glass);
  -webkit-backdrop-filter: blur(18px) saturate(180%);
  backdrop-filter: blur(18px) saturate(180%);
  box-shadow:
    inset 0 1px 0 var(--glass-edge),
    inset 0 -1px 0 var(--glass-shade),
    inset 0 0 0 1px rgba(255, 255, 255, 0.08),
    0 8px 30px -12px rgba(0, 0, 0, 0.12);
  border-radius: 999px;
}

/* chips: what the project is */
.chips { display: flex; flex-wrap: wrap; gap: 4px; }
.chip {
  display: inline-flex; align-items: center;
  height: 24px; padding: 0 10px;
  border-radius: 8px;
  font-size: var(--s); line-height: 1; white-space: nowrap;
  background: var(--card);
  color: var(--ink);
}
.chip--glass {
  background: var(--chip);
  color: #fff;
  -webkit-backdrop-filter: blur(10px) saturate(150%);
  backdrop-filter: blur(10px) saturate(150%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18);
}

.btn {
  display: inline-flex; align-items: center; gap: 8px;
  height: 40px; padding: 0 18px; border-radius: 999px;
  font-size: var(--s);
  transition: transform var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease);
}
.btn:active { transform: scale(0.97); }
.btn--ink { background: var(--ink); color: var(--bg); }
.btn .arrow { transition: transform var(--t-fast) var(--ease); }
@media (hover: hover) { .btn:hover .arrow { transform: translateX(3px); } }

/* ---- header ------------------------------------------------------------ */
.header {
  position: fixed; inset: 0 0 auto 0; z-index: 50;
  height: var(--header-h);
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
  padding-inline: var(--pad);
  pointer-events: none;
}
.header > * { pointer-events: auto; }
.wordmark { justify-self: start; font-size: var(--s); padding: 8px 0; }
.clock { justify-self: center; color: var(--ink); }
.clock .grey { margin-left: 2px; }
.nav-wrap { justify-self: end; display: flex; align-items: center; gap: 6px; }
.nav { position: relative; display: flex; align-items: center; height: 40px; padding: 4px; }
.nav a {
  position: relative; z-index: 1;
  display: inline-flex; align-items: center; height: 32px; padding: 0 14px;
  border-radius: 999px; color: var(--ink-2);
  transition: color var(--t-fast) var(--ease);
}
.nav a.is-active { color: var(--ink); }
@media (hover: hover) { .nav a:hover { color: var(--ink); } }
.nav-indicator {
  position: absolute; z-index: 0; top: 4px; height: 32px; border-radius: 999px;
  background: rgba(255, 255, 255, 0.7);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.9), 0 1px 6px -2px rgba(0,0,0,.12);
  transition: transform var(--t) var(--ease), width var(--t) var(--ease), opacity var(--t-fast);
}
:root[data-theme="dark"] .nav-indicator { background: rgba(255, 255, 255, 0.12); box-shadow: inset 0 1px 0 rgba(255,255,255,.14); }
.theme-toggle { width: 40px; height: 40px; display: grid; place-items: center; border-radius: 999px; }
.theme-toggle i {
  width: 12px; height: 12px; border-radius: 50%;
  background: linear-gradient(90deg, var(--ink) 50%, transparent 50%);
  box-shadow: inset 0 0 0 1.2px var(--ink);
  transition: transform var(--t) var(--ease);
}
:root[data-theme="dark"] .theme-toggle i { transform: rotate(180deg); }

/* header entrance after loader */
.header .wordmark, .header .clock, .header .nav-wrap {
  opacity: 0; transform: translateY(-10px); filter: blur(6px);
  transition: opacity var(--t-slow) var(--ease), transform var(--t-slow) var(--ease), filter var(--t-slow) var(--ease);
}
body.is-ready .header .wordmark { opacity: 1; transform: none; filter: none; transition-delay: 0ms; }
body.is-ready .header .clock    { opacity: 1; transform: none; filter: none; transition-delay: 90ms; }
body.is-ready .header .nav-wrap { opacity: 1; transform: none; filter: none; transition-delay: 180ms; }

/* ---- top edge: progressive blur + liquid distortion -------------------- */
.edge {
  position: fixed; inset: 0 0 auto 0; height: 132px; z-index: 40; pointer-events: none;
  opacity: 0; transition: opacity var(--t) var(--ease);
}
body.is-scrolled .edge { opacity: 1; }
.edge > div { position: absolute; inset: 0; }
.edge > div:nth-child(1) { -webkit-backdrop-filter: blur(1px); backdrop-filter: blur(1px);
  -webkit-mask: linear-gradient(to bottom, #000 0%, #000 60%, transparent 100%); mask: linear-gradient(to bottom, #000 0%, #000 60%, transparent 100%); }
.edge > div:nth-child(2) { -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
  -webkit-mask: linear-gradient(to bottom, #000 0%, #000 45%, transparent 80%); mask: linear-gradient(to bottom, #000 0%, #000 45%, transparent 80%); }
.edge > div:nth-child(3) { -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px);
  -webkit-mask: linear-gradient(to bottom, #000 0%, #000 30%, transparent 62%); mask: linear-gradient(to bottom, #000 0%, #000 30%, transparent 62%); }
.edge > div:nth-child(4) { -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  -webkit-mask: linear-gradient(to bottom, #000 0%, transparent 46%); mask: linear-gradient(to bottom, #000 0%, transparent 46%); }
.edge::after { /* soft wash so text under the header stays legible */
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to bottom, color-mix(in srgb, var(--bg) 72%, transparent) 0%, transparent 70%);
}
/* liquid: Chromium supports SVG filters in backdrop-filter */
.has-liquid .edge > div:nth-child(2) { -webkit-backdrop-filter: url(#liquid) blur(3px); backdrop-filter: url(#liquid) blur(3px); }

/* ---- loader ------------------------------------------------------------ */
.loader {
  position: fixed; inset: 0; z-index: 100;
  display: grid; place-items: center;
  background: var(--loader-b);
  transition: opacity 600ms var(--ease);
}
.loader__blob {
  position: absolute; inset: -10% -10% 0 -10%;
  background:
    radial-gradient(ellipse 70% 62% at 50% 46%, var(--loader-a) 0%, color-mix(in srgb, var(--loader-a) 70%, var(--loader-b)) 48%, transparent 78%),
    linear-gradient(to bottom, var(--loader-a) 0%, color-mix(in srgb, var(--loader-a) 40%, var(--loader-b)) 55%, var(--loader-b) 100%);
  transform-origin: 50% 0%;
  opacity: 0;
  animation: blob-in 700ms var(--ease-soft, ease-out) forwards;
}
.loader__name {
  position: relative;
  font-size: clamp(28px, 2.6vw, 44px); /* loader only: matches the provided frames */
  letter-spacing: -0.02em;
  color: #fff;
  opacity: 0;
  animation: name-in 900ms cubic-bezier(0.16, 1, 0.3, 1) 150ms forwards;
}
:root[data-theme="dark"] .loader__name { color: var(--ink); }
/* the exit is a single two-keyframe move: no intermediate stops, so it never pauses */
.loader.is-out .loader__blob { opacity: 1; animation: blob-out 1500ms cubic-bezier(0.65, 0, 0.35, 1) forwards; }
.loader.is-out .loader__name { opacity: 1; animation: name-out 1000ms cubic-bezier(0.65, 0, 0.35, 1) forwards; }
.loader.is-gone { opacity: 0; pointer-events: none; }
@keyframes blob-in { from { opacity: 0; transform: scale(1.04); } to { opacity: 1; transform: none; } }
@keyframes blob-out { from { transform: none; opacity: 1; } to { transform: translateY(-46%) scaleY(0.42); opacity: 0; } }
@keyframes name-in { from { opacity: 0; filter: blur(14px); transform: translateY(6px); } to { opacity: 1; filter: blur(0); transform: none; } }
@keyframes name-out { from { opacity: 1; filter: blur(0); transform: none; } to { opacity: 0; filter: blur(16px); transform: translateY(-8px); } }

/* ---- page + reveals ---------------------------------------------------- */
main { min-height: 100vh; transition: opacity 360ms var(--ease), filter 360ms var(--ease), transform 360ms var(--ease); }
main.is-leaving { opacity: 0; filter: blur(10px); transform: translateY(-8px); }
.page { padding-top: calc(var(--header-h) + 96px); padding-bottom: 96px; }

[data-reveal] {
  opacity: 0; transform: translateY(18px); filter: blur(10px);
  transition: opacity var(--t-slow) var(--ease), transform var(--t-slow) var(--ease), filter var(--t-slow) var(--ease);
  transition-delay: var(--d, 0ms);
}
[data-reveal].is-in { opacity: 1; transform: none; filter: none; }

/* split line reveal for large statements */
.lines .ln { display: inline; }
.lines .ln > span {
  display: inline-block; text-indent: 0; opacity: 0; transform: translateY(0.35em); filter: blur(8px);
  transition: opacity var(--t-slow) var(--ease), transform var(--t-slow) var(--ease), filter var(--t-slow) var(--ease);
  transition-delay: calc(var(--i, 0) * 28ms);
}
.lines.is-in .ln > span { opacity: 1; transform: none; filter: none; }

/* ---- media + placeholder ---------------------------------------------- */
.media { position: relative; overflow: hidden; border-radius: var(--radius); background: var(--card); isolation: isolate; }
.media > img, .media > video { width: 100%; height: 100%; object-fit: cover; }
.ph {
  position: absolute; inset: 0;
  background:
    radial-gradient(ellipse 60% 55% at var(--px, 40%) var(--py, 45%), var(--card-2) 0%, transparent 70%),
    var(--card);
}
.ph__meta { position: absolute; left: 16px; bottom: 14px; color: var(--ink-3); }
.ph--moving { animation: ph-drift 9s ease-in-out infinite alternate; }
@keyframes ph-drift {
  0% { --px: 30%; --py: 40%; background-position: 0 0; }
  100% { --px: 70%; --py: 60%; }
}
@property --px { syntax: "<percentage>"; inherits: false; initial-value: 40%; }
@property --py { syntax: "<percentage>"; inherits: false; initial-value: 45%; }

/* ---- card: blurred moving cover, sharp on hover ------------------------ */
.card { position: relative; display: block; }
.card .media { aspect-ratio: var(--ar, 1 / 1); }
.card .cover {
  position: absolute; inset: 0;
  filter: blur(26px) saturate(115%);
  transform: scale(1.18);
  transition: filter 900ms var(--ease), transform 1100ms var(--ease);
}
.card .cover > * { width: 100%; height: 100%; object-fit: cover; }
.card .overlay {
  position: absolute; inset: 0; z-index: 2;
  display: grid; place-content: center; justify-items: center; gap: 14px;
  padding: 24px; text-align: center; color: #fff;
  transition: opacity 600ms var(--ease), transform 900ms var(--ease), filter 600ms var(--ease);
}
.card .overlay .t-l { text-shadow: 0 0 40px rgba(0, 0, 0, 0.08); }
.card.is-ph .overlay { color: var(--ink); }
.card.is-ph .chip--glass { background: rgba(255,255,255,.55); color: var(--ink); }
@media (hover: hover) {
  .card:hover .cover { filter: blur(0) saturate(100%); transform: scale(1.02); }
  .card:hover .overlay { opacity: 0; transform: scale(0.98); filter: blur(8px); }
}
.card .under { display: flex; justify-content: space-between; gap: 12px; padding-top: 10px; }
.card .under .grey { text-align: right; }

/* cursor label */
.cursor {
  position: fixed; left: 0; top: 0; z-index: 60; pointer-events: none;
  height: 36px; padding: 0 16px; display: inline-flex; align-items: center;
  font-size: var(--s);
  opacity: 0; transform: translate(-50%, -50%) scale(0.6);
  transition: opacity var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
  color: var(--ink);
}
.cursor.is-on { opacity: 1; }
@media (hover: none) { .cursor { display: none; } }

/* ---- home -------------------------------------------------------------- */
.home-intro { min-height: 62vh; display: grid; align-content: end; padding-bottom: 48px; }
.home-intro .lead { max-width: 30ch; }
.home-intro .meta { align-self: end; }

.rail { position: relative; }
.rail__pin { position: sticky; top: 0; height: 100vh; overflow: hidden; display: grid; grid-template-columns: minmax(0, 1fr); align-content: center; }
.rail__track { display: flex; gap: var(--gap); padding-inline: var(--pad); will-change: transform; }
.rail__track .card { flex: 0 0 auto; width: min(44vw, 74vh); }
.rail__foot { display: flex; justify-content: space-between; align-items: baseline; padding: 16px var(--pad) 0; }
.rail__bar { position: relative; flex: 1; height: 1px; background: var(--line); margin: 0 24px; align-self: center; }
.rail__bar > i { position: absolute; inset: 0 auto 0 0; width: 100%; background: var(--ink); transform-origin: 0 50%; transform: scaleX(var(--p, 0)); }

.list-row {
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--gap);
  align-items: baseline; padding: 11px 0; border-bottom: 1px solid var(--line);
  transition: color var(--t-fast) var(--ease);
}
.list-row > * { min-width: 0; }
.list-head { color: var(--ink-2); }
.list .list-row:not(.list-head) { cursor: pointer; }
@media (hover: hover) {
  .list:hover .list-row:not(.list-head) { color: var(--ink-3); }
  .list .list-row:not(.list-head):hover { color: var(--ink); }
}
.list-row .chips .chip { height: 20px; padding: 0 7px; border-radius: 6px; }
.list:hover .list-row:not(:hover) .chip { opacity: 0.5; }

/* floating preview for text lists */
.preview {
  position: fixed; left: 0; top: 0; z-index: 55; pointer-events: none;
  width: 260px; aspect-ratio: 4 / 5; border-radius: 22px; overflow: hidden;
  opacity: 0; transform: translate(-50%, -50%) scale(0.9); filter: blur(10px);
  transition: opacity 360ms var(--ease), transform 360ms var(--ease), filter 360ms var(--ease);
  background: var(--card);
}
.preview.is-on { opacity: 1; transform: translate(-50%, -50%) scale(1); filter: none; }
.preview > * { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
@media (hover: none) { .preview { display: none; } }

/* ---- work -------------------------------------------------------------- */
.filters { display: flex; gap: 48px; }
.filter { display: grid; grid-template-columns: auto auto; column-gap: 12px; align-items: start; }
.filter ul { list-style: none; margin: 0; padding: 0; }
.filter button { display: block; color: var(--ink-3); line-height: 1.12; transition: color var(--t-fast) var(--ease); text-align: left; }
.filter button.is-active { color: var(--ink); }
@media (hover: hover) { .filter button:hover { color: var(--ink); } }

.seg { display: inline-flex; padding: 4px; height: 40px; position: relative; }
.seg button { position: relative; z-index: 1; height: 32px; padding: 0 14px; border-radius: 999px; color: var(--ink-2); transition: color var(--t-fast); }
.seg button.is-active { color: var(--ink); }
.seg .nav-indicator { top: 4px; }

.work-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 48px var(--gap); }
.work-grid .card { transition: opacity var(--t) var(--ease), transform var(--t) var(--ease), filter var(--t) var(--ease); }
.work-grid .card.is-hidden { display: none; }
.work-grid .card.is-filtering { opacity: 0; transform: translateY(12px); filter: blur(8px); }

/* ---- case study -------------------------------------------------------- */
.cs-head { padding-top: calc(var(--header-h) + 22vh); }
.cs-info .k { color: var(--ink-2); margin-bottom: 4px; }
.cs-flow { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--gap); }
.cs-flow .full { grid-column: 1 / -1; }
.cs-flow .half { grid-column: span 6; }
.cs-flow .narrow { grid-column: 4 / span 6; }
.cs-flow .media { aspect-ratio: var(--ar, 16 / 9); }
.cs-flow .group-label { grid-column: 1 / -1; padding: 96px 0 8px; display: flex; justify-content: space-between; border-bottom: 1px solid var(--line); margin-bottom: 8px; }

.statement { padding: 192px 0; text-align: center; display: grid; justify-items: center; gap: 28px; }
.statement .t-l { max-width: 18ch; }

.sound {
  position: absolute; right: 16px; bottom: 16px; z-index: 3;
  height: 36px; padding: 0 14px; display: inline-flex; align-items: center; gap: 8px; color: var(--ink);
}
.sound i { width: 6px; height: 6px; border-radius: 50%; background: currentColor; opacity: 0.4; transition: opacity var(--t-fast); }
.sound.is-on i { opacity: 1; }

/* read more: blurred page, light card */
.modal {
  position: fixed; inset: 0; z-index: 80; display: grid; place-items: center; padding: var(--pad);
  background: color-mix(in srgb, var(--bg) 30%, transparent);
  -webkit-backdrop-filter: blur(22px) saturate(120%); backdrop-filter: blur(22px) saturate(120%);
  opacity: 0; pointer-events: none; transition: opacity var(--t) var(--ease);
}
.modal.is-open { opacity: 1; pointer-events: auto; }
.modal__card {
  position: relative; width: min(520px, 100%); max-height: 80vh; overflow: auto;
  background: var(--bg); border-radius: 28px; padding: 28px 28px 32px;
  transform: translateY(16px) scale(0.98); transition: transform var(--t) var(--ease);
}
.modal.is-open .modal__card { transform: none; }
.modal__close { position: absolute; top: 14px; right: 14px; width: 32px; height: 32px; border-radius: 999px; background: var(--card); display: grid; place-items: center; }
.modal__card p { margin: 0 0 1em; }
.modal__card p + p { text-indent: 0; }

.next { display: block; padding: 192px 0 48px; text-align: center; }
.next .t-l { transition: letter-spacing var(--t) var(--ease), filter var(--t) var(--ease); }
@media (hover: hover) { .next:hover .t-l { filter: blur(2px); } }

/* ---- about ------------------------------------------------------------- */
.about-statement p { margin: 0; }
.about-statement p + p { text-indent: 4.6em; }
.principles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 64px var(--gap); }
.principle .n { color: var(--ink-2); margin-bottom: 10px; }
.principle .t-m { margin-bottom: 10px; }
.principle p { margin: 0; max-width: 36ch; }
.cols3 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--gap); }
.cols3 ul { list-style: none; margin: 0; padding: 0; }
.cols3 .k { text-transform: uppercase; letter-spacing: 0.05em; color: var(--ink-2); margin-bottom: 8px; }

/* ---- contact + footer ------------------------------------------------- */
.copy { position: relative; }
.copy .copied { position: absolute; left: 0; top: 0; opacity: 0; transition: opacity var(--t-fast); color: var(--ink-2); }
.copy.is-copied .val { opacity: 0; }
.copy.is-copied .copied { opacity: 1; }
.footer { padding-block: 96px 24px; }
.footer .row { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--gap); align-items: end; }

/* ---- responsive -------------------------------------------------------- */
@media (max-width: 900px) {
  :root { --header-h: 52px; }
  .clock { display: none; }
  .header { grid-template-columns: 1fr auto; }
  .nav a { padding: 0 10px; }
  .work-grid { grid-template-columns: 1fr; gap: 32px; }
  .principles { grid-template-columns: 1fr 1fr; }
  .cols3 { grid-template-columns: 1fr 1fr; row-gap: 32px; }
  .cs-flow .half { grid-column: 1 / -1; }
  .cs-flow .narrow { grid-column: 1 / -1; }
  .filters { gap: 24px; }
}
@media (max-width: 640px) {
  .wordmark .last { display: none; }
  .nav a { padding: 0 8px; }
  .nav-wrap { gap: 4px; }
  .span-4, .span-5, .span-6, .span-8, .span-9, .span-10, .span-3, .span-2 { grid-column: 1 / -1; }
  [class*="start-"] { grid-column-start: 1; }
  .principles { grid-template-columns: 1fr; gap: 40px; }
  .statement { padding: 120px 0; }
  .list-row .hide-sm { display: none; }
  .indent, .about-statement p + p { text-indent: 2.4em; }
  .rail__pin { position: relative; height: auto; overflow: visible; padding-block: 24px; }
  .rail__track { flex-direction: column; transform: none !important; }
  .rail__track .card { width: 100%; }
  .rail { height: auto !important; }
  .rail__foot { display: none; }
  .filters { flex-direction: column; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 1ms !important; animation-iteration-count: 1 !important; transition-duration: 1ms !important; }
  [data-reveal], .lines .ln > span { opacity: 1; transform: none; filter: none; }
  .card .cover { filter: blur(26px); }
}


/* ==========================================================================
   v2: one grid, baseline-aligned page heads, three sizes
   12 columns. Key column starts: 1, 2, 4, 6, 9, 10, 12.
   ========================================================================== */
.head { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--gap); align-items: first baseline; }
.head > * { min-width: 0; }
.c1  { grid-column: 1 / span 5; }
.c2  { grid-column: 2 / span 4; }
.c4  { grid-column: 4 / span 5; }
.c6  { grid-column: 6 / span 3; }
.c6w { grid-column: 6 / span 4; }
.c9  { grid-column: 9 / span 3; }
.c10 { grid-column: 10 / span 3; }
.c12 { grid-column: 12 / span 1; text-align: right; }
.full-row { grid-column: 1 / -1; }

/* home intro, per mock: grey line + ink line, sitting low */
.home-intro { min-height: 58vh; display: grid; align-content: end; padding-bottom: 40px; }
.home-intro .lede { grid-column: 1 / span 9; }
.home-intro .meta { margin-top: 40px; }

/* lists: No | Project | Client | Services | Year */
.list-row > .col-no { grid-column: 1 / span 1; }
.list-row > .col-title { grid-column: 2 / span 4; }
.list-row > .col-client { grid-column: 6 / span 3; }
.list-row > .col-cats { grid-column: 9 / span 3; }
.list-row > .col-year { grid-column: 12 / span 1; text-align: right; }

/* work filters as a quiet legend, Holographik style */
.legend { display: grid; grid-template-columns: auto 1fr; column-gap: 12px; }
.legend ul { list-style: none; margin: 0; padding: 0; }
.legend button { display: block; color: var(--ink-3); text-align: left; padding: 0; line-height: 1.32; transition: color var(--t-fast) var(--ease); }
.legend button.is-active { color: var(--ink); }
@media (hover: hover) { .legend button:hover { color: var(--ink); } }
.legend .k { color: var(--ink); }

/* preview: title in a glass pill, centred */
.preview { width: 300px; border-radius: 24px; }
.preview .pill {
  position: absolute; inset: auto; left: 50%; top: 50%; width: auto; height: auto;
  transform: translate(-50%, -50%); white-space: nowrap;
  padding: 10px 18px; border-radius: 999px; color: #fff; font-size: var(--s);
  background: rgba(255, 255, 255, 0.16);
  -webkit-backdrop-filter: blur(14px) saturate(160%); backdrop-filter: blur(14px) saturate(160%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35), inset 0 0 0 1px rgba(255, 255, 255, 0.12);
}
.preview .ph + .pill, .preview.is-ph .pill { color: var(--ink); background: rgba(255, 255, 255, 0.55); }

/* principles + operations */
.principle .ttl { color: var(--ink); margin-bottom: 8px; }
.principle .n { margin-bottom: 0; }
.principle p { color: var(--ink-2); }
.ops-cols p { margin: 0; }
.ops-cols .k { color: var(--ink-2); margin-bottom: 6px; }

/* accordion rows (contact) */
.acc { border-bottom: 1px solid var(--line); }
.acc__btn { width: 100%; display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--gap); align-items: baseline; padding: 14px 0; text-align: left; }
.acc__btn .plus { grid-column: 12; justify-self: end; width: 28px; height: 28px; border-radius: 999px; display: grid; place-items: center; transition: transform var(--t) var(--ease); }
.acc.is-open .acc__btn .plus { transform: rotate(45deg); }
.acc__panel { display: grid; grid-template-rows: 0fr; transition: grid-template-rows var(--t) var(--ease); }
.acc.is-open .acc__panel { grid-template-rows: 1fr; }
.acc__panel > div { overflow: hidden; }

/* form */
.form { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--gap); row-gap: 28px; padding: 24px 0 48px; }
.field { display: grid; gap: 6px; }
.field label { color: var(--ink-2); }
.field input, .field textarea {
  font: inherit; font-size: var(--m); letter-spacing: -0.015em; color: var(--ink);
  background: transparent; border: 0; border-bottom: 1px solid var(--line);
  padding: 6px 0 10px; border-radius: 0; outline: none; width: 100%;
  transition: border-color var(--t-fast) var(--ease);
}
.field textarea { resize: vertical; min-height: 3.4em; line-height: 1.1; }
.field input:focus, .field textarea:focus { border-bottom-color: var(--ink); }
.field input::placeholder, .field textarea::placeholder { color: var(--ink-3); }
.form .note { color: var(--ink-2); }

@media (max-width: 900px) {
  .c1, .c2, .c4, .c6, .c6w, .c9, .c10 { grid-column: 1 / -1; }
  .head { row-gap: 24px; }
  .list-row > .col-title { grid-column: 2 / span 7; }
  .list-row > .col-client, .list-row > .col-cats { display: none; }
  .list-row > .col-year { grid-column: 12 / span 1; }
  .home-intro .lede { grid-column: 1 / -1; }
  .form > * { grid-column: 1 / -1 !important; }
}

/* ==========================================================================
   v3
   ========================================================================== */
.center { text-align: center; }

/* justified rows: each item keeps its own ratio, heights match, nothing is cropped */
.jrow { grid-column: 1 / -1; display: flex; gap: var(--gap); align-items: flex-start; }
.jrow > .media { flex: var(--a) 1 0; min-width: 0; }
.cs-flow .narrow { grid-column: 4 / span 6; }

/* statements in case studies: same size as the rest, wide measure */
.statement { padding: 168px 0; }
.statement .t-m { max-width: min(980px, 92%); text-wrap: balance; }

.credit { display: grid; justify-items: start; gap: 10px; }
.credit p { max-width: 52ch; }

/* operations: soft cards, centred */
.ops-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--gap); }
.ops-card {
  display: grid; justify-items: center; align-content: start; gap: 14px; text-align: center;
  background: var(--card); border-radius: 28px; padding: 32px 28px 40px; min-height: 280px;
}
.ops-card h3 { text-wrap: balance; }
.ops-card p { max-width: 36ch; color: var(--ink-2); }

/* brief form inside the bubble */
.modal.is-wide .modal__card { width: min(680px, 100%); padding: 32px 32px 28px; }
.brief { display: grid; gap: 22px; }
.brief .field input, .brief .field textarea { font-size: var(--s); letter-spacing: 0; padding: 8px 0 10px; }
.brief .field textarea { min-height: 5em; line-height: 1.32; }
.brief__foot { display: flex; justify-content: space-between; align-items: center; gap: 16px; padding-top: 6px; }

@media (max-width: 900px) {
  .ops-grid { grid-template-columns: 1fr; }
  .jrow { flex-direction: column; }
  .jrow > .media { flex: none; width: 100%; }
  .cs-flow .narrow { grid-column: 1 / -1; }
}
/* a justified row never grows taller than the viewport */
.jrow { max-width: calc(var(--sum) * 88vh + (var(--n) - 1) * var(--gap)); margin-inline: auto; width: 100%; }

/* ==========================================================================
   v4: smoother reveals, operations table
   ========================================================================== */
:root { --ease-soft: cubic-bezier(0.16, 1, 0.3, 1); }
[data-reveal] {
  transform: translateY(14px); filter: blur(6px);
  transition: opacity 1200ms var(--ease-soft), transform 1400ms var(--ease-soft), filter 1200ms var(--ease-soft);
  transition-delay: var(--d, 0ms);
}
.lines .ln > span {
  transform: translateY(0.18em); filter: blur(4px);
  transition: opacity 1100ms var(--ease-soft), transform 1300ms var(--ease-soft), filter 1100ms var(--ease-soft);
  transition-delay: calc(min(var(--i, 0), 30) * 18ms);
}
.about-statement p.soft { will-change: opacity, transform, filter; }

.pill-chip {
  display: inline-flex; align-items: center; height: 26px; padding: 0 12px;
  border-radius: 999px; background: var(--card); color: var(--ink);
}
.ops-table {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  margin-inline: calc((100% - 11 * var(--gap)) / 12 * 0.35);
  border-top: 1px solid var(--line);
}
.ops-col {
  display: grid; justify-items: center; align-content: start; text-align: center;
  padding: 40px clamp(20px, 3vw, 64px) 72px;
  border-left: 1px solid var(--line);
}
.ops-col:nth-child(3n + 1) { border-left: 0; }
.ops-col:nth-child(n + 4) { border-top: 1px solid var(--line); }
.ops-title { font-size: clamp(18px, 0.7rem + 0.7vw, 22px); line-height: 1.15; letter-spacing: -0.01em; margin: 40px 0 28px; text-wrap: balance; }
.ops-col p { color: var(--ink-2); max-width: 44ch; text-wrap: pretty; }

@media (max-width: 900px) {
  .ops-table { grid-template-columns: 1fr; margin-inline: 0; }
  .ops-col { border-left: 0; }
  .ops-col + .ops-col { border-top: 1px solid var(--line); }
}
/* about: paragraphs separated by an empty line, no indent */
.about-statement p + p { text-indent: 0; margin-top: 1.1em; }

/* work: editorial grid of mixed formats, cards sharpen as they reach the middle of the screen */
.show-grid { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--gap); row-gap: 72px; align-items: start; }
.show-grid .card .media { container-type: inline-size; }
.show-grid .card .overlay .t-l { font-size: clamp(26px, 7.5cqw, 64px); }
.card.is-focus .cover { filter: blur(0) saturate(100%); transform: scale(1.02); }
.card.is-focus .overlay { opacity: 0; transform: scale(0.98); filter: blur(8px); }
@media (hover: hover) {
  /* on desktop the hover decides; scroll focus is for touch screens */
  .card.is-focus:not(:hover) .cover { filter: blur(26px) saturate(115%); transform: scale(1.18); }
  .card.is-focus:not(:hover) .overlay { opacity: 1; transform: none; filter: none; }
}
@media (max-width: 900px) {
  .show-grid { row-gap: 32px; }
  .show-grid .card { grid-column: 1 / -1 !important; }
}
/* about: Mouthwash style breakers, right half only */
.breaker { padding: 22px 0 96px; position: relative; }
.breaker::before { content: ""; position: absolute; top: 0; right: 0; left: calc((100% - 11 * var(--gap)) / 12 * 6 + 6 * var(--gap)); border-top: 1px solid var(--line); }
.breaker .ops-title { margin: 0 0 18px; }
.breaker p.ops-title { margin: 0; max-width: 30ch; }
.breaker a.u:hover { color: var(--ink); }
@media (max-width: 900px) {
  .breaker > div { grid-column: 1 / -1 !important; margin-bottom: 28px; }
  .breaker::before { left: 0; }
  .breaker { padding-bottom: 40px; }
}

/* natural ratios everywhere: rows of cards share a height, widths follow each format */
.show-rows { display: grid; row-gap: 72px; }
.card-row { display: flex; gap: var(--gap); align-items: flex-start; max-width: calc(var(--sum) * 82vh + (var(--n) - 1) * var(--gap)); margin-inline: auto; width: 100%; }
.card-row > .card { flex: var(--a) 1 0; min-width: 0; }
.card .media { aspect-ratio: var(--ar, 1); }
.card .overlay .t-l { font-size: clamp(24px, 7cqw, 64px); }
.card .media { container-type: inline-size; }
.rail__track .card { width: calc(min(68vh, 760px) * var(--a)); }
@media (max-width: 900px) {
  .show-rows { row-gap: 32px; }
  .card-row { flex-direction: column; max-width: none; }
  .card-row > .card { flex: none; width: 100%; }
}
@media (max-width: 640px) { .rail__track .card { width: 100%; } }

/* cards: one title size everywhere, chips and titles anchored to the same height */
.card .overlay { display: block; }
.card .overlay .ov {
  position: absolute; left: 20px; right: 20px; top: 50%; transform: translateY(-36px);
  display: grid; justify-items: center; gap: 12px; text-align: center;
}
.card .overlay .t-m { font-size: var(--m); line-height: 1.05; letter-spacing: -0.02em; text-wrap: balance; }
.card .overlay .chips { justify-content: center; }
.card .overlay .t-l, .show-grid .card .overlay .t-l { font-size: var(--m); }

/* home entrance after the loader: lines rise out of blur one after another */
.home-intro .lede .enter { display: block; }
.rail__track { transition: none !important; }

/* header: wordmark left, navigation centred, clock and theme right */
.header .nav { justify-self: center; }
.header .nav-wrap { justify-self: end; gap: 14px; }
.header .clock { justify-self: auto; }
.header .wordmark, .header .nav, .header .nav-wrap {
  opacity: 0; transform: translateY(-10px); filter: blur(6px);
  transition: opacity var(--t-slow) var(--ease), transform var(--t-slow) var(--ease), filter var(--t-slow) var(--ease);
}
body.is-ready .header .nav { opacity: 1; transform: none; filter: none; transition-delay: 90ms; }
@media (max-width: 900px) {
  .header { grid-template-columns: auto 1fr auto; }
  .header .nav { justify-self: center; }
  .header .clock { display: none; }
}

/* top edge v2: six blur layers, each fading in and out, so there is no visible seam */
.edge { height: 170px; }
.edge > div { position: absolute; inset: 0; }
.edge > div:nth-child(1) { -webkit-backdrop-filter: blur(0.5px); backdrop-filter: blur(0.5px);
  -webkit-mask: linear-gradient(to bottom, #000 0%, #000 55%, transparent 100%); mask: linear-gradient(to bottom, #000 0%, #000 55%, transparent 100%); }
.edge > div:nth-child(2) { -webkit-backdrop-filter: blur(1px); backdrop-filter: blur(1px);
  -webkit-mask: linear-gradient(to bottom, #000 0%, #000 45%, transparent 88%); mask: linear-gradient(to bottom, #000 0%, #000 45%, transparent 88%); }
.edge > div:nth-child(3) { -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  -webkit-mask: linear-gradient(to bottom, #000 0%, #000 35%, transparent 76%); mask: linear-gradient(to bottom, #000 0%, #000 35%, transparent 76%); }
.edge > div:nth-child(4) { -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
  -webkit-mask: linear-gradient(to bottom, #000 0%, #000 25%, transparent 64%); mask: linear-gradient(to bottom, #000 0%, #000 25%, transparent 64%); }
.edge > div:nth-child(5) { -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  -webkit-mask: linear-gradient(to bottom, #000 0%, #000 15%, transparent 52%); mask: linear-gradient(to bottom, #000 0%, #000 15%, transparent 52%); }
.edge > div:nth-child(6) { -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  -webkit-mask: linear-gradient(to bottom, #000 0%, transparent 40%); mask: linear-gradient(to bottom, #000 0%, transparent 40%); }
/* liquid distortion only in the top band, where it fades out softly */
.has-liquid .edge > div:nth-child(2) { -webkit-backdrop-filter: blur(1px); backdrop-filter: blur(1px); }
.has-liquid .edge > div:nth-child(6) {
  -webkit-backdrop-filter: url(#liquid) blur(14px); backdrop-filter: url(#liquid) blur(14px);
}
.edge::after { background: linear-gradient(to bottom, color-mix(in srgb, var(--bg) 62%, transparent) 0%, color-mix(in srgb, var(--bg) 25%, transparent) 30%, transparent 62%); }

/* rail: label and rule live inside the pinned view */
.rail__head { padding: 0 var(--pad) 16px; }
.c7 { grid-column: 7 / span 3; }
@media (max-width: 900px) { .c7 { grid-column: 1 / -1; } }
/* home intro sits on the 12 column grid; the meta row spans the full width */
.home-intro { grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--gap); }
.home-intro .meta { grid-column: 1 / -1; }
@media (max-width: 900px) { .home-intro .lede { grid-column: 1 / -1; } }
.home-intro .meta .c4 { grid-column: 4 / span 3; }
.home-intro .meta .c7 { grid-column: 7 / span 3; }
@media (max-width: 900px) { .home-intro .meta .c4, .home-intro .meta .c7 { grid-column: 1 / -1; } }

/* ==========================================================================
   performance: fewer full-screen filters, no backdrop blur over playing video,
   no blur on whole-page transitions
   ========================================================================== */
.edge > div:nth-child(1) { -webkit-backdrop-filter: blur(1px); backdrop-filter: blur(1px);
  -webkit-mask: linear-gradient(to bottom, #000 0%, #000 50%, transparent 100%); mask: linear-gradient(to bottom, #000 0%, #000 50%, transparent 100%); }
.edge > div:nth-child(2) { -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
  -webkit-mask: linear-gradient(to bottom, #000 0%, #000 30%, transparent 80%); mask: linear-gradient(to bottom, #000 0%, #000 30%, transparent 80%); }
.edge > div:nth-child(3) { -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px);
  -webkit-mask: linear-gradient(to bottom, #000 0%, #000 15%, transparent 60%); mask: linear-gradient(to bottom, #000 0%, #000 15%, transparent 60%); }
.edge > div:nth-child(4) { -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  -webkit-mask: linear-gradient(to bottom, #000 0%, transparent 40%); mask: linear-gradient(to bottom, #000 0%, transparent 40%); }
.has-liquid .edge > div:nth-child(2) { -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); }
.has-liquid .edge > div:nth-child(4) { -webkit-backdrop-filter: url(#liquid) blur(14px); backdrop-filter: url(#liquid) blur(14px); }

.chip--glass { -webkit-backdrop-filter: none; backdrop-filter: none; background: rgba(40, 40, 42, 0.32); }
main.is-leaving { filter: none; }
main { transition: opacity 320ms var(--ease), transform 320ms var(--ease); }

/* cards: isolate their paint, animate only opacity and transform on reveal */
.card .media { contain: paint; }
.card .cover { will-change: transform; }
.card[data-reveal], .rail__reveal[data-reveal] { filter: none !important; }
.preview { left: 0; top: 0; transition: opacity 360ms var(--ease), filter 360ms var(--ease); }

/* wordmark: plain text that softly blurs on hover, inviting a click */
.header .wordmark { transition: opacity 900ms var(--ease), transform 900ms var(--ease), filter 500ms var(--ease-soft, ease-out); }
@media (hover: hover) {
  body.is-ready .header .wordmark:hover { filter: blur(2.5px); }
}
body.is-ready .header .wordmark:active { filter: blur(4px); }

/* contact: the question owns the whole first screen, details sit right above the footer */
.contact-hero { min-height: calc(100vh - var(--header-h) - 96px); padding: 0; align-content: center; }
.contact-info { margin-top: 24vh; }
.contact-info + * { margin-top: 0; }
.page:has(.contact-info) { padding-bottom: 0; }
.page:has(.contact-info) + .footer { padding-top: 48px; }

/* contact v2: everything on one screen. The question takes the free space,
   the details sit directly on the footer rule */
.contact-page { min-height: 100vh; display: flex; flex-direction: column; }
.contact-page > .page { flex: 1; display: flex; flex-direction: column; padding-bottom: 0; }
.contact-page .contact-hero { flex: 1; min-height: 0; padding: 48px 0; }
.contact-page .contact-info { margin-top: 0; }
.contact-page .contact-info .list-row:last-child { border-bottom: 0; }
.contact-page > .page + .footer { padding-top: 1px; }
.contact-page > .footer .head.sp-3:first-of-type { margin-top: 48px; }
.cs-lead { max-width: 52ch; }
.loader { transition: opacity 500ms cubic-bezier(0.65, 0, 0.35, 1); }

/* one pill everywhere: category chips, the View cursor and the list preview title
   share the liquid glass look, 24px high, fully round like the header nav.
   Chips sit on already blurred video, so they skip backdrop-filter (cheap). */
.chip--glass, .cursor, .preview .pill {
  height: 24px; padding: 0 10px; display: inline-flex; align-items: center;
  border-radius: 999px; font-size: var(--s); line-height: 1; color: #fff;
  background: rgba(255, 255, 255, 0.16);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35), inset 0 0 0 1px rgba(255, 255, 255, 0.12);
}
.cursor, .preview .pill {
  -webkit-backdrop-filter: blur(14px) saturate(160%); backdrop-filter: blur(14px) saturate(160%);
}
.card.is-ph .chip--glass, .preview .ph + .pill, .preview.is-ph .pill { color: var(--ink); background: rgba(255, 255, 255, 0.55); }

/* nothing stands out: every button and pill is the same liquid glass.
   40px = things you click (nav, segment, buttons), 24px = labels.
   On light surfaces the glass is light with dark text, on video it is clear with white text. */
.pill-chip {
  height: 24px; padding: 0 10px; border-radius: 999px; font-size: var(--s); line-height: 1;
  background: var(--glass); color: var(--ink);
  box-shadow:
    inset 0 1px 0 var(--glass-edge),
    inset 0 -1px 0 var(--glass-shade),
    inset 0 0 0 1px rgba(255, 255, 255, 0.08),
    0 8px 30px -12px rgba(0, 0, 0, 0.12);
}
.chip--glass, .cursor, .preview .pill { box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35), inset 0 0 0 1px rgba(255, 255, 255, 0.12), 0 8px 30px -12px rgba(0, 0, 0, 0.12); }

/* Operations live in a bubble on About, opened like "Tell me about it" */
.ops-list { display: grid; grid-template-columns: 1fr 1fr; gap: 40px 32px; }
.ops-item { display: grid; justify-items: start; gap: 12px; }
.ops-item .t-m { line-height: 1.1; }
.ops-item p { margin: 0; max-width: 46ch; }
@media (max-width: 640px) { .ops-list { grid-template-columns: 1fr; gap: 32px; } }
.ops-item { grid-row: span 3; grid-template-rows: subgrid; align-items: end; row-gap: 12px; }
.ops-item .num { align-self: start; }
.ops-item p { align-self: start; }

/* Operations bubble v2: one row per principle on a 12-col grid
   (number, title, text), hairline between rows */
.modal.is-ops .modal__card { width: min(1000px, 100%); padding: 32px 32px 28px; }
.ops-list { display: block; }
.ops-item {
  display: grid; grid-template-columns: repeat(12, 1fr); column-gap: 16px; row-gap: 0;
  grid-row: auto; align-items: start; padding: 20px 0; border-top: 1px solid var(--line);
}
.ops-item:first-child { border-top: 0; padding-top: 8px; }
.ops-item .num { grid-column: 1 / span 1; justify-self: start; }
.ops-item .t-m { grid-column: 2 / span 4; line-height: 1.1; }
.ops-item p { grid-column: 6 / span 6; max-width: none; margin: 0; }
.ops-item .num, .ops-item p { align-self: start; }
@media (max-width: 640px) {
  .ops-item .num { grid-column: 1 / -1; }
  .ops-item .t-m, .ops-item p { grid-column: 1 / -1; margin-top: 10px; }
}
/* title same size as the text, only darker; number, title and text share one baseline */
.ops-item { align-items: first baseline; }
.ops-item .num, .ops-item .ops-name, .ops-item p { align-self: first baseline; }
.ops-item .ops-name { grid-column: 2 / span 4; color: var(--ink); }
/* Operations bubble v3: same card as the case study "Read more", no numbers,
   narrower; the label sits centred in a pill */
.modal.is-ops .modal__card { width: min(760px, 100%); padding: 28px 28px 32px; }
.ops-item .ops-name { grid-column: 1 / span 4; }
.ops-item p { grid-column: 5 / span 8; }
.ops-item:first-child { padding-top: 12px; }

/* Operations bubble: the card stays put and only the content scrolls, so
   "Operations" and × behave like the site header, with the same soft blur under them */
.modal.is-ops .modal__card { padding: 0; overflow: hidden; display: flex; flex-direction: column; }
.modal.is-ops #modal-body { overflow: auto; max-height: 80vh; padding: 0 28px 32px; overscroll-behavior: contain; }
.modal.is-ops .modal__close { z-index: 3; }
.modal-head { position: sticky; top: 0; z-index: 2; padding: 18px 0 56px; margin-bottom: -16px; }
.modal-head .pill-chip { position: relative; z-index: 1; }
.modal-head::before, .modal-head::after { content: ""; position: absolute; inset: 0 -28px; pointer-events: none; }
.modal-head::before {
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  -webkit-mask: linear-gradient(to bottom, #000 0%, #000 45%, transparent 100%); mask: linear-gradient(to bottom, #000 0%, #000 45%, transparent 100%);
}
.modal-head::after { background: linear-gradient(to bottom, var(--bg) 0%, color-mix(in srgb, var(--bg) 80%, transparent) 45%, transparent 100%); }
/* label back to the plain grey caption, left, on the × line */
.modal-head { padding-top: 21.5px; }
.modal-head > span { position: relative; z-index: 1; }
/* grey chips keep their colour, fully round like every other button */
.chip, .list-row .chips .chip { border-radius: 999px; }

/* plain text: words inside a small radius around the cursor blur, strongest at the centre;
   the filter eases so the blur trails the cursor smoothly */
.bl { transition: filter 450ms var(--ease); }

/* top edge v3: no opacity fade (an ancestor with opacity < 1 makes Chromium drop and re-grab the
   backdrop, which flickers) and no SVG displacement in the backdrop (glitches over video).
   The band slides in from above instead, so every blur layer stays live the whole time. */
.edge { opacity: 1 !important; transform: translate3d(0, -100%, 0); transition: transform 600ms var(--ease); will-change: transform; }
body.is-scrolled .edge { transform: translate3d(0, 0, 0); }
.has-liquid .edge > div:nth-child(4) { -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px); }

/* clickable titles roll: each letter slides up to an identical copy below it, staggered.
   Plain text blurs, links roll, so what can be clicked reads differently. */
.roll-w { display: inline-block; white-space: nowrap; }
.roll-c { display: inline-block; overflow: hidden; vertical-align: top; height: 1.12em; line-height: 1.12; }
/* split-text roll: the moment the cursor touches the words every letter slides up in a quick
   wave and a grey copy comes in from below; on leave it waves straight back the same way */
.roll-c > span { display: block; text-shadow: 0 1.12em 0 var(--ink-2);
  transition: transform 300ms cubic-bezier(0.7, 0, 0.3, 1) calc(var(--i) * 14ms); }
@media (hover: hover) { .roll:hover .roll-c > span { transform: translateY(-1.12em); } }
.next .t-m { filter: none !important; }

/* big text: 36px on 36px everywhere */
.t-m { line-height: 1; }

/* Read more: label, statement, a hairline, then the text with room to breathe */
.modal__card .more-title { margin-top: 40px; padding-bottom: 32px; position: relative; }
.modal__card .more-title::after { content: ""; position: absolute; left: -16px; right: -16px; bottom: 0; border-bottom: 1px solid var(--line); }
.modal__card .more-body { margin-top: 48px; }


/* case study head: title, and straight underneath the short description in grey, same size */
.cs-head .cs-sub { color: var(--ink-2); grid-column: 1 / span 8; margin-top: 0; }
.cs-head { row-gap: 0; }

.roll { display: inline-block; }

/* next project: the title waits out of focus, like the cards, and sharpens the moment the
   cursor reaches it */
.next-title { display: inline-block; transition: filter 450ms var(--ease), opacity 450ms var(--ease); }
@media (hover: hover) {
  .next-title { filter: blur(6px); opacity: 0.85; }
  .next-title:hover { filter: none; opacity: 1; }
}
/* slower, softer reveal: sharpens over ~1.1s on a gentle ease-out, settles back a little quicker */
.next-title { transition: filter 800ms cubic-bezier(0.33, 1, 0.68, 1), opacity 800ms cubic-bezier(0.33, 1, 0.68, 1); }
@media (hover: hover) { .next-title:hover { transition-duration: 1100ms; transition-timing-function: cubic-bezier(0.22, 1, 0.36, 1); } }

/* next project, wave version: a soft blur keeps travelling left to right through the letters,
   like the cursor lens over plain text, inviting a hover. On hover the whole wave fades out
   smoothly (--k eases to 0) and the title sits sharp. */
@property --b { syntax: "<length>"; inherits: false; initial-value: 0px; }
@property --k { syntax: "<number>"; inherits: true; initial-value: 1; }
.next-title.wave { filter: none; opacity: 1; --k: 1; transition: --k 1100ms cubic-bezier(0.22, 1, 0.36, 1); }
.next-title.wave .wv { display: inline-block; filter: blur(calc(var(--b) * var(--k)));
  animation: next-wave 2600ms cubic-bezier(0.45, 0, 0.55, 1) infinite; animation-delay: calc(var(--i) * 55ms); }
@keyframes next-wave {
  0%, 100% { --b: 1.5px; }
  22% { --b: 6px; }
  48% { --b: 1.5px; }
}
@media (hover: hover) { .next-title.wave:hover { filter: none; --k: 0; } }
@media (prefers-reduced-motion: reduce) { .next-title.wave .wv { animation: none; filter: none; } }
.next-title.wave .wv { animation-fill-mode: both; }
/* wave v2: quicker, softer curve, strong enough that the name can't quite be read until hovered */
.next-title.wave .wv { animation: next-wave2 1800ms cubic-bezier(0.37, 0, 0.63, 1) infinite both; animation-delay: calc(var(--i) * 40ms); }
@keyframes next-wave2 {
  0%, 100% { --b: 5px; }
  35% { --b: 11px; }
  70% { --b: 5px; }
}
.cs-head .cs-sub { grid-column: 1 / span 6; text-wrap: balance; }
/* big text: 36px on 38px (same ratio when the size scales down) */
.t-m { line-height: 1.0556; }

/* ==========================================================================
   phone and tablet: hover is replaced by scroll and touch
   - cards sharpen when they reach the middle of the screen (is-focus)
   - plain text: the blur lens follows the finger
   - next project: the wave clears when the title reaches the middle
   - everything you can press gives a small press-in
   ========================================================================== */
@media (hover: none) {
  .next.is-armed .next-title.wave { --k: 0; }
  .card.is-armed .cover { filter: blur(0) saturate(100%); transform: scale(1.02); }
  .card.is-armed .overlay { opacity: 0; transform: scale(0.98); filter: blur(8px); }
  .btn, .card, .list-row, .nav a, .next-title, .chip, .copy { -webkit-tap-highlight-color: transparent; }
  .btn:active, .card:active .media, .list-row:active, .copy:active { transform: scale(0.97); transition: transform 120ms var(--ease); }
  .card .media, .list-row { transition: transform 360ms var(--ease); }
}
@media (max-width: 640px) {
  /* every caption column stacks full width, in reading order */
  .head > * { grid-column: 1 / -1 !important; }
  .home-intro .meta { row-gap: 24px; }
  .cs-info { row-gap: 20px; }
  .footer .head .t-m { margin-bottom: 8px; }
}

/* next project wave, text-shadow version: the letters are drawn by their own shadow, so the blur
   has no box edge (Safari clips filter blur on small inline boxes). Blur 0 = the crisp letter. */
.next-title.wave .wv { filter: none !important; color: transparent;
  text-shadow: 0 0 calc(var(--b) * var(--k) * 1.6 + 0.001px) var(--ink); }

/* footer bottom row stays one line on phones: copyright left, back to top right */
@media (max-width: 640px) {
  .footer .head.t-s.grey > .c1 { grid-column: 1 / span 6 !important; }
  .footer .head.t-s.grey > .c10 { grid-column: 7 / -1 !important; }
}

/* iPhone draws the page under the status bar too: carry the top blur up to the very edge */
.edge::before { content: ""; position: absolute; left: 0; right: 0; bottom: 100%; height: 160px;
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  background: color-mix(in srgb, var(--bg) 62%, transparent); }

/* iOS: no grey tap box on links and buttons; the press feedback is our own */
a, button, [data-card], .next { -webkit-tap-highlight-color: transparent; }
@media (hover: none) { .next:active { background: none; } .next-title { transform: none !important; } }

/* iPhone status bar: Safari tints the area behind the clock and battery from the page background
   and from a solid fixed strip on the top edge. Give it both, in the current theme colour, so
   content never shows sharp up there; the progressive blur then starts right under it. */
html { background: var(--bg); }
.topbar-tint { position: fixed; top: 0; left: 0; right: 0; height: max(1px, env(safe-area-inset-top, 0px));
  background: var(--bg); z-index: 49; pointer-events: none; }
.edge { height: calc(170px + env(safe-area-inset-top, 0px)); }
/* touch screens never show the View cursor or the list preview */
@media (hover: none) { .cursor, .preview { display: none !important; } }
/* status bar tint strip: tall enough for Safari to pick it up as the top bar colour */
.topbar-tint { height: max(12px, env(safe-area-inset-top, 0px)); }

/* status-bar experiments reverted: Safari ignores them and the strip only drew a dark band */
.topbar-tint { display: none !important; }
.edge::before { display: none; }
/* phones, All work: Type and Service filters side by side; count and Grid/Text toggle on one line */
@media (max-width: 640px) {
  .head > .legend.c6 { grid-column: 1 / span 5 !important; }
  .head > .legend.c9 { grid-column: 6 / -1 !important; }
  .head > #work-count { grid-column: 1 / span 6 !important; }
  .head > .c10:has(#seg) { grid-column: 7 / -1 !important; }
}
/* phones: cards show at most three categories, so chips stay on one line and titles line up */
@media (max-width: 640px) { .card .chips .chip:nth-child(n+4) { display: none; } }
/* phones, case study info: each label sits to the left of its value, like the contact rows */
@media (max-width: 640px) {
  .cs-info > div { display: grid; grid-template-columns: 4fr 8fr; column-gap: var(--gap); align-items: first baseline; }
  .cs-info > div > .k { grid-column: 1; }
  .cs-info > div > :not(.k) { grid-column: 2; }
  .cs-info { row-gap: 14px; }
}
@media (max-width: 640px) {
  .cs-info > div:has(.chips) { align-items: start; }
  .cs-info > div:has(.chips) > .k { line-height: 24px; }
}
/* chips under or beside a label: the chip text lines up with the text column, not the pill edge */
.cs-info .chips { margin-left: -10px; }

/* work cards: title and category chips in a soft grey-white instead of pure white */
:root { --on-media: rgba(255, 255, 255, 0.6); }
.card .overlay, .card .overlay .t-m, .card .chip--glass { color: var(--on-media); }
/* card text uses the exact grey of the header navigation */
:root, :root[data-theme="dark"] { --on-media: var(--ink-2); }
/* title stays white; only the category chips take the header grey */
.card .overlay, .card .overlay .t-m { color: #fff; }
/* chips a touch lighter than the header grey */
.card .chip--glass { color: color-mix(in srgb, var(--ink-2) 72%, #fff); }

/* card overlay: the title sits exactly in the middle of the card; the categories sit right above
   it (two equal flexible rows around the title keep it centred whatever the chips do) */
.card .overlay .ov {
  top: 0; bottom: 0; left: 20px; right: 20px; transform: none;
  grid-template-rows: 1fr auto 1fr; align-items: center; gap: 0;
}
.card .overlay .ov > .chips { grid-row: 1; align-self: end; margin-bottom: 12px; }
.card .overlay .ov > .t-m { grid-row: 2; }
/* credits: their own row under Client / Year / Services, same label style */
.cs-info .cs-credits { margin-top: 8px; }
/* services chips align by their pill edge again (reverted the text-edge alignment) */
.cs-info .chips { margin-left: 0; }

/* ==========================================================================
   modal as liquid glass: the page stays visible behind (lighter backdrop blur),
   the card itself is translucent frosted glass with a bright rim and a very
   faint grain, so it reads like a pane of glass but text stays legible
   ========================================================================== */
:root {
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.5  0 0 0 0 0.5  0 0 0 0 0.5  0 0 0 0.09 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
.modal {
  background: color-mix(in srgb, var(--bg) 18%, transparent);
  -webkit-backdrop-filter: blur(9px) saturate(115%); backdrop-filter: blur(9px) saturate(115%);
}
.modal__card {
  background-color: color-mix(in srgb, var(--bg) 62%, transparent);
  background-image: var(--grain), linear-gradient(160deg, rgba(255, 255, 255, 0.28), rgba(255, 255, 255, 0) 45%);
  -webkit-backdrop-filter: blur(26px) saturate(170%); backdrop-filter: blur(26px) saturate(170%);
  box-shadow:
    inset 0 1px 0 var(--glass-edge),
    inset 0 0 0 1px rgba(255, 255, 255, 0.28),
    inset 0 -1px 0 var(--glass-shade),
    0 30px 80px -32px rgba(0, 0, 0, 0.28);
}
:root[data-theme="dark"] .modal__card { background-image: var(--grain), linear-gradient(160deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0) 45%); box-shadow: inset 0 1px 0 var(--glass-edge), inset 0 0 0 1px rgba(255, 255, 255, 0.08), 0 30px 80px -32px rgba(0, 0, 0, 0.6); }
.modal__close { background: color-mix(in srgb, var(--bg) 55%, transparent); box-shadow: inset 0 1px 0 var(--glass-edge), inset 0 0 0 1px rgba(255, 255, 255, 0.2); }
/* Operations bubble: its sticky head fades into the glass instead of a solid colour */
.modal-head::after { background: linear-gradient(to bottom, color-mix(in srgb, var(--bg) 70%, transparent) 0%, color-mix(in srgb, var(--bg) 35%, transparent) 50%, transparent 100%); }

/* liquid glass rim (Apple-like): a soft band along every edge bends the page behind the pane,
   and a thin specular rim catches light top-left and bottom-right. The bend needs SVG filters in
   backdrop-filter (Chromium); elsewhere the rim light alone carries the effect. */
.modal__card { isolation: isolate; }
.modal__card > * { position: relative; z-index: 2; }
.modal__card > .modal__close { position: absolute; z-index: 3; }
.modal__card::before, .modal__card::after { content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; }
.modal__card::before {
  z-index: 0;
  -webkit-backdrop-filter: blur(3px) saturate(180%) brightness(1.06); backdrop-filter: blur(3px) saturate(180%) brightness(1.06);
  -webkit-mask: linear-gradient(to right, #000, transparent 26px, transparent calc(100% - 26px), #000), linear-gradient(to bottom, #000, transparent 26px, transparent calc(100% - 26px), #000);
          mask: linear-gradient(to right, #000, transparent 26px, transparent calc(100% - 26px), #000), linear-gradient(to bottom, #000, transparent 26px, transparent calc(100% - 26px), #000);
}
.has-liquid .modal__card::before { -webkit-backdrop-filter: url(#glassrim) blur(2px) saturate(180%) brightness(1.06); backdrop-filter: url(#glassrim) blur(2px) saturate(180%) brightness(1.06); }
.modal__card::after {
  z-index: 1; padding: 1.2px;
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.95), rgba(255, 255, 255, 0.25) 22%, rgba(255, 255, 255, 0) 45%, rgba(255, 255, 255, 0) 60%, rgba(255, 255, 255, 0.45) 88%, rgba(255, 255, 255, 0.8));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor;
          mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
}
:root[data-theme="dark"] .modal__card::after { opacity: 0.45; }

/* clickable buttons: a quick focus pull on hover, the pill slips out of focus and snaps back sharp,
   and the glass brightens a touch */
@keyframes focus-pull { 0% { filter: blur(0); } 38% { filter: blur(2.6px); } 100% { filter: blur(0); } }
@media (hover: hover) {
  .btn:hover, .nav a:not(.is-active):hover, .modal__close:hover { animation: focus-pull 560ms cubic-bezier(0.33, 1, 0.68, 1); }
  .btn.glass:hover { background-color: color-mix(in srgb, var(--glass) 70%, #fff 30%); }
  :root[data-theme="dark"] .btn.glass:hover { background-color: color-mix(in srgb, var(--glass) 80%, #fff 8%); }
}
@media (prefers-reduced-motion: reduce) { .btn:hover, .nav a:hover, .modal__close:hover { animation: none !important; } }

/* ==========================================================================
   liquid glass v2 (replaces the rim band): refraction comes from a per-shape
   displacement map (see liquid() in app.js), so the edges bend what's behind.
   ========================================================================== */
@property --lg-blur { syntax: "<length>"; inherits: false; initial-value: 2px; }
@property --lg-sat { syntax: "<number>"; inherits: false; initial-value: 1.7; }
.lg.lg {
  -webkit-backdrop-filter: blur(var(--lg-blur)) var(--lg, ) saturate(var(--lg-sat)) brightness(1.04) !important;
          backdrop-filter: blur(var(--lg-blur)) var(--lg, ) saturate(var(--lg-sat)) brightness(1.04) !important;
}
.btn.lg, .theme-toggle.lg { transition: --lg-blur 420ms cubic-bezier(0.22, 1, 0.36, 1), transform 520ms cubic-bezier(0.34, 1.4, 0.64, 1), background-color 420ms var(--ease), opacity var(--t) var(--ease), filter var(--t) var(--ease); }
.modal__card::before { display: none; }
/* specular rim on every glass pill too, like the modal */
.btn.glass, .theme-toggle, .nav, .seg { position: relative; }
.btn.glass::after, .theme-toggle::after, .nav::after, .seg::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; padding: 1px;
  background: linear-gradient(135deg, rgba(255,255,255,0.95), rgba(255,255,255,0.2) 25%, rgba(255,255,255,0) 50%, rgba(255,255,255,0.35) 85%, rgba(255,255,255,0.7));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor;
          mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
}
:root[data-theme="dark"] .btn.glass::after, :root[data-theme="dark"] .theme-toggle::after, :root[data-theme="dark"] .nav::after, :root[data-theme="dark"] .seg::after { opacity: 0.35; }

/* ==========================================================================
   button hover: "focus swap". The resting glass is slightly frosted; on hover the
   glass clears into a pure lens (blur off, refraction shows), the pill swells a
   touch on a soft spring, and the label is swapped: the old word drifts up and
   dissolves into blur while a sharp copy rises from below. The + turns a quarter,
   arrows dissolve and re-form. Leaving runs it all back.
   ========================================================================== */
.btn .btn-l { display: inline-grid; vertical-align: top; }
.btn .btn-l > span { grid-area: 1 / 1; transition: transform 460ms cubic-bezier(0.22, 1, 0.36, 1), filter 460ms cubic-bezier(0.22, 1, 0.36, 1), opacity 460ms cubic-bezier(0.22, 1, 0.36, 1); }
.btn .btn-l > span + span { transform: translateY(70%); filter: blur(6px); opacity: 0; }
.btn .arrow { display: inline-block; transition: transform 520ms cubic-bezier(0.34, 1.4, 0.64, 1), filter 380ms var(--ease), opacity 380ms var(--ease); }
@media (hover: hover) {
  .btn:hover, .nav a:not(.is-active):hover, .modal__close:hover { animation: none; }
  .btn.glass:hover { --lg-blur: 0px; transform: scale(1.04); background-color: color-mix(in srgb, var(--glass) 55%, transparent); }
  .btn:hover .btn-l > span:first-child { transform: translateY(-70%); filter: blur(6px); opacity: 0; }
  .btn:hover .btn-l > span + span { transform: none; filter: none; opacity: 1; }
  .btn:hover .arrow { transform: none; animation: arrow-reform 520ms cubic-bezier(0.22, 1, 0.36, 1); }
  .btn[data-more]:hover .arrow, .btn[data-ops]:hover .arrow, .btn[data-brief]:hover .arrow { animation: none; transform: rotate(90deg); }
  .theme-toggle.lg:hover { --lg-blur: 0px; transform: scale(1.06); }
}
@keyframes arrow-reform { 0% { filter: blur(0); opacity: 1; } 40% { filter: blur(5px); opacity: 0.2; } 100% { filter: blur(0); opacity: 1; } }
.btn:active { transform: scale(0.97) !important; }
/* less blur on the page behind the modal, so the glass rim has detail to bend */
.modal { -webkit-backdrop-filter: blur(5px) saturate(112%); backdrop-filter: blur(5px) saturate(112%); }

/* ==========================================================================
   buttons v3: white at rest; on hover a soft, blurred black pill blooms behind
   the label (the shape itself is out of focus, the text stays crisp and turns
   white), and the + makes a quarter turn. Replaces the label swap.
   ========================================================================== */
.btn.glass {
  background: #fff; color: var(--ink); isolation: isolate;
  -webkit-backdrop-filter: none !important; backdrop-filter: none !important;
  box-shadow: 0 8px 26px -14px rgba(0, 0, 0, 0.22);
  transition: color 420ms var(--ease), background-color 420ms var(--ease), box-shadow 420ms var(--ease), transform var(--t-fast) var(--ease);
}
:root[data-theme="dark"] .btn.glass { color: #111; }
.btn.glass::after { display: none; }
.btn.glass::before {
  content: ""; position: absolute; inset: -2px; border-radius: inherit; z-index: -1; pointer-events: none;
  background: #111; filter: blur(9px); opacity: 0; transform: scale(0.82);
  transition: opacity 460ms cubic-bezier(0.22, 1, 0.36, 1), transform 560ms cubic-bezier(0.22, 1, 0.36, 1), filter 560ms cubic-bezier(0.22, 1, 0.36, 1);
}
.btn .btn-l > span + span { display: none; }
.btn .arrow { transition: transform 560ms cubic-bezier(0.34, 1.4, 0.64, 1); }
@media (hover: hover) {
  .btn.glass:hover { background-color: transparent; color: #fff; transform: none; box-shadow: none; }
  .btn.glass:hover::before { opacity: 0.92; transform: scale(1); filter: blur(5px); }
  .btn:hover .arrow { animation: none; filter: none; opacity: 1; transform: rotate(90deg); }
  .btn:hover .btn-l > span:first-child { transform: none; filter: none; opacity: 1; }
}

/* ==========================================================================
   modal glass material from Sven's Figma glass (light -45° 80%, refraction 100,
   depth 21, dispersion 100, frost 24, white fill 50%). Only the material changed;
   shape, radius, type colours and layout stay as they were.
   ========================================================================== */
.modal__card {
  background-color: rgba(255, 255, 255, 0.5);
  background-image: var(--grain), linear-gradient(135deg, rgba(255, 255, 255, 0.35), rgba(255, 255, 255, 0.05) 40%, rgba(255, 255, 255, 0) 60%);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.3), 0 30px 80px -30px rgba(0, 0, 0, 0.28);
}
:root[data-theme="dark"] .modal__card { background-color: rgba(40, 40, 44, 0.5); background-image: var(--grain), linear-gradient(135deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0) 50%); }
/* light from the top-left (-45°), 80%: bright rim there, softer echo bottom-right */
.modal__card::after {
  padding: 1.5px;
  background: linear-gradient(135deg, rgba(255,255,255,0.95), rgba(255,255,255,0.3) 18%, rgba(255,255,255,0) 40%, rgba(255,255,255,0) 62%, rgba(255,255,255,0.35) 86%, rgba(255,255,255,0.8));
}

/* modal glass layer: the card no longer filters its own backdrop; a layer 48px bigger on every
   side does it (so the rim can pull in what sits just outside), clipped back to the card's shape.
   The card stops clipping, the text area scrolls instead. */
.modal__card.lg { overflow: visible !important; -webkit-backdrop-filter: none !important; backdrop-filter: none !important; }
.modal__card.lg::before {
  display: block !important; content: ""; position: absolute; inset: -48px; z-index: 0; pointer-events: none;
  border-radius: 0; -webkit-mask: none; mask: none;
  clip-path: inset(48px round 28px);
  -webkit-backdrop-filter: blur(var(--lg-blur)) var(--lg, ) saturate(var(--lg-sat)) brightness(1.04);
          backdrop-filter: blur(var(--lg-blur)) var(--lg, ) saturate(var(--lg-sat)) brightness(1.04);
}
.modal:not(.is-ops) .modal__card.lg #modal-body { max-height: calc(80vh - 60px); overflow: auto; overscroll-behavior: contain; }
/* the tint and grain live on the glass layer itself, so the rim and the middle share one material */
.modal__card.lg { background-color: transparent !important; background-image: none !important; }
.modal__card.lg::before {
  background-color: rgba(255, 255, 255, 0.5);
  background-image: var(--grain), linear-gradient(135deg, rgba(255, 255, 255, 0.35), rgba(255, 255, 255, 0.05) 40%, rgba(255, 255, 255, 0) 60%);
  background-origin: content-box; padding: 48px; background-clip: content-box;
}
:root[data-theme="dark"] .modal__card.lg::before { background-color: rgba(40, 40, 44, 0.5); background-image: var(--grain), linear-gradient(135deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0) 50%); }
/* button hover: the black spreads wider and softer, so no pill edge shows */
.btn.glass::before { inset: -6px; }
@media (hover: hover) { .btn.glass:hover::before { filter: blur(13px); transform: scale(1.06); opacity: 0.95; } }
@media (hover: hover) { .btn.glass:hover::before { box-shadow: 0 0 0 5px #111; filter: blur(12px); transform: scale(1.04); opacity: 1; } }

/* ==========================================================================
   Read more / Operations / brief windows = exactly the header nav glass:
   same tint (--glass), same rim shadows, same specular edge, same refraction
   map recipe (bezel 16, scale 34, blur 2px, saturate 1.7, brightness 1.04).
   Everything earlier in this file about the modal material is overridden here.
   ========================================================================== */
.modal__card.lg {
  background-color: var(--glass) !important; background-image: none !important;
  box-shadow: inset 0 1px 0 var(--glass-edge), inset 0 -1px 0 var(--glass-shade), inset 0 0 0 1px rgba(255, 255, 255, 0.08), 0 8px 30px -12px rgba(0, 0, 0, 0.12) !important;
  -webkit-backdrop-filter: blur(var(--lg-blur)) var(--lg, ) saturate(var(--lg-sat)) brightness(1.04) !important;
          backdrop-filter: blur(var(--lg-blur)) var(--lg, ) saturate(var(--lg-sat)) brightness(1.04) !important;
}
.modal__card.lg::before { display: none !important; }
.modal__card::after {
  padding: 1px; opacity: 1;
  background: linear-gradient(135deg, rgba(255,255,255,0.95), rgba(255,255,255,0.2) 25%, rgba(255,255,255,0) 50%, rgba(255,255,255,0.35) 85%, rgba(255,255,255,0.7));
}
:root[data-theme="dark"] .modal__card::after { opacity: 0.35; }
/* page behind the window stays as sharp as it is behind the header nav */
.modal { background: transparent !important; -webkit-backdrop-filter: none !important; backdrop-filter: none !important; }

/* open/close without a glitch: the overlay itself never fades (a fading parent hides the page
   from the glass until the fade ends, then the glass pops in); only the card fades and rises */
.modal { opacity: 1 !important; visibility: hidden; transition: visibility 0s linear var(--t); }
.modal.is-open { visibility: visible; transition: visibility 0s; }
.modal__card { opacity: 0; transition: opacity var(--t) var(--ease), transform var(--t) var(--ease) !important; }
.modal.is-open .modal__card { opacity: 1; }

/* buttons v4: white at rest; on hover the pill itself turns solid black (no blur), the text turns
   white and the + makes a quarter turn */
.btn.glass::before { display: none !important; }
.btn.glass { transition: background-color 280ms var(--ease), color 280ms var(--ease), box-shadow 280ms var(--ease), transform var(--t-fast) var(--ease); }
@media (hover: hover) {
  .btn.glass:hover { background-color: #111 !important; color: #fff !important; box-shadow: 0 8px 26px -14px rgba(0, 0, 0, 0.4); }
  :root[data-theme="dark"] .btn.glass:hover { background-color: #000 !important; }
}
/* dark theme: the inverse, dark pill at rest, white on hover with dark text */
:root[data-theme="dark"] .btn.glass { background-color: #1c1c1e !important; color: #f1f1f1 !important; box-shadow: 0 8px 26px -14px rgba(0, 0, 0, 0.6); }
@media (hover: hover) {
  :root[data-theme="dark"] .btn.glass:hover { background-color: #fff !important; color: #111 !important; }
}

/* ==========================================================================
   buttons v5: the pill's outline goes soft in a blur wave that travels left to
   right (like the next-project title, but on the shape, not the text), inviting
   a click. Two copies of the pill share one moving mask band: the sharp copy
   steps aside inside the band, the blurred copy shows only there. Text stays
   crisp. Hover stops the wave and the pill turns solid black (dark theme: white).
   ========================================================================== */
.btn.glass { --pill: #fff; --pill-hover: #111; background: transparent !important; box-shadow: none !important; isolation: isolate; }
:root[data-theme="dark"] .btn.glass { --pill: #1c1c1e; --pill-hover: #fff; background: transparent !important; box-shadow: none !important; }
.btn.glass::before, .btn.glass::after {
  content: "" !important; display: block !important; position: absolute; inset: -12px; z-index: -1; pointer-events: none;
  padding: 12px; border-radius: 999px; background: var(--pill); background-clip: content-box; opacity: 1;
  filter: none; transform: none; box-shadow: none;
  -webkit-mask-size: 320% 100%; mask-size: 320% 100%; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  animation: pill-wave 3s cubic-bezier(0.45, 0, 0.55, 1) infinite;
  transition: background-color 280ms var(--ease), opacity 280ms var(--ease);
}
.btn.glass::before {
  -webkit-mask-image: linear-gradient(90deg, #000 0%, #000 42%, transparent 48%, transparent 52%, #000 58%, #000 100%);
          mask-image: linear-gradient(90deg, #000 0%, #000 42%, transparent 48%, transparent 52%, #000 58%, #000 100%);
}
.btn.glass::after {
  filter: blur(7px);
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, transparent 42%, #000 48%, #000 52%, transparent 58%, transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0%, transparent 42%, #000 48%, #000 52%, transparent 58%, transparent 100%);
}
@keyframes pill-wave {
  0% { -webkit-mask-position: 100% 0; mask-position: 100% 0; }
  62%, 100% { -webkit-mask-position: 0% 0; mask-position: 0% 0; }
}
@media (hover: hover) {
  .btn.glass:hover { background: transparent !important; box-shadow: none !important; color: var(--pill) !important; }
  .btn.glass:hover::before, .btn.glass:hover::after { background-color: var(--pill-hover); animation: none; -webkit-mask-image: none; mask-image: none; }
  .btn.glass:hover::after { opacity: 0; }
}
:root[data-theme="dark"] .btn.glass:hover { color: #111 !important; }
@media (prefers-reduced-motion: reduce) { .btn.glass::before, .btn.glass::after { animation: none; -webkit-mask-image: none; mask-image: none; } .btn.glass::after { opacity: 0; } }
/* only the blur: hover just stops the wave and the pill sits sharp; no colour change, no turning + */
@media (hover: hover) {
  .btn.glass:hover { color: var(--ink) !important; }
  :root[data-theme="dark"] .btn.glass:hover { color: #f1f1f1 !important; }
  .btn.glass:hover::before, .btn.glass:hover::after { background-color: var(--pill) !important; }
  .btn:hover .arrow, .btn[data-more]:hover .arrow, .btn[data-ops]:hover .arrow, .btn[data-brief]:hover .arrow { transform: none !important; animation: none !important; }
}
:root[data-theme="dark"] .btn.glass { color: #f1f1f1 !important; }
/* the blurred copy keeps a solid middle: it is grown a few px before blurring, so only the outline goes soft */
.btn.glass::after { box-shadow: 0 0 0 5px var(--pill) !important; filter: blur(9px); }
.btn.glass::before, .btn.glass::after { -webkit-mask-size: 260% 100%; mask-size: 260% 100%; }
.btn.glass::before {
  -webkit-mask-image: linear-gradient(90deg, #000 0%, #000 38%, transparent 46%, transparent 54%, #000 62%, #000 100%);
          mask-image: linear-gradient(90deg, #000 0%, #000 38%, transparent 46%, transparent 54%, #000 62%, #000 100%);
}
.btn.glass::after {
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, transparent 38%, #000 46%, #000 54%, transparent 62%, transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0%, transparent 38%, #000 46%, #000 54%, transparent 62%, transparent 100%);
}
.btn.glass::after { box-shadow: none !important; outline: 5px solid var(--pill); outline-offset: -12px; }
/* the sharp pill always stays whole (no see-through middle); the blurred copy only adds the soft rim */
.btn.glass::before { -webkit-mask-image: none !important; mask-image: none !important; animation: none !important; }
.btn.glass::after { outline-width: 7px; filter: blur(8px); }
/* reset the old specular-rim mask settings that clipped the blurred copy to the pill */
.btn.glass::after { -webkit-mask-origin: border-box; mask-origin: border-box; -webkit-mask-clip: border-box; mask-clip: border-box; -webkit-mask-composite: source-over; mask-composite: add; }
/* Read more window: a little whiter than the nav glass (42% → 58% white), same effect */
:root:not([data-theme="dark"]) .modal__card.lg { background-color: rgba(255, 255, 255, 0.58) !important; }

/* buttons v6: the wave dissolves the pill's edge into the page (a same-size blurred copy shows only
   inside a quick moving band, while the sharp pill steps aside there); hover = the plain button. */
.btn.glass::before {
  filter: none !important; box-shadow: none !important; transform: none !important; opacity: 1 !important;
  -webkit-mask-image: linear-gradient(90deg, #000 0%, #000 38%, transparent 46%, transparent 54%, #000 62%, #000 100%) !important;
          mask-image: linear-gradient(90deg, #000 0%, #000 38%, transparent 46%, transparent 54%, #000 62%, #000 100%) !important;
  -webkit-mask-size: 260% 100%; mask-size: 260% 100%;
  animation: pill-wave 1.5s cubic-bezier(0.45, 0, 0.55, 1) infinite !important;
}
.btn.glass::after { outline: none !important; filter: blur(7px) !important; box-shadow: none !important; transform: none !important;
  animation: pill-wave 1.5s cubic-bezier(0.45, 0, 0.55, 1) infinite !important; }
@media (hover: hover) {
  .btn.glass:hover::before { animation: none !important; -webkit-mask-image: none !important; mask-image: none !important; filter: none !important; box-shadow: none !important; transform: none !important; }
  .btn.glass:hover::after { animation: none !important; opacity: 0 !important; }
}
@media (prefers-reduced-motion: reduce) { .btn.glass::before { animation: none !important; -webkit-mask-image: none !important; mask-image: none !important; } }
/* wave timing: the blur itself crosses more slowly (~1.3s), with almost no pause before the next one */
@keyframes pill-wave2 {
  0% { -webkit-mask-position: 100% 0; mask-position: 100% 0; }
  90%, 100% { -webkit-mask-position: 0% 0; mask-position: 0% 0; }
}
.btn.glass::before, .btn.glass::after { animation-name: pill-wave2 !important; animation-duration: 1.45s !important; animation-timing-function: cubic-bezier(0.37, 0, 0.63, 1) !important; }
@media (hover: hover) { .btn.glass:hover::before, .btn.glass:hover::after { animation: none !important; } }
@media (prefers-reduced-motion: reduce) { .btn.glass::before, .btn.glass::after { animation: none !important; } }

/* Safari / iPhone: no SVG refraction in backdrop-filter, so the glass edge is built from light
   instead. A thick inner rim glows and catches the colours behind (saturated, brighter), the
   specular edge is stronger, and the middle stays the same frosted glass. */
.modal__card.lg:not(.lg-svg) {
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.35),
    inset 0 1px 1px rgba(255, 255, 255, 0.9),
    inset 0 0 18px 2px rgba(255, 255, 255, 0.55),
    inset 0 -10px 22px -12px rgba(0, 0, 0, 0.12),
    0 8px 30px -12px rgba(0, 0, 0, 0.18) !important;
  -webkit-backdrop-filter: blur(16px) saturate(2) brightness(1.06) !important;
          backdrop-filter: blur(16px) saturate(2) brightness(1.06) !important;
}
.modal__card.lg:not(.lg-svg)::after {
  padding: 1.5px;
  background: linear-gradient(135deg, rgba(255,255,255,1), rgba(255,255,255,0.35) 22%, rgba(255,255,255,0) 48%, rgba(255,255,255,0.4) 82%, rgba(255,255,255,0.9));
}
:root[data-theme="dark"] .modal__card.lg:not(.lg-svg) {
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1), inset 0 1px 1px rgba(255, 255, 255, 0.35), inset 0 0 18px 2px rgba(255, 255, 255, 0.08), 0 8px 30px -12px rgba(0, 0, 0, 0.5) !important;
}
/* dark theme wave: a wider, softer band (long ramps instead of a narrow strip) and a gentler blur,
   so the passage reads as smooth as in light mode */
:root[data-theme="dark"] .btn.glass::before {
  -webkit-mask-image: linear-gradient(90deg, #000 0%, #000 30%, rgba(0,0,0,0.35) 44%, rgba(0,0,0,0.2) 50%, rgba(0,0,0,0.35) 56%, #000 70%, #000 100%) !important;
          mask-image: linear-gradient(90deg, #000 0%, #000 30%, rgba(0,0,0,0.35) 44%, rgba(0,0,0,0.2) 50%, rgba(0,0,0,0.35) 56%, #000 70%, #000 100%) !important;
}
:root[data-theme="dark"] .btn.glass::after {
  filter: blur(10px) !important;
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, transparent 30%, rgba(0,0,0,0.65) 44%, rgba(0,0,0,0.8) 50%, rgba(0,0,0,0.65) 56%, transparent 70%, transparent 100%) !important;
          mask-image: linear-gradient(90deg, transparent 0%, transparent 30%, rgba(0,0,0,0.65) 44%, rgba(0,0,0,0.8) 50%, rgba(0,0,0,0.65) 56%, transparent 70%, transparent 100%) !important;
}
@media (hover: hover) { :root[data-theme="dark"] .btn.glass:hover::before { -webkit-mask-image: none !important; mask-image: none !important; } }
/* light theme wave = the approved dark-theme wave: wide soft band, gentle blur */
.btn.glass::before {
  -webkit-mask-image: linear-gradient(90deg, #000 0%, #000 30%, rgba(0,0,0,0.35) 44%, rgba(0,0,0,0.2) 50%, rgba(0,0,0,0.35) 56%, #000 70%, #000 100%) !important;
          mask-image: linear-gradient(90deg, #000 0%, #000 30%, rgba(0,0,0,0.35) 44%, rgba(0,0,0,0.2) 50%, rgba(0,0,0,0.35) 56%, #000 70%, #000 100%) !important;
}
.btn.glass::after {
  filter: blur(10px) !important;
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, transparent 30%, rgba(0,0,0,0.65) 44%, rgba(0,0,0,0.8) 50%, rgba(0,0,0,0.65) 56%, transparent 70%, transparent 100%) !important;
          mask-image: linear-gradient(90deg, transparent 0%, transparent 30%, rgba(0,0,0,0.65) 44%, rgba(0,0,0,0.8) 50%, rgba(0,0,0,0.65) 56%, transparent 70%, transparent 100%) !important;
}
@media (hover: hover) { .btn.glass:hover::before { -webkit-mask-image: none !important; mask-image: none !important; } }
@media (prefers-reduced-motion: reduce) { .btn.glass::before { -webkit-mask-image: none !important; mask-image: none !important; } .btn.glass::after { opacity: 0 !important; } }
/* light theme keeps the earlier, more intense wave (narrow band, sharp pill fully steps aside, blur 7px) */
:root:not([data-theme="dark"]) .btn.glass::before {
  -webkit-mask-image: linear-gradient(90deg, #000 0%, #000 38%, transparent 46%, transparent 54%, #000 62%, #000 100%) !important;
          mask-image: linear-gradient(90deg, #000 0%, #000 38%, transparent 46%, transparent 54%, #000 62%, #000 100%) !important;
}
:root:not([data-theme="dark"]) .btn.glass::after {
  filter: blur(7px) !important;
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, transparent 38%, #000 46%, #000 54%, transparent 62%, transparent 100%) !important;
          mask-image: linear-gradient(90deg, transparent 0%, transparent 38%, #000 46%, #000 54%, transparent 62%, transparent 100%) !important;
}
@media (hover: hover) { :root:not([data-theme="dark"]) .btn.glass:hover::before { -webkit-mask-image: none !important; mask-image: none !important; } }
/* the legal note sits quietly at the end of a case study and opens in the glass window */
.cs-note-wrap { display: flex; justify-content: center; margin-top: 96px; }
.cs-note-btn { color: var(--ink-2); transition: color var(--t-fast) var(--ease); }
.cs-note-btn .arrow { display: inline-block; margin-left: 4px; }
@media (hover: hover) { .cs-note-btn:hover { color: var(--ink); } }
.cs-note-wrap + .next { padding-top: 96px; }
/* note v2: an underlined word; the text unfolds right beneath it, no window */
.cs-note-wrap { flex-direction: column; align-items: center; text-align: center; }
.cs-note-btn { text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
.cs-note-text { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 520ms var(--ease), opacity 420ms var(--ease), filter 520ms var(--ease); opacity: 0; filter: blur(6px); }
.cs-note-text > div { overflow: hidden; }
.cs-note-text p { max-width: 46ch; margin: 12px auto 0; }
.cs-note-wrap.is-open .cs-note-text { grid-template-rows: 1fr; opacity: 1; filter: none; }
.cs-note-text { width: 100%; }
/* note at the top, under Client, left aligned; opens in place */
.cs-note-top { margin-top: 8px; align-items: flex-start; text-align: left; }
.cs-note-top .cs-note-text p { margin: 8px 0 0; max-width: 52ch; }
/* seamless loop: a wider mask lets the band start and finish fully off the pill, so the restart is
   never seen; no hold at the end, the next pass simply follows */
@keyframes pill-wave3 {
  from { -webkit-mask-position: 100% 0; mask-position: 100% 0; }
  to { -webkit-mask-position: 0% 0; mask-position: 0% 0; }
}
.btn.glass::before, .btn.glass::after {
  -webkit-mask-size: 420% 100% !important; mask-size: 420% 100% !important;
  animation-name: pill-wave3 !important; animation-duration: 2.3s !important;
  animation-timing-function: cubic-bezier(0.42, 0, 0.58, 1) !important; animation-iteration-count: infinite !important;
}
@media (hover: hover) { .btn.glass:hover::before, .btn.glass:hover::after { animation: none !important; } }
@media (prefers-reduced-motion: reduce) { .btn.glass::before, .btn.glass::after { animation: none !important; } }
/* just wide enough for the band to clear the pill at both ends (so passes follow each other closely) */
.btn.glass::before, .btn.glass::after { -webkit-mask-size: 340% 100% !important; mask-size: 340% 100% !important; animation-duration: 1.8s !important; }
@media (hover: hover) { .btn.glass:hover::before, .btn.glass:hover::after { animation: none !important; } }

/* hover: the wave keeps running, only the + makes its quarter turn */
@media (hover: hover) {
  .btn.glass:hover::before, .btn.glass:hover::after {
    animation-name: pill-wave3 !important; animation-duration: 1.8s !important; animation-iteration-count: infinite !important;
    animation-timing-function: cubic-bezier(0.42, 0, 0.58, 1) !important; animation-play-state: running !important;
  }
  .btn.glass:hover::after { opacity: 1 !important; }
  :root:not([data-theme="dark"]) .btn.glass:hover::before {
    -webkit-mask-image: linear-gradient(90deg, #000 0%, #000 38%, transparent 46%, transparent 54%, #000 62%, #000 100%) !important;
            mask-image: linear-gradient(90deg, #000 0%, #000 38%, transparent 46%, transparent 54%, #000 62%, #000 100%) !important;
  }
  :root[data-theme="dark"] .btn.glass:hover::before {
    -webkit-mask-image: linear-gradient(90deg, #000 0%, #000 30%, rgba(0,0,0,0.35) 44%, rgba(0,0,0,0.2) 50%, rgba(0,0,0,0.35) 56%, #000 70%, #000 100%) !important;
            mask-image: linear-gradient(90deg, #000 0%, #000 30%, rgba(0,0,0,0.35) 44%, rgba(0,0,0,0.2) 50%, rgba(0,0,0,0.35) 56%, #000 70%, #000 100%) !important;
  }
  /* dark theme: an old white hover fill was showing as a ring around the pill */
  :root[data-theme="dark"] .btn.glass:hover { background: transparent !important; background-color: transparent !important; box-shadow: none !important; }
  .btn.glass:hover .arrow { transform: rotate(90deg) !important; transition: transform 520ms cubic-bezier(0.34, 1.4, 0.64, 1) !important; }
}
.btn.glass .arrow { display: inline-block; transition: transform 520ms cubic-bezier(0.34, 1.4, 0.64, 1); }
/* only the + turns; arrows (→, ↗) stay put */
@media (hover: hover) {
  .btn.glass:not([data-more]):not([data-ops]):not([data-brief]):hover .arrow { transform: none !important; }
}

/* the + is drawn as two hairlines so it sits exactly on the text's middle and turns around its own
   centre; hover spins it a full turn */
.btn[data-more] .arrow, .btn[data-ops] .arrow, .btn[data-brief] .arrow {
  font-size: 0 !important; width: 9px; height: 9px; display: inline-block; vertical-align: middle; position: relative; top: -1px;
  margin-left: 2px; transform-origin: 50% 50%;
  background:
    linear-gradient(currentColor, currentColor) center / 100% 1.2px no-repeat,
    linear-gradient(currentColor, currentColor) center / 1.2px 100% no-repeat;
  transform: rotate(0deg) !important; transition: transform 700ms cubic-bezier(0.65, 0, 0.35, 1) !important;
}
@media (hover: hover) {
  .btn[data-more]:hover .arrow, .btn[data-ops]:hover .arrow, .btn[data-brief]:hover .arrow { transform: rotate(360deg) !important; }
}
.btn[data-more] .arrow, .btn[data-ops] .arrow, .btn[data-brief] .arrow { top: 0; }

/* arrow for All projects / Send: short shaft, longer head strokes (after Sven's reference),
   pointing up at rest; on hover it turns to point right */
.btn .arrow-up {
  display: inline-block; width: 11px; height: 11px; vertical-align: middle; position: relative; top: -1px; margin-left: 2px;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='%23000' stroke-width='1.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9.6V2.2M2.1 6.1L6 2.2l3.9 3.9'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='%23000' stroke-width='1.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9.6V2.2M2.1 6.1L6 2.2l3.9 3.9'/%3E%3C/svg%3E") center / contain no-repeat;
  transform: rotate(0deg) !important; transition: transform 560ms cubic-bezier(0.65, 0, 0.35, 1) !important;
}
@media (hover: hover) { .btn:hover .arrow-up { transform: rotate(90deg) !important; } }
@media (hover: hover) { html body .btn.glass:not([data-more]):not([data-ops]):not([data-brief]):hover .arrow.arrow-up { transform: rotate(90deg) !important; } }

/* All projects / Send: just the word at rest; on hover the pill stretches and a right arrow
   slides in after the text (arrow points right, no turning) */
.btn .arrow-up {
  width: 0; margin-left: 0; opacity: 0; top: 0; align-self: center;
  transform: translateX(-6px) rotate(90deg) !important;
  transition: width 460ms cubic-bezier(0.22, 1, 0.36, 1), margin-left 460ms cubic-bezier(0.22, 1, 0.36, 1), opacity 320ms var(--ease), transform 460ms cubic-bezier(0.22, 1, 0.36, 1) !important;
}
@media (hover: hover) {
  html body .btn.glass:not([data-more]):not([data-ops]):not([data-brief]):hover .arrow.arrow-up { width: 11px; margin-left: 6px; opacity: 1; transform: translateX(0) rotate(90deg) !important; }
}
.btn:has(.arrow-up) { gap: 0; }

/* All projects / Send, like the +: the right arrow is always there, aligned to the text, and on
   hover it spins a full turn, smooth, with the same timing as the + */
.btn .arrow-up {
  width: 11px !important; margin-left: 2px !important; opacity: 1 !important; top: 0;
  transform: rotate(90deg) !important;
  transition: transform 700ms cubic-bezier(0.65, 0, 0.35, 1) !important;
}
.btn:has(.arrow-up) { gap: 8px; }
@media (hover: hover) {
  html body .btn.glass:not([data-more]):not([data-ops]):not([data-brief]):hover .arrow.arrow-up { width: 11px !important; margin-left: 2px !important; opacity: 1 !important; transform: rotate(450deg) !important; }
}
/* privacy & 404 */
.legal .legal-body p { margin: 0 0 1em; max-width: 64ch; }
.legal .list-row a { pointer-events: auto; }
.notfound .statement { min-height: 60vh; display: grid; align-content: center; justify-items: center; gap: 20px; text-align: center; }
.legal .head:first-child { row-gap: 0; }

/* footer: the big line and the small columns share one top line (cap height), not the baseline */
.footer .head.sp-3:not(.grey) { align-items: start; }
.footer .head.sp-3:not(.grey) > *, .footer .head.sp-3:not(.grey) > * > :first-child { text-box: trim-start cap alphabetic; }

/* phones: footer Contact left, Zagreb + time right, on one row */
@media (max-width: 640px) {
  .footer .head.sp-3:not(.grey) > .c6 { grid-column: 1 / span 6 !important; }
  .footer .head.sp-3:not(.grey) > .c10 { grid-column: 7 / -1 !important; }
}
/* phones: the Note link sits under Type, left aligned like the other labels; its text opens below */
@media (max-width: 640px) {
  .cs-info > .cs-note-wrap { display: flex !important; flex-direction: column; align-items: flex-start !important; text-align: left; grid-column: 1 / -1 !important; margin-top: 4px; }
  .cs-info > .cs-note-wrap .cs-note-text p { margin-left: 0; max-width: none; }
}
/* Operations window head: an opaque fade of the window's own colour (Safari can't blur inside the
   glass window), so scrolled text disappears under "Operations" instead of overlapping it */
.modal-head::before { display: none !important; }
.modal-head::after { background: linear-gradient(to bottom, rgba(244, 244, 245, 0.98) 0%, rgba(244, 244, 245, 0.92) 55%, rgba(244, 244, 245, 0) 100%) !important; }
:root[data-theme="dark"] .modal-head::after { background: linear-gradient(to bottom, rgba(32, 32, 35, 0.98) 0%, rgba(32, 32, 35, 0.92) 55%, rgba(32, 32, 35, 0) 100%) !important; }
.modal-head { z-index: 3; }
/* phones: Privacy & legal on its own line under the copyright */
@media (max-width: 640px) { .foot-sep { display: none; } .foot-legal { display: block; } }
/* phones (v2): Zagreb under Contact, with the time on the same line, to the right */
@media (max-width: 640px) {
  .footer .head.sp-3:not(.grey) > .c6, .footer .head.sp-3:not(.grey) > .c10 { grid-column: 1 / -1 !important; }
  .footer .head.sp-3:not(.grey) > .c10 { display: flex; justify-content: space-between; align-items: baseline; }
}
@media (max-width: 640px) { .footer .head.sp-3:not(.grey) > .c10 > * { text-box: normal; } }
/* touch: tap plays the same spin as hover on desktop */
@media (hover: none) {
  .btn[data-more].is-tapped .arrow, .btn[data-ops].is-tapped .arrow, .btn[data-brief].is-tapped .arrow { transform: rotate(360deg) !important; }
  html body .btn.glass.is-tapped .arrow.arrow-up { transform: rotate(450deg) !important; }
}
@media (hover: none) { .btn .arrow { transition-duration: 460ms !important; } }

/* Operations window v3: the head never moves and only the list scrolls under a soft top fade,
   so nothing can slide behind "Operations" (the old sticky head failed in Safari's glass) */
.modal.is-ops #modal-body { overflow: hidden !important; display: flex; flex-direction: column; max-height: 80vh; padding: 0 28px 0 !important; }
.modal.is-ops .modal-head { position: static !important; flex: none; padding: 21.5px 0 20px !important; margin: 0 !important; }
.modal.is-ops .modal-head::before, .modal.is-ops .modal-head::after { display: none !important; }
.modal.is-ops .ops-scroll {
  flex: 1 1 auto; min-height: 0; overflow: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
  padding: 16px 0 32px;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 28px, #000 calc(100% - 20px), transparent 100%);
          mask-image: linear-gradient(to bottom, transparent 0, #000 28px, #000 calc(100% - 20px), transparent 100%);
}
/* text lists on phones: the year gets three columns, so it ends exactly on the rule's right edge
   (one column was narrower than "2026" and the number spilled past the line) */
@media (max-width: 900px) {
  .list-row > .col-year { grid-column: 10 / -1 !important; justify-self: end; text-align: right; white-space: nowrap; }
  .list-row > .col-title { grid-column: 2 / span 8 !important; }
}

/* windows scroll only vertically: nothing inside may push them sideways */
.modal__card, .modal__card #modal-body, .modal .ops-scroll { overflow-x: hidden !important; overscroll-behavior-x: none; touch-action: pan-y; }
.modal__card .more-title::after { left: 0; right: 0; }
.modal__card .brief, .modal__card .field, .modal__card input, .modal__card textarea { max-width: 100%; box-sizing: border-box; }
