/*
  Armsin Digital Media — style.css
  Build stamp (tastemaker):
  macrostructure=Simplified Feature Stack | archetypes=minimal-sticky-nav, split-hero+illustration, 3col-icon-cards, form-contact
  mood=retro-terminal/CRT (user-directed repaint, 2026-09-05, see .tastemaker/decisions.log) | palette=user-chosen from 3 named directions
  contrast=hand-calculated (Python unavailable) — see decisions.log for the accent/on-accent pairing math
  scope=site-wide recolor: light "paper" theme -> dark CRT theme. Structure/layout/motion unchanged from
  the previous pass — only color tokens and per-rule color assignments changed. --ink/--paper previously
  did double duty as both a background AND a text color depending on context; this repaint splits those
  roles into --bg/--surface (backgrounds) and --text/--text-dim (text), see the token block below.
*/

/* ---------- Tokens ---------- */
:root {
  --bg: #0A0E0C;              /* page background + hero/nav/footer chrome — all unified under one near-black now that the whole site is dark by default, not just a few accent sections */
  --surface: #131E17;         /* elevated card/panel fill (service cards, forms, booking frame) — was --paper/--white's "light card" role */
  --surface-2: #0E1512;       /* recessed fill for inputs nested inside a --surface card, between --bg and --surface */
  --secondary: #0F1A14;       /* alternate section background (Services, Booking) — distinct dark green-black from --bg for section rhythm */
  --text: #D6E8DD;            /* primary text everywhere — was --ink's text role + --paper's light-text-on-dark role, now one token since the whole page is dark */
  --text-dim: rgba(214, 232, 221, 0.68); /* secondary/muted text — was --neutral + --paper-dim */
  --accent: #39D97A;          /* phosphor-green primary accent — was the burnt-orange #C1592B */
  --accent-dark: #2BB863;     /* accent hover-darken */
  --on-accent: #06120B;       /* near-black text for use ON the bright accent fill (buttons, badges) — white-on-accent measured ~1.8:1 (fails), --on-accent measures ~10.5:1 */
  --amber: #BA5629;           /* logo orange — measured from the real asset (assets/logo/armsin-wordmark.png's cursor bar), was a guessed generic amber #E0A458; now the site's second terminal color alongside phosphor-green */
  --amber-dark: #9A4620;      /* amber hover-darken, same lightness-step relationship as --accent/--accent-dark */
  --amber-glow: rgba(186, 86, 41, 0.35);
  --amber-wash: rgba(186, 86, 41, 0.12);

  --font-head: 'JetBrains Mono', 'Courier New', monospace;
  --font-body: 'Inter', -apple-system, sans-serif;

  --space-1: 8px;
  --space-2: 16px;
  --space-3: 24px;
  --space-4: 32px;
  --space-6: 48px;
  --space-8: 64px;
  --space-12: 96px;
  --space-16: 128px;

  --radius: 14px;
  --max-width: 1880px;

  /* Alpha-blended surface tokens — named once, reused everywhere instead of
     hand-typed rgba() at each call site. All light-alpha tokens are now
     based on --text (since backgrounds are dark), not --ink/--paper. */
  --wash: rgba(214, 232, 221, 0.05);
  --border-subtle: rgba(214, 232, 221, 0.08);
  --border-default: rgba(214, 232, 221, 0.14);
  --border-strong: rgba(214, 232, 221, 0.24);
  --shadow-soft: rgba(0, 0, 0, 0.35);
  --shadow-lift: rgba(0, 0, 0, 0.5);
  --shadow-card: rgba(0, 0, 0, 0.4);
  --accent-wash: rgba(57, 217, 122, 0.12);
  --accent-tint: rgba(57, 217, 122, 0.14);
  --accent-ring: rgba(57, 217, 122, 0.28);
  --accent-glow: rgba(57, 217, 122, 0.12);
  --accent-glow-strong: rgba(57, 217, 122, 0.28);
  --accent-shadow: rgba(57, 217, 122, 0.35);

  /* Motion scale — every transition/animation in this file draws from here.
     Curves are the strong UI-grade beziers, not the weak CSS built-ins. */
  --duration-fast: 150ms;
  --duration-base: 200ms;
  --duration-lift: 220ms;
  --duration-reveal: 500ms;
  --duration-drawer: 320ms;
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-swing: cubic-bezier(0.77, 0, 0.175, 1);
  --stagger-step: 90ms;
}

/* ---------- Reset ---------- */
* { box-sizing: border-box; margin: 0; padding: 0; }

html { scroll-behavior: smooth; scroll-padding-top: 84px; }

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  position: relative;
  /* Header is fixed (see .site-header) and sits outside document flow;
     this keeps every page's first section clear of the floating pill. */
  padding-top: 84px;
}

/* Faint paper grain over the whole page — a cheap, honest way to keep flat
   color fields from reading as a slick, machine-perfect gradient render. */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 999;
  pointer-events: none;
  opacity: 0.035;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

@media (prefers-reduced-motion: reduce) {
  body::before { opacity: 0.025; }
}

/* One retro CRT scanline field + phosphor sweep for every secondary page
   (scoped to body.crt-page — every page except the homepage, which keeps
   its own existing Trust/Process treatment) — fixed to the viewport so
   the whole page shares one continuous beat instead of each section
   running its own separate copy. */
body.crt-page::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 998;
  pointer-events: none;
  background-image:
    repeating-linear-gradient(
      to bottom,
      var(--wash) 0,
      var(--wash) 1px,
      transparent 1px,
      transparent 3px
    ),
    linear-gradient(
      to bottom,
      transparent,
      var(--accent-glow-strong) 45%,
      var(--accent-glow-strong) 55%,
      transparent
    );
  background-repeat: repeat, no-repeat;
  background-size: 100% 100%, 100% 45vh;
  background-position: 0 0, 0 -45vh;
  animation: crt-page-sweep 14s linear infinite;
}

@keyframes crt-page-sweep {
  0%   { background-position: 0 0, 0 -45vh; }
  100% { background-position: 0 0, 0 100vh; }
}

@media (prefers-reduced-motion: reduce) {
  body.crt-page::after { animation: none; background-position: 0 0, 0 30vh; }
}


/* Every heading uses the display face at a size well above body text, so
   it needs its own tighter rhythm — inheriting body's 1.6 line-height (a
   value tuned for long-form German paragraphs) read visibly loose on
   every H1/H2 that didn't already set its own. Selectors below with their
   own line-height (.hero h1, .contact-info h2) win on specificity. */
h1, h2, h3 {
  line-height: 1.15;
  letter-spacing: -0.01em;
}

img { max-width: 100%; display: block; }

.container {
  width: 94%;
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0 var(--space-3);
}

/* ---------- Header: floating pill nav ---------- */
/* Transparent full-width strip that just positions the pill; the pill
   itself (.floating-nav) is the only thing that paints, so it reads as
   floating above the page rather than a bar spanning the viewport. See
   body's padding-top and html's scroll-padding-top for the clearance this
   fixed positioning requires elsewhere. */
.site-header {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  z-index: 1000;
  height: 0;
  display: flex;
  justify-content: center;
  align-items: flex-start;
  pointer-events: none;
}

.floating-nav {
  position: relative;
  pointer-events: auto;
  margin-top: 14px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  width: max-content;
  max-width: calc(100vw - 32px);
  background: var(--bg);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 999px;
  padding: 6px;
  box-shadow: 0 12px 32px var(--shadow-lift), 0 2px 8px var(--shadow-soft);
  /* Drop-in on load: a single, rare-tier entrance (see .site-header — the
     nav is the first thing painted, so it earns a small announcement). */
  opacity: 0;
  transform: translateY(-14px);
  animation: nav-drop-in var(--duration-reveal) var(--ease-out) 120ms forwards;
}

@keyframes nav-drop-in {
  to { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .floating-nav {
    animation: none;
    opacity: 1;
    transform: none;
  }
}

.nav-logo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  flex-shrink: 0;
  text-decoration: none;
  transition: transform var(--duration-fast) var(--ease-out);
}

.nav-logo img {
  width: 100%;
  height: 100%;
  border-radius: 50%;
}

@media (hover: hover) and (pointer: fine) {
  .nav-logo:hover {
    transform: scale(1.06);
  }
}

.nav-logo:active {
  transform: scale(0.94);
}

.nav-menu {
  display: flex;
  align-items: center;
  gap: 4px;
}

.nav-links {
  position: relative;
  display: flex;
  align-items: center;
}

/* The sliding highlight — JS sets `left`/`width` directly to match the
   hovered link's own box. (A scaleX-transform version of this used to fake
   the width change to keep it compositor-only, but non-uniformly scaling a
   round-cornered box distorts its border-radius into flattened ellipses —
   the pill stopped looking round and reads as misaligned. Transitioning
   left/width is a hair more expensive but the nav is tiny, so it's fine.) */
.nav-indicator {
  position: absolute;
  top: 0;
  left: var(--indicator-x, 0);
  width: var(--indicator-width, 0);
  height: 100%;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.08);
  opacity: 0;
  transition: left var(--duration-base) var(--ease-out), width var(--duration-base) var(--ease-out), opacity var(--duration-fast) ease;
  pointer-events: none;
}

.nav-links.is-tracking .nav-indicator {
  opacity: 1;
}

.site-nav,
.nav-links a {
  position: relative;
  display: inline-flex;
  align-items: center;
  padding: 10px 18px;
  border-radius: 999px;
  color: rgba(255, 255, 255, 0.68);
  text-decoration: none;
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.01em;
  white-space: nowrap;
  transition: color var(--duration-base) ease;
}

.nav-links a:hover,
.nav-links a:focus-visible,
.nav-links a.is-active {
  color: var(--text);
}

.nav-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 10px 20px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--on-accent);
  text-decoration: none;
  font-size: 0.8125rem;
  font-weight: 700;
  white-space: nowrap;
  transition: background-color var(--duration-base) ease, transform var(--duration-fast) var(--ease-out), box-shadow var(--duration-base) ease;
}

.nav-cta:hover {
  background: var(--accent-dark);
  box-shadow: 0 6px 16px var(--accent-shadow);
}

@media (hover: hover) and (pointer: fine) {
  .nav-cta:hover { transform: translateY(-1px); }
}

.nav-cta:active {
  transform: translateY(0) scale(0.97);
}

/* Nav trigger — hidden on desktop (the pill has room for links inline),
   shown only once the menu collapses into the dropdown below. */
.nav-toggle {
  display: none;
  width: 40px;
  height: 40px;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  flex-shrink: 0;
  background: transparent;
  border: none;
  border-radius: 50%;
  cursor: pointer;
  transition: background-color var(--duration-base) ease;
}

.nav-toggle:hover {
  background: rgba(255, 255, 255, 0.08);
}

.nav-toggle span {
  display: block;
  width: 16px;
  height: 1.5px;
  background: rgba(255, 255, 255, 0.75);
  transition: background-color var(--duration-base) ease, transform var(--duration-base) ease, opacity var(--duration-base) ease;
}

.floating-nav.nav-open .nav-toggle span:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
.floating-nav.nav-open .nav-toggle span:nth-child(2) { opacity: 0; }
.floating-nav.nav-open .nav-toggle span:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); }

@media (max-width: 700px) {
  /* Below 700px the pill shrinks to just the logo + toggle; the links and
     CTA move into a dropdown card anchored under it, so the collapsed pill
     still hugs its (now much smaller) content instead of reserving space
     for a menu that isn't there. */
  .nav-toggle {
    display: flex;
  }

  .nav-menu {
    position: absolute;
    top: calc(100% + 10px);
    left: 50%;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    width: max-content;
    min-width: 220px;
    background: var(--bg);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 20px;
    padding: 8px;
    box-shadow: 0 16px 40px var(--shadow-lift);
    transform: translateX(-50%) translateY(-6px) scale(0.96);
    transform-origin: top center;
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--duration-base) var(--ease-out), transform var(--duration-base) var(--ease-out);
  }

  .floating-nav.nav-open .nav-menu {
    opacity: 1;
    pointer-events: auto;
    transform: translateX(-50%) translateY(0) scale(1);
  }

  .nav-links {
    flex-direction: column;
    align-items: stretch;
  }

  .nav-indicator {
    display: none;
  }

  .nav-links a {
    padding: 12px 16px;
    border-radius: 12px;
  }

  .nav-links a:hover,
  .nav-links a:focus-visible,
  .nav-links a.is-active {
    background: rgba(255, 255, 255, 0.06);
  }

  .nav-cta {
    margin-top: 4px;
  }

  /* Each dropdown item gets its own small stagger on open rather than the
     card fading in as one flat block. */
  .nav-menu > * {
    opacity: 0;
    transform: translateY(-6px);
    transition: opacity var(--duration-base) var(--ease-out), transform var(--duration-base) var(--ease-out);
  }

  .floating-nav.nav-open .nav-menu > * {
    opacity: 1;
    transform: translateY(0);
  }

  .floating-nav.nav-open .nav-links a:nth-child(1) { transition-delay: calc(var(--stagger-step) * 1); }
  .floating-nav.nav-open .nav-links a:nth-child(2) { transition-delay: calc(var(--stagger-step) * 2); }
  .floating-nav.nav-open .nav-links a:nth-child(3) { transition-delay: calc(var(--stagger-step) * 3); }
  .floating-nav.nav-open .nav-cta { transition-delay: calc(var(--stagger-step) * 4); }
}

@media (prefers-reduced-motion: reduce) {
  .nav-menu,
  .nav-menu > * {
    transition-duration: 1ms !important;
    transition-delay: 0ms !important;
    transform: none !important;
  }
}

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  padding: 14px 28px;
  border-radius: 999px;
  font-family: var(--font-body);
  font-size: 1rem;
  font-weight: 700;
  text-decoration: none;
  border: none;
  cursor: pointer;
  transition:
    transform var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-base) ease,
    background-color var(--duration-base) ease;
}

.btn-primary {
  background: var(--accent);
  color: var(--on-accent);
}

.btn-primary:hover {
  background: var(--accent-dark);
  box-shadow: 0 8px 20px var(--accent-shadow);
}

@media (hover: hover) and (pointer: fine) {
  .btn-primary:hover { transform: translateY(-2px); }
}

/* Press feedback: every button click gets a quick tactile scale-down,
   not just the primary CTA — this is feedback, not decoration, so it's tier-appropriate
   even at "clicked occasionally" frequency. */
.btn:active { transform: translateY(0) scale(0.97); }

.btn-ghost {
  background: transparent;
  color: var(--text);
  border: 1.5px solid var(--border-strong);
}

@media (hover: hover) and (pointer: fine) {
  .btn-ghost:hover {
    border-color: var(--amber);
    background: var(--amber-wash);
  }
}

/* ---------- Focus states (keyboard navigation) ---------- */
.btn:focus-visible,
.logo:focus-visible,
.footer-links a:focus-visible,
.contact-details a:focus-visible,
.nav-toggle:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.form-row input:focus-visible,
.form-row textarea:focus-visible {
  outline: none;
}

/* ---------- Hero ---------- */
/* Full-bleed dark stage: the retro PC is the main character, copy sits over
   it on a plain ink field — no blurred decorative color blobs (an earlier
   version had them; removed, see .tastemaker/decisions.log, they read as
   the generic AI-hero background tell regardless of palette). */
.hero {
  position: relative;
  background: var(--bg);
  /* Pulls up into body's fixed-nav clearance (see body's padding-top) so
     the dark hero fills the viewport edge-to-edge instead of leaving a
     paper-colored strip above it. */
  margin-top: -84px;
  padding: calc(10px + 84px) 0 10px;
  overflow: hidden;
  isolation: isolate;
  /* Gives the absolutely centered .hero-visual room to sit behind the copy
     at full size, at every viewport height, instead of the section's
     height being dictated by content flow. */
  min-height: clamp(480px, 72vh, 760px);
  display: grid;
}

.hero .container {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  text-align: left;
  width: 100%;
  height: 100%;
}

/* Small kicker tag above the 3D object, styled like the floating code
   panels behind it (dark box, hairline border, same glow shadow) so it
   reads as part of the same terminal-window vocabulary. */
.hero-eyebrow {
  position: relative;
  z-index: 2;
  display: inline-block;
  justify-self: center;
  margin: 0 auto var(--space-2);
  padding: 0.5em 0.9em;
  background: #06120b;
  border: 1px solid var(--border-subtle);
  border-radius: 0.5em;
  box-shadow: 0 0.8em 1.6em rgba(0, 0, 0, 0.45), 0 0 1.4em rgba(57, 217, 122, 0.06);
  font-family: var(--font-head);
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
}

.hero-copy {
  position: relative;
  z-index: 1;
  max-width: 640px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  height: 100%;
  padding: var(--space-6) 0;
}

.hero-copy::before {
  content: '';
  position: absolute;
  inset: -10% -10% -10% -30%;
  z-index: -1;
  background: radial-gradient(closest-side, rgba(0, 0, 0, 0.75), rgba(0, 0, 0, 0) 72%);
  filter: blur(6px);
  pointer-events: none;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  justify-content: flex-start;
}

/* .btn-ghost is otherwise ink-on-paper; the hero sits on a dark ink
   background, so it needs paper-colored text/border here instead. */
.hero .btn-ghost {
  color: var(--text);
  border-color: var(--border-subtle);
}

@media (hover: hover) and (pointer: fine) {
  .hero .btn-ghost:hover {
    border-color: var(--amber);
    background: var(--amber-wash);
  }
}

@media (max-width: 600px) {
  .hero { padding: calc(10px + 84px) 0 10px; }

  .hero-actions {
    justify-content: flex-start;
    flex-direction: column;
    width: 100%;
  }

  .hero-actions .btn { width: 100%; }
}

/* The illustration is the hero's centerpiece: a single large square centered
   over the whole section, behind the copy (z-index below .container),
   sized off both viewport width and height so it stays big and in the
   middle at every screen size without ever outgrowing the section. The
   text column is narrower than this, so the object's floating panels and
   chips show past its edges — the object reads as surrounded by the copy
   rather than stacked with it. Decorative only, so pointer-events stay off. */
.hero-visual {
  position: absolute;
  top: 50%;
  right: 0;
  left: auto;
  transform: translateY(-50%);
  /* Full section width, but backed off by calc() so the box (1:1 here)
     never grows taller than the viewport has room for — plain width:100%
     let it overflow past the fold on short viewports instead of just
     filling the width the section actually has spare. */
  width: min(100%, calc(100vh - 220px));
  z-index: 1;
  pointer-events: none;
  animation: hero-visual-enter 1.2s var(--ease-out) both;
}

@keyframes hero-visual-enter {
  from { opacity: 0; transform: translateY(-50%) scale(0.82) rotate(-3deg); }
  to   { opacity: 1; transform: translateY(-50%) scale(1) rotate(0); }
}

.hero-visual-frame {
  filter: drop-shadow(0 30px 50px rgba(0, 0, 0, 0.45));
  animation: hero-float 6s var(--ease-swing) infinite;
}

.hero-visual img { width: 100%; height: auto; }

@keyframes hero-float {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-10px); }
}

/* ---------- Retro PC hero centerpiece ----------
   The 3D retro-workstation (see .hero-model below) plus two floating
   code-window panels: the objects the hero composition is built from.
   .pc-scene holds the CSS perspective for the code-floats' pointer-tilt
   effect (see initHeroParallax in assets/js/site.js); .pc-scene-inner is
   the tilted, preserve-3d layer so the floaters read as sitting at their
   own depth. All sizes are in em off a single clamp()'d font-size below,
   so the whole scene scales as one unit with no extra breakpoints. */
.pc-scene {
  position: relative;
  aspect-ratio: 1 / 1;
  perspective: 1400px;
}

.pc-scene-inner {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  transform-style: preserve-3d;
  transform: rotateX(calc(var(--tilt-y, 0) * -6deg)) rotateY(calc(var(--tilt-x, 0) * 9deg));
  transition: transform 500ms var(--ease-out);
  font-size: clamp(11px, 3.6vw, 21px);
}

@media (min-width: 900px) {
  .pc-scene-inner { font-size: clamp(13px, 2.6vw, 24px); }
}

/* -- the 3D retro-workstation model (assets/models/retro-workstation.glb,
   rendered by assets/js/hero-model.js via three.js) -- sits centered in
   .pc-scene, a sibling of .pc-scene-inner rather than inside its tilted
   layer: the canvas gets its own pointer-driven rotation in JS (real 3D),
   so stacking it under a CSS 3D transform too would double the effect and
   skew the WebGL output. The two code-float panels keep the original CSS
   tilt on .pc-scene-inner. */
.hero-model {
  /* Real box sizing, not a CSS transform: scale() — the canvas is sized off
     this element's clientWidth/clientHeight (see fit() in hero-model.js), so
     stretching it bigger with `transform` would render at the old small
     resolution and blow the raster up (fuzzy). Growing the actual box means
     three.js renders natively at the bigger size. */
  position: absolute;
  top: 50%;
  left: 50%;
  /* 225% oversized the canvas to compensate for the old wide establishing
     shot, where the PC only filled a modest part of the camera's view (see
     the ≥900px override below, which already dropped this for the same
     reason). The close-up camera now does that framing itself end to end,
     so the box should match its container ~1:1 here too — the leftover
     225% on mobile was zooming in and clipping the screen mesh's edges. */
  width: 106%;
  height: 106%;
  z-index: 0;
  opacity: 0; /* faded in by hero-model.js (adds .is-loaded) once the GLB has loaded */
  transform: translate(-50%, -50%) scale(0.94);
  transition: opacity 400ms cubic-bezier(0.23, 1, 0.32, 1), transform 400ms cubic-bezier(0.23, 1, 0.32, 1);
}

.hero-model.is-loaded {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}

/* Soft CRT-style glow sitting behind the model, on its own layer so only
   `opacity` animates — the canvas above it (renderer alpha:true) stays
   untouched by the breathing loop. */
.hero-model::before {
  content: '';
  position: absolute;
  inset: -34%;
  z-index: 0;
  background: radial-gradient(circle at 50% 46%, var(--accent-glow-strong) 0%, var(--accent-glow) 45%, transparent 72%);
  opacity: 0.75;
  animation: hero-model-glow-breathe 4.5s ease-in-out infinite;
  pointer-events: none;
}

@keyframes hero-model-glow-breathe {
  0%, 100% { opacity: 0.55; }
  50% { opacity: 1; }
}

.hero-model canvas {
  display: block;
  width: 100%;
  height: 100%;
  position: relative;
  z-index: 1;
}

/* -- the two floating code-window panels -- */
.code-float {
  position: absolute;
  width: 8.4em;
  padding: 0.6em 0.7em;
  background: #06120b;
  border: 1px solid var(--border-subtle);
  border-radius: 0.5em;
  box-shadow: 0 0.8em 1.6em rgba(0, 0, 0, 0.45), 0 0 1.4em rgba(57, 217, 122, 0.06);
  display: flex;
  flex-direction: column;
  gap: 0.3em;
  /* Secondary to the monitor screen, not competing with it for focus. */
  opacity: 0.7;
}

.code-float-bar {
  display: flex;
  gap: 0.22em;
  margin-bottom: 0.15em;
}

.code-float-dot {
  width: 0.4em;
  height: 0.4em;
  border-radius: 50%;
  background: rgba(214, 232, 221, 0.25);
}

.code-line {
  display: block;
  width: var(--w, 60%);
  height: 0.32em;
  border-radius: 999px;
  background: var(--text);
  opacity: 0.9;
}

.code-line-accent { background: var(--accent); }
.code-line-amber { background: var(--amber); }

/* One-time "typing in" of each code bar on page load — reinforces the
   terminal identity as the hero's first impression (rare/first-time tier,
   so the delight budget applies). Growing scaleX from the left reads as
   text appearing, same motion a real terminal cursor would trace, without
   animating width/layout. Runs once after the monitor/floaters have faded
   and settled in (see hero-visual-enter/hero-float delays below), then
   holds — it never repeats on scroll or revisit within the same load. */
.code-line {
  transform-origin: left center;
  animation: code-line-grow var(--duration-reveal) var(--ease-out) both;
  animation-delay: 1.05s;
}

@keyframes code-line-grow {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

.code-float-a .code-line:nth-child(2) { animation-delay: calc(1.35s + var(--stagger-step)); }
.code-float-a .code-line:nth-child(3) { animation-delay: calc(1.35s + var(--stagger-step) * 2); }
.code-float-a .code-line:nth-child(4) { animation-delay: calc(1.35s + var(--stagger-step) * 3); }
.code-float-a .code-line:nth-child(5) { animation-delay: calc(1.35s + var(--stagger-step) * 4); }

.code-float-b .code-line:nth-child(2) { animation-delay: calc(1.35s + var(--stagger-step)); }
.code-float-b .code-line:nth-child(3) { animation-delay: calc(1.35s + var(--stagger-step) * 2); }
.code-float-b .code-line:nth-child(4) { animation-delay: calc(1.35s + var(--stagger-step) * 3); }

/* Each floater sits at its own depth/position and runs its own float loop
   (own duration + negative delay so they start mid-cycle, out of phase with
   each other and with the monitor's own hero-float bob) so the three
   objects in the scene read as independently alive, not one rigid group. */
.code-float-a {
  top: 14%;
  left: 10%;
  transform: translateZ(1.1em) rotate(-4deg);
  animation: code-float-drift-a 7s ease-in-out infinite;
}

.code-float-b {
  bottom: 16%;
  right: 8%;
  width: 7.6em;
  transform: translateZ(1.6em) rotate(3deg);
  animation: code-float-drift-b 8.5s ease-in-out infinite -3.2s;
}

/* Desktop-only: ease the two floaters outward, away from the monitor, over
   the same span and curve as the camera's cinematic push-in (INTRO_MS/
   EASE_GENTLE in hero-model.js — 8.5s, easeInOutCubic) so all three elements
   read as one deliberate shot settling into place together. Left/top and
   right/bottom (not `transform`) carry the move so it composes with the
   drift keyframes above instead of fighting them for the same property.
   `.hero-model.is-loaded` lands the instant the GLB decodes, which is also
   when the JS intro starts — see `container.classList.add('is-loaded')`
   right before `intro.phase = 'in'` in hero-model.js. Phone/tablet keep the
   floaters static; only worth the motion where the wider 4:3 close-up (see
   the ≥900px .pc-scene rule) gives them room to travel. */
@media (min-width: 900px) and (prefers-reduced-motion: no-preference) {
  .code-float-a,
  .code-float-b {
    transition: left 8.5s cubic-bezier(0.65, 0, 0.35, 1), top 8.5s cubic-bezier(0.65, 0, 0.35, 1),
      right 8.5s cubic-bezier(0.65, 0, 0.35, 1), bottom 8.5s cubic-bezier(0.65, 0, 0.35, 1);
  }

  .hero-model.is-loaded ~ .pc-scene-inner .code-float-a {
    top: 4%;
    left: -8%;
  }

  .hero-model.is-loaded ~ .pc-scene-inner .code-float-b {
    bottom: 8%;
    right: -8%;
  }
}

@keyframes code-float-drift-a {
  0%, 100% { transform: translateZ(1.1em) translateY(0) rotate(-4deg); }
  50% { transform: translateZ(1.1em) translateY(-0.7em) rotate(-2deg); }
}

@keyframes code-float-drift-b {
  0%, 100% { transform: translateZ(1.6em) translateY(0) rotate(3deg); }
  50% { transform: translateZ(1.6em) translateY(0.6em) rotate(5deg); }
}

@media (max-width: 600px) {
  /* Small screens: less side clearance around the model overall, so the
     floaters shrink and pin to the actual corners (0% insets, not the
     desktop's 14%/16%) instead of overlapping its screen. */
  .code-float-a { top: 0; left: 0; width: 6.2em; }
  .code-float-b { bottom: 0; right: 0; width: 5.6em; }
}

/* Below the desktop breakpoint the overlay layout (visual centered full-hero,
   copy vertically centered on top of it) makes the CTA buttons land mid-image
   instead of below it. Fall back to plain stacked flow here — visual first,
   then buttons underneath — same idea as the ≥900px block below, just left-
   aligned instead of centered. */
@media (max-width: 899px) {
  .hero {
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    min-height: 0;
  }

  .hero-visual {
    position: relative;
    top: auto;
    right: auto;
    transform: none;
    /* var(--space-5) doesn't exist in the spacing scale (1,2,3,4,6,8 —
       see :root) — that made this whole margin shorthand invalid, so the
       browser dropped it entirely and left zero space here, letting the
       desk plate/glow sit right on top of the CTA button below it. */
    margin: 0 auto var(--space-6);
    animation-name: hero-visual-enter-centered;
  }

  .hero .container {
    height: auto;
    align-items: center;
    justify-content: flex-start;
  }

  .hero-copy {
    height: auto;
    padding: 0;
  }

  .hero-copy::before {
    display: none;
  }

  /* Stacked layout puts the buttons under the (centered) visual, not beside
     it — left-aligned here read as off-center under a centered monitor. */
  .hero-actions {
    justify-content: center;
  }
}

@media (min-width: 900px) {
  .hero { padding: calc(10px + 84px) 0 10px; }

  /* Full section width when there's room, but backed off through the box's
     own aspect ratio (4/3 here, see .pc-scene below) by the height the
     viewport actually has spare — plain width:100% let a 4:3 box grow
     taller than the viewport on typical laptop heights, pushing the CTA
     row off-screen below the fold. The camera's own framing (fillFraction
     in hero-model.js) still controls how close the shot is, independent of
     this box's size. */
  .hero-visual { width: min(100%, calc((100vh - 260px) * 4 / 3)); }

  /* Desktop close-up widens from the base 1:1 (see .pc-scene) to 4:3 — the
     square box left the desk plate's corners sitting right at the frame's
     left/right edges with no breathing room. Widening the frame (not the
     camera's zoom on the monitor) gives that geometry room either side
     instead of nudging the whole close-up out further to compensate. */
  .pc-scene { aspect-ratio: 4 / 3; }

  /* Big screens: object centered, buttons stacked under it (DOM order
     already puts .hero-visual before .container, so switching both out
     of the absolute-overlay layout into a centered flex column is enough). */
  .hero {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: left;
    gap: var(--space-2);
  }

  .hero-visual {
    position: relative;
    top: auto;
    right: auto;
    transform: none;
    animation-name: hero-visual-enter-centered;
  }

  .hero .container,
  .hero-copy {
    height: auto;
    align-items: center;
    text-align: center;
    padding: 0;
  }

  .hero-copy::before { display: none; }

  .hero-actions { justify-content: center; }
}

@keyframes hero-visual-enter-centered {
  from { opacity: 0; transform: scale(0.82) rotate(-3deg); }
  to   { opacity: 1; transform: scale(1) rotate(0); }
}

/* Hero copy is now just the CTA buttons (no headline/lead), so the visual
   no longer has legibility to fight for on phones — let it stay full size. */
@media (max-width: 600px) {
  .hero-copy::before {
    inset: -15% -15% -15% -15%;
  }
}

/* ---------- Reveal-on-scroll ----------
   Single declarative primitive: mark anything with [data-reveal] and it fades
   and rises into place the first time it enters the viewport. Stagger is
   expressed as transition-delay on direct children where a group should
   cascade rather than pop in together (hero copy, service cards) — no
   parallel animation mechanism, this is the only one in the codebase. */
[data-reveal] {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity var(--duration-reveal) var(--ease-out), transform var(--duration-reveal) var(--ease-out);
}

[data-reveal].is-visible {
  opacity: 1;
  transform: translateY(0);
}

/* Reusable version of the same cascade for any other group of direct
   [data-reveal] siblings (page-hero tag/h1/lead, studio/about hero copy)
   instead of one-off nth-child rules per section. */
[data-reveal-group] > [data-reveal]:nth-child(2) { transition-delay: var(--stagger-step); }
[data-reveal-group] > [data-reveal]:nth-child(3) { transition-delay: calc(var(--stagger-step) * 2); }
[data-reveal-group] > [data-reveal]:nth-child(4) { transition-delay: calc(var(--stagger-step) * 3); }

@media (prefers-reduced-motion: reduce) {
  [data-reveal] {
    opacity: 1;
    transform: none;
    transition: none;
  }
  .btn-primary:hover,
  .btn:active,
  .service-card:hover,
  .service-card:hover .service-icon-badge,
  .process-step:hover .process-num {
    transform: none;
  }
  .hero-visual-frame {
    animation: none;
  }
  .hero-visual {
    animation: none;
    opacity: 1;
  }
  .pc-scene-inner {
    transition: none;
    transform: none;
  }
  .hero-model {
    transition: opacity 400ms ease;
  }
  .hero-model::before {
    animation: none;
    opacity: 0.55;
  }
  .code-float-a,
  .code-float-b,
  .code-line,
  .timeline-cursor {
    animation: none;
  }
  .timeline-cursor { opacity: 1; }
  .timeline-node {
    transition: none;
  }
}

/* ---------- Services ---------- */
.services {
  background: var(--secondary);
  padding: var(--space-12) 0;
}

@media (max-width: 600px) {
  .services { padding: var(--space-8) 0; }
}

.section-head {
  text-align: center;
  max-width: 560px;
  margin: 0 auto var(--space-8);
}

.section-head h2 {
  font-family: var(--font-head);
  font-size: clamp(1.7rem, 3.5vw, 2.3rem);
  font-weight: 600;
  color: var(--text);
  margin-bottom: var(--space-2);
  text-wrap: pretty;
}

.section-head p {
  color: var(--text-dim);
  font-size: 1.05rem;
}

.services-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-4);
}

.services-grid-4 {
  grid-template-columns: repeat(4, 1fr);
}

@media (max-width: 860px) {
  .services-grid { grid-template-columns: 1fr; }
}

@media (min-width: 861px) and (max-width: 1080px) {
  .services-grid-4 { grid-template-columns: repeat(2, 1fr); }
}

/* Group stagger: each card lags the previous by one --stagger-step so they
   cascade into place instead of popping in together (same [data-reveal]
   primitive as the hero, just a different parent selector). */
.services-grid [data-reveal]:nth-child(2) { transition-delay: var(--stagger-step); }
.services-grid [data-reveal]:nth-child(3) { transition-delay: calc(var(--stagger-step) * 2); }
.services-grid [data-reveal]:nth-child(4) { transition-delay: calc(var(--stagger-step) * 3); }

.service-card {
  background: var(--surface);
  border-radius: var(--radius);
  padding: var(--space-6);
  transform: rotate(var(--tilt, 0deg));
  transition: transform var(--duration-lift) var(--ease-out), box-shadow var(--duration-lift) var(--ease-out);
}

.service-card:nth-child(1) { --tilt: -0.6deg; }
.service-card:nth-child(2) { --tilt: 0.5deg; }
.service-card:nth-child(3) { --tilt: -0.4deg; }

@media (hover: hover) and (pointer: fine) {
  .service-card:hover {
    transform: rotate(0deg) translateY(-4px);
    box-shadow: 0 16px 32px var(--shadow-lift);
  }

  .service-card:hover .service-icon-badge {
    transform: scale(1.08);
  }
}

.service-icon-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  border-radius: 14px;
  background: var(--accent-wash);
  margin-bottom: var(--space-3);
  transition: transform var(--duration-base) var(--ease-out);
}

.service-icon {
  width: 28px;
  height: 28px;
}

.service-card h3 {
  font-family: var(--font-head);
  font-size: 1.25rem;
  font-weight: 600;
  color: var(--text);
  margin-bottom: var(--space-2);
}

.service-card p {
  color: var(--text-dim);
  font-size: 0.98rem;
}

/* ---------- Portfolio (projects.html) ---------- */
.portfolio {
  padding: var(--space-4) 0 var(--space-12);
}

@media (max-width: 600px) {
  .portfolio { padding: var(--space-2) 0 var(--space-8); }
}

.portfolio-filter {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2);
  margin-bottom: var(--space-8);
}

.portfolio-filter-btn {
  font-family: var(--font-head);
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--text-dim);
  background: var(--surface);
  border: 1px solid var(--border-default);
  border-radius: 999px;
  padding: var(--space-2) var(--space-4);
  cursor: pointer;
  transition: color var(--duration-base) var(--ease-out),
              border-color var(--duration-base) var(--ease-out),
              background var(--duration-base) var(--ease-out);
}

.portfolio-filter-btn:hover {
  color: var(--text);
  border-color: var(--border-strong);
}

.portfolio-filter-btn.is-active {
  color: var(--on-accent);
  background: var(--accent);
  border-color: var(--accent);
}

.portfolio-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-4);
}

@media (max-width: 860px) {
  .portfolio-grid { grid-template-columns: 1fr; }
}

.portfolio-card.is-hidden {
  display: none;
}

/* Real project card: a .service-card underneath, so it gets the same
   tilt/hover-lift/box-shadow treatment as Services and Studio cards. */
.portfolio-thumb {
  display: block;
  overflow: hidden;
  width: 100%;
  height: 96px;
  border-radius: calc(var(--radius) - 4px);
  margin-bottom: var(--space-3);
  background: linear-gradient(135deg, var(--surface-2), var(--secondary));
  border: 1px solid var(--border-subtle);
}

.portfolio-thumb img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Minimal card variant: just the image and the arrow link, no title/copy
   below it — the screenshot does the talking. Square crop keeps it
   consistent no matter how wide the source screenshot is. */
.portfolio-card-minimal .portfolio-thumb {
  height: auto;
  aspect-ratio: 1 / 1;
  margin-bottom: var(--space-4);
}

.portfolio-empty {
  text-align: center;
  color: var(--text-dim);
  padding: var(--space-6) 0 0;
}

/* ---------- Project story (project-*.html) ---------- */
.project-story-back {
  display: inline-block;
  color: var(--text-dim);
  font-size: 0.9rem;
  margin-bottom: var(--space-3);
}

.project-story-back:hover {
  color: var(--accent);
}

.project-story {
  padding: var(--space-4) 0 var(--space-12);
}

@media (max-width: 600px) {
  .project-story { padding: var(--space-2) 0 var(--space-8); }
}

.project-story-image {
  display: block;
  text-decoration: none;
  color: inherit;
  max-width: 640px;
  margin: 0 auto var(--space-8);
  border-radius: var(--radius);
  transition: transform var(--duration-lift) var(--ease-out), box-shadow var(--duration-lift) var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .project-story-image:hover {
    transform: translateY(-4px);
    box-shadow: 0 16px 32px var(--shadow-lift);
  }
}

.project-story-thumb {
  height: 280px;
  margin-bottom: 0;
}

.project-story-copy {
  max-width: 640px;
  margin: 0 auto;
}

.project-story-copy p {
  color: var(--text-dim);
  font-size: 1.05rem;
  line-height: 1.6;
  margin-bottom: var(--space-4);
}

.project-story-link a {
  color: var(--accent);
  font-weight: 600;
}

/* ---------- Why us ("Warum Armsin") ---------- */
/* A third, deliberately different archetype from Services (boxed tilted
   cards) and Process (numbered rail): plain text columns divided by a
   thin rule, no card chrome and no icons — three short, honest claims,
   nothing to fabricate proof for. */
.trust {
  position: relative;
  overflow: hidden;
  padding: var(--space-12) 0;
}

@media (max-width: 600px) {
  .trust { padding: var(--space-8) 0; }
}

/* CRT scanline field, not a drifting gradient blob — this project's own
   style-lock already flagged blurred glow blobs as the single most
   recognizable "AI generated this" hero decoration and removed them once
   (see .tastemaker/style-lock.md's anti-slop pass); reusing that same
   pattern here would be the identical mistake on a different section.
   Instead: a faint static scanline texture (the actual retro-terminal
   material) plus one thin light band that sweeps down like a CRT refresh
   pass — a single deliberate motion beat, not two competing shapes. */
.trust::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: repeating-linear-gradient(
    to bottom,
    var(--wash) 0,
    var(--wash) 1px,
    transparent 1px,
    transparent 3px
  );
  opacity: 0.5;
}

.trust::after {
  content: '';
  position: absolute;
  z-index: 0;
  top: -180px;
  left: 0;
  right: 0;
  height: 180px;
  background: linear-gradient(
    to bottom,
    transparent,
    var(--accent-glow-strong) 45%,
    var(--accent-glow-strong) 55%,
    transparent
  );
  filter: blur(22px);
  opacity: 0.3;
  pointer-events: none;
  animation: crt-scan-sweep 11s linear infinite;
}

.trust > .container {
  position: relative;
  z-index: 1;
}

@keyframes crt-scan-sweep {
  0%   { transform: translateY(0); }
  100% { transform: translateY(720px); }
}

@media (prefers-reduced-motion: reduce) {
  .trust::after { animation: none; transform: translateY(260px); }
}

.trust-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-6);
}

@media (max-width: 700px) {
  .trust-grid { grid-template-columns: 1fr; }
}

.trust-grid [data-reveal]:nth-child(2) { transition-delay: var(--stagger-step); }
.trust-grid [data-reveal]:nth-child(3) { transition-delay: calc(var(--stagger-step) * 2); }

.trust-item {
  padding-left: var(--space-4);
  border-left: 1.5px solid var(--border-default);
}

.trust-item:first-child {
  padding-left: 0;
  border-left: none;
}

@media (max-width: 700px) {
  .trust-item {
    padding-left: 0;
    border-left: none;
    padding-top: var(--space-4);
    border-top: 1.5px solid var(--border-default);
  }

  .trust-item:first-child {
    padding-top: 0;
    border-top: none;
  }
}

.trust-item h3 {
  font-family: var(--font-head);
  font-size: 1.3rem;
  font-weight: 600;
  color: var(--text);
  margin-bottom: var(--space-1);
}

.trust-item p {
  color: var(--text-dim);
  font-size: 0.98rem;
}

/* ---------- Process ("So arbeite ich") ---------- */
.process {
  position: relative;
  overflow: hidden;
  padding: var(--space-12) 0;
}

@media (max-width: 600px) {
  .process { padding: var(--space-8) 0; }
}

/* Same scanline-field treatment as .trust, mirrored (amber sweep moving
   upward instead of green moving down) so the two sections read as one
   consistent terminal material, not copy-pasted twins. */
.process::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: repeating-linear-gradient(
    to bottom,
    var(--wash) 0,
    var(--wash) 1px,
    transparent 1px,
    transparent 3px
  );
  opacity: 0.5;
}

.process::after {
  content: '';
  position: absolute;
  z-index: 0;
  top: -160px;
  left: 0;
  right: 0;
  height: 160px;
  background: linear-gradient(
    to bottom,
    transparent,
    var(--amber-glow) 45%,
    var(--amber-glow) 55%,
    transparent
  );
  filter: blur(22px);
  opacity: 0.3;
  pointer-events: none;
  animation: crt-scan-sweep-reverse 13s linear infinite;
}

.process > .container {
  position: relative;
  z-index: 1;
}

@keyframes crt-scan-sweep-reverse {
  0%   { transform: translateY(680px); }
  100% { transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .process::after { animation: none; transform: translateY(300px); }
}

.process-steps {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-4);
  counter-reset: step;
  position: relative;
}

@media (max-width: 860px) {
  .process-steps { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 560px) {
  .process-steps { grid-template-columns: 1fr; }
}

/* Dashed thread connecting the steps — a hand-pinned index-card board,
   not a polished SaaS "feature grid." */
.process-steps::before {
  content: '';
  position: absolute;
  top: 18px;
  left: 4%;
  right: 4%;
  height: 0;
  border-top: 2px dashed var(--border-default);
  z-index: 0;
}

@media (max-width: 860px) {
  .process-steps::before { display: none; }
}

/* Flat rail item, deliberately un-boxed: no card background/border/shadow,
   so this doesn't read as a second card grid stacked under Services (both
   used to be icon+heading+sentence cards with the same tilt-on-hover
   treatment — the numbered dashed thread above is the thing that should
   read as distinct, not another set of card edges). */
.process-step {
  position: relative;
  z-index: 1;
  text-align: center;
  padding: 0 var(--space-2);
}

.process-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.85rem;
  color: var(--on-accent);
  background: var(--accent);
  border-radius: 50%;
  margin: 0 auto var(--space-3);
  transition: transform var(--duration-lift) var(--ease-out);
}

/* Alternate green/orange down the rail — the two-tone terminal pairing
   (phosphor-green + logo-orange) reads as one connected system rather than
   the orange showing up only in isolated one-off spots. */
.process-step:nth-child(even) .process-num {
  background: var(--amber);
  color: var(--on-accent);
}

@media (hover: hover) and (pointer: fine) {
  .process-step:hover .process-num {
    transform: scale(1.1);
  }
}

.process-icon {
  display: inline-flex;
  margin-bottom: var(--space-2);
}

.process-icon img {
  width: 26px;
  height: 26px;
}

.process-step h3 {
  font-family: var(--font-head);
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--text);
  margin-bottom: var(--space-1);
}

.process-step p {
  color: var(--text-dim);
  font-size: 0.9rem;
}

.process-steps [data-reveal]:nth-child(2) { transition-delay: var(--stagger-step); }
.process-steps [data-reveal]:nth-child(3) { transition-delay: calc(var(--stagger-step) * 2); }
.process-steps [data-reveal]:nth-child(4) { transition-delay: calc(var(--stagger-step) * 3); }

.process-more {
  text-align: center;
  margin-top: var(--space-6);
}

/* ---------- Booking ---------- */
.booking {
  position: relative;
  background: var(--secondary);
  padding: var(--space-12) 0;
  overflow: hidden;
  isolation: isolate;
}

@media (max-width: 600px) {
  .booking { padding: var(--space-8) 0; }
}

.booking::before {
  content: '';
  position: absolute;
  top: -140px;
  right: -140px;
  width: 520px;
  height: 520px;
  background: radial-gradient(circle, var(--accent-glow-strong) 0%, transparent 72%);
  z-index: -1;
  pointer-events: none;
}

.booking-head {
  text-align: center;
  max-width: 560px;
  margin: 0 auto var(--space-6);
}

.booking-head h2 {
  font-family: var(--font-head);
  font-size: clamp(1.7rem, 3.5vw, 2.3rem);
  font-weight: 600;
  color: #FFFFFF;
  margin-bottom: var(--space-2);
  text-wrap: pretty;
}

.booking-head p {
  color: #FFFFFF;
  font-size: 1.05rem;
  text-wrap: pretty;
}

.booking-frame {
  max-width: 1100px;
  margin: 0 auto;
  /* Cream/vanilla instead of the site's dark --surface: the Google
     Calendar embed inside renders with its own white background
     regardless (cross-origin, can't be recolored), so a dark frame around
     it used to read as a mismatched dark-ring-around-a-white-box. A warm
     light frame blends into the embed's own white instead of fighting it. */
  background: #FAF6F0;
  border-radius: var(--radius);
  box-shadow: 0 24px 56px var(--shadow-lift), 0 0 0 1px var(--accent-glow-strong);
  overflow: hidden;
  aspect-ratio: 3 / 4;
}

@media (min-width: 700px) {
  .booking-frame { aspect-ratio: 16 / 9; }
}

.booking-frame iframe {
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
  opacity: 0;
  transition: opacity var(--duration-reveal) var(--ease-out);
}

.booking-frame iframe.is-loaded {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .booking-frame iframe {
    transition-duration: 1ms;
  }
}

.booking-fallback {
  text-align: center;
  margin-top: var(--space-3);
  color: #FFFFFF;
  font-size: 0.9rem;
}

.booking-fallback a {
  color: #FFFFFF;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: color var(--duration-base) ease;
}

.booking-fallback a:hover {
  color: var(--accent);
}

.booking-fallback a:focus-visible {
  outline: 2px solid #FFFFFF;
  outline-offset: 3px;
}

/* ---------- Contact ---------- */
.contact {
  padding: var(--space-12) 0;
}

@media (max-width: 600px) {
  .contact { padding: var(--space-8) 0; }
}

.contact-grid {
  display: grid;
  grid-template-columns: 1fr 1.1fr;
  gap: var(--space-8);
  align-items: start;
}

@media (max-width: 860px) {
  .contact-grid { grid-template-columns: 1fr; gap: var(--space-6); }
}

.contact-info h2 {
  font-family: var(--font-head);
  font-size: clamp(1.7rem, 3.5vw, 2.3rem);
  font-weight: 600;
  line-height: 1.2;
  color: var(--text);
  margin: var(--space-2) 0 var(--space-2);
}

.contact-info .lead {
  font-size: 1.05rem;
  color: var(--text-dim);
  max-width: 440px;
  margin-bottom: var(--space-6);
}

.contact-details {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.contact-details li {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.contact-label {
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--text-dim);
}

.contact-details a {
  color: var(--text);
  text-decoration: none;
  font-size: 1.1rem;
  font-weight: 600;
  border-bottom: 1.5px solid transparent;
  transition: border-color var(--duration-base) ease, color var(--duration-base) ease;
}

.contact-details a:hover {
  color: var(--accent-dark);
  border-color: currentColor;
}

.contact-details span:not(.contact-label) {
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--text);
}

.contact-form {
  background: var(--surface);
  border-radius: var(--radius);
  padding: var(--space-6);
  box-shadow: 0 16px 40px var(--shadow-card);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.form-row {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.form-row label {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--text);
}

.form-row input,
.form-row textarea {
  font-family: var(--font-body);
  font-size: 1rem;
  color: var(--text);
  background: var(--surface-2);
  border: 1.5px solid var(--border-default);
  border-radius: 10px;
  padding: 12px 14px;
  resize: vertical;
  transition: border-color var(--duration-base) ease, box-shadow var(--duration-base) ease;
}

.form-row input:focus,
.form-row textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-ring);
}

.contact-form .btn {
  align-self: flex-start;
  margin-top: var(--space-1);
}

@media (max-width: 600px) {
  .contact-form .btn { width: 100%; }
}

.form-note {
  font-size: 0.85rem;
  color: var(--text-dim);
}

/* ---------- Footer ---------- */
.site-footer {
  background: var(--bg);
  padding: var(--space-4) 0;
  border-top: 3px solid var(--accent);
}

.footer-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}

@media (max-width: 600px) {
  .footer-inner { flex-direction: column; text-align: center; }
}

.footer-brand {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-head);
  font-size: 1rem;
  font-weight: 600;
  color: var(--text);
}

.footer-brand img {
  width: 40px;
  height: 40px;
}

.footer-links {
  display: flex;
  gap: var(--space-4);
}

.footer-links a {
  color: var(--text-dim);
  font-size: 0.9rem;
  text-decoration: none;
  transition: color var(--duration-base) ease;
}

.footer-links a:hover {
  color: var(--text);
}

.lang-switch {
  display: flex;
  gap: 2px;
  padding: 3px;
  border: 1px solid rgba(214, 232, 221, 0.16);
  border-radius: 999px;
}

.lang-btn {
  font-family: var(--font-head);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--text-dim);
  background: none;
  border: none;
  padding: 4px 10px;
  border-radius: 999px;
  cursor: pointer;
  transition: color var(--duration-base) ease, background var(--duration-base) ease;
}

.lang-btn:hover {
  color: var(--text);
}

.lang-btn.is-active {
  color: var(--on-accent);
  background: var(--accent);
}

/* ---------- Legal stub pages ---------- */
.legal-page {
  padding: var(--space-12) 0;
  min-height: 50vh;
}

.legal-page h1 {
  font-family: var(--font-head);
  font-size: clamp(1.8rem, 4vw, 2.4rem);
  font-weight: 600;
  color: var(--text);
  margin-bottom: var(--space-3);
}

.legal-pending {
  color: var(--text-dim);
  max-width: 560px;
  font-size: 1.05rem;
}

.legal-content {
  max-width: 640px;
}

.legal-content h2 {
  font-family: var(--font-head);
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--text);
  margin: var(--space-6) 0 var(--space-2);
}

.legal-content h2:first-child {
  margin-top: 0;
}

.legal-content p {
  color: var(--text-dim);
  font-size: 1rem;
  line-height: 1.6;
}

.legal-content a {
  color: var(--accent);
}

/* ---------- Page hero (light, reusable for secondary pages) ---------- */
.page-hero {
  padding: var(--space-12) 0 var(--space-8);
  text-align: center;
}

@media (max-width: 600px) {
  .page-hero { padding: var(--space-8) 0 var(--space-6); }
}

.page-hero h1 {
  font-family: var(--font-head);
  font-size: clamp(2rem, 4.5vw, 3rem);
  font-weight: 600;
  color: var(--text);
  margin-bottom: var(--space-3);
  text-wrap: pretty;
}

.page-hero .lead {
  max-width: 620px;
  margin: 0 auto;
  color: var(--text-dim);
  font-size: 1.1rem;
  text-wrap: pretty;
}

/* ---------- Ablauf (detailed process page) ---------- */
.ablauf-timeline {
  padding: var(--space-4) 0 var(--space-12);
}

/* Narrower than the site's default 1880px container: at full width the
   visual+copy row below would let .ablauf-body's text column stretch far
   past a comfortable German measure. Capping the row itself keeps visual
   and copy proportionate instead of just capping the text and leaving a
   dead gap in the row. */
.ablauf-timeline .container {
  max-width: 1100px;
}

@media (max-width: 600px) {
  .ablauf-timeline { padding: var(--space-2) 0 var(--space-8); }
}

.ablauf-steps {
  list-style: none;
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--space-12);
}

.ablauf-step {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  align-items: center;
}

@media (min-width: 800px) {
  .ablauf-step {
    flex-direction: row;
    gap: var(--space-8);
  }

  .ablauf-step:nth-child(even) { flex-direction: row-reverse; }
}

.ablauf-visual {
  position: relative;
  flex: 1 1 320px;
  max-width: 320px;
}

.ablauf-num {
  position: absolute;
  top: -14px;
  left: -14px;
  z-index: 2;
  font-weight: 700;
  font-size: 0.8rem;
  letter-spacing: 0.06em;
  color: var(--on-accent);
  background: var(--accent);
  border-radius: 999px;
  padding: 5px 14px;
  box-shadow: 0 6px 16px var(--accent-shadow);
}

.ablauf-illustration-frame {
  background: var(--surface);
  border: 1.5px solid var(--border-default);
  border-radius: var(--radius);
  padding: var(--space-4);
  transform: rotate(var(--tilt, 0deg));
  transition: transform var(--duration-lift) var(--ease-out), box-shadow var(--duration-lift) var(--ease-out), border-color var(--duration-lift) var(--ease-out);
}

.ablauf-step:nth-child(1) .ablauf-illustration-frame { --tilt: -1deg; }
.ablauf-step:nth-child(2) .ablauf-illustration-frame { --tilt: 0.8deg; }
.ablauf-step:nth-child(3) .ablauf-illustration-frame { --tilt: -0.7deg; }
.ablauf-step:nth-child(4) .ablauf-illustration-frame { --tilt: 0.9deg; }

@media (hover: hover) and (pointer: fine) {
  .ablauf-illustration-frame:hover {
    transform: rotate(0deg) translateY(-3px);
    box-shadow: 0 16px 32px var(--shadow-card);
    border-color: var(--accent);
  }
}

.ablauf-illustration-frame img {
  width: 100%;
  height: auto;
}

.ablauf-body { flex: 1 1 380px; }

.ablauf-body h2 {
  font-family: var(--font-head);
  font-size: clamp(1.3rem, 2.6vw, 1.6rem);
  font-weight: 600;
  color: var(--text);
  margin-bottom: var(--space-2);
}

.ablauf-body > p {
  color: var(--text-dim);
  font-size: 1.02rem;
  margin-bottom: var(--space-3);
  text-wrap: pretty;
}

.ablauf-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.ablauf-list li {
  position: relative;
  padding-left: 22px;
  color: var(--text-dim);
  font-size: 0.95rem;
}

.ablauf-list li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 8px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
}

.ablauf-cta {
  text-align: center;
  padding: 0 0 var(--space-8);
}

.ablauf-cta p {
  color: var(--text-dim);
  margin-bottom: var(--space-3);
}

/* Duration badge next to the booking tag ("30 Minuten") */
.booking-duration {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.85rem;
  font-weight: 600;
  color: #FFFFFF;
  background: var(--accent-tint);
  border: 1px solid var(--accent-glow-strong);
  border-radius: 999px;
  padding: 6px 14px;
  margin: 0 0 var(--space-2);
}

.booking-duration::before {
  content: '';
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
}

/* ---------- About ---------- */
.about-hero {
  padding: var(--space-12) 0 var(--space-8);
}

@media (max-width: 600px) {
  .about-hero { padding: var(--space-8) 0 var(--space-6); }
}

.about-hero-grid {
  display: grid;
  grid-template-columns: 200px 1fr;
  align-items: center;
  gap: var(--space-8);
  max-width: 900px; /* Constrain max-width to exactly match .story-grid below */
  margin: 0 auto; /* Center the grid container to align horizontally with .story-grid */
}

@media (max-width: 640px) {
  .about-hero-grid {
    grid-template-columns: 1fr;
    text-align: center;
    justify-items: center;
  }
}

/* ── Retro CRT monitor frame around the profile photo ── */
.about-photo-frame {
  position: relative;
  width: 200px; /* restored original width so text lines up below */
  height: auto;
  border-radius: 0;
  overflow: visible;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* drop-shadow on the whole unit */
  filter: drop-shadow(0 18px 36px rgba(0,0,0,0.55));
}

/* ── cream plastic case ── */
.about-photo-frame::before {
  content: '';
  position: absolute;
  /* sits behind and slightly larger than the bezel */
  inset: -6px -8px -8px -8px;
  top: -10px;
  border-radius: 10px 10px 6px 6px;
  background:
    radial-gradient(circle at 18% 16%, rgba(255,255,255,0.5), transparent 40%),
    linear-gradient(165deg, #f2e9d2 0%, #e8ddc4 45%, #d9cba9 100%);
  box-shadow:
    inset 0 2px 0 rgba(255,255,255,0.5),
    inset 0 -4px 10px rgba(120,100,55,0.16),
    0 4px 0 #d6c9a8,
    0 6px 16px rgba(0,0,0,0.35),
    0 0 28px var(--accent-glow-strong);
  z-index: 0;
  pointer-events: none;
}

/* ── the actual photo inside the screen ── */
.about-photo-screen {
  position: relative;
  z-index: 1;
  width: 100%;
  background: #020a05; /* completely black/dark green background */
  border-radius: 6px 6px 4px 4px;
  padding: 10px 8px 8px;
  /* clip the glowing scanline so it doesn't leak out of the bezel */
  overflow: hidden;
  box-shadow:
    inset 0 0 0 1.5px #efe4c8,
    inset 0 2px 8px rgba(0,0,0,0.6);
}

.about-photo-frame img {
  width: 100%;
  height: 200px; /* Note: since frame is now 200px, screen is slighty narrower than 200px due to padding, but height keeps it square */
  object-fit: cover;
  display: block;
  border-radius: 3px;
  /* Normal positive image, desaturated slightly to merge with the green, natural contrast */
  filter: grayscale(0.5) contrast(1.05) brightness(1.05);
}

/* Green phosphor overlay that colorizes the greyscale image while leaving blacks black.
   Using multiply/screen combo to tint the white pixels green. */
.about-photo-screen::before {
  content: '';
  position: absolute;
  /* needs to cover the image exactly, sitting inside the padding */
  left: 8px; right: 8px; top: 10px; bottom: 8px;
  background: #39d97a;
  mix-blend-mode: multiply;
  pointer-events: none;
  z-index: 2;
  border-radius: 3px;
}

/* ── phosphor scanline sweep ──
   Clipped to the screen area by being a sibling of the img inside
   .about-photo-screen, positioned absolute within that container. */
.about-photo-screen::after {
  content: '';
  position: absolute;
  /* limit to the screen inner bound */
  left: 8px; right: 8px; top: 10px; bottom: 8px;
  z-index: 3;
  pointer-events: none;
  border-radius: 3px;
  background: linear-gradient(
    to bottom,
    transparent,
    rgba(57, 217, 122, 0.15) 35%,
    rgba(57, 217, 122, 0.4) 50%,
    rgba(57, 217, 122, 0.15) 65%,
    transparent
  );
  filter: blur(12px);
  animation: photo-scan-sweep 5s linear infinite;
}

/* keep ::after on the frame itself clear so it doesn't interfere */
.about-photo-frame::after { display: none; }

@keyframes photo-scan-sweep {
  0%   { transform: translateY(-200px); }
  100% { transform: translateY(200px); }
}

/* ── monitor neck ── */
.about-photo-neck {
  width: 36px;
  height: 16px;
  background: linear-gradient(180deg, #d9cba9, #c9b98f);
  box-shadow: inset 0 2px 4px rgba(120,100,55,0.25);
  z-index: 1;
}

/* ── monitor base ── */
.about-photo-base {
  width: 110px;
  height: 10px;
  border-radius: 999px;
  background: linear-gradient(180deg, #d9cba9, #c2b38c);
  box-shadow: 0 4px 10px rgba(0,0,0,0.3);
  z-index: 1;
}

/* ── amber power LED bottom-right of bezel ── */
.about-photo-led {
  position: absolute;
  right: 14px;
  bottom: 42px; /* above neck */
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--amber);
  box-shadow: 0 0 6px var(--amber);
  z-index: 3;
  animation: pc-led-breathe 2.4s ease-in-out infinite;
}

/* ── vent lines across top of case ── */
.about-photo-vents {
  position: absolute;
  top: -4px;
  left: 50%;
  transform: translateX(-50%);
  width: 55%;
  display: flex;
  flex-direction: column;
  gap: 3px;
  z-index: 3;
  pointer-events: none;
}

.about-photo-vents span {
  display: block;
  height: 1px;
  border-radius: 999px;
  background: #c9b98f;
  box-shadow: 0 1px 0 rgba(255,255,255,0.35);
}

@media (prefers-reduced-motion: reduce) {
  .about-photo-frame::after { animation: none; opacity: 0.6; }
  .about-photo-led          { animation: none; opacity: 1; }
}

.about-photo-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--wash);
  border: 1px dashed var(--border-strong);
  border-radius: 50%;
  color: var(--text-dim);
  font-size: 0.9rem;
  text-align: center;
}

.about-hero-copy h1 {
  font-family: var(--font-head);
  font-size: clamp(1.9rem, 4vw, 2.6rem);
  font-weight: 600;
  color: var(--text);
  margin: var(--space-2) 0 var(--space-1);
}

.about-hero-copy .lead {
  color: var(--text-dim);
  font-size: 1.05rem;
  max-width: 480px;
}

.about-story {
  padding: var(--space-8) 0 var(--space-12);
}

@media (max-width: 600px) {
  .about-story { padding: var(--space-4) 0 var(--space-8); }
}

.about-story-inner {
  max-width: 640px;
  margin: 0 auto;
}

.about-story-inner h2 {
  font-family: var(--font-head);
  font-size: clamp(1.5rem, 3vw, 1.9rem);
  font-weight: 600;
  color: var(--text);
  margin-bottom: var(--space-3);
}

.about-story-inner p {
  color: var(--text-dim);
  font-size: 1.05rem;
}

/* Two-column variant used on about/projects/careers: an icon-anchored pull
   quote next to the paragraph, so the section isn't a flat text block —
   the quote is a real excerpt from the section's own copy, not new claims. */
.story-grid {
  max-width: 900px;
  display: grid;
  grid-template-columns: 200px 1fr;
  gap: var(--space-8);
  align-items: start;
  text-align: left;
}

@media (max-width: 700px) {
  .story-grid {
    grid-template-columns: 1fr;
    text-align: center;
  }
}

.story-visual {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2);
}

@media (max-width: 700px) {
  .story-visual { align-items: center; }
}

.story-icon-badge {
  width: 64px;
  height: 64px;
}

.story-icon-badge .service-icon {
  width: 32px;
  height: 32px;
}

.story-pull {
  font-family: var(--font-head);
  font-size: 1.2rem;
  font-weight: 600;
  line-height: 1.35;
  color: var(--text);
  margin: 0;
  border-left: 2px solid var(--accent);
  padding-left: var(--space-2);
}

@media (max-width: 700px) {
  .story-pull {
    border-left: none;
    border-top: 2px solid var(--accent);
    padding-left: 0;
    padding-top: var(--space-2);
  }
}

/* Career timeline (about.html) — a vertical dashed rail with a node per
   milestone. Reuses the site's one reveal primitive: each <li> already
   carries [data-reveal] (fade + rise) and [data-reveal-group] gives it the
   same nth-child stagger as the services grid, so no new JS/observer is
   needed. The only addition is a second rule keyed off the same
   .is-visible class the existing IntersectionObserver already toggles:
   the node lights up from a dim ring to a glowing accent dot. */
.about-timeline {
  padding: var(--space-8) 0 var(--space-12);
}

@media (max-width: 600px) {
  .about-timeline { padding: var(--space-4) 0 var(--space-8); }
}

.timeline-rail {
  list-style: none;
  max-width: 640px;
  margin: 0 auto;
  padding: 0;
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

.timeline-rail::before {
  content: '';
  position: absolute;
  top: 6px;
  bottom: 6px;
  left: 5px;
  width: 0;
  border-left: 2px dashed var(--border-default);
}

.timeline-item {
  position: relative;
  padding-left: var(--space-4);
}

.timeline-node {
  position: absolute;
  left: -1px;
  top: 5px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--surface-2);
  border: 2px solid var(--border-strong);
  transition: background-color var(--duration-reveal) var(--ease-out),
              border-color var(--duration-reveal) var(--ease-out),
              box-shadow var(--duration-reveal) var(--ease-out);
}

.timeline-item.is-visible .timeline-node {
  background: var(--accent);
  border-color: var(--accent);
  box-shadow: 0 0 0 4px var(--accent-wash), 0 0 12px var(--accent-glow-strong);
}

.timeline-year {
  display: inline-flex;
  align-items: center;
  font-family: var(--font-head);
  font-weight: 600;
  font-size: 0.95rem;
  letter-spacing: 0.02em;
  color: var(--accent);
  margin-bottom: var(--space-1);
}

/* Blinking terminal cursor — only on the most recent (2026, "you are
   here") entry. One persistent blinking element reads as "this is now";
   four of them would just be flicker. */
.timeline-cursor {
  display: inline-block;
  width: 0.5em;
  height: 0.9em;
  background: var(--accent);
  margin-left: 0.2em;
  animation: pc-cursor-blink 1.1s step-end infinite;
}

.timeline-body h3 {
  font-family: var(--font-head);
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--text);
  margin: 0 0 var(--space-1);
}

.timeline-body p {
  color: var(--text-dim);
  font-size: 1rem;
}

@media (max-width: 600px) {
  .timeline-rail { gap: var(--space-4); }
}

.about-cta {
  padding: var(--space-12) 0;
  text-align: center;
}

@media (max-width: 600px) {
  .about-cta { padding: var(--space-8) 0; }
}

.about-cta-inner h2 {
  font-family: var(--font-head);
  font-size: clamp(1.5rem, 3vw, 2rem);
  font-weight: 600;
  color: var(--text);
  margin-bottom: var(--space-4);
}

/* ---------- Studio hub ---------- */
.studio-hero {
  padding: var(--space-12) 0 var(--space-6);
  text-align: center;
}

@media (max-width: 600px) {
  .studio-hero { padding: var(--space-8) 0 var(--space-4); }
}

.studio-hero-inner {
  max-width: 620px;
  margin: 0 auto;
}

.studio-hero-inner h1 {
  font-family: var(--font-head);
  font-size: clamp(1.9rem, 4vw, 2.6rem);
  font-weight: 600;
  color: var(--text);
  margin: var(--space-2) 0 var(--space-1);
}

.studio-hero-inner .lead {
  color: var(--text-dim);
  font-size: 1.05rem;
}

a.service-card {
  display: block;
  text-decoration: none;
  color: inherit;
}

a.service-card .service-arrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  color: var(--accent);
  font-weight: 600;
  font-size: 0.92rem;
}

@media (hover: hover) and (pointer: fine) {
  a.service-card:hover .service-arrow { transform: translateX(3px); }
}

.service-arrow {
  display: inline-flex;
  transition: transform var(--duration-base) var(--ease-out);
}
