
/* The brand's fonts, subset to woff2 by the web app's build (web/scripts/fonts.sh). */
@font-face {
  font-family: 'Trame Serif';
  src: url(/fonts/TrameSerif-Regular.woff2) format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Inter';
  src: url(/fonts/Inter-VariableFont_opsz-wght.woff2) format('woff2');
  font-weight: 100 900; font-style: normal; font-display: swap;
}
/* Always dark, one palette (no light/dark switch): ink canvas, paper for titles,
   white for body text. The ink is the brand's colour (brand/BRAND.md, #0a0120); the
   site keeps the shades it has always had around it, which the brand's dark theme, a
   neutral one, does not give. --text-muted is the grey of labels and metadata (8:1 on
   ink). Sizes, radii and timings follow the brand's steps. */
:root {
  color-scheme: dark;
  --ink: #0A0120;
  --paper: #F0EFF6;
  --bg: var(--ink);
  --surface: #140F24;
  --surface-soft: #1E1733;
  --border: #2B2343;
  --border-mid: #332C4E;
  --text: #FFFFFF;
  --text-mid: var(--paper);
  --text-dim: var(--paper);
  --text-muted: #A9A6BA;
  --danger: #FC7568;
  --focus: rgb(165 158 201 / 0.75);
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-press: cubic-bezier(0.34, 1.56, 0.64, 1);
  --ease-emph: cubic-bezier(0.2, 0.8, 0.2, 1);
  --font-mono: ui-monospace, 'SF Mono', SFMono-Regular, Menlo, Consolas, monospace;
  --radius-sm: 6px; --radius-md: 10px; --radius-lg: 14px; --radius-xl: 20px;
  --gutter: 24px;
  --page-x: 64px;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; background: var(--bg); }
body {
  background: var(--bg);
  color: var(--text);
  font-family: 'Inter', -apple-system, sans-serif;
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
a { color: inherit; text-decoration: none; }
img, video { display: block; max-width: 100%; }
ul { list-style: none; }
:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.wrap { max-width: 1312px; margin: 0 auto; padding: 0 var(--page-x); }
.serif { font-family: 'Trame Serif', serif; font-weight: 400; letter-spacing: -0.016em; color: var(--paper); }
.over {
  font-size: 11px; font-weight: 600; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--text-muted);
}
.muted { color: var(--text-muted); }
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* Buttons, brand/BRAND.md's recipes in the site's colours: primary is paper on ink
   (one per view), secondary a soft surface, ghost text only. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 38px; padding: 0 16px; border-radius: var(--radius-md);
  font: 600 13px/1 'Inter', -apple-system, sans-serif; letter-spacing: 0;
  border: 1px solid transparent; cursor: pointer; white-space: nowrap;
  transition: background-color 150ms var(--ease), border-color 150ms var(--ease), color 150ms var(--ease), transform 150ms var(--ease-press);
}
.btn:active { transform: scale(0.95); }
.btn.lg { height: 46px; padding: 0 24px; font-size: 15px; }
.btn.sm { height: 30px; padding: 0 10px; }
.btn-primary { background: var(--paper); color: var(--ink); }
.btn-primary:hover { background: var(--text); }
.btn-secondary { background: var(--surface-soft); border-color: var(--border-mid); color: var(--paper); }
.btn-secondary:hover { background: var(--border); }
.btn-ghost { background: transparent; color: var(--text); padding: 0 12px; margin-left: -12px; }
.btn-ghost:hover { background: var(--surface-soft); }

/* The header: the logo (the brand's file, 28px high, its clear space of half its height
   kept around it), then Work, About, Contact. It holds still through a page change. */
header.site {
  display: flex; justify-content: space-between; align-items: center;
  max-width: 1312px; height: 80px; margin: 0 auto; padding: 0 var(--page-x);
  view-transition-name: site-header;
}
.wordmark { display: block; padding: 14px; margin-left: -14px; border-radius: var(--radius-sm); }
.wordmark img { height: 28px; width: auto; transition: transform 380ms var(--ease-emph); }
.wordmark:hover img { transform: scale(1.08) rotate(-3deg); }
.site-nav { display: flex; gap: 32px; }
/* A 1px line that grows from the left on hover (KJC concept, 07), and stays drawn
   under the page we are on. */
.nav-link {
  position: relative; font-size: 13px; color: var(--text-muted); padding: 4px 0;
  transition: color 150ms var(--ease);
}
.nav-link::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: currentColor; transform: scaleX(0); transform-origin: left center;
  transition: transform 380ms var(--ease-emph);
}
.nav-link:hover { color: var(--text); }
.nav-link:hover::after, .nav-link[aria-current="page"]::after { transform: scaleX(1); }
.nav-link[aria-current="page"] { color: var(--text); }

/* A page change is a short cut through ink: the old page fades out, the new one fades
   in (View Transitions, opacity only). Off under reduced motion. */
@view-transition { navigation: auto; }
::view-transition-group(root) { animation-duration: 0s; }
::view-transition-old(root) { animation: vt-out 160ms cubic-bezier(0.4, 0, 1, 1) both; }
::view-transition-new(root) { animation: vt-in 300ms var(--ease) 120ms both; }
@keyframes vt-out { to { opacity: 0; } }
@keyframes vt-in { from { opacity: 0; } }

/* Fade and a 28px rise as a block comes into view (the script in page() starts it;
   without the script everything simply shows). Reduced motion keeps the fade only. */
.rise-on .rise { opacity: 0; transform: translateY(28px); transition: opacity 0.8s var(--ease), transform 0.8s var(--ease); }
.rise-on .rise.in { opacity: 1; transform: none; }
.rise-on .rise.d1 { transition-delay: 120ms; }
.rise-on .rise.d2 { transition-delay: 240ms; }

/* A sober stand-in for a picture that is not there yet. */
.ph { background: var(--surface-soft); display: flex; align-items: center; justify-content: center; text-align: center; }
.ph span { font-family: 'Trame Serif', serif; font-size: 18px; color: var(--text-muted); padding: 16px; }

@media (max-width: 900px) {
  :root { --page-x: 24px; }
}
@media (max-width: 700px) {
  :root { --page-x: 16px; }
  header.site { height: 64px; }
  .site-nav { gap: 20px; }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; }
  html { scroll-behavior: auto; }
  .rise-on .rise { transform: none !important; transition: opacity 0.6s linear !important; }
  @view-transition { navigation: none; }
}

/* Footer links, on the page's grid (.wrap): the first column starts on its left edge,
   the last one ends on its right edge. The gap above the columns is 8.3vw, as the hero
   canvas's empty top band (down to the sliding wordmark's cap line) measures 8.3vw at
   any width, so the links sit centred between the page and the visible animation. */
.footer-grid {
  max-width: 1312px; margin: 0 auto; padding: max(8.3vw, 64px) var(--page-x) 0;
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: 32px 48px; flex-wrap: wrap;
}
.footer-links { display: flex; flex-direction: column; gap: 12px; }
.footer-links a, .hero-legal a {
  font-size: 13px; color: var(--text-muted);
  transition: color 150ms var(--ease);
}
.footer-links a:hover, .hero-legal a:hover { color: var(--text); }
@media (max-width: 900px) {
  .footer-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* Footer hero: full-bleed stripe-field animation, the last thing on the page.
   The canvas paints ink itself, so the band melts into the page background.
   No margin of its own: the empty band above the wordmark is the spacing. */
.kjc-hero { position: relative; width: 100%; aspect-ratio: 20 / 6; overflow: hidden; }
.kjc-hero canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
/* Legal line: the copyright, on a line of their own between the links
   and the stripe field, never over it. */
.hero-legal {
  max-width: 1312px; margin: 64px auto 0; padding: 0 var(--page-x);
  display: flex; justify-content: space-between; align-items: baseline; gap: 8px 24px; flex-wrap: wrap;
  font-size: 13px; color: var(--text-muted);
}
@media (max-width: 700px) {
  .hero-legal { margin-top: 48px; }
}
