/* ====================================================================
   Cali Schweder — modernised 70s flower-power: chunky soft type, stripes, sunbursts, daisies, sticker shapes.
   Palette stays: Candy Corn / Pumpkin Orange / Coven Black / Ghost Cream.
   ==================================================================== */

@font-face { font-family: "Bakso Menu"; src: url("../assets/fonts/BaksoMenu.woff2") format("woff2"), url("../assets/fonts/BaksoMenu.ttf") format("truetype"); font-weight: 400; font-style: normal; font-display: swap; size-adjust: 80%; /* Bakso runs ~30% bigger than Bagel at the same size; tune this one number to resize it everywhere */ }

:root {
  /* Brand palette */
  --yellow: #F2C230;   /* Candy Corn */
  --orange: #E8641C;   /* Pumpkin Orange */
  --black: #1A1A1A;    /* Coven Black */
  --cream: #F2EFE4;    /* Ghost Cream */

  --bg: var(--black);
  --fg: var(--cream);
  --muted: #a9a598;
  --line: rgba(242, 239, 228, .2);
  --accent: var(--yellow);
  --accent-2: var(--orange);
  /* Display face: swap with <html data-font="bagel|bakso"> (default bakso). Try it live with ?font=bagel or Shift+F. */
  --font-bakso: "Bakso Menu", "Bagel Fat One", "Arial Rounded MT Bold", sans-serif;
  --font-bagel: "Bagel Fat One", "Arial Rounded MT Bold", "Trebuchet MS", sans-serif;
  --display: var(--font-bakso);
  --label: "Syncopate", "Inter Tight", sans-serif;
  --sans: "Inter Tight", system-ui, sans-serif;
  --pad: clamp(16px, 4vw, 56px);
  --ease: cubic-bezier(.2, .8, .2, 1);
  --bounce: cubic-bezier(.34, 1.56, .64, 1);
  --daisy: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Cg fill='%23000'%3E%3Cellipse cx='50' cy='21' rx='10.5' ry='19' transform='rotate(0 50 50)'/%3E%3Cellipse cx='50' cy='21' rx='10.5' ry='19' transform='rotate(45 50 50)'/%3E%3Cellipse cx='50' cy='21' rx='10.5' ry='19' transform='rotate(90 50 50)'/%3E%3Cellipse cx='50' cy='21' rx='10.5' ry='19' transform='rotate(135 50 50)'/%3E%3Cellipse cx='50' cy='21' rx='10.5' ry='19' transform='rotate(180 50 50)'/%3E%3Cellipse cx='50' cy='21' rx='10.5' ry='19' transform='rotate(225 50 50)'/%3E%3Cellipse cx='50' cy='21' rx='10.5' ry='19' transform='rotate(270 50 50)'/%3E%3Cellipse cx='50' cy='21' rx='10.5' ry='19' transform='rotate(315 50 50)'/%3E%3Ccircle cx='50' cy='50' r='13'/%3E%3C/g%3E%3C/svg%3E");
  --hdr: 52px;      /* fixed header height */
  --ft: 64px;       /* footer height */
  --stripes: 21px; /* height of the stripe stack above the banner */
}
:root[data-font="bagel"] { --display: var(--font-bagel); }
:root[data-theme="light"] {
  --bg: var(--cream);
  --fg: var(--black);
  --muted: #6b675c;
  --line: rgba(26, 26, 26, .2);
  --accent: var(--orange);
  --accent-2: var(--yellow);
}
*, *::before, *::after { box-sizing: border-box; margin: 0; }
html { scroll-behavior: auto; scrollbar-gutter: stable; }
html.modal-open { overflow: hidden; } /* anchor jumps are eased in js/main.js */
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
body {
  background: var(--bg); color: var(--fg);
  font: 400 17px/1.5 var(--sans);
  -webkit-font-smoothing: antialiased;
  transition: background .4s, color .4s;
}
/* PRINT LAYER: makes the page read as ink on uncoated paper. Scrolls with the content (it's the sheet, not a lens).
   Three baked tiles, palette colours only: fibres, fine grit and slow uneven
   ink density (assets/texture/*.webp, made by a script). Plain repeating images are the cheapest thing a browser can draw. --print scales the whole thing. Toggle with Shift+P or ?print=off (falls back to the old flat grain). */
body { position: relative; --print: .75; }
:root[data-theme="light"] body { --print: .55; }   /* dark specks show more on cream, so less of it */
body::after { content: ""; position: absolute; inset: 0; z-index: 40; pointer-events: none; opacity: var(--print, 1);
  background-image: url("../assets/texture/fibres.webp"), url("../assets/texture/grit.webp"), url("../assets/texture/mottle.webp");
  background-size: 512px 512px, 256px 256px, 1400px 1400px; }
.grid { z-index: 45; }   /* your actual work sits on top of the paper, untouched (the header, z 50, stays above both) */
:root[data-print="off"] body::after { position: fixed; opacity: .07; background-size: auto; background-image: 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='.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .5 0 0 0 0 .5 0 0 0 0 .5 0 0 0 .9 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); }
/* Ink soaking into the paper: big headlines get slightly wobbly edges (SVG filter #ink / #ink-sm in index.html).
   SVG filters are drawn on the CPU, so they only go on big text that never moves, each isolated in its own layer (will-change)
   so the browser draws the filter ONCE and reuses the picture. The hero only gets it after its letter intro has finished
   (js adds .inked). Not on anything that animates or sits in the stretching gallery. */
:root:not([data-print="off"]) :is(.hero-title.inked, .project-title) { filter: url(#ink); will-change: transform; }
:root:not([data-print="off"]) .lede { filter: url(#ink-sm); will-change: transform; }
img { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
em { font-style: normal; color: var(--accent); }
.about em { color: var(--orange); }
::selection { background: var(--orange); color: var(--black); }
html { accent-color: var(--orange); }
:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }
.skip { position: absolute; left: -999px; }
.skip:focus { left: var(--pad); top: 8px; z-index: 100; background: var(--yellow); color: var(--black); padding: 8px 12px; }
.sparkle { width: 1em; height: 1em; display: inline-block; }
.daisy { width: 1em; height: 1em; display: inline-block; --hole: var(--black); }

/* Header */
.site-header {
  position: fixed; inset: 0 0 auto 0; z-index: 50;
  display: flex; justify-content: space-between; align-items: center;
  height: var(--hdr); padding: 0 var(--pad); color: var(--fg); background: color-mix(in srgb, var(--bg) 82%, transparent); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
}
.logo { font-family: var(--display); font-size: 24px; line-height: 1; letter-spacing: .01em; }
.site-header nav { display: flex; gap: clamp(14px, 3vw, 32px); align-items: center; font-family: var(--label); font-weight: 700; font-size: 11px; text-transform: uppercase; letter-spacing: .08em; }
.site-header nav a { position: relative; }
.site-header nav a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -6px; height: 3px; border-radius: 3px;
  background: var(--orange); transform: scaleX(0); transform-origin: left; transition: transform .45s var(--bounce);
}
.site-header nav a:hover::after, .site-header nav a.active::after { transform: scaleX(1); }
.hdr-title { position: absolute; left: 50%; top: 50%; translate: -50% -50%; display: inline-flex; align-items: center; gap: .55em; font-family: var(--display); font-size: 22px; line-height: 1; opacity: 0; pointer-events: none; white-space: nowrap; }
.hdr-title::before { content: ""; width: .95em; height: .95em; background: var(--orange); -webkit-mask: var(--daisy) center / contain no-repeat; mask: var(--daisy) center / contain no-repeat; }
.theme-toggle { width: 24px; height: 24px; border: 2px solid currentColor; border-radius: 50%; position: relative; overflow: hidden; }
.theme-toggle span { position: absolute; inset: 0; background: currentColor; clip-path: inset(0 50% 0 0); transition: transform .5s var(--ease); }
:root[data-theme="light"] .theme-toggle span { transform: rotate(180deg); }

/* Hero */
.hero { --mq: calc(20px + 1.15 * clamp(24px, 3.3vw, 46px)); /* banner height */ position: relative; overflow: hidden; height: 100svh; min-height: 520px; padding: 100px 0 0; display: flex; flex-direction: column; container-type: size; }
.hero-main {
  --hl: 8.6;   /* width of the LONGEST headline line in em, plus a hair ("that look and work" = 8.45em in Bakso). Update if the copy changes. */
  --fs: max(30px, min(calc((100vw - 2 * var(--pad)) / var(--hl)), calc((100svh - 350px) / 3.3)));   /* headline size: as big as fits the width AND one screen with the banner */
  position: relative; z-index: 1; flex: 1; display: flex; flex-direction: column; justify-content: flex-end; gap: 20px; padding: 0 var(--pad) 44px;
}
.badge { position: absolute; z-index: 2; right: var(--pad); bottom: calc(var(--stripes) + 12px); width: calc(var(--fs) * .92); aspect-ratio: 1; display: grid; place-items: center; color: var(--black); transition: scale .5s var(--bounce); }
.badge:hover { scale: 1.08; }
.badge svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; animation: spin 26s linear infinite; }
.badge text { font-family: var(--label); font-weight: 700; font-size: 6.4px; text-transform: uppercase; fill: currentColor; }
.badge-arrow { position: relative; font-family: var(--display); font-size: calc(var(--fs) * .36); line-height: 1; transition: transform .4s var(--bounce); }
.badge:hover .badge-arrow { transform: translateY(5px); }
@keyframes spin { to { transform: rotate(360deg); } }
.eyebrow { align-self: flex-start; display: inline-flex; align-items: center; gap: 12px; padding: 10px 0; color: var(--fg); font-family: var(--label); font-weight: 700; font-size: clamp(11px, 1.15vw, 15px); text-transform: uppercase; letter-spacing: .14em; }
.eyebrow::before { content: "✦"; color: var(--orange); font-size: 1.2em; letter-spacing: 0; }
.label { display: inline-flex; align-items: center; gap: .8em; font-family: var(--label); font-weight: 700; font-size: 11px; text-transform: uppercase; letter-spacing: .12em; color: var(--muted); }
.label::before { content: ""; width: 2.2em; height: 2.2em; background: var(--orange); -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Cg fill='%23000'%3E%3Cellipse cx='50' cy='21' rx='10.5' ry='19' transform='rotate(0 50 50)'/%3E%3Cellipse cx='50' cy='21' rx='10.5' ry='19' transform='rotate(45 50 50)'/%3E%3Cellipse cx='50' cy='21' rx='10.5' ry='19' transform='rotate(90 50 50)'/%3E%3Cellipse cx='50' cy='21' rx='10.5' ry='19' transform='rotate(135 50 50)'/%3E%3Cellipse cx='50' cy='21' rx='10.5' ry='19' transform='rotate(180 50 50)'/%3E%3Cellipse cx='50' cy='21' rx='10.5' ry='19' transform='rotate(225 50 50)'/%3E%3Cellipse cx='50' cy='21' rx='10.5' ry='19' transform='rotate(270 50 50)'/%3E%3Cellipse cx='50' cy='21' rx='10.5' ry='19' transform='rotate(315 50 50)'/%3E%3Ccircle cx='50' cy='50' r='13'/%3E%3C/g%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 100 100'%3E%3Cg fill='%23000'%3E%3Cellipse cx='50' cy='21' rx='10.5' ry='19' transform='rotate(0 50 50)'/%3E%3Cellipse cx='50' cy='21' rx='10.5' ry='19' transform='rotate(45 50 50)'/%3E%3Cellipse cx='50' cy='21' rx='10.5' ry='19' transform='rotate(90 50 50)'/%3E%3Cellipse cx='50' cy='21' rx='10.5' ry='19' transform='rotate(135 50 50)'/%3E%3Cellipse cx='50' cy='21' rx='10.5' ry='19' transform='rotate(180 50 50)'/%3E%3Cellipse cx='50' cy='21' rx='10.5' ry='19' transform='rotate(225 50 50)'/%3E%3Cellipse cx='50' cy='21' rx='10.5' ry='19' transform='rotate(270 50 50)'/%3E%3Cellipse cx='50' cy='21' rx='10.5' ry='19' transform='rotate(315 50 50)'/%3E%3Ccircle cx='50' cy='50' r='13'/%3E%3C/g%3E%3C/svg%3E") center / contain no-repeat; }
@supports (height: 1cqh) { .hero-main { --fs: max(30px, min(calc((100vw - 2 * var(--pad)) / var(--hl)), calc((100cqh - 120px - var(--mq)) / 3.3))); } }
.hero-title { font-family: var(--display); font-weight: 400; font-size: var(--fs); line-height: .98; letter-spacing: -.01em; }
.hero-title .line { display: block; }
.hero-title .w { display: inline-block; vertical-align: top; white-space: nowrap; overflow: hidden; padding: .06em 0 .17em; margin: -.06em 0 -.12em; }   /* clips its letters as they rise */
.hero-title .ch { display: inline-block; transform: translateY(115%); animation: rise 1s var(--bounce) forwards; animation-delay: calc(var(--i) * 28ms + 150ms); white-space: pre; }
@keyframes rise { to { transform: none; } }

/* Banner: orange band with racing stripes above it */
.marquee {
  position: relative; z-index: 2; flex: none; overflow: hidden; background: var(--orange); color: var(--black); padding: 10px 0; white-space: nowrap;
  box-shadow: 0 -7px 0 var(--yellow), 0 -14px 0 var(--cream), 0 -21px 0 var(--orange);
}
.marquee-track { display: inline-flex; animation: scroll 30s linear infinite; }
.marquee-track > span { font-family: var(--display); font-size: clamp(24px, 3.3vw, 46px); line-height: 1.15; display: inline-flex; align-items: center; gap: .45em; padding-right: .45em; }
.marquee .star { color: var(--black); font-size: .7em; line-height: 1; }
@keyframes scroll { to { transform: translateX(var(--mq-shift, -50%)); } }   /* --mq-shift = one copy of the list (set by js) */

/* Sections */
section { padding: clamp(72px, 12vw, 160px) var(--pad); }
.work { min-height: 100svh; padding: calc(var(--hdr) + 36px) var(--pad) 80px; }
/* Masonry via grid: each card spans however many 8px rows it needs (set in js/main.js). Unlike CSS columns there are no column
   edges to clip a card's shadow or border, and cards read left-to-right in order. */
.grid { position: relative; --gap: 30px; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); grid-auto-rows: 8px; column-gap: 28px; align-items: start; }
.card { --r: 30px; margin: 0; position: relative; display: block; width: 100%; padding: 0; text-align: left; border: 3px solid var(--fg); border-radius: var(--r); box-shadow: 7px 7px 0 var(--orange); opacity: 1; transition: opacity .4s, transform .5s var(--bounce), box-shadow .5s var(--bounce); }
/* The image + caption live in their own clipped layer: an explicit rounded clip-path keeps the corners sharp-free even while
   (or after) the image is scaled, which overflow:hidden alone doesn't guarantee. The colour-block shadow stays on the outer card. */
.card-in { position: relative; display: block; overflow: hidden; border-radius: calc(var(--r) - 3px); clip-path: inset(0 round calc(var(--r) - 3px)); isolation: isolate; }
.card[hidden] { display: none; }
.card.out { opacity: 0; transform: scale(.97); }
.card:hover { transform: translate(-3px, -3px) rotate(-.6deg); box-shadow: 11px 11px 0 var(--orange); }
.card img { width: 100%; height: auto; transition: transform .8s var(--ease); }
.card:hover img { transform: scale(1.05); }
/* --cap-x: the yellow bar reaches this far below the card (hidden by the card's clip) so the bouncy overshoot never opens a gap under it */
.card .cap {
  --cap-x: 20px;
  position: absolute; inset: auto 0 calc(-1 * var(--cap-x)) 0; padding: 14px 20px calc(14px + var(--cap-x)); color: var(--black); background: var(--yellow); border-top: 3px solid var(--black);
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
  transform: translateY(100%); transition: transform .5s var(--bounce);
}
.card:hover .cap, .card:focus-visible .cap { transform: none; }
.card .cap strong { font-family: var(--display); font-weight: 400; font-size: 24px; line-height: 1; }
.card .cap span { font-family: var(--label); font-weight: 700; font-size: 9px; text-transform: uppercase; letter-spacing: .1em; }

/* About: exactly one screen. The photo scales to the screen height and sits right under the header when you jump here. */
.about { --ph: max(240px, min(calc(100svh - 240px), 70vw)); position: relative; min-height: 100svh; padding: calc(var(--hdr) + 52px) var(--pad) 56px; display: flex; align-items: center; }
.about-grid { width: 100%; display: grid; grid-template-columns: auto 1fr; gap: clamp(32px, 7vw, 120px); align-items: center; }
.about-body { align-self: center; }
.portrait { position: relative; margin: 0 0 0 42px; width: calc(var(--ph) * 2 / 3); }  /* exactly the frame width, so the caption below can never widen the column */
/* concentric rainbow stripes hugging the arch */
.portrait-frame { width: calc(var(--ph) * 2 / 3); height: var(--ph); overflow: hidden; border-radius: 999px 999px 30px 30px; background: var(--yellow); box-shadow: 0 0 0 12px var(--orange), 0 0 0 24px var(--yellow), 0 0 0 36px var(--orange), 0 0 0 39px var(--fg); }
.portrait img { width: 100%; height: 112%; object-fit: cover; filter: grayscale(1) contrast(1.08); mix-blend-mode: multiply; transition: filter .7s var(--ease); will-change: transform; }
.portrait:hover img { filter: none; mix-blend-mode: normal; }
.portrait-spark { position: absolute; color: var(--orange); z-index: 1; }
.portrait-spark.s1 { right: -42px; top: 40%; font-size: clamp(44px, 6vw, 84px); }
.portrait-spark.s2 { right: 4%; top: -34px; font-size: clamp(18px, 2.2vw, 30px); color: var(--fg); }
.portrait-spark.s3 { left: -40px; top: 21%; font-size: clamp(14px, 1.7vw, 24px); color: var(--yellow); }
/* Caption spans the OUTER edge of the striped frame (rings extend 39px past the photo). The name and role scale up together until they
   fill that width, so the C sits on the frame's left edge and the final R on its right edge; js/main.js (fitCaption) sets --cs-name / --cs-role. */
.portrait figcaption { display: flex; justify-content: space-between; align-items: baseline; gap: 14px; margin: 54px -39px 0; line-height: 1; }
.portrait figcaption.stack { flex-direction: column; align-items: stretch; gap: 10px; }
.cap-name { font-family: var(--display); font-size: calc(24px * var(--cs-name, 1)); white-space: nowrap; }
.cap-role { font-family: var(--label); font-weight: 700; font-size: calc(9px * var(--cs-role, 1)); text-transform: uppercase; letter-spacing: .1em; color: var(--muted); white-space: nowrap; }
.lede { font-family: var(--display); font-size: clamp(30px, min(4.6vw, 7svh), 76px); line-height: 1.12; }

/* Contact — sunburst colour block with a wavy stripe edge */
.contact { position: relative; isolation: isolate; overflow-x: clip; min-height: calc(100svh - var(--ft)); padding: calc(var(--hdr) + 24px) var(--pad) 40px; display: flex; flex-direction: column; justify-content: center; background: var(--yellow); color: var(--black); --accent: var(--orange); --muted: rgba(26, 26, 26, .65); --line: rgba(26, 26, 26, .25); }
.contact::before { content: ""; position: absolute; z-index: -1; left: 0; width: calc(100% + 180px); will-change: transform; top: -45px; height: 46px; background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='46' viewBox='0 0 180 46'%3E%3Cpath fill='%23E8641C' d='M0 12 C30 0 60 0 90 12 S150 24 180 12 L180 46 L0 46Z'/%3E%3Cpath fill='%23F2EFE4' d='M0 22 C30 10 60 10 90 22 S150 34 180 22 L180 46 L0 46Z'/%3E%3Cpath fill='%23F2C230' d='M0 32 C30 20 60 20 90 32 S150 44 180 32 L180 46 L0 46Z'/%3E%3C/svg%3E") repeat-x 0 0 / 180px 46px; animation: wave-x 16s linear infinite; }
@keyframes wave-x { to { transform: translateX(-180px); } }
@keyframes wave-x-flip { from { transform: scaleY(-1) translateX(0); } to { transform: scaleY(-1) translateX(-180px); } }
.contact::after { content: ""; position: absolute; z-index: -1; inset: 0; pointer-events: none; background: repeating-conic-gradient(from 0deg at 100% 100%, rgba(255, 255, 255, .22) 0 6deg, transparent 6deg 12deg); -webkit-mask-image: radial-gradient(circle at 100% 100%, #000, transparent 75%); mask-image: radial-gradient(circle at 100% 100%, #000, transparent 75%); }
.contact-daisy { position: absolute; z-index: -1; right: -9vw; top: 10%; width: min(34vw, 520px); height: min(34vw, 520px); max-width: none; pointer-events: none; user-select: none; animation: spin 70s linear infinite; }   /* assets/daisy.webp, from Daisy.png */
.contact-daisy img { position: absolute; inset: 0; width: 100%; height: 100%; max-width: none; }
.contact-daisy .ghost { will-change: transform; }   /* motion-blur copies while hand-spun (js): own layers; the softening is pre-baked into assets/daisy-blur.webp (a live CSS blur here was far too heavy for Chrome) */
.big-mail { align-self: flex-start; display: inline-block; font-family: var(--display); font-size: max(44px, min(12.5vw, calc((100svh - 330px) / 2.1))); line-height: 1; letter-spacing: -.01em; }
.contact em { color: var(--black); transition: color .35s var(--ease); }
.contact.go em { color: var(--orange); }
.socials { position: relative; display: flex; flex-wrap: nowrap; gap: 28px; margin-top: 56px; }
/* The pill shapes are drawn as SVG behind the buttons (see js/main.js); the buttons themselves just carry the text. */
.social { position: relative; z-index: 1; white-space: nowrap; flex: 0 0 auto; padding: 15px 30px; border: 0; background: none; color: var(--black); font-family: var(--display); font-weight: 400; font-size: 17px; line-height: 1.2; letter-spacing: .01em; transition: color .3s; display: inline-flex; gap: 10px; align-items: center; --under: transparent; }
.social.on { color: var(--yellow); --under: rgb(26, 26, 26); }
.goo { position: absolute; left: -30px; top: -30px; overflow: visible; pointer-events: none; z-index: 0; }
.goo-i { fill: var(--black); } .goo-y { fill: var(--yellow); } .goo-b { fill: var(--black); }
.site-footer a:hover { color: var(--orange); }
.site-footer { display: flex; justify-content: space-between; align-items: center; height: var(--ft); padding: 0 var(--pad); color: var(--muted); font-family: var(--label); font-size: 10px; text-transform: uppercase; letter-spacing: .1em; }

/* Reveal */
.reveal { opacity: 0; transform: translateY(28px); transition: opacity .9s var(--ease), transform .9s var(--ease); }
.reveal.in { opacity: 1; transform: none; }

/* Lightbox */

/* Cursor (fine pointers only). Positioned directly from mousemove — no smoothing, so no lag. */
.cursor { display: none; }
@media (pointer: fine) {
  .cursor { --bounce: cubic-bezier(.34, 1.56, .64, 1); --bounce-big: cubic-bezier(.3, 1.9, .5, 1); display: block; position: fixed; left: 0; top: 0; z-index: 300; pointer-events: none; will-change: transform; opacity: 0; }
  .cursor.on { opacity: 1; }
  .cursor span {
    position: absolute; width: 12px; height: 12px; margin: -6px 0 0 -6px; border-radius: 50%;
    background: var(--cur-fill, var(--yellow)); color: var(--cur-ink, var(--black));
    border: 0 solid var(--cur-ring, transparent);
    display: grid; place-items: center; font-family: var(--label); font-size: 0; letter-spacing: .08em; text-transform: uppercase;
    transition: width .5s var(--bounce), height .5s var(--bounce), margin .5s var(--bounce), transform .7s var(--bounce-big), background-color .15s linear, color .15s linear, border-color .15s linear;
  }
  /* Two-tone edge (black/cream chosen against the backdrop) whenever the colour underneath can't be known exactly, e.g. photos */
  .cursor.ring span { border-width: 2px; box-shadow: 0 0 0 1.5px var(--cur-ring2, transparent); }
  .cursor.view span { width: 88px; height: 88px; margin: -44px 0 0 -44px; font-size: 10px; }
  .cursor.view span::after { content: "View"; }
  .cursor.link span { width: 36px; height: 36px; margin: -18px 0 0 -18px; }
  /* Gentle pulse on anything interactive: the dot breathes and a soft ring ripples outward */
  .cursor.view span, .cursor.link span { animation: cur-breathe 1.8s ease-in-out infinite; }
  .cursor.view span::before, .cursor.link span::before {
    content: ""; position: absolute; inset: 0; border-radius: 50%; border: 2px solid var(--cur-fill, var(--yellow));
    animation: cur-ripple 1.8s ease-out infinite; pointer-events: none;
  }
  /* Press: grow fast, then spring back (overshoots below 1 and settles) once released */
  .cursor.press span { transform: scale(1.8); transition: width .5s var(--bounce), height .5s var(--bounce), margin .5s var(--bounce), transform .14s ease-out, background-color .15s linear, color .15s linear, border-color .15s linear; }
  @keyframes cur-breathe { 50% { scale: 1.1; } }
  @keyframes cur-ripple { 0% { transform: scale(1); opacity: .75; } 100% { transform: scale(1.7); opacity: 0; } }
  body.has-cursor, body.has-cursor a, body.has-cursor button { cursor: none; }
}

@media (max-width: 760px) {
  .about { --ph: min(calc(100svh - 300px), 105vw); align-items: flex-start; }
  .about-grid { grid-template-columns: 1fr; gap: 28px; }
  .portrait { margin-left: 40px; }
  .hdr-title { display: none; }
  .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 14px; --gap: 20px; }
  .card { --r: 20px; box-shadow: 4px 4px 0 var(--orange); }
  .card .cap { --cap-x: 0px; position: static; transform: none; padding: 9px 12px 10px; }   /* phones: always shown, so it sits UNDER the art instead of covering it */
  .card .cap strong { font-size: 17px; }
  .card .cap span { display: none; }
  }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
  .reveal, .hero-title .ch { opacity: 1; transform: none; }
}


@media (max-width: 520px) { .eyebrow { font-size: 10px; letter-spacing: .06em; padding: 8px 0; gap: 8px; } }

/* Socials: always full names. One row while they fit; on phones a 2x2 grid of bigger, easy-to-tap buttons. */
.social .lbl-s { display: none; }
@media (max-width: 920px) {
  .socials { gap: 16px; }
  .social { padding: 15px 22px; gap: 8px; }
}
@media (max-width: 640px) {
  .socials { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-top: 40px; max-width: 460px; }
  .social { justify-content: center; padding: 17px 12px; font-size: 19px; }
}
@media (max-width: 520px) {
  .logo { font-size: 17px; white-space: nowrap; }
  .site-header nav { font-size: 9.5px; gap: 12px; letter-spacing: .05em; }
}

/* Corner-anchored radial page wipe for the social buttons (driven from JS) */
.wipe { position: fixed; inset: 0; z-index: 200; pointer-events: none; visibility: hidden; }
.wipe.on { visibility: visible; pointer-events: auto; }
.wipe i { position: absolute; inset: 0; background: var(--orange); clip-path: circle(0 at 0 0); }
.wipe i:nth-child(2) { background: var(--black); }

/* "Sealed with a daisy": the email moment (envelope + seal + flight, then a "Copied!" sticker). Built and driven by js/main.js. */
.mail-fx { position: fixed; left: 0; top: 0; z-index: 260; pointer-events: none; width: 226px; height: 171px; margin: -85px 0 0 -113px; }
.mail-fx .mail-fy { width: 100%; height: 100%; }
.mail-fx svg { display: block; width: 100%; height: 100%; overflow: visible; transform-origin: 50% 60%; }
.mail-fx .env { transform-box: view-box; transform-origin: 90px 120px; }
.mail-fx .flap-open, .mail-fx .flap-shut { transform-box: view-box; transform-origin: 90px 30px; }
.mail-fx .seal { transform-box: view-box; transform-origin: 90px 86px; opacity: 0; }
.mail-spark { position: fixed; left: 0; top: 0; z-index: 259; width: 30px; height: 30px; margin: -15px 0 0 -15px; pointer-events: none; color: var(--orange); }
.mail-spark svg { display: block; width: 100%; height: 100%; }
.mail-spark:nth-child(3n) { color: var(--cream); } .mail-spark:nth-child(3n+1) { color: var(--black); }
.mail-toast { position: fixed; z-index: 261; pointer-events: none; display: flex; flex-direction: column; gap: 6px; padding: 14px 22px 13px; border: 3px solid var(--black); border-radius: 22px; background: var(--cream); color: var(--black); box-shadow: 6px 6px 0 var(--orange); white-space: nowrap; }
.mail-toast b { font-family: var(--display); font-weight: 400; font-size: 26px; line-height: 1; }
.mail-toast span { font-family: var(--label); font-weight: 700; font-size: 11px; letter-spacing: .08em; text-transform: uppercase; }

/* ==== Project modal: a framed "page" that opens over the home page through a radial wipe ==== */
.open-ring { position: fixed; inset: 0; z-index: 149; background: var(--orange); }
.open-ring[hidden], .project[hidden] { display: none; }
.project { position: fixed; inset: 0; z-index: 150; background: color-mix(in srgb, var(--black) 74%, transparent); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }
.project-frame { --m: 44px; position: absolute; inset: var(--m); border-radius: 38px; background: var(--bg); box-shadow: 0 0 0 10px var(--orange), 0 0 0 20px var(--yellow), 0 0 0 23px var(--cream); }
.project-scroll { position: absolute; inset: 0; overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; border-radius: 38px; outline: none; transition: opacity .18s; }
.project-scroll.swap { opacity: 0; }
.project-top { position: relative; z-index: 1; margin-bottom: 45px; padding: clamp(40px, 6vw, 84px) clamp(24px, 6vw, 96px) clamp(48px, 6vw, 84px); background: var(--yellow); color: var(--black); }
.project-top::after { content: ""; position: absolute; left: 0; width: calc(100% + 180px); will-change: transform; bottom: -45px; height: 46px; background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='46' viewBox='0 0 180 46'%3E%3Cpath fill='%23E8641C' d='M0 12 C30 0 60 0 90 12 S150 24 180 12 L180 46 L0 46Z'/%3E%3Cpath fill='%23F2EFE4' d='M0 22 C30 10 60 10 90 22 S150 34 180 22 L180 46 L0 46Z'/%3E%3Cpath fill='%23F2C230' d='M0 32 C30 20 60 20 90 32 S150 44 180 32 L180 46 L0 46Z'/%3E%3C/svg%3E") repeat-x 0 0 / 180px 46px; transform: scaleY(-1); animation: wave-x-flip 16s linear infinite; }
.project-kicker { display: flex; align-items: center; gap: 12px; font-family: var(--label); font-weight: 700; font-size: 11px; text-transform: uppercase; letter-spacing: .14em; }
.project-kicker::before { content: "✦"; font-size: 1.3em; letter-spacing: 0; }
.project-title { margin: .25em 0 .55em; max-width: 14em; font-family: var(--display); font-weight: 400; font-size: clamp(38px, 6.4vw, 100px); line-height: 1.02; letter-spacing: -.01em; }
.project-info { display: grid; grid-template-columns: minmax(0, 1.7fr) minmax(220px, .8fr); gap: clamp(28px, 6vw, 96px); align-items: start; }
.project-desc p { max-width: 62ch; margin-bottom: 1em; font-size: clamp(16px, 1.3vw, 20px); line-height: 1.55; }
.project-meta { display: grid; gap: 14px; margin: 0; font-size: 16px; line-height: 1.4; }
.project-meta dt { display: inline; font-weight: 700; }
.project-meta dt::after { content: ":"; }
.project-meta dd { display: inline; margin: 0 0 0 .4em; }
.project-images { display: grid; gap: clamp(26px, 4vw, 60px); padding: clamp(40px, 5vw, 72px) clamp(24px, 6vw, 96px) clamp(30px, 4vw, 56px); }
.project-images figure { margin: 0; }
.project-images img { width: 100%; height: auto; border: 3px solid var(--fg); border-radius: 30px; box-shadow: 8px 8px 0 var(--orange); }
/* single illustration: the whole piece fits on screen instead of filling the width */
.project-images.is-fit img { width: auto; max-width: 100%; max-height: calc(100svh - 2 * var(--m, 44px) - 60px); margin: 0 auto; }
/* sets (icons / spots): a grid of sticker tiles; a tile never grows past the piece's real size (--max), so small icons stay sharp */
.project-images.is-grid { grid-template-columns: repeat(var(--cols), minmax(0, var(--max))); justify-content: center; gap: clamp(22px, 3vw, 44px); }
.project-images.is-grid img { border-radius: 22px; box-shadow: 6px 6px 0 var(--orange); background: #fff; }
.project-images figcaption { margin-top: 14px; font-family: var(--label); font-weight: 700; font-size: 10px; text-transform: uppercase; letter-spacing: .12em; color: var(--muted); }
/* style-guide pages under a set (cut from the PDF by tools/build-guides.py): white sheets, full width so the small print stays readable */
.project-guide { display: grid; justify-items: center; gap: clamp(26px, 4vw, 52px); padding: clamp(10px, 2vw, 24px) clamp(24px, 6vw, 96px) clamp(30px, 4vw, 56px); }
.project-guide-title { justify-self: start; display: flex; align-items: center; gap: 12px; margin: 0; font-family: var(--label); font-weight: 700; font-size: 11px; text-transform: uppercase; letter-spacing: .14em; color: var(--fg); }
.project-guide-title::before { content: "\2726"; color: var(--orange); font-size: 14px; }
.project-guide figure { margin: 0; width: 100%; max-width: 920px; }
.project-guide img { width: 100%; height: auto; border: 3px solid var(--fg); border-radius: 22px; box-shadow: 6px 6px 0 var(--orange); background: #fff; }
.project-nav { display: flex; justify-content: space-between; gap: 16px; padding: 8px clamp(24px, 6vw, 96px) clamp(40px, 5vw, 72px); }
.project-nav button { max-width: 46%; padding: 14px 26px; border: 3px solid var(--fg); border-radius: 99px; font-family: var(--display); font-size: clamp(16px, 1.6vw, 22px); line-height: 1.1; box-shadow: 5px 5px 0 var(--orange); transition: transform .45s var(--bounce), box-shadow .45s var(--bounce), background .25s, color .25s; }
.project-nav button:hover { transform: translate(-2px, -2px) rotate(-1deg); box-shadow: 8px 8px 0 var(--orange); background: var(--yellow); color: var(--black); }
.project-nav button:only-child { margin-left: auto; }
/* flower-shaped close button with a bubbly x, nudged toward the cursor (see js/main.js) */
.project-close { position: absolute; z-index: 5; top: -38px; right: -38px; width: 88px; height: 88px; display: grid; place-items: center; border-radius: 50%; --under: rgb(232, 100, 28); transition: scale .5s var(--bounce); }
.project-close svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.project-close .petals { fill: var(--orange); stroke: var(--black); stroke-width: 2.5; transform-origin: 50px 50px; animation: spin 26s linear infinite; }
.project-close .core { fill: var(--yellow); stroke: var(--black); stroke-width: 2.5; }
.project-close .x { position: relative; margin-top: -5px; font-family: var(--display); font-size: 42px; line-height: 1; color: var(--black); }
.project-close:hover { scale: 1.1; }
.project-close:hover .petals { animation-duration: 6s; }
@media (max-width: 760px) {
  .project-frame { --m: 20px; border-radius: 26px; box-shadow: 0 0 0 6px var(--orange), 0 0 0 12px var(--yellow), 0 0 0 14px var(--cream); }
  .project-scroll { border-radius: 26px; }
  .project-info { grid-template-columns: 1fr; }
  .project-close { top: -22px; right: -16px; width: 70px; height: 70px; }
  .project-close .x { font-size: 34px; }
  .project-images img { border-radius: 20px; box-shadow: 5px 5px 0 var(--orange); }
  .project-images.is-grid { --cols: 2 !important; }
  .project-images.is-grid img, .project-guide img { border-radius: 16px; box-shadow: 4px 4px 0 var(--orange); }
}

/* "Let's make something." — an orange spotlight that follows the pointer, visible only inside the letters.
   The letters are painted by background-clip:text (black base + a pointer-positioned orange circle); js/main.js sets --sx/--sy/--sr. */
@property --sr { syntax: "<length>"; inherits: false; initial-value: 0px; }   /* orange fill radius */
@property --sr2 { syntax: "<length>"; inherits: false; initial-value: 0px; }  /* radius of the cream rim around it (>= --sr) */
@supports (-webkit-background-clip: text) or (background-clip: text) {
  .big-mail, .big-mail em {
    --sx: -999px; --sy: -999px;
    color: transparent;
    background-color: var(--black);
    background-image: radial-gradient(circle at var(--sx) var(--sy), var(--orange) 0 var(--sr), var(--cream) var(--sr) var(--sr2), transparent calc(var(--sr2) + 1px));
    -webkit-background-clip: text; background-clip: text;
    transition: --sr var(--srt, .45s) var(--srease, var(--ease)) var(--d1, 0s), --sr2 var(--srt, .45s) var(--srease, var(--ease)) var(--d2, 0s), background-color .35s var(--ease);
  }
  .contact.go .big-mail em { color: transparent; background-color: var(--orange); }
}
@media (min-width: 761px) and (max-width: 940px) { .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* Easter egg: sunglasses drop onto the centre of the contact flower when its spin is restarted 5 times in quick succession */
.contact-shades { position: absolute; z-index: -1; right: -9vw; top: 10%; width: min(34vw, 520px); height: min(34vw, 520px); display: grid; place-items: center; pointer-events: none; opacity: 0; }
.contact-shades svg { width: 23%; height: auto; overflow: visible; filter: drop-shadow(0 3px 0 rgba(26, 26, 26, .25)); }
.contact-shades.on { animation: shades 1.6s both; }
@keyframes shades {
  0%   { opacity: 0; transform: translateY(-34%) scale(.92); animation-timing-function: cubic-bezier(.34, 1.56, .64, 1); }
  16%  { opacity: 1; transform: none; }
  74%  { opacity: 1; transform: none; animation-timing-function: ease-in; }
  100% { opacity: 0; transform: translateY(6%) scale(.97); }
}
@media (prefers-reduced-motion: reduce) { .contact-shades.on { animation: none; } }

/* Long-lived decorative animations are re-started (see js/main.js) when the tab returns after sitting hidden for a while */
.anim-reset .marquee-track, .anim-reset .badge svg, .anim-reset .contact::before, .anim-reset .project-top::after { animation: none !important; }

/* ==== Portrait phones & tablets: no full-screen hero (it left a big empty band above the headline) ==== */
@media (max-width: 1024px) and (orientation: portrait) {
  .hero { height: auto; min-height: 0; container-type: normal; padding-top: calc(var(--hdr) + 48px); }
  .hero-main { flex: none; padding-bottom: 40px; --fs: calc((100vw - 2 * var(--pad)) / var(--hl)); }
}
@media (max-width: 600px) {
  .hero-main { --hl: 5.4; }   /* the headline wraps word by word here, so only the longest WORD has to fit ("beautifully." = 5.14em) */
  .badge { top: calc(var(--hdr) + 26px); bottom: auto; width: 74px; }
  .badge-arrow { font-size: 26px; }
  .portrait { margin: 0 auto; justify-self: center; }
  .contact { justify-content: flex-start; padding-top: calc(var(--hdr) + 64px); padding-bottom: 46vw; }
  .contact-daisy, .contact-shades { top: auto; bottom: -16vw; right: -20vw; width: 74vw; height: 74vw; }
  .contact { overflow: clip; }                 /* the daisy tucks under the footer edge instead of covering it */
  .big-mail { font-size: min(15.5vw, 84px); }
}
@media (min-width: 601px) and (max-width: 760px) { .portrait { margin: 0 auto; justify-self: center; } }
