/* Inter, self-hosted (OFL 1.1, see assets/fonts/OFL.txt). Weights per brandbook section 14. */
@font-face {
  font-family: "Inter";
  src: url("/assets/fonts/Inter-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("/assets/fonts/Inter-600.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("/assets/fonts/Inter-800.woff2") format("woff2");
  font-weight: 800;
  font-style: normal;
  font-display: swap;
}

/* Layout tokens. Color tokens live in tokens.css, loaded before this file. */
:root {
  --radius: 10px;
  --font: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", "Cascadia Code", Consolas, "Liberation Mono", monospace;

  /* Type scale in rem, so text follows the browser's font-size setting.
     Steps follow Apple's text styles at the default size: 13 / 15 / 17 / 20. */
  --text-footnote: .8125rem;
  --text-subhead: .9375rem;
  --text-body: 1.0625rem;
  --text-title3: 1.25rem;
  --text-title2: clamp(1.625rem, 1rem + 1.5vw, 2.25rem);
  --text-title1: clamp(1.75rem, .5rem + 4.6vw, 4rem);

  /* Minimum hit region for links and buttons (HIG: 44 x 44 pt). */
  --target: 44px;
  /* Sticky header height, used for anchor offsets. */
  --header-h: 64px;
  /* Neutral tint for selected and hovered controls; same mix as --color-border by default,
     kept separate so Increase Contrast can strengthen borders without darkening fills. */
  --fill: color-mix(in srgb, var(--color-text) 12%, transparent);

  /* Strong ease-out for press feedback (emil-design-eng / animate vocabulary). */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
}

*, *::before, *::after { box-sizing: border-box; }

/* No smooth scrolling: anchor jumps come from the skip link and keyboard focus as often as
   from the mouse, and a long smooth scroll reads as delay. Anchors still land below the header. */
html {
  scroll-padding-top: calc(var(--header-h) + 16px);
  /* Every tappable element has its own :active state, so the browser's gray tap flash goes. */
  -webkit-tap-highlight-color: transparent;
}

/* Controls fire on tap without the double-tap-zoom wait; their labels don't get selected
   on long press. Text content (the mail address, body copy) stays selectable. */
a, button, summary { touch-action: manipulation; }
.btn, .nav a, .lang a, .logo { -webkit-user-select: none; user-select: none; }

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font: var(--text-body)/1.6 var(--font);
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  text-rendering: optimizeLegibility;
  overflow-wrap: break-word;
}

h1, h2, h3 { line-height: 1.2; margin: 0; letter-spacing: -.01em; }
h1 { font-size: var(--text-title1); font-weight: 800; letter-spacing: -.02em; line-height: 1.05; hyphens: auto; }
h2 { font-size: var(--text-title2); font-weight: 800; }
h3 { font-size: var(--text-title3); font-weight: 600; }
p { margin: 0; }
a { color: var(--color-link); }

.wrap { max-width: 1120px; margin: 0 auto; padding: 0 20px; }

.skip {
  position: absolute; left: -9999px; top: 8px; z-index: 100;
  display: inline-flex; align-items: center; min-height: var(--target); padding: 0 16px;
  background: var(--color-accent); color: var(--color-accent-text); border-radius: 8px;
  font-weight: 600;
}
.skip:focus { left: 8px; }

:focus-visible { outline: 3px solid var(--color-link); outline-offset: 2px; }

/* header */
.top {
  position: sticky; top: 0; z-index: 50;
  background: color-mix(in srgb, var(--color-bg) 88%, transparent);
  backdrop-filter: saturate(1.4) blur(10px);
  -webkit-backdrop-filter: saturate(1.4) blur(10px);
  border-bottom: 1px solid var(--color-border);
}
.top__inner { display: flex; flex-wrap: wrap; align-items: center; gap: 0 24px; min-height: var(--header-h); }
.logo { display: inline-flex; align-items: center; gap: 8px; min-width: var(--target); min-height: var(--target); color: var(--color-text); text-decoration: none; font-weight: 800; font-size: var(--text-body); letter-spacing: -.02em; white-space: nowrap; border-radius: 8px; }
.logo__mark { width: 32px; height: 32px; flex: none; transition: transform 160ms var(--ease-out); }
/* Brand sign (section 14): ring with a dot on a graphite rounded square. */
.logo__bg { fill: var(--sign-bg); stroke: var(--fill); }
.logo__ring { fill: none; stroke: var(--color-accent); stroke-width: 4; }
.logo__dot { fill: var(--color-accent); transform-box: fill-box; transform-origin: center; transition: transform 200ms var(--ease-out); }

.nav { display: flex; gap: 4px; margin-left: auto; }
.nav a {
  display: inline-flex; align-items: center; min-height: var(--target); padding: 0 12px; border-radius: 8px;
  color: var(--color-text-muted); text-decoration: none; font-size: var(--text-subhead); white-space: nowrap;
  transition: transform 160ms var(--ease-out);
}

/* Narrow widths: sections stay reachable. The nav moves to a second header row
   and scrolls sideways inside itself; the page never scrolls horizontally. */
@media (max-width: 1000px) {
  :root { --header-h: 108px; }
  .top__inner > .lang { margin-left: auto; }
  .nav {
    order: 1; flex: 1 0 100%; margin: 0 -20px; padding: 0 8px;
    overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none;
  }
  .nav::-webkit-scrollbar { display: none; }
  /* The scrolling strip clips anything outside it, so the focus ring goes inside the link. */
  .nav a:focus-visible { outline-offset: -3px; }
  /* Tab follows the visual order (sign, language, contact, then the section row)
     where reading-flow is supported; elsewhere the DOM order stays as before. */
  .top__inner { reading-flow: flex-visual; }
  /* Keyboard focus scrolls a link clear of the edge fade below. */
  .nav { scroll-padding-inline: 32px; }
}

/* Scroll hint for the nav strip: the edge that has more links fades out.
   Driven by the strip's own scroll position; when nothing overflows the timeline
   is inactive and no fade is drawn. */
@property --nav-fade-start { syntax: "<length>"; inherits: false; initial-value: 0px; }
@property --nav-fade-end { syntax: "<length>"; inherits: false; initial-value: 0px; }
@keyframes nav-fade {
  0% { --nav-fade-start: 0px; --nav-fade-end: 32px; }
  12% { --nav-fade-start: 32px; }
  88% { --nav-fade-end: 32px; }
  100% { --nav-fade-start: 32px; --nav-fade-end: 0px; }
}
@supports (animation-timeline: scroll()) {
  @media (max-width: 1000px) {
    .nav {
      -webkit-mask-image: linear-gradient(to right, transparent, #000 var(--nav-fade-start), #000 calc(100% - var(--nav-fade-end)), transparent);
      mask-image: linear-gradient(to right, transparent, #000 var(--nav-fade-start), #000 calc(100% - var(--nav-fade-end)), transparent);
      animation: nav-fade linear both;
      animation-timeline: scroll(self inline);
    }
  }
}

/* buttons */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 48px; padding: 0 24px; border-radius: var(--radius);
  background: var(--color-accent); color: var(--color-accent-text);
  font: inherit; font-weight: 600; font-size: var(--text-body); line-height: 1.25; text-decoration: none; text-align: center;
  border: 1px solid var(--color-accent); cursor: pointer;
  transition: transform 160ms var(--ease-out), filter .15s ease, background-color .15s ease, border-color .15s ease;
}
.btn:active { filter: brightness(.94); transform: scale(.97); }
.btn--ghost { background: transparent; color: var(--color-text); border-color: var(--color-border); }
.btn--ghost:active { background: var(--fill); filter: none; }
.btn--small { min-height: var(--target); padding: 0 16px; font-size: var(--text-subhead); }

/* hero: heading across the full width, lead and actions below */
.hero { padding: clamp(56px, 11vw, 128px) 0 clamp(56px, 9vw, 104px); }
.hero h1 { max-width: 22ch; }
.eyebrow { color: var(--color-link); font-weight: 600; font-size: var(--text-footnote); letter-spacing: .12em; text-transform: uppercase; margin-bottom: 24px; }
.lead { color: var(--color-text-muted); font-size: var(--text-title3); line-height: 1.5; margin-top: 24px; max-width: 40em; }
.hero__cta { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 40px; }

/* Entrances. Only opacity and transform, so layout never moves (no CLS).
   Hero: pure CSS, plays once per page load and always finishes (550 ms in total);
   the heading leads and travels furthest, the lead and actions follow. */
@keyframes rise-in { from { opacity: 0; transform: translateY(var(--rise, 10px)); } }
@keyframes fade-in { from { opacity: 0; } }
.hero .eyebrow { animation: fade-in 400ms var(--ease-out) backwards; }
.hero h1 { --rise: 16px; animation: rise-in 500ms var(--ease-out) backwards; }
.hero .lead { animation: rise-in 450ms var(--ease-out) 80ms backwards; }
.hero__cta { --rise: 8px; animation: rise-in 400ms var(--ease-out) 150ms backwards; }

/* Section blocks: site.js marks blocks that start below the screen as pending and
   switches them to "in" once, when they scroll into view. Without JS, without
   IntersectionObserver or with reduced motion nothing is ever marked, so nothing hides.
   Steps are the block's place in the batch that entered together; gaps shrink
   (70, 60, 50, 20 ms), and the last block finishes by 600 ms. */
[data-reveal="pending"] { opacity: 0; }
[data-reveal="in"] { animation: rise-in 400ms var(--ease-out) backwards; }
.section__head[data-reveal] { --rise: 16px; }
[data-reveal="in"][data-reveal-step="1"] { animation-delay: 70ms; }
[data-reveal="in"][data-reveal-step="2"] { animation-delay: 130ms; }
[data-reveal="in"][data-reveal-step="3"] { animation-delay: 180ms; }
[data-reveal="in"][data-reveal-step="4"] { animation-delay: 200ms; }

/* sections: numbered grid, heading on the left, content on the right */
.section { padding: clamp(56px, 8vw, 96px) 0; border-top: 1px solid var(--color-border); }
.section--alt { background: var(--color-surface); }
.split { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: 56px; align-items: start; }
@media (max-width: 860px) { .split { grid-template-columns: minmax(0, 1fr); gap: 32px; } }
.section__num { color: var(--color-link); font-weight: 800; font-size: var(--text-subhead); font-variant-numeric: tabular-nums; letter-spacing: .04em; margin-bottom: 12px; }
.section__lead { color: var(--color-text-muted); margin-top: 16px; }

/* vertical amber line instead of cards */
.rail { list-style: none; margin: 0; padding: 0; border-left: 2px solid var(--color-accent); }
.rail > li { padding: 0 0 40px 32px; }
.rail > li:last-child { padding-bottom: 4px; }
.rail > li > p { color: var(--color-text-muted); margin-top: 8px; }
.rail--steps { counter-reset: step; }
.rail--steps > li { counter-increment: step; }
.rail--steps > li::before {
  content: counter(step, decimal-leading-zero);
  display: block; font-weight: 800; font-size: var(--text-subhead); font-variant-numeric: tabular-nums; color: var(--color-link); margin-bottom: 8px;
}

.ticks { margin: 16px 0 0; padding: 0; list-style: none; }
.ticks li { position: relative; padding-left: 20px; margin-top: 8px; }
.ticks li::before {
  content: ""; position: absolute; left: 2px; top: .66em;
  width: 7px; height: 7px; border-radius: 2px; background: var(--color-accent);
}

.rows { display: grid; }
.row { padding: 24px 0; border-top: 1px solid var(--color-border); }
.row:first-child { padding-top: 0; border-top: 0; }
.row p { color: var(--color-text-muted); margin-top: 8px; }

.projects { display: grid; gap: 48px; }
.project { border-top: 2px solid var(--color-accent); padding-top: 24px; }
.project__tag { font-weight: 600; font-size: var(--text-footnote); color: var(--color-link); margin-bottom: 8px; }
.project > p:not(.project__tag) { color: var(--color-text-muted); margin-top: 8px; }

.stack { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 32px; }
@media (max-width: 560px) { .stack { grid-template-columns: minmax(0, 1fr); } }
.stack__group h3 { font-size: var(--text-body); margin-bottom: 12px; }
.chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 0; padding: 0; list-style: none; }
.chips li { font-size: var(--text-subhead); line-height: 1.5; padding: 4px 12px; border-radius: 999px; border: 1px solid var(--color-border); color: var(--color-text); }

.faq { display: grid; border-top: 1px solid var(--color-border); }
.faq details { border-bottom: 1px solid var(--color-border); }
.faq summary {
  cursor: pointer; list-style: none; padding: 20px 40px 20px 0; position: relative;
  font-weight: 600; border-radius: 4px;
  transition: color .15s ease;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: ""; position: absolute; right: 8px; top: 50%; width: 9px; height: 9px;
  border-right: 2px solid var(--color-link); border-bottom: 2px solid var(--color-link);
  transform: translateY(-70%) rotate(45deg); transition: transform 250ms var(--ease-out);
}
.faq details[open] summary::after { transform: translateY(-30%) rotate(-135deg); }
.faq details p { color: var(--color-text-muted); padding-bottom: 24px; }
/* Answer opens and closes smoothly where the browser can animate to height: auto.
   Elsewhere it opens instantly, as before. Markup stays native details/summary. */
@supports (interpolate-size: allow-keywords) and selector(::details-content) {
  .faq details { interpolate-size: allow-keywords; }
  .faq details::details-content {
    block-size: 0; opacity: 0; overflow-y: clip;
    transition: block-size 250ms var(--ease-out), opacity 200ms var(--ease-out), content-visibility 250ms allow-discrete;
  }
  .faq details[open]::details-content { block-size: auto; opacity: 1; }
}

.contact__box { border-left: 2px solid var(--color-accent); padding: 4px 0 4px 32px; }
.contact__mail {
  display: inline-flex; align-items: center; min-height: var(--target); max-width: 100%;
  font-weight: 800; font-size: clamp(1.25rem, .75rem + 2.5vw, 2rem); line-height: 1.25; letter-spacing: -.01em;
  color: var(--color-text); text-decoration: none; overflow-wrap: anywhere; border-radius: 8px;
  transform-origin: left center; transition: transform 160ms var(--ease-out);
}
.contact__actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 24px; }
.contact__note { min-height: 1.6em; margin-top: 16px; color: var(--color-text-muted); font-size: var(--text-subhead); }

.foot { border-top: 1px solid var(--color-border); padding: 16px 0; color: var(--color-text-muted); font-size: var(--text-subhead); }
.foot__inner { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0 24px; }
.foot__inner > span { padding: 12px 0; }
.foot a { display: inline-flex; align-items: center; min-height: var(--target); color: var(--color-text-muted); border-radius: 4px; }

/* 404 */
.body-nf { min-height: 100vh; min-height: 100svh; display: flex; flex-direction: column; }
.nf { flex: 1; display: grid; place-items: center; text-align: center; padding: 64px 0; }
.nf__code { font-weight: 800; font-size: clamp(4rem, 14vw, 7rem); letter-spacing: -.02em; color: var(--color-link); line-height: 1; }
.nf p { color: var(--color-text-muted); margin: 16px 0 32px; }

/* language switcher */
.lang { display: flex; gap: 0; font-size: var(--text-subhead); font-weight: 600; }
.lang a {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: var(--target); min-height: var(--target); padding: 0 8px; border-radius: 8px;
  color: var(--color-text-muted); text-decoration: none;
  transition: transform 160ms var(--ease-out);
}
.lang a[aria-current="page"] { color: var(--color-text); background: var(--fill); }

@media (max-width: 480px) {
  .wrap { padding: 0 16px; }
  .nav { margin: 0 -16px; padding: 0 4px; }
  .top__inner { gap: 0 8px; }
  .top__inner > .btn { padding: 0 10px; }
  .logo { font-size: 1rem; }
  .logo__mark { width: 28px; height: 28px; }
  .lang a { min-width: 36px; }
}
/* Very narrow phones: the sign stays, the wordmark is kept for screen readers only,
   so the header row (sign, language, contact) fits without wrapping. */
@media (max-width: 380px) {
  .logo > span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
}

/* Pointer feedback only where a pointer can hover, so touch screens don't keep a stuck hover state. */
@media (hover: hover) and (pointer: fine) {
  .nav a:hover, .lang a:hover { color: var(--color-text); background: var(--fill); }
  .btn:hover { filter: brightness(1.06); }
  .btn--ghost:hover { background: var(--fill); border-color: var(--color-text-muted); filter: none; }
  .faq summary:hover { color: var(--color-link); }
  .logo:hover .logo__dot { transform: scale(1.5); }
  .contact__mail:hover { color: var(--color-link); }
  .foot a:hover { color: var(--color-text); }
}
/* Press feedback for every input, after the hover block so :active wins over :hover.
   It replaces the browser tap highlight removed above. */
.btn:active, .btn:hover:active { filter: brightness(.94); }
.btn--ghost:active, .btn--ghost:hover:active { background: var(--fill); filter: none; }
.nav a:active, .lang a:active { color: var(--color-text); background: var(--fill); transform: scale(.96); }
.logo:active { opacity: .7; }
.logo:active .logo__mark { transform: scale(.92); }
.faq summary:active, .contact__mail:active { color: var(--color-link); }
.contact__mail:active { transform: scale(.98); }
.foot a:active { color: var(--color-text); }

/* System accessibility settings. Reduced motion drops movement (press scale, chevron turn)
   and keeps color and opacity changes, which carry state rather than motion. */
@media (prefers-reduced-motion: reduce) {
  .btn { transition-property: filter, background-color, border-color; }
  .btn:active, .btn:hover:active { transform: none; }
  .faq summary::after { transition: none; }
  /* Hero: a short fade, all together, no rise and no delays. */
  .hero .eyebrow, .hero h1, .hero .lead, .hero__cta { animation: fade-in 200ms var(--ease-out) backwards; }
  /* Section blocks never hide (site.js also skips them); this covers a setting changed mid-visit. */
  [data-reveal] { opacity: 1; animation: none; }
  .logo__mark, .logo__dot, .nav a, .lang a, .contact__mail { transition: none; }
  .logo:hover .logo__dot, .logo:active .logo__mark, .nav a:active, .lang a:active, .contact__mail:active { transform: none; }
}
/* FAQ under reduced motion: the height snaps, only the answer's fade stays. */
@supports (interpolate-size: allow-keywords) and selector(::details-content) {
  @media (prefers-reduced-motion: reduce) {
    .faq details::details-content { transition: opacity 200ms var(--ease-out), content-visibility 200ms allow-discrete; }
  }
}

/* Print: everything at rest and visible. */
@media print {
  .hero .eyebrow, .hero h1, .hero .lead, .hero__cta, [data-reveal] { animation: none; opacity: 1; }
}

/* Reduce Transparency: a solid header instead of the blurred one. */
@media (prefers-reduced-transparency: reduce) {
  .top { background: var(--color-bg); -webkit-backdrop-filter: none; backdrop-filter: none; }
}

/* Increase Contrast: stronger separators and secondary text, derived from the brand text color.
   Token overrides live in tokens.css. */
@media (prefers-contrast: more) {
  .top { background: var(--color-bg); -webkit-backdrop-filter: none; backdrop-filter: none; }
  .lang a[aria-current="page"] { text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 4px; }
}
