/* ============================================================
   Kodelig — Cyberpunk
   Deliberately a different shape from the other kodelig-* themes:
   no document-flow header/nav, a fixed 3D parallax scene behind
   everything, a right-edge "depth rail" for navigation, holo-deck
   cards instead of a plain grid, a 3D coverflow carousel for
   prosjekter, and a materializing console instead of a flat modal.
   ============================================================ */

@font-face {
  font-family: 'Chakra Petch';
  src: url('../fonts/chakra-petch-400.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Chakra Petch';
  src: url('../fonts/chakra-petch-600.woff2') format('woff2');
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Chakra Petch';
  src: url('../fonts/chakra-petch-700.woff2') format('woff2');
  font-weight: 700; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Chakra Petch';
  src: url('../fonts/chakra-petch-600italic.woff2') format('woff2');
  font-weight: 600; font-style: italic; font-display: swap;
}
@font-face {
  font-family: 'JetBrains Mono';
  src: url('../fonts/jetbrains-mono.woff2') format('woff2');
  font-weight: 400 700; font-style: normal; font-display: swap;
}
@font-face {
  /* The actual wordmark font — used only for the corner logo, not loaded
     into --font-display, so the rest of the theme's type stays Chakra
     Petch. */
  font-family: 'Cyberway Riders';
  src: url('../fonts/cyberway-riders.ttf') format('truetype');
  font-weight: 400; font-style: normal; font-display: swap;
}

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

:root {
  --void: #060310;
  --ink: #0a0716;
  --panel: #0f0b20;
  --panel-2: #150f2c;
  --border: #322a52;
  --border-soft: rgba(122, 92, 255, 0.28);
  --text: #ece7fb;
  --muted: #9a91c2;

  --cyan: #22f0ff;
  --magenta: #ff2e9a;
  --yellow: #f3ff3d;
  --violet: #7a5cff;

  --font-display: 'Chakra Petch', ui-sans-serif, system-ui, sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, 'SFMono-Regular', monospace;

  --container: clamp(20rem, 90vw, 76rem);
  --gutter: clamp(1.25rem, 5vw, 3.5rem);

  --space-1: 0.25rem; --space-2: 0.5rem; --space-3: 0.75rem; --space-4: 1rem;
  --space-5: 1.5rem; --space-6: 2rem; --space-7: 3rem; --space-8: 4.5rem; --space-9: 6.5rem;

  --radius: 3px;
  --dur-fast: 140ms; --dur-base: 240ms; --dur-slow: 560ms;
  --ease: cubic-bezier(0.16, 1, 0.3, 1);

  color-scheme: dark;
}

html {
  scroll-behavior: smooth;
  scroll-padding-top: 2rem;
  /* `overflow-x: hidden` here previously broke window.scrollTo entirely --
     setting overflow-x to a non-visible value while overflow-y stays
     visible forces overflow-y to compute to `auto` too, which turns html
     into its own scroll container instead of the visual viewport.
     `clip` avoids that: it never establishes a scroll container, so
     vertical scrolling is untouched, while any element anywhere in the
     theme that overflows horizontally (the carousel's off-canvas coverflow
     neighbors, previously) is clipped instead of quietly widening the
     whole document and letting iOS pan the entire page sideways. */
  overflow-x: clip;
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--void);
  color: var(--text);
  font-family: var(--font-display);
  font-size: 1rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  overscroll-behavior-x: none;
}

h1, h2, h3 { margin: 0; font-family: var(--font-display); font-weight: 700; }
p { margin: 0; }
a { color: inherit; }
img { max-width: 100%; display: block; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; top: -100%; left: var(--space-4); z-index: 999;
  background: var(--magenta); color: var(--ink); padding: var(--space-3) var(--space-5);
  font-family: var(--font-mono); font-weight: 700; text-decoration: none; border-radius: var(--radius);
  transition: top var(--dur-fast) var(--ease);
}
.skip-link:focus { top: var(--space-4); }

/* ---------- fixed 3D scene (stays put; page content scrolls over it) ---------- */

.cp-scene {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}
.cp-scene-sky {
  position: absolute; inset: 0;
  background:
    radial-gradient(ellipse 70% 45% at 22% 8%, rgba(255,46,154,0.16), transparent 60%),
    radial-gradient(ellipse 60% 40% at 82% 88%, rgba(34,240,255,0.14), transparent 60%),
    linear-gradient(180deg, #0a0620 0%, #060310 55%, #030108 100%);
}
.cp-scene-skyline {
  position: absolute; left: 0; right: 0; bottom: 0; height: 46vh;
  background:
    repeating-linear-gradient(90deg, rgba(122,92,255,0.10) 0 2px, transparent 2px 64px),
    linear-gradient(180deg, transparent 0%, rgba(6,3,16,0.9) 92%);
  clip-path: polygon(0 40%, 4% 40%, 4% 22%, 9% 22%, 9% 55%, 15% 55%, 15% 15%, 21% 15%, 21% 48%, 27% 48%, 27% 30%, 33% 30%, 33% 60%, 39% 60%, 39% 10%, 45% 10%, 45% 42%, 52% 42%, 52% 25%, 58% 25%, 58% 52%, 64% 52%, 64% 18%, 70% 18%, 70% 46%, 76% 46%, 76% 12%, 82% 12%, 82% 50%, 88% 50%, 88% 28%, 94% 28%, 94% 44%, 100% 44%, 100% 100%, 0 100%);
  opacity: 0.85;
}
.cp-scene-glow {
  /* Kept deliberately modest: filter:blur() at large sizes is one of the
     most GPU-expensive things a browser can composite every frame, and
     this animates forever in the background on every page view — smaller
     + less blur reads almost the same but costs meaningfully less. */
  position: absolute; width: 34vmax; height: 34vmax; border-radius: 50%; filter: blur(54px);
  opacity: 0.35;
  animation: cp-drift 26s ease-in-out infinite;
}
.cp-scene-glow--a { top: -14vmax; left: -10vmax; background: var(--magenta); animation-delay: 0s; }
.cp-scene-glow--b { bottom: -16vmax; right: -12vmax; background: var(--cyan); animation-duration: 32s; animation-delay: -8s; }
@keyframes cp-drift {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50% { transform: translate(4vmax, -3vmax) scale(1.12); }
}

/* Behind the page content by default (z 0 vs main's 1), so a sign can
   never sit on top of body copy. Only on very wide screens, where the
   signs fit in the gutters beside the content column, do they move above
   it and become clickable easter eggs. */
.cp-scene-signs { position: fixed; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; --px: 0; --py: 0; --sy: 0; }
.cp-scene-signs .cp-sign { pointer-events: none; }
@media (min-width: 100em) {
  .cp-scene-signs { z-index: 40; }
  .cp-scene-signs .cp-sign { pointer-events: auto; }
}
/* Holographic signs: projected glyphs with an inner scan pattern, an RGB
   ghost split (::before/::after from data-text) and a faint projector
   cone. Each sign has its own depth (--z) for pointer/scroll parallax. */
.cp-sign {
  position: absolute; left: var(--x); top: var(--y);
  font-family: var(--font-display); font-weight: 700; font-size: clamp(1.25rem, 3vw, 2.75rem);
  letter-spacing: 0.05em;
  pointer-events: auto;
  cursor: pointer;
  background: none; border: 0; padding: 0.4em 0.6em;
  transform: translate3d(calc(var(--px) * var(--z, 0.5) * -70px), calc(var(--py) * var(--z, 0.5) * -40px + sin(var(--sy) * 1.3rad + var(--z, 0.5) * 6rad) * var(--z, 0.5) * 36px), 0);
  transition: transform 600ms var(--ease);
  animation: cp-flicker 5.5s ease-in-out infinite;
}
.cp-sign::before, .cp-sign::after {
  content: attr(data-text);
  position: absolute; inset: 0; padding: inherit;
  pointer-events: none; mix-blend-mode: screen; opacity: 0.45;
}
.cp-sign::before { color: var(--cyan); transform: translate(-2px, 0); clip-path: inset(0 0 55% 0); }
.cp-sign::after { color: var(--magenta); transform: translate(2px, 1px); clip-path: inset(55% 0 0 0); }
.cp-sign--3::before { color: var(--magenta); }
.cp-sign--1::after { color: var(--yellow); }
.cp-sign--4 { color: var(--violet); text-shadow: 0 0 12px rgba(122,92,255,0.9), 0 0 34px rgba(122,92,255,0.45); animation-duration: 7.3s; animation-delay: -3.1s; }
.cp-sign--vert { writing-mode: vertical-rl; letter-spacing: 0.25em; font-size: clamp(1rem, 1.6vw, 1.5rem); display: none; }
@media (min-width: 90em) { .cp-sign--vert { display: block; } }
.cp-scene-signs.is-glitching .cp-sign { animation: cp-sign-glitch 520ms steps(6, end) 1, cp-flicker 5.5s ease-in-out infinite 520ms; }
@keyframes cp-sign-glitch {
  0% { opacity: 1; filter: hue-rotate(0deg); }
  20% { opacity: 0.2; filter: hue-rotate(90deg); }
  40% { opacity: 1; filter: hue-rotate(-60deg) brightness(1.6); }
  60% { opacity: 0.4; }
  80% { opacity: 1; filter: brightness(1.3); }
  100% { opacity: 0.85; filter: none; }
}
.cp-sign--1 { color: var(--magenta); text-shadow: 0 0 12px rgba(255,46,154,0.85), 0 0 34px rgba(255,46,154,0.4); animation-duration: 4.2s; }
.cp-sign--2 { color: var(--cyan); text-shadow: 0 0 12px rgba(34,240,255,0.85), 0 0 34px rgba(34,240,255,0.4); animation-duration: 6.1s; animation-delay: -1.4s; }
.cp-sign--3 { color: var(--yellow); text-shadow: 0 0 12px rgba(243,255,61,0.85), 0 0 34px rgba(243,255,61,0.4); animation-duration: 5s; animation-delay: -2.7s; }
@keyframes cp-flicker {
  0%, 100% { opacity: 0.85; }
  4% { opacity: 0.25; }
  6% { opacity: 0.9; }
  8% { opacity: 0.3; }
  10% { opacity: 0.9; }
  50% { opacity: 0.8; }
  52% { opacity: 0.4; }
  54% { opacity: 0.88; }
}
.cp-sign:hover, .cp-sign:focus-visible { filter: brightness(1.4); }

.cp-scene-rain {
  position: absolute; inset: -10% -20%;
  mix-blend-mode: screen;
  background-image: repeating-linear-gradient(112deg,
    transparent 0, transparent 2px,
    rgba(180, 210, 255, 0.5) 2px, rgba(180, 210, 255, 0.5) 3px,
    transparent 3px, transparent 96px);
  animation: cp-rain linear infinite;
}
.cp-scene-rain--mid { opacity: 0.24; animation-duration: 1.3s; filter: blur(0.3px); }
.cp-scene-rain--near { opacity: 0.4; animation-duration: 0.8s; filter: blur(0.2px); }
@keyframes cp-rain {
  from { background-position: 0 0; }
  to { background-position: -420px 1400px; }
}

.cp-scene-scanline {
  position: absolute; inset: 0;
  background: repeating-linear-gradient(0deg, rgba(255,255,255,0.028) 0 1px, transparent 1px 3px);
  mix-blend-mode: overlay;
}
.cp-scene-vignette {
  position: absolute; inset: 0;
  background: radial-gradient(ellipse 85% 75% at 50% 45%, transparent 55%, rgba(3,1,8,0.85) 100%);
}
.cp-scene-grid {
  position: absolute; left: 0; right: 0; bottom: 0; height: 34vh;
  background-image:
    linear-gradient(rgba(122,92,255,0.22) 1px, transparent 1px),
    linear-gradient(90deg, rgba(122,92,255,0.22) 1px, transparent 1px);
  background-size: 48px 48px;
  transform: perspective(300px) rotateX(72deg) scale(2.2);
  transform-origin: bottom center;
  -webkit-mask-image: linear-gradient(180deg, transparent, black 60%);
          mask-image: linear-gradient(180deg, transparent, black 60%);
  opacity: 0.5;
}

@media (prefers-reduced-motion: reduce) {
  .cp-scene-glow, .cp-sign, .cp-scene-rain, .cp-scene-signs.is-glitching .cp-sign { animation: none; }
  .cp-sign { transform: none; transition: none; }
  /* "Stillestående by": no falling rain at all, just the static city. */
  .cp-scene-rain { display: none; }
}

/* ---------- WebGL Night City (assets/js/nightcity.js) ---------- */
.cp-gl-canvas {
  position: absolute; inset: 0; width: 100%; height: 100%; display: block;
  opacity: 0; transition: opacity 1.2s var(--ease);
}
/* Crossfade from the CSS fallback scene to the WebGL city once the first
   frame is drawn - never a hard cut. Scanline/vignette layers are folded
   into the shader's post pass, so they fade out with the rest. */
.cp-gl .cp-gl-canvas { opacity: 1; }
.cp-scene > div { transition: opacity 1.2s var(--ease); }
.cp-gl .cp-scene > div { opacity: 0; }

/* District change: a neon scan band sweeps the viewport once. */
.cp-wipe { position: fixed; inset: 0; z-index: 45; pointer-events: none; overflow: hidden; }
.cp-wipe span {
  position: absolute; left: 0; right: 0; top: -12vh; height: 10vh;
  background:
    linear-gradient(180deg, transparent, rgba(34,240,255,0.10) 40%, rgba(255,46,154,0.16) 60%, transparent),
    repeating-linear-gradient(0deg, rgba(255,255,255,0.06) 0 1px, transparent 1px 3px);
  border-bottom: 1px solid rgba(34,240,255,0.55);
  box-shadow: 0 1px 18px rgba(34,240,255,0.45);
  opacity: 0;
}
.cp-wipe.is-active span { animation: cp-wipe 620ms cubic-bezier(0.5, 0, 0.3, 1) 1; }
@keyframes cp-wipe {
  0% { transform: translateY(0); opacity: 0; }
  12% { opacity: 1; }
  85% { opacity: 1; }
  100% { transform: translateY(124vh); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) { .cp-wipe { display: none; } }

/* ---------- breach easter egg overlay ---------- */

.cp-breach {
  position: fixed; inset: 0; z-index: 500; pointer-events: none;
  background: repeating-linear-gradient(0deg, rgba(255,46,154,0.5) 0 2px, transparent 2px 5px),
              repeating-linear-gradient(90deg, rgba(34,240,255,0.35) 0 2px, transparent 2px 5px);
  opacity: 0;
  mix-blend-mode: screen;
}
.cp-breach.is-active {
  animation: cp-breach-flash 550ms steps(2, end);
}
@keyframes cp-breach-flash {
  0% { opacity: 0; transform: translateX(0); }
  15% { opacity: 0.9; transform: translateX(-6px); }
  30% { opacity: 0.2; transform: translateX(4px); }
  45% { opacity: 0.85; transform: translateX(-3px); }
  60% { opacity: 0.1; transform: translateX(2px); }
  75% { opacity: 0.7; transform: translateX(0); }
  100% { opacity: 0; transform: translateX(0); }
}

.cp-toast {
  position: fixed; z-index: 400; pointer-events: none;
  transform: translate(-50%, -120%);
  background: var(--ink);
  border: 1px solid var(--cyan);
  color: var(--cyan);
  font-family: var(--font-mono); font-size: 0.75rem; letter-spacing: 0.03em;
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius);
  box-shadow: 0 0 18px rgba(34,240,255,0.4);
  opacity: 0;
  transition: opacity 200ms var(--ease), transform 200ms var(--ease);
  white-space: nowrap;
}
.cp-toast.is-visible { opacity: 1; transform: translate(-50%, -140%); }

/* ---------- corner brand mark ---------- */

.cp-brandmark {
  /* Absolute, not fixed: it's part of the hero moment, not persistent
     chrome — it should scroll away with the page like the rest of the
     hero, not hover pinned over every section (the depth-rail is the
     thing that stays put as navigation). */
  position: absolute; top: var(--space-5); left: var(--space-5); z-index: 100;
  display: flex; align-items: center; gap: 0.6em;
  color: var(--text);
}
.cp-brandmark-ring {
  position: absolute; inset: -10px; border-radius: 50%;
  border: 1px solid var(--magenta); opacity: 0; transform: scale(0.6);
}
.cp-brandmark.is-pulsing .cp-brandmark-ring {
  animation: cp-ring-pulse 550ms var(--ease);
}
@keyframes cp-ring-pulse {
  0% { opacity: 0.9; transform: scale(0.6); }
  100% { opacity: 0; transform: scale(2.4); }
}
.cp-brandmark-icon {
  width: 40px; height: 40px; color: var(--magenta);
  filter: drop-shadow(0 0 6px rgba(255,46,154,0.7));
}
/* Yellow logotype set in the actual Cyberway Riders font (the user's own
   file, dropped in assets/fonts/) — a thin CYAN outline (not black — that's
   the detail that actually sells the CYBERPUNK 2077 title-card look) and a
   hard offset black drop-shadow for sticker-like depth. No artificial skew
   or duplicated glitch-slice layers: the font's own jagged letterforms
   already carry the torn/slanted energy, and stacking more cyan-stroked
   copies on top just pulled the color toward green instead of yellow. */
.cp-brandmark-word {
  position: relative;
  display: inline-block;
  font-family: 'Cyberway Riders', var(--font-display); font-weight: 400; font-size: 2.0625rem; letter-spacing: 0.01em;
  color: var(--yellow);
  -webkit-text-stroke: 0.75px var(--cyan);
  paint-order: stroke fill;
  filter: drop-shadow(2px 3px 0 rgba(0,0,0,0.75)) drop-shadow(0 0 10px rgba(243,255,61,0.35));
}
.cp-brandmark-word-ghost {
  position: absolute; inset: 0; color: var(--cyan); opacity: 0; mix-blend-mode: screen;
  -webkit-text-stroke: 0;
}
.cp-brandmark:hover .cp-brandmark-word-ghost { opacity: 0.7; transform: translate(1.5px, -1px); }

/* ---------- depth rail (primary navigation) ---------- */

.depthrail {
  position: fixed; right: var(--space-5); top: 50%; transform: translateY(-50%);
  z-index: 100;
  display: flex; flex-direction: column; align-items: flex-end; gap: var(--space-4);
}
.depthrail-line {
  position: absolute; right: 5px; top: 4px; bottom: 4px; width: 1px;
  background: linear-gradient(180deg, transparent, var(--border-soft) 15%, var(--border-soft) 85%, transparent);
}
.depthrail-node {
  display: flex; align-items: center; gap: var(--space-2);
  text-decoration: none; color: var(--muted);
  font-family: var(--font-mono); font-size: 0.6875rem; letter-spacing: 0.08em;
}
.depthrail-index {
  display: grid; place-items: center;
  width: 11px; height: 11px; border-radius: 50%;
  border: 1px solid var(--border-soft);
  font-size: 0; color: transparent;
}
.depthrail-index::before { content: ''; width: 4px; height: 4px; border-radius: 50%; background: var(--muted); transition: background var(--dur-base) var(--ease); }
/* Labels are the actual, permanent navigation text now -- they used to
   sit at opacity:0 (hover/focus/active only), which left every dot but
   the active one as an unlabelled glowing speck with no way to discover
   what it linked to short of hovering each one in turn. Dimmed rather
   than hidden when inactive keeps the active item visually distinct
   without making the rest illegible. */
.depthrail-label {
  opacity: 0.65;
  text-transform: uppercase;
  transition: opacity var(--dur-base) var(--ease), color var(--dur-base) var(--ease);
}
.depthrail-node:hover .depthrail-label,
.depthrail-node:focus-visible .depthrail-label,
.depthrail-node.is-active .depthrail-label { opacity: 1; }
.depthrail-node.is-active { color: var(--text); }
.depthrail-node.is-active .depthrail-index { border-color: var(--magenta); box-shadow: 0 0 10px rgba(255,46,154,0.7); }
.depthrail-node.is-active .depthrail-index::before { background: var(--magenta); box-shadow: 0 0 6px var(--magenta); }
.depthrail-node:hover .depthrail-index::before { background: var(--cyan); }

@media (max-width: 56em) {
  /* A vertical rail pinned to the right edge works on desktop, where
     there's spare width beside the content, but on narrower screens it
     either has to shrink to unreadable dots or crowd the content — a
     dock pinned along the bottom edge instead is the shape mobile
     visitors already expect from every other kodelig-* theme.
     Horizontal scroll (rather than shrinking every label further) keeps
     all seven items reachable even on the narrowest phones. */
  body { padding-bottom: 4.5rem; }
  .depthrail {
    top: auto; right: 0; bottom: 0; left: 0;
    transform: none;
    flex-direction: row;
    align-items: center;
    justify-content: flex-start;
    width: 100%;
    gap: var(--space-5);
    padding: var(--space-3) var(--space-4);
    background: rgba(6, 3, 16, 0.85);
    border-top: 1px solid var(--border-soft);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  .depthrail::-webkit-scrollbar { display: none; }
  .depthrail-line { display: none; }
  .depthrail-node { flex-shrink: 0; }
  .depthrail-label { font-size: 0.625rem; }
}

/* ---------- HUD readout (bottom-left, purely ambient) ---------- */

.cp-hud {
  position: fixed; left: var(--space-5); bottom: var(--space-5); z-index: 100;
  font-family: var(--font-mono); font-size: 0.6875rem; letter-spacing: 0.05em;
  color: var(--muted);
  display: flex; flex-direction: column; gap: 4px;
}
.cp-hud-row { display: flex; align-items: center; gap: var(--space-2); }
.cp-hud-dot {
  width: 6px; height: 6px; border-radius: 50%; background: var(--cyan);
  box-shadow: 0 0 6px var(--cyan);
  animation: cp-blink 1.6s ease-in-out infinite;
}
@keyframes cp-blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.2; } }
.cp-hud-bars { display: inline-flex; gap: 2px; align-items: flex-end; height: 9px; }
.cp-hud-bars i { display: block; width: 3px; background: var(--cyan); opacity: 0.85; animation: cp-bars 1.4s ease-in-out infinite; }
.cp-hud-bars i:nth-child(1) { height: 4px; animation-delay: 0s; }
.cp-hud-bars i:nth-child(2) { height: 7px; animation-delay: -0.3s; }
.cp-hud-bars i:nth-child(3) { height: 9px; animation-delay: -0.6s; }
.cp-hud-bars i:nth-child(4) { height: 6px; animation-delay: -0.9s; }
@keyframes cp-bars { 0%, 100% { transform: scaleY(0.5); } 50% { transform: scaleY(1); } }
.cp-hud-coords { opacity: 0.7; }
.cp-hud-sector { color: var(--cyan); letter-spacing: 0.12em; }
.cp-hud-sector-label { display: inline-block; transition: opacity 180ms linear, filter 180ms linear, transform 180ms var(--ease); }
.cp-hud-sector-label.is-swapping { opacity: 0; filter: blur(3px); transform: translateX(-6px); }

/* Matches the depth-rail's own breakpoint, not a separate one: below
   56em the rail becomes a bottom dock occupying this same corner, so the
   HUD readout needs to be gone by the same width or the two overlap. */
@media (max-width: 56em) { .cp-hud { display: none; } }
@media (prefers-reduced-motion: reduce) { .cp-hud-dot, .cp-hud-bars i { animation: none; } }

/* ---------- scroll reveal ---------- */

/* Hidden only when JS runs (html.js, set inline in <head> with a 4 s
   failsafe that removes it again if main.js never boots), so without JS
   every word is visible from the first paint. */
.js .reveal {
  opacity: 0; transform: translateY(18px);
  transition: opacity var(--dur-slow) var(--ease), transform var(--dur-slow) var(--ease);
}
.js .reveal.is-visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .js .reveal { opacity: 1; transform: none; transition: none; } }

/* ---------- layout primitives ---------- */

main, .cp-footer { position: relative; z-index: 1; }
section { position: relative; padding-inline: var(--gutter); }

/* ---------- hero ---------- */

.cp-hero {
  min-height: 100svh;
  display: flex; align-items: center; justify-content: center;
  text-align: center;
  padding-block: var(--space-9);
}
.cp-hero-inner {
  position: relative;
  max-width: 54rem;
  transform: perspective(1400px) translateZ(calc(var(--dive, 0) * 380px)) rotateX(calc(var(--ry, 0deg) + var(--dive, 0) * -14deg)) rotateY(var(--rx, 0deg));
  opacity: calc(1 - var(--dive, 0) * 0.95);
  transition: transform 400ms var(--ease);
  will-change: transform;
}
/* Readability veil: the hero copy sits directly on the live city, so a
   soft dark pool sits behind it (not a text-shadow) to keep the lede well
   above AA whatever the windows and neon behind it are doing. */
.cp-hero-inner::before {
  content: ''; position: absolute; z-index: -1;
  inset: -12% -14%;
  background: radial-gradient(closest-side, rgba(6,3,16,0.86), rgba(6,3,16,0.62) 55%, transparent);
  pointer-events: none;
}
.cp-hero-eyebrow {
  font-family: var(--font-mono); font-size: 0.8125rem; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--cyan); text-shadow: 0 0 10px rgba(34,240,255,0.6);
}
.cp-hero-title {
  margin-top: var(--space-4);
  font-size: clamp(1.9rem, 0.9rem + 5.2vw, 5.25rem);
  line-height: 1.02; text-transform: uppercase; letter-spacing: -0.01em;
  overflow-wrap: anywhere; hyphens: manual;
  display: flex; flex-direction: column; gap: 0.1em;
}
.cp-glitch { position: relative; color: var(--text); }
.cp-glitch--accent { color: var(--magenta); text-shadow: 0 0 24px rgba(255,46,154,0.55); }
.cp-glitch::before, .cp-glitch::after {
  content: attr(data-text);
  position: absolute; left: 0; top: 0; width: 100%;
  overflow: hidden;
  opacity: 0;
}
@media (prefers-reduced-motion: no-preference) {
  .cp-glitch::before, .cp-glitch::after { opacity: 1; }
  .cp-glitch::before { color: var(--cyan); mix-blend-mode: screen; animation: cp-glitch-1 7s infinite; }
  .cp-glitch::after { color: var(--magenta); mix-blend-mode: screen; animation: cp-glitch-2 7s infinite; }
  .cp-glitch--accent::before { color: var(--cyan); }
  .cp-glitch--accent::after { color: var(--yellow); }
}
@keyframes cp-glitch-1 {
  0%, 92%, 100% { transform: translate(0, 0); clip-path: inset(0 0 0 0); opacity: 0; }
  93% { transform: translate(-3px, 1px); clip-path: inset(10% 0 60% 0); opacity: 0.8; }
  95% { transform: translate(2px, -1px); clip-path: inset(60% 0 5% 0); opacity: 0.8; }
  97% { transform: translate(-1px, 0); clip-path: inset(30% 0 40% 0); opacity: 0.6; }
}
@keyframes cp-glitch-2 {
  0%, 90%, 100% { transform: translate(0, 0); clip-path: inset(0 0 0 0); opacity: 0; }
  91% { transform: translate(3px, -1px); clip-path: inset(70% 0 5% 0); opacity: 0.8; }
  94% { transform: translate(-2px, 1px); clip-path: inset(5% 0 70% 0); opacity: 0.8; }
  96.5% { transform: translate(1px, 0); clip-path: inset(45% 0 20% 0); opacity: 0.6; }
}
.cp-hero-lede {
  margin-top: var(--space-5);
  font-family: var(--font-mono);
  font-size: clamp(0.9375rem, 0.9rem + 0.3vw, 1.0625rem);
  color: var(--muted);
  max-width: 38rem; margin-inline: auto;
}
.cp-hero-actions {
  margin-top: var(--space-7);
  display: flex; flex-direction: column; align-items: center; gap: var(--space-5);
}
.cp-cta {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0.9em 1.9em;
  font-family: var(--font-mono); font-weight: 700; font-size: 0.875rem; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--ink);
  background: linear-gradient(95deg, var(--magenta), var(--violet));
  clip-path: polygon(10px 0, 100% 0, 100% calc(100% - 10px), calc(100% - 10px) 100%, 0 100%, 0 10px);
  box-shadow: 0 0 24px rgba(255,46,154,0.45);
  transition: transform var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.cp-cta em { font-style: normal; opacity: 0.75; margin: 0 0.4em; }
.cp-cta:hover, .cp-cta:focus-visible {
  transform: translateY(-2px);
  box-shadow: 0 0 34px rgba(34,240,255,0.55);
}
.cp-cta:active { transform: translateY(0); }
.cp-cta--lg { padding: 1.05em 2.4em; font-size: 0.9375rem; }

.cp-scrollhint {
  display: inline-flex; flex-direction: column; align-items: center; gap: var(--space-2);
  text-decoration: none; color: var(--muted);
  font-family: var(--font-mono); font-size: 0.6875rem; letter-spacing: 0.14em;
}
.cp-scrollhint-line { width: 1px; height: 26px; background: linear-gradient(180deg, var(--cyan), transparent); animation: cp-scrollhint 1.8s ease-in-out infinite; }
@keyframes cp-scrollhint { 0%, 100% { transform: scaleY(0.6); opacity: 0.5; } 50% { transform: scaleY(1); opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .cp-scrollhint-line { animation: none; } }

/* ---------- floating glass panel (om / founder) ---------- */

.cp-panel { padding-block: var(--space-8); display: flex; justify-content: center; }
/* .cp-panel-card is just a sizing/reveal shell now — .cp-panel-card-inner
   carries the actual visual chrome and hover-tilt transform. Keeping them
   split matters: .cp-panel-card also carries .reveal, and the site-wide
   `.reveal.is-visible { transform: none; }` rule (two classes) has higher
   specificity than a plain `.cp-panel-card { transform: ... }` rule (one
   class) would, so it would permanently clobber the tilt transform the
   moment the card was revealed if it lived on the same element. */
.cp-panel-card { max-width: 46rem; width: 100%; }
.cp-panel-card-inner {
  background: linear-gradient(160deg, rgba(21,15,44,0.85), rgba(10,7,22,0.85));
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: clamp(1.75rem, 4vw, 3rem);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  box-shadow: 0 30px 60px rgba(0,0,0,0.5), inset 0 1px 0 rgba(255,255,255,0.04);
  transform: perspective(1200px) rotateX(var(--tiltx, 0deg)) rotateY(var(--tilty, 0deg));
  transition: transform 260ms var(--ease), border-color var(--dur-base) var(--ease);
  position: relative;
}
.cp-panel-card-inner:hover { border-color: var(--border-soft); }
.cp-panel-eyebrow {
  font-family: var(--font-mono); font-size: 0.75rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--yellow);
}
.cp-panel-text { margin-top: var(--space-4); font-size: 1.0625rem; line-height: 1.7; color: var(--text); }
.cp-panel--founder .cp-panel-card { max-width: 40rem; text-align: center; }
.cp-panel--founder .cp-panel-eyebrow { color: var(--cyan); }

/* ---------- standalone pages (Tjenester, Priser, Prosjekter) ---------- */
/* No .cp-section-tag above the title here (a tag reusing that section's
   homepage wording, e.g. "03 · Priser", still visibly repeats the title
   word even numbered) - just the page's own <h1>, centered like every
   other section on this theme. No fixed top bar to clear (the depth-rail
   sits on the right edge, not overlapping the top), so this only needs
   normal section padding. */
.page-hero {
  padding-block: var(--space-8) var(--space-4);
  text-align: center;
}
.page-title {
  font-family: var(--font-display);
  font-size: clamp(1.875rem, 1.6rem + 1.6vw, 2.75rem);
  line-height: 1.05;
  text-transform: uppercase;
  letter-spacing: -0.01em;
  color: var(--text);
  margin: 0;
}

/* Plain wrapping grid version of .cp-carousel-card, for the standalone
   Prosjekter page -- unlike the homepage's 3D coverflow carousel (built
   for a fixed 3-item highlight reel with prev/next controls), this list
   keeps growing as new customer sites are added, so a scalable grid
   suits it better. */
.cp-project-grid {
  max-width: var(--container);
  margin-inline: auto;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: var(--space-5);
}

/* ---------- section tag (HUD label) ---------- */

.cp-section-tag {
  display: block; text-align: center;
  font-family: var(--font-mono); font-size: 0.75rem; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--magenta);
  margin-bottom: var(--space-7);
}
.cp-section-tag::after {
  content: ''; display: block; width: 40px; height: 1px; margin: var(--space-3) auto 0;
  background: var(--magenta); box-shadow: 0 0 8px var(--magenta);
}

/* ---------- holo-deck (tjenester) — scattered, not a grid ---------- */

.cp-deck-section { padding-block: var(--space-8); }
.cp-deck {
  max-width: var(--container); margin-inline: auto;
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: var(--space-6) var(--space-5);
  perspective: 1400px;
}
.cp-deck-card {
  flex: 1 1 17rem; max-width: 20rem;
}
/* Staggered offsets via nth-child rather than CSS trig functions, so the
   scattered look doesn't depend on newer sin()/cos() support. */
.cp-deck > .cp-deck-card.cp-deck-card:nth-child(6n+1) { transform: translateY(-10px) rotate(-1.4deg); }
.cp-deck > .cp-deck-card.cp-deck-card:nth-child(6n+2) { transform: translateY(14px) rotate(1.1deg); }
.cp-deck > .cp-deck-card.cp-deck-card:nth-child(6n+3) { transform: translateY(-4px) rotate(1.8deg); }
.cp-deck > .cp-deck-card.cp-deck-card:nth-child(6n+4) { transform: translateY(10px) rotate(-2deg); }
.cp-deck > .cp-deck-card.cp-deck-card:nth-child(6n+5) { transform: translateY(-14px) rotate(0.6deg); }
.cp-deck > .cp-deck-card.cp-deck-card:nth-child(6n+6) { transform: translateY(6px) rotate(-0.9deg); }
@media (max-width: 40em) {
  .cp-deck-card { transform: none !important; }
}
.cp-deck-card-inner {
  height: 100%;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--space-6);
  transform: perspective(900px) rotateX(var(--tiltx, 0deg)) rotateY(var(--tilty, 0deg));
  transition: transform 220ms var(--ease), border-color var(--dur-base) var(--ease), box-shadow var(--dur-base) var(--ease);
  position: relative;
}
.cp-deck-card-inner::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(18rem circle at var(--mx, 50%) var(--my, 0%), rgba(34,240,255,0.16), transparent 60%),
    linear-gradient(120deg, transparent 40%, rgba(255,46,154,0.08) 50%, transparent 60%);
  opacity: 0; transition: opacity var(--dur-base) var(--ease);
}
.cp-deck-card-inner:hover {
  border-color: var(--cyan);
  box-shadow: 0 0 30px rgba(34,240,255,0.25);
}
.cp-deck-card-inner:hover::before { opacity: 1; }
.cp-deck-card-index {
  font-family: var(--font-mono); font-size: 0.6875rem; letter-spacing: 0.1em; color: var(--cyan);
}
.cp-deck-card-inner h3 {
  margin-top: var(--space-2); font-size: 1.25rem; text-transform: uppercase; letter-spacing: 0.01em;
}
.cp-deck-card-desc { margin-top: var(--space-3); color: var(--muted); font-size: 0.9375rem; line-height: 1.6; }
.cp-deck-card-desc p { margin: 0; }

/* ---------- holo-stack (priser) — layered depth deck ---------- */

.cp-stack-section { padding-block: var(--space-8); }
.cp-stack {
  max-width: 40rem; margin-inline: auto;
  display: flex; flex-direction: column; gap: var(--space-5);
  perspective: 1600px;
}
/* .cp-stack-card is just the reveal/perspective shell now — see the note
   above .cp-panel-card for why the visual chrome and hover-tilt transform
   live on .cp-stack-card-inner instead: the site-wide `.reveal.is-visible`
   rule outranks a plain single-class rule on the .reveal element itself. */
.cp-stack-card-inner {
  background: linear-gradient(155deg, var(--panel-2), var(--panel));
  border: 1px solid var(--border);
  border-left: 3px solid var(--magenta);
  border-radius: var(--radius);
  padding: var(--space-6);
  transform-origin: left center;
  transform: perspective(1000px) rotateY(calc(-1deg * var(--i))) translateZ(0) rotateX(var(--tiltx, 0deg));
  transition: transform 240ms var(--ease), border-color var(--dur-base) var(--ease), box-shadow var(--dur-base) var(--ease);
  position: relative;
}
.cp-stack-card-inner:hover {
  transform: perspective(1000px) rotateY(0deg) translateZ(30px) rotateX(var(--tiltx, 0deg));
  border-left-color: var(--yellow);
  box-shadow: 0 20px 50px rgba(255,46,154,0.25);
}
.cp-stack-card-index { font-family: var(--font-mono); font-size: 0.6875rem; letter-spacing: 0.1em; color: var(--magenta); }
.cp-stack-card-inner h3 { margin-top: var(--space-2); font-size: 1.375rem; text-transform: uppercase; }
.cp-stack-price {
  margin-top: var(--space-2); font-family: var(--font-mono); font-weight: 700; font-size: 1.0625rem; color: var(--yellow);
}
.cp-stack-desc { margin-top: var(--space-3); color: var(--muted); font-size: 0.9375rem; line-height: 1.6; }
.cp-stack-desc p { margin: 0; }
.cp-stack-desc ul { margin-top: var(--space-2); padding-left: 0; list-style: none; }
.cp-stack-desc li { position: relative; padding-left: 1.4em; }
.cp-stack-desc li + li { margin-top: var(--space-1); }
.cp-stack-desc li::before { content: "✓"; position: absolute; left: 0; color: var(--yellow); }

@media (max-width: 40em) {
  .cp-stack-card-inner { transform: none !important; }
}

/* ---------- 3D coverflow carousel (prosjekter) ---------- */

.cp-carousel-section {
  padding-block: var(--space-8);
  /* The coverflow's neighbor cards sit at translateX values that push
     them to genuinely negative/overflowing x-coordinates (peeking in from
     off-canvas) -- without clipping that here, those cards widen the whole
     document's scrollable area, which is what let a horizontal drag on
     mobile pan the entire site instead of just the carousel. */
  overflow-x: hidden;
}
.cp-carousel {
  position: relative;
  outline: none;
}
.cp-carousel-track {
  position: relative;
  /* Height is set inline by main.js to exactly fit the active card's own
     content (screenshot + full text) — no card is ever clipped or forced
     to scroll internally. This is just a sane first-paint value before JS
     measures it. */
  height: 34rem;
  transition: height 320ms var(--ease);
  perspective: 1800px;
  /* The JS drag handler (touchstart/touchend on this element) reads the
     gesture itself -- letting the browser also treat it as a native pan
     drags the whole page sideways a few pixels on iOS Safari before the
     handler ever fires. pan-y keeps vertical page scroll working while
     telling the browser not to touch the horizontal axis here. */
  touch-action: pan-y;
}
.cp-carousel-item {
  position: absolute; top: 0; left: 50%;
  width: min(84vw, 26rem);
  margin-left: calc(min(84vw, 26rem) / -2);
  transition: transform 520ms var(--ease), opacity 520ms var(--ease), z-index 0s 260ms;
  will-change: transform;
}
.cp-carousel-card {
  position: relative;
  display: flex; flex-direction: column;
  width: 100%;
  text-decoration: none; color: var(--text);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: 0 30px 60px rgba(0,0,0,0.55);
}
.cp-carousel-corner { position: absolute; width: 16px; height: 16px; border: 2px solid var(--cyan); opacity: 0.8; z-index: 2; }
.cp-carousel-corner--tl { top: 8px; left: 8px; border-right: 0; border-bottom: 0; }
.cp-carousel-corner--br { bottom: 8px; right: 8px; border-left: 0; border-top: 0; }
.cp-carousel-media {
  aspect-ratio: 16/10;
  flex-shrink: 0;
  overflow: hidden;
  background: var(--ink);
}
.cp-carousel-media img { width: 100%; height: 100%; object-fit: contain; }
.cp-carousel-body { padding: var(--space-5); }
.cp-carousel-tag {
  font-family: var(--font-mono); font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.1em; color: var(--magenta);
}
.cp-carousel-body h3 { margin-top: var(--space-2); font-size: 1.1875rem; text-transform: uppercase; }
.cp-carousel-body p:not(.cp-carousel-tag) { margin-top: var(--space-2); color: var(--muted); font-size: 0.875rem; line-height: 1.55; }
.cp-carousel-link { display: inline-block; margin-top: var(--space-3); font-family: var(--font-mono); font-size: 0.8125rem; color: var(--cyan); }

/* Glitch cut when the coverflow switches project: an RGB-split stutter
   on the incoming card. Only filter/clip-path animate, never transform
   (the coverflow owns that). */
.cp-carousel.is-switching .cp-carousel-item.is-active .cp-carousel-card { animation: cp-card-glitch 480ms steps(8, end) 1; }
@keyframes cp-card-glitch {
  0% { filter: drop-shadow(-6px 0 0 rgba(255,46,154,0.8)) drop-shadow(6px 0 0 rgba(34,240,255,0.8)); clip-path: inset(0 0 60% 0); }
  25% { filter: drop-shadow(4px 0 0 rgba(255,46,154,0.7)) drop-shadow(-4px 0 0 rgba(34,240,255,0.7)); clip-path: inset(30% 0 0 0); }
  50% { filter: drop-shadow(-2px 0 0 rgba(255,46,154,0.6)) drop-shadow(2px 0 0 rgba(34,240,255,0.6)); clip-path: inset(0 0 10% 0); }
  100% { filter: none; clip-path: inset(0); }
}
@media (prefers-reduced-motion: reduce) { .cp-carousel.is-switching .cp-carousel-item.is-active .cp-carousel-card { animation: none; } }
/* Wet-floor reflection under the active card. */
.cp-carousel-item.is-active::after {
  content: ''; position: absolute; left: 6%; right: 6%; top: 100%; height: 3.5rem; margin-top: 0.5rem;
  background: radial-gradient(ellipse at 50% 0%, rgba(34,240,255,0.22), rgba(255,46,154,0.08) 45%, transparent 70%);
  filter: blur(6px); pointer-events: none;
}

.cp-carousel-controls {
  display: flex; align-items: center; justify-content: center; gap: var(--space-5);
  margin-top: var(--space-6);
}
.cp-carousel-btn {
  display: grid; place-items: center;
  width: 42px; height: 42px; border-radius: 50%;
  border: 1px solid var(--border-soft); color: var(--text);
  font-size: 1.25rem;
  transition: border-color var(--dur-base) var(--ease), color var(--dur-base) var(--ease), transform var(--dur-fast) var(--ease);
}
.cp-carousel-btn:hover, .cp-carousel-btn:focus-visible { border-color: var(--magenta); color: var(--magenta); transform: scale(1.08); }
.cp-carousel-dots { display: flex; gap: var(--space-2); }
.cp-carousel-dot {
  width: 8px; height: 8px; border-radius: 50%; background: var(--border-soft); border: 0; padding: 0;
  transition: background var(--dur-base) var(--ease), transform var(--dur-base) var(--ease);
}
.cp-carousel-dot.is-active { background: var(--magenta); box-shadow: 0 0 8px var(--magenta); transform: scale(1.3); }

.cp-empty { text-align: center; color: var(--muted); font-family: var(--font-mono); font-size: 0.9375rem; }

/* ---------- kontakt ---------- */

.cp-terminal-cta {
  padding-block: var(--space-9);
  text-align: center;
}
.cp-cta-heading {
  margin-top: var(--space-4);
  font-size: clamp(1.75rem, 1.4rem + 2vw, 2.75rem);
  text-transform: uppercase;
}
.cp-cta-lede { margin-top: var(--space-4); color: var(--muted); font-family: var(--font-mono); }
.cp-terminal-cta .cp-cta { margin-top: var(--space-7); }

/* ---------- footer ---------- */

.cp-footer { padding-block: var(--space-7); text-align: center; }
.cp-footer-inner { max-width: var(--container); margin-inline: auto; }
.cp-footer-tagline { font-family: var(--font-mono); color: var(--cyan); font-size: 0.875rem; }
.cp-footer-meta { margin-top: var(--space-2); font-family: var(--font-mono); font-size: 0.75rem; color: var(--muted); letter-spacing: 0.04em; }
.cp-footer-contact { margin-top: var(--space-3); font-family: var(--font-mono); font-size: 0.8125rem; display: flex; gap: var(--space-4); justify-content: center; flex-wrap: wrap; color: var(--muted); }
.cp-footer-contact a { color: var(--magenta); text-decoration: none; }
.cp-footer-contact a:hover { text-decoration: underline; }

/* ---------- console (contact dialog) ---------- */

.cp-console {
  border: 0; padding: 0; background: transparent; color: var(--text);
  max-width: min(94vw, 30rem); width: 100%;
  overflow: visible;
}
.cp-console::backdrop { background: rgba(3,1,8,0.75); -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); }
.cp-console-frame {
  background: var(--panel);
  border: 1px solid var(--magenta);
  border-radius: var(--radius);
  box-shadow: 0 0 60px rgba(255,46,154,0.35), 0 30px 70px rgba(0,0,0,0.6);
  transform: perspective(1200px) rotateX(-8deg) scale(0.92);
  opacity: 0;
  transition: transform var(--dur-slow) var(--ease), opacity var(--dur-slow) var(--ease);
}
.cp-console.is-open .cp-console-frame { transform: perspective(1200px) rotateX(0deg) scale(1); opacity: 1; }
.cp-console-bar {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border);
  font-family: var(--font-mono); font-size: 0.75rem; letter-spacing: 0.08em; color: var(--cyan);
}
.cp-console-close { display: grid; place-items: center; width: 26px; height: 26px; color: var(--muted); }
.cp-console-close:hover { color: var(--magenta); }
.cp-console-close svg { width: 16px; height: 16px; }
.cp-console-body { padding: var(--space-6); }
.cp-console-line { font-family: var(--font-mono); font-size: 0.8125rem; color: var(--yellow); margin-bottom: var(--space-4); }
.cp-field { margin-top: var(--space-4); display: flex; flex-direction: column; gap: var(--space-2); }
.cp-field label { font-family: var(--font-mono); font-size: 0.75rem; letter-spacing: 0.06em; color: var(--muted); text-transform: uppercase; }
.cp-optional { text-transform: none; opacity: 0.7; }
.cp-field input, .cp-field textarea {
  background: var(--ink); border: 1px solid var(--border); border-radius: var(--radius);
  color: var(--text); font-family: var(--font-mono);
  /* 16px minimum — anything smaller makes mobile Safari/Chrome auto-zoom
     the page on focus. */
  font-size: 16px;
  padding: var(--space-3); resize: vertical;
}
.cp-field input:focus, .cp-field textarea:focus { outline: none; border-color: var(--cyan); box-shadow: 0 0 0 3px rgba(34,240,255,0.18); }
.cp-console-footer { margin-top: var(--space-5); display: flex; align-items: center; gap: var(--space-4); flex-wrap: wrap; }
.cp-submit {
  padding: 0.8em 1.8em;
  font-family: var(--font-mono); font-weight: 700; font-size: 0.8125rem; letter-spacing: 0.08em;
  color: var(--ink);
  background: linear-gradient(95deg, var(--cyan), var(--violet));
  clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px);
}
.cp-submit:hover { filter: brightness(1.1); }
.cp-submit:disabled { opacity: 0.6; cursor: progress; }
.cp-console-status { font-family: var(--font-mono); font-size: 0.8125rem; color: var(--muted); margin: 0; }
.cp-console-status[data-state="error"] { color: #ff6767; }
.cp-console-status[data-state="loading"] { color: var(--cyan); }
.cp-success { font-family: var(--font-mono); font-size: 0.875rem; }
.cp-success-ok { color: var(--cyan); margin-top: var(--space-2); }

@media (prefers-reduced-motion: reduce) {
  .cp-console-frame { transition: opacity var(--dur-base) linear; transform: none !important; }
}

/* ---------- signal lock-in: card scroll-reveal ---------- */
/*
 * The site-wide .reveal class (plain fade + rise) is too quiet for this
 * theme, so cards get their own entrance instead: a HUD "locking onto a
 * target" moment — a couple of RGB-shifted glitch stutters, a bright
 * scan-line sweeping once down the card, then a snap into full focus.
 * Deliberately animates only opacity/filter/clip-path, never transform or
 * box-shadow/border-color, so it can never fight the cards' own resting
 * stagger transforms or :hover styles once the animation ends.
 *
 * .cp-deck-card/.cp-stack-card/.cp-panel-card keep the shared .reveal
 * class for the IntersectionObserver in main.js to toggle .is-visible on,
 * but their own opacity/transform transition is neutralized below (the
 * lock-in animation drives visibility instead). The animation itself
 * always plays on the *-inner element, never the .reveal element itself:
 * the site-wide `.reveal.is-visible { transform: none; }` rule (two
 * classes) has higher specificity than a plain single-class rule on
 * .cp-stack-card/.cp-panel-card would, so it would permanently overwrite
 * — and for a while, during testing, silently DID overwrite — each card's
 * own resting/hover transform the moment it was revealed, which is what
 * made priser and the panels fail to render at all in some browsers.
 */
.js .cp-deck-card.reveal,
.js .cp-stack-card.reveal,
.js .cp-panel-card.reveal { opacity: 1; transform: none; transition: none; }
.js .cp-deck-card.reveal .cp-deck-card-inner,
.js .cp-stack-card.reveal .cp-stack-card-inner,
.js .cp-panel-card.reveal .cp-panel-card-inner {
  opacity: 0;
  filter: blur(8px) brightness(2.4);
  clip-path: inset(0 0 100% 0);
}
.cp-deck-card.reveal.is-visible .cp-deck-card-inner,
.cp-stack-card.reveal.is-visible .cp-stack-card-inner,
.cp-panel-card.reveal.is-visible .cp-panel-card-inner {
  animation: cp-lockin 780ms cubic-bezier(0.2, 0.9, 0.25, 1) forwards;
}
.cp-deck-card.reveal.is-visible .cp-deck-card-inner::after,
.cp-stack-card.reveal.is-visible .cp-stack-card-inner::after,
.cp-panel-card.reveal.is-visible .cp-panel-card-inner::after {
  content: '';
  position: absolute; left: 0; right: 0; top: 0; height: 3px;
  background: linear-gradient(90deg, transparent, var(--cyan), transparent);
  box-shadow: 0 0 16px 2px var(--cyan), 0 0 30px 6px rgba(34, 240, 255, 0.5);
  animation: cp-lockin-scan 780ms cubic-bezier(0.2, 0.9, 0.25, 1) forwards;
  pointer-events: none;
  z-index: 3;
}
@keyframes cp-lockin {
  /* The last keyframe's clip-path is what the element is left with forever
     (animation-fill-mode: forwards outranks any static clip-path on the
     element, regardless of specificity) — it has to end at the card's own
     resting cut-corner shape, not a plain rectangle, or the corner-cut
     look gets permanently wiped the moment a card is revealed. inset() and
     polygon() don't interpolate smoothly into each other, but by 75% the
     card is already fully unclipped, so the switch to the polygon at 100%
     lands as an imperceptible snap on a sliver of one corner. */
  0%   { opacity: 0;    filter: blur(8px) brightness(2.4);              clip-path: inset(0 0 100% 0); }
  10%  { opacity: 0.7;  filter: blur(4px) brightness(2.8) hue-rotate(20deg);  clip-path: inset(0 0 62% 0); }
  18%  { opacity: 0.15; filter: blur(6px) brightness(0.5);              clip-path: inset(0 0 78% 0); }
  28%  { opacity: 0.85; filter: blur(2px) brightness(2.2) hue-rotate(-15deg); clip-path: inset(0 0 34% 0); }
  38%  { opacity: 0.3;  filter: blur(4px) brightness(0.6);              clip-path: inset(0 0 48% 0); }
  55%  { opacity: 1;    filter: blur(1px) brightness(1.6);              clip-path: inset(0 0 10% 0); }
  75%  { opacity: 1;    filter: blur(0)   brightness(1.15);             clip-path: inset(0 0 0% 0); }
  100% { opacity: 1;    filter: none;                                   clip-path: inset(0 0 0% 0); }
}
@keyframes cp-lockin-scan {
  0%   { top: 0%;   opacity: 0; }
  8%   { opacity: 1; }
  70%  { top: 100%; opacity: 1; }
  100% { top: 100%; opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .js .cp-deck-card.reveal .cp-deck-card-inner,
  .js .cp-stack-card.reveal .cp-stack-card-inner,
  .js .cp-panel-card.reveal .cp-panel-card-inner {
    opacity: 1; filter: none; clip-path: none;
  }
  .cp-deck-card.reveal.is-visible .cp-deck-card-inner,
  .cp-stack-card.reveal.is-visible .cp-stack-card-inner,
  .cp-panel-card.reveal.is-visible .cp-panel-card-inner,
  .cp-deck-card.reveal.is-visible .cp-deck-card-inner::after,
  .cp-stack-card.reveal.is-visible .cp-stack-card-inner::after,
  .cp-panel-card.reveal.is-visible .cp-panel-card-inner::after {
    animation: none;
    display: none;
  }
}

/* ---------- responsive ---------- */

@media (max-width: 40em) {
  section { padding-inline: var(--space-4); }
  .cp-hero-actions { gap: var(--space-4); }
}

/* ============================================================
   2.0 — Night City, levende
   ============================================================ */

[hidden] { display: none !important; }

/* ---------- boot-in (hero + page tops) ----------
   Pure CSS, so it runs from the very first paint: `both` fill keeps the
   element hidden through its delay (no flash of finished text before the
   animation), and it always ends fully visible - with or without JS. */
.cp-boot {
  animation: cp-boot 1s cubic-bezier(0.2, 0.9, 0.25, 1) both;
  animation-delay: calc(var(--b, 0) * 150ms + 120ms);
}
.cp-boot--title { animation-duration: 1.25s; }
@keyframes cp-boot {
  0%   { opacity: 0;   filter: blur(10px) brightness(2.6); clip-path: inset(-20% 100% -20% -10%); }
  14%  { opacity: 0.85; filter: blur(4px) brightness(2.4) hue-rotate(25deg); clip-path: inset(-20% 62% -20% -10%); }
  22%  { opacity: 0.2; filter: blur(6px) brightness(0.6); clip-path: inset(-20% 70% -20% -10%); }
  36%  { opacity: 1;   filter: blur(2px) brightness(1.9) hue-rotate(-20deg); clip-path: inset(-20% 28% -20% -10%); }
  44%  { opacity: 0.45; filter: blur(3px) brightness(0.8); clip-path: inset(-20% 34% -20% -10%); }
  70%  { opacity: 1;   filter: blur(0) brightness(1.2); clip-path: inset(-20% -10% -20% -10%); }
  100% { opacity: 1;   filter: none; clip-path: none; }
}
@media (prefers-reduced-motion: reduce) { .cp-boot { animation: none; } }

/* ---------- depth camera on sections (main.js sets --e / --x) ---------- */
.cp-depth main > section.cp-district:not(.page-hero) {
  transform-origin: 50% 0%;
  transform: perspective(1400px)
    translate3d(0, calc(var(--e, 0) * 80px), calc(var(--e, 0) * -300px + var(--x, 0) * 120px))
    rotateX(calc(var(--e, 0) * 16deg - var(--x, 0) * 8deg));
  opacity: calc(1 - var(--e, 0) * 0.72 - var(--x, 0) * 0.55);
}
@media (max-width: 56em) {
  .cp-depth main > section.cp-district:not(.page-hero) {
    transform: perspective(900px)
      translate3d(0, calc(var(--e, 0) * 40px), calc(var(--e, 0) * -120px))
      rotateX(calc(var(--e, 0) * 9deg));
    opacity: calc(1 - var(--e, 0) * 0.6 - var(--x, 0) * 0.4);
  }
}

/* ---------- page tops (Tjenester / Priser / Prosjekter / Facebook / sider) ---------- */
.page-hero {
  min-height: 56svh;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding-block: var(--space-9) var(--space-6);
}
.page-hero--compact { min-height: 38svh; }
.page-hero::before {
  content: ''; position: absolute; left: 50%; top: 50%; z-index: -1;
  width: min(60rem, 110vw); height: 70%; transform: translate(-50%, -50%);
  background: radial-gradient(closest-side, rgba(6,3,16,0.84), rgba(6,3,16,0.55) 60%, transparent);
  pointer-events: none;
}
.page-sector {
  display: flex; gap: 1.4em; justify-content: center; flex-wrap: wrap;
  margin-bottom: var(--space-4);
  font-family: var(--font-mono); font-size: 0.75rem; letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--cyan);
}
.page-sector span + span { color: var(--muted); }
.page-title {
  font-size: clamp(2.1rem, 1.1rem + 4.2vw, 4.75rem);
  line-height: 1.02;
  max-width: 22ch;
  overflow-wrap: anywhere;
}
.page-title .cp-glitch { display: inline-block; }
.page-lede {
  max-width: 40rem; margin: var(--space-5) auto 0;
  color: var(--text);
}
.page-lede p + p { margin-top: 1em; }
.cp-section-lede { max-width: 38rem; margin: 0 auto var(--space-6); text-align: center; }
.cp-carousel-section--grid { overflow-x: visible; }
.cp-project-grid .cp-carousel-card { height: 100%; transition: border-color var(--dur-base) var(--ease), box-shadow var(--dur-base) var(--ease), transform var(--dur-base) var(--ease); }
.cp-project-grid .cp-carousel-card:hover,
.cp-project-grid .cp-carousel-card:focus-visible { border-color: var(--cyan); box-shadow: 0 0 34px rgba(34,240,255,0.28), 0 30px 60px rgba(0,0,0,0.55); transform: translateY(-4px); }

/* ---------- prose (page.php) ---------- */
.cp-prose-section { padding-block: 0 var(--space-9); }
.cp-prose {
  position: relative;
  max-width: 46rem; margin-inline: auto;
  background: rgba(10, 7, 22, 0.93);
  border: 1px solid var(--border);
  border-left: 2px solid var(--violet);
  border-radius: var(--radius);
  padding: clamp(1.5rem, 4vw, 3rem);
  font-size: 1.0625rem; line-height: 1.75;
  box-shadow: 0 30px 60px rgba(0,0,0,0.5), 0 0 40px rgba(122,92,255,0.12);
  overflow-wrap: break-word;
}
.cp-prose-corner { position: absolute; width: 16px; height: 16px; border: 2px solid var(--cyan); opacity: 0.8; }
.cp-prose-corner--tl { top: 8px; left: 8px; border-right: 0; border-bottom: 0; }
.cp-prose-corner--br { bottom: 8px; right: 8px; border-left: 0; border-top: 0; }
.cp-prose > :first-child { margin-top: 0; }
.cp-prose p, .cp-prose ul, .cp-prose ol, .cp-prose figure, .cp-prose table { margin: 0 0 1.2em; }
.cp-prose h2 {
  margin: 2.2em 0 0.7em;
  font-size: clamp(1.2rem, 1rem + 0.9vw, 1.55rem); line-height: 1.2;
  text-transform: uppercase; letter-spacing: 0.02em;
}
.cp-prose h2::before { content: '// '; font-family: var(--font-mono); color: var(--magenta); }
.cp-prose h3 { margin: 1.8em 0 0.6em; font-size: 1.125rem; color: var(--cyan); }
.cp-prose a { color: var(--cyan); text-underline-offset: 0.2em; }
.cp-prose a:hover { color: var(--text); }
.cp-prose em { color: var(--muted); }
.cp-prose strong, .cp-prose b { color: var(--text); font-weight: 700; }
.cp-prose ul, .cp-prose ol { padding-left: 1.3em; }
.cp-prose li { margin-bottom: 0.45em; }
.cp-prose li::marker { color: var(--magenta); }
.cp-prose figure { overflow-x: auto; }
.cp-prose table { width: 100%; border-collapse: collapse; font-size: 0.9375rem; }
.cp-prose th, .cp-prose td { text-align: left; padding: 0.6em 0.8em; border-bottom: 1px solid var(--border); vertical-align: top; }
.cp-prose th { font-family: var(--font-mono); font-size: 0.8125rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--yellow); }
.cp-prose img { height: auto; }

/* ---------- Holder det ikke med Facebook? ---------- */
.cp-fb-intro { padding-top: 0; }
.cp-fb-intro .cp-panel-card { max-width: 48rem; }
.cp-fb-lede { margin-top: var(--space-4); font-size: 1.0625rem; line-height: 1.75; }
.cp-fb-lede p + p { margin-top: 1em; }

.cp-fb-compare { padding-block: var(--space-7); }
.cp-scanner {
  position: relative;
  max-width: 70rem; margin-inline: auto;
  background: rgba(10, 7, 22, 0.93);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: 0 30px 70px rgba(0,0,0,0.55);
  overflow: hidden;
}
.cp-scanner::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg, transparent 0 46%, rgba(34,240,255,0.07) 49%, rgba(34,240,255,0.35) 50%, transparent 50.6%);
  background-size: 100% 220%;
  animation: cp-scanbeam 7s linear infinite;
}
@keyframes cp-scanbeam { from { background-position: 0 110%; } to { background-position: 0 -110%; } }
.cp-scanner table { width: 100%; border-collapse: collapse; }
.cp-scanner caption {
  caption-side: top; text-align: left;
  padding: 1.1rem 1.5rem;
  font-family: var(--font-mono); font-size: 0.8125rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--yellow);
  border-bottom: 1px solid var(--border);
}
.cp-scanner thead th {
  padding: 1.1rem 1.5rem; text-align: left; vertical-align: bottom;
  font-family: var(--font-mono); font-size: 0.75rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
}
.cp-scanner thead th.cp-scanner-weak { color: var(--muted); }
.cp-scanner thead th.cp-scanner-strong { color: var(--cyan); }
.cp-scanner .digital-home-plus { color: var(--magenta); }
.cp-scanner-meter { display: inline-flex; gap: 2px; align-items: flex-end; height: 10px; margin-right: 0.7em; vertical-align: -1px; }
.cp-scanner-meter i { display: block; width: 3px; background: currentColor; }
.cp-scanner-meter i:nth-child(1) { height: 3px; }
.cp-scanner-meter i:nth-child(2) { height: 5px; }
.cp-scanner-meter i:nth-child(3) { height: 7px; }
.cp-scanner-meter i:nth-child(4) { height: 10px; }
.cp-scanner-weak .cp-scanner-meter i:nth-child(n+2) { opacity: 0.2; }
.cp-scanner-strong .cp-scanner-meter i { box-shadow: 0 0 6px currentColor; }
.cp-scanner tbody tr { border-top: 1px solid var(--border); }
.cp-scanner tbody th {
  width: 22%; padding: 1.15rem 1.5rem; text-align: left; vertical-align: top;
  font-size: 1rem; text-transform: uppercase; letter-spacing: 0.01em; line-height: 1.25;
}
.cp-scanner-idx { display: block; margin-bottom: 0.35em; font-family: var(--font-mono); font-size: 0.6875rem; letter-spacing: 0.12em; color: var(--magenta); }
.cp-scanner tbody td { padding: 1.15rem 1.5rem; vertical-align: top; font-size: 0.9375rem; line-height: 1.6; }
.cp-scanner tbody td.cp-scanner-weak {
  color: var(--muted);
  background: repeating-linear-gradient(0deg, rgba(255,255,255,0.018) 0 1px, transparent 1px 3px);
}
.cp-scanner tbody td.cp-scanner-strong {
  color: var(--text);
  border-left: 1px solid rgba(34,240,255,0.35);
  background: linear-gradient(90deg, rgba(34,240,255,0.08), transparent 75%);
  transition: background var(--dur-base) var(--ease), box-shadow var(--dur-base) var(--ease);
}
.cp-scanner tbody tr:hover td.cp-scanner-strong { background: linear-gradient(90deg, rgba(34,240,255,0.16), transparent 85%); box-shadow: inset 2px 0 0 var(--cyan); }
.digital-home-mobile-label { display: none; }
/* Rows power on one by one once the scanner is revealed. */
.js .cp-scanner.reveal tbody tr { opacity: 0; }
.js .cp-scanner.reveal.is-visible tbody tr { animation: cp-row-on 700ms cubic-bezier(0.2, 0.9, 0.25, 1) both; animation-delay: calc(var(--r, 0) * 110ms + 200ms); }
@keyframes cp-row-on {
  0% { opacity: 0; filter: brightness(2.4) blur(3px); transform: translateX(-14px); }
  30% { opacity: 0.4; }
  45% { opacity: 1; filter: brightness(1.6) blur(1px); }
  100% { opacity: 1; filter: none; transform: none; }
}
@media (max-width: 48em) {
  .cp-scanner table, .cp-scanner tbody, .cp-scanner tr, .cp-scanner th, .cp-scanner td { display: block; width: auto; }
  .cp-scanner thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .cp-scanner caption { display: block; }
  .cp-scanner tbody th { width: auto; padding: 1.1rem 1.1rem 0.4rem; }
  .cp-scanner tbody td { padding: 0.6rem 1.1rem; }
  .cp-scanner tbody td.cp-scanner-strong { border-left: 2px solid rgba(34,240,255,0.5); margin: 0 1.1rem 1.1rem; padding-left: 0.9rem; }
  .cp-scanner tbody td.cp-scanner-weak { margin: 0 1.1rem 0.4rem; padding-left: 0.9rem; border-left: 2px solid var(--border); }
  .digital-home-mobile-label { display: block; margin-bottom: 0.25em; font-family: var(--font-mono); font-size: 0.6875rem; letter-spacing: 0.1em; text-transform: uppercase; }
  .cp-scanner-weak .digital-home-mobile-label { color: var(--muted); }
  .cp-scanner-strong .digital-home-mobile-label { color: var(--cyan); }
}

.cp-fb-details {
  max-width: 70rem; margin-inline: auto;
  padding-block: var(--space-7);
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr)); gap: var(--space-5);
}
.cp-fb-details .cp-panel-card { max-width: none; }
.cp-fb-details .cp-panel-card-inner { height: 100%; }
.cp-fb-details .cp-panel-card:nth-child(2) .cp-panel-eyebrow { color: var(--cyan); }
.cp-fb-subheading { margin-top: var(--space-3); font-size: clamp(1.2rem, 1rem + 0.8vw, 1.5rem); line-height: 1.2; text-transform: uppercase; }
.cp-fb-details .cp-panel-text + .cp-panel-text { margin-top: var(--space-3); }

.cp-fb-takeaway { padding-block: var(--space-8) var(--space-6); text-align: center; }
.cp-neonsign {
  display: inline-block;
  padding: 1em 1.4em;
  font-size: clamp(1.25rem, 0.8rem + 1.9vw, 2.4rem); line-height: 1.18; text-transform: uppercase; letter-spacing: 0.01em;
  background: rgba(6, 3, 16, 0.82);
  border: 2px solid rgba(34, 240, 255, 0.65);
  border-radius: 14px;
  box-shadow: 0 0 22px rgba(34,240,255,0.35), inset 0 0 22px rgba(34,240,255,0.18);
}
.cp-neonsign-line { color: var(--text); }
.cp-neonsign-line--hot { color: #ff4fa8; text-shadow: 0 0 18px rgba(255,46,154,0.65), 0 0 46px rgba(255,46,154,0.35); }
/* The tube "ignites": only the glow flickers on - the letters themselves
   keep their colour (and contrast) the whole time. */
.js .cp-neonsign.reveal.is-visible .cp-neonsign-line--hot { animation: cp-ignite 1.8s linear 1 both 300ms; }
.js .cp-neonsign.reveal.is-visible { animation: cp-tube 1.8s linear 1 both 150ms; }
@keyframes cp-ignite {
  0%, 9%, 15%, 31% { text-shadow: none; }
  10%, 14%, 32%, 100% { text-shadow: 0 0 18px rgba(255,46,154,0.65), 0 0 46px rgba(255,46,154,0.35); }
}
@keyframes cp-tube {
  0%, 6%, 12% { box-shadow: none; border-color: rgba(34,240,255,0.25); }
  7%, 11%, 100% { box-shadow: 0 0 22px rgba(34,240,255,0.35), inset 0 0 22px rgba(34,240,255,0.18); border-color: rgba(34,240,255,0.65); }
}

.cp-cta-row { margin-top: var(--space-7); display: flex; gap: var(--space-5) var(--space-6); align-items: center; justify-content: center; flex-wrap: wrap; }
.cp-terminal-cta .cp-cta-row .cp-cta { margin-top: 0; }
.cp-textlink { font-family: var(--font-mono); font-size: 0.875rem; letter-spacing: 0.06em; color: var(--cyan); text-underline-offset: 0.35em; }
.cp-textlink:hover, .cp-textlink:focus-visible { color: var(--text); }

@media (prefers-reduced-motion: reduce) {
  .cp-scanner::after { animation: none; display: none; }
  .js .cp-scanner.reveal tbody tr { opacity: 1; }
  .js .cp-scanner.reveal.is-visible tbody tr,
  .js .cp-neonsign.reveal.is-visible,
  .js .cp-neonsign.reveal.is-visible .cp-neonsign-line--hot { animation: none; }
  .cp-hero-inner { opacity: 1; }
}

/* ---------- mobile: signs behind content, out of the copy's way ---------- */
@media (max-width: 40em) {
  .cp-scene-signs { z-index: 0; }
  .cp-sign { pointer-events: none; opacity: 0.55; font-size: 1.15rem; }
  .cp-sign--1, .cp-sign--2:not(.cp-sign--low) { display: none; }
  .cp-hero-inner::before { inset: -6% -8%; }
}

/* Readability pools behind copy that sits directly on the city (no panel). */
.cp-terminal-cta::before, .cp-footer::before {
  content: ''; position: absolute; left: 50%; top: 50%; z-index: -1;
  width: min(56rem, 115vw); height: 100%; transform: translate(-50%, -50%);
  background: radial-gradient(closest-side, rgba(6,3,16,0.88), rgba(6,3,16,0.6) 60%, transparent);
  pointer-events: none;
}
.cp-footer { isolation: isolate; }
.cp-terminal-cta { isolation: isolate; }
