/* ============================================================================
   iBadProductions - studio site
   Design system: APERTURE. Everything here is derived from the logo.

   The badge is an RGB-split glitch eye on a black field. So:
     - the page IS that black field; the badge is the one saturated object in it
     - the glitch bars become the rule system (a hairline with offset colour)
     - chromatic aberration becomes the interaction language (text-shadow only)
     - the badge ring becomes the section marker (a thin aperture ring)

   Colours are sampled from the artwork itself, not guessed:
     red #D50A21 / green #04A745 / blue #0441B7
   Measured against the #0B0B0B ground:
     paper 17.75:1  muted 6.71:1  GREEN 6.20:1  RED 3.65:1  BLUE 2.29:1
   So: green may carry text, red is large-text/UI only, blue is DECORATIVE
   ONLY and never carries text. Those limits are respected throughout.

   Mandate held: flat, quiet, engineered. No gradients, no glassmorphism,
   radius <= 4px, no emoji.
   ========================================================================= */

@font-face {
  font-family: 'Inter Tight';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/inter-tight-latin.woff2') format('woff2');
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('/assets/jetbrains-mono-latin.woff2') format('woff2');
}

:root {
  /* ground + type */
  --ink:        #0B0B0B;
  --ink-2:      #111111;
  --ink-3:      #171717;
  --paper:      #F5F3EE;
  --paper-dim:  #EDEAE3;
  --muted:      #9A9693;   /* 6.71:1 - safe for secondary text */
  --line:       #262626;
  --line-2:     #343434;   /* borders only, never text */

  /* the RGB triad, straight off the badge */
  --r: #D50A21;
  --g: #04A745;
  --b: #0441B7;
  --b-lit: #6E9CF5;        /* 7.25:1 - the only blue allowed to carry text */

  --sans: 'Inter Tight', ui-sans-serif, system-ui, -apple-system, sans-serif;
  --mono: 'JetBrains Mono', ui-monospace, 'Cascadia Mono', Consolas, monospace;

  --r-sm: 2px;
  --r-md: 4px;

  --gutter: 32px;
  --container: 1280px;
  --section: 140px;

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-io: cubic-bezier(0.76, 0, 0.24, 1);
}

@media (max-width: 720px) {
  :root { --gutter: 20px; --section: 88px; }
}

*, *::before, *::after { box-sizing: border-box; }

html {
  background: var(--ink);
  color-scheme: dark;
  scrollbar-gutter: stable;   /* kills the classic 100vw horizontal-overflow bug */
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  background: var(--ink);
  color: var(--paper);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.6;
  letter-spacing: -0.011em;
  font-feature-settings: 'ss01', 'cv11';
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

img, svg, picture { max-width: 100%; height: auto; display: block; }

a { color: inherit; text-decoration: none; }

::selection { background: var(--paper); color: var(--ink); }

:focus-visible {
  outline: 2px solid var(--paper);
  outline-offset: 3px;
  border-radius: var(--r-sm);
}
:focus:not(:focus-visible) { outline: none; }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--paper); color: var(--ink);
  padding: 12px 18px; font-family: var(--mono); font-size: 12px;
  letter-spacing: 0.1em; text-transform: uppercase;
}
.skip:focus { left: 0; }

/* ---------------------------------------------------------------- layout - */

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

section { padding-block: var(--section); }
section:first-of-type:not(.hero) { padding-block-start: 0; }

/* ------------------------------------------------------------ typography - */

h1, h2, h3, h4 {
  margin: 0;
  font-weight: 600;
  letter-spacing: -0.032em;
  line-height: 1.06;
  text-wrap: balance;
}

.display {
  font-size: clamp(2.6rem, 6.4vw, 5.4rem);
  letter-spacing: -0.042em;
  line-height: 1.02;
}

h2 { font-size: clamp(2rem, 4.2vw, 3.4rem); }
h3 { font-size: clamp(1.15rem, 1.7vw, 1.5rem); letter-spacing: -0.024em; }

p { margin: 0 0 1.1em; text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

.lede {
  font-size: clamp(1.1rem, 1.65vw, 1.375rem);
  line-height: 1.5;
  color: var(--paper-dim);
  max-width: 62ch;
}

.prose { max-width: 68ch; color: var(--paper-dim); }
.prose strong { color: var(--paper); font-weight: 600; }

.meta {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.145em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0;
}

.muted { color: var(--muted); }

/* ------------------------------------------------- the glitch rule system -
   The logo's offset colour bars, rebuilt as a divider. A hairline, with a
   short red segment kicked one way and a blue one kicked the other - the
   same chromatic split the badge does, at 1px.                              */

.rule {
  position: relative;
  height: 1px;
  background: var(--line);
  border: 0;
  margin: 0;
}
.rule::before,
.rule::after {
  content: '';
  position: absolute;
  height: 1px;
  top: 0;
}
.rule::before { left: 0;   width: 56px;  background: var(--r); transform: translateY(-2px); }
.rule::after  { left: 72px; width: 28px; background: var(--b); transform: translateY(2px); }

/* --------------------------------------------------- section marker (eye) -
   A decimal index plus a thin ring - the badge's outer circle, reduced.     */

.section-head {
  display: flex;
  align-items: baseline;
  gap: 16px;
  margin-bottom: 40px;
}
.section-head .idx {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.145em;
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  gap: 10px;
  flex: none;
}
.section-head .idx::before {
  content: '';
  width: 9px; height: 9px;
  border: 1px solid var(--r);
  border-radius: 50%;
  display: inline-block;
}

/* -------------------------------------------------- chromatic aberration -
   The interaction language. Pure text-shadow: flat, no gradients, and it
   costs nothing. Red kicks left, blue kicks right, exactly like the bars.   */

.split { position: relative; display: inline-block; }
.split::selection { background: var(--paper); color: var(--ink); }

a.split, button.split { transition: text-shadow 180ms var(--ease); }

a.split:hover, a.split:focus-visible,
.split-target:hover .split {
  text-shadow: -0.035em 0 0 var(--r), 0.035em 0 0 var(--b);
}
@media (prefers-reduced-motion: reduce) {
  a.split, button.split { transition: none; }
}

/* underline that grows from the left, editorial rather than decorative */
.ulink {
  position: relative;
  display: inline-block;
  padding-bottom: 2px;
}
.ulink::after {
  content: '';
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 320ms var(--ease);
}
.ulink:hover::after, .ulink:focus-visible::after { transform: scaleX(1); }
@media (prefers-reduced-motion: reduce) {
  .ulink::after { transition: none; }
}

/* -------------------------------------------------------------- masthead - */

.masthead {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--ink);
  border-bottom: 1px solid var(--line);
}
.masthead .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  min-height: 68px;
  padding-block: 10px;
}
.masthead .brand {
  display: flex; align-items: center; gap: 12px;
  font-family: var(--mono); font-size: 12px; font-weight: 500;
  letter-spacing: 0.12em; text-transform: uppercase;
}
.masthead .brand img { width: 30px; height: 30px; }
.masthead nav { display: flex; gap: 26px; align-items: center; }
.masthead nav a {
  font-family: var(--mono); font-size: 11px; font-weight: 500;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted);
  transition: color 180ms var(--ease);
}
.masthead nav a:hover, .masthead nav a:focus-visible { color: var(--paper); }
@media (max-width: 860px) {
  .masthead nav a:not(.nav-cta) { display: none; }
}

.nav-cta {
  color: var(--ink) !important;
  background: var(--paper);
  padding: 8px 15px;
  border-radius: var(--r-sm);
  white-space: nowrap;   /* it was wrapping to two lines and stretching the bar */
}
@media (max-width: 480px) {
  .nav-cta { font-size: 10px; padding: 7px 11px; letter-spacing: 0.1em; }
  .masthead .brand span { font-size: 11px; }
}
.nav-cta:hover, .nav-cta:focus-visible { background: var(--paper-dim); }

/* ------------------------------------------------------------------ hero -
   The badge is not decoration next to a wordmark - the badge IS the
   wordmark, so the oversized type carries the positioning line instead of
   repeating the name.                                                       */

.hero {
  padding-block: clamp(40px, 5vw, 76px) clamp(56px, 7vw, 96px);
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.78fr);
  gap: clamp(32px, 6vw, 88px);
  align-items: center;
}
@media (max-width: 900px) {
  .hero { grid-template-columns: 1fr; gap: 44px; }
  .hero .hero-mark { order: -1; max-width: 300px; }
}

.hero-mark { position: relative; width: 100%; justify-self: end; }
.hero-mark img { width: 100%; }

.hero .display { margin-bottom: 26px; }
.hero .meta { margin-bottom: 22px; }
.hero .lede { margin-bottom: 34px; }

.hero-actions { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; }

.btn {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--mono); font-size: 12px; font-weight: 500;
  letter-spacing: 0.12em; text-transform: uppercase;
  padding: 14px 22px;
  border-radius: var(--r-sm);
  border: 1px solid var(--paper);
  background: var(--paper);
  color: var(--ink);
  cursor: pointer;
  transition: background 200ms var(--ease), color 200ms var(--ease),
              border-color 200ms var(--ease);
}
.btn:hover, .btn:focus-visible { background: transparent; color: var(--paper); }

.btn-ghost {
  background: transparent; color: var(--paper); border-color: var(--line-2);
}
.btn-ghost:hover, .btn-ghost:focus-visible {
  background: transparent; color: var(--paper); border-color: var(--paper);
}
@media (prefers-reduced-motion: reduce) { .btn { transition: none; } }

/* ------------------------------------------------------------ the eye ----
   The mark is an eye, so it looks at you. Two stacked images: the badge with
   the pupil painted out (the iris stripes extended inward to fill the socket),
   and the pupil floating over it. The specular highlights belong to the socket,
   so the pupil slides beneath them exactly as a real eye does.

   At rest the two layers compose back into the untouched artwork - so a visitor
   with no pointer, no JavaScript, or reduced motion simply sees the logo. There
   is no fallback to maintain because the resting state IS the fallback.        */

.eye { position: relative; --px: 0px; --py: 0px; }

.eye-socket { display: block; width: 100%; }

.eye-pupil {
  position: absolute;
  top: 0; left: 0;
  width: 100%;
  pointer-events: none;
  transform: translate3d(var(--px), var(--py), 0);
  will-change: transform;
}

@media (prefers-reduced-motion: reduce) {
  .eye-pupil { transform: none !important; will-change: auto; }
}

/* ------------------------------------------------------- facts hairline - */

.facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.facts div {
  padding: 22px 0;
  border-right: 1px solid var(--line);
  padding-right: 20px;
}
.facts div:last-child { border-right: 0; }
.facts .n {
  font-size: clamp(1.6rem, 2.6vw, 2.2rem);
  font-weight: 600; letter-spacing: -0.03em; line-height: 1;
  margin-bottom: 8px;
}
.facts .k {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--muted);
}

/* -------------------------------------------------------------- services - */

.services { display: grid; gap: 0; border-top: 1px solid var(--line); }

.service {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr) minmax(0, 1.15fr) auto;
  gap: 28px;
  align-items: start;
  padding: 34px 0;
  border-bottom: 1px solid var(--line);
  transition: background 240ms var(--ease);
}
.service:hover { background: var(--ink-2); }
@media (prefers-reduced-motion: reduce) { .service { transition: none; } }

.service .num {
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.12em;
  color: var(--muted); padding-top: 6px;
}
.service h3 { padding-top: 2px; }
.service .desc { color: var(--paper-dim); font-size: 16px; margin: 0; }
.service .deliv {
  margin: 12px 0 0; padding: 0; list-style: none;
  display: flex; flex-wrap: wrap; gap: 6px 8px;
}
.service .deliv li {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--muted);
  border: 1px solid var(--line-2); border-radius: var(--r-sm);
  padding: 4px 8px;
}
.service .price {
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.1em;
  color: var(--muted); white-space: nowrap; padding-top: 6px;
}
@media (max-width: 900px) {
  .service { grid-template-columns: 32px minmax(0, 1fr); gap: 8px 16px; }
  .service .desc, .service .price { grid-column: 2; }
  .service .price { padding-top: 10px; }
}

/* ------------------------------------------------------------------ work - */

.work { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1px;
        background: var(--line); border: 1px solid var(--line); }
.work-item { background: var(--ink); padding: 28px 26px; display: flex;
             flex-direction: column; gap: 12px; transition: background 240ms var(--ease); }
.work-item:hover { background: var(--ink-2); }
@media (prefers-reduced-motion: reduce) { .work-item { transition: none; } }
.work-item .tag {
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--muted);
  flex: none;   /* must not absorb slack, or headings stop aligning across the row */
}
.work-item h3 { font-size: 1.25rem; }
.work-item p { color: var(--paper-dim); font-size: 15.5px; margin: 0; flex: 1; }
.work-item .live {
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.02em;
  color: var(--g);                     /* 6.20:1 - the readable accent */
  display: flex; align-items: baseline; gap: 8px;
  /* hostnames like reliquary.thefracturedarchive.org are longer than the
     column; let them wrap rather than clip at the card edge */
  overflow-wrap: anywhere;
  min-width: 0;
}
.work-item .live::before {
  content: ''; width: 6px; height: 6px; border-radius: 50%;
  background: var(--g); flex: none; transform: translateY(-1px);
}

/* The fifth card would otherwise leave a bare grid cell that reads as a
   broken tile, so the empty slot becomes the call to action instead. */
.work-cta .go { margin-top: auto; }
.work-cta .go {
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--paper);
}

/* --------------------------------------------------------------- process - */

.steps { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 28px; }
.step { border-top: 1px solid var(--line-2); padding-top: 18px; }
.step .n {
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.14em;
  color: var(--r); margin-bottom: 10px;   /* 3.65:1 - short label, not body */
}
.step h3 { font-size: 1.05rem; margin-bottom: 8px; }
.step p { font-size: 15px; color: var(--muted); margin: 0; }

/* ------------------------------------------------------------------ form - */

.contact { display: grid; grid-template-columns: minmax(0, 0.85fr) minmax(0, 1fr);
           gap: clamp(32px, 6vw, 80px); align-items: start; }
@media (max-width: 900px) { .contact { grid-template-columns: 1fr; } }

.field { margin-bottom: 20px; }
.field label {
  display: block; margin-bottom: 8px;
  font-family: var(--mono); font-size: 10.5px; font-weight: 500;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted);
}
.field .req { color: var(--r); }

input[type=text], input[type=email], select, textarea {
  width: 100%;
  background: var(--ink-2);
  border: 1px solid var(--line-2);
  border-radius: var(--r-sm);
  color: var(--paper);
  font: inherit;
  font-size: 16px;          /* 16px stops iOS zooming the page on focus */
  padding: 12px 14px;
  transition: border-color 180ms var(--ease);
}
textarea { min-height: 130px; resize: vertical; line-height: 1.55; }
input:hover, select:hover, textarea:hover { border-color: #454545; }
input:focus, select:focus, textarea:focus { border-color: var(--paper); outline: none; }
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--paper); outline-offset: 2px;
}
/* No gradients anywhere, per the mandate - the caret is a border triangle on
   a wrapper, and a data: URI would be blocked by our own img-src 'self' CSP. */
select { appearance: none; padding-right: 38px; }

.select-wrap { position: relative; display: block; }
.select-wrap::after {
  content: '';
  position: absolute;
  right: 15px; top: 50%;
  width: 0; height: 0;
  margin-top: -2px;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-top: 5px solid var(--muted);
  pointer-events: none;
}
.select-wrap:hover::after { border-top-color: var(--paper); }
::placeholder { color: #6A6764; }

.two-up { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
@media (max-width: 620px) { .two-up { grid-template-columns: 1fr; gap: 0; } }

/* the honeypot - present for bots, gone for humans and screen readers */
.hp {
  position: absolute; left: -9999px; width: 1px; height: 1px;
  overflow: hidden; opacity: 0;
}

.form-note { font-size: 14px; color: var(--muted); margin-top: 14px; }
.form-msg {
  margin-top: 16px; font-size: 15px; min-height: 1.4em;
  font-family: var(--mono); letter-spacing: 0.02em;
}
.form-msg[data-state="err"] { color: #E8737F; }
.form-msg[data-state="ok"]  { color: var(--g); }

/* ---------------------------------------------------------------- footer - */

.footer { border-top: 1px solid var(--line); padding-block: 52px 64px; }
.footer .container { display: flex; justify-content: space-between;
                     gap: 28px; flex-wrap: wrap; align-items: flex-start; }
.footer a { color: var(--muted); }
.footer a:hover, .footer a:focus-visible { color: var(--paper); }
.footer .cols { display: flex; gap: clamp(28px, 6vw, 76px); flex-wrap: wrap; }
.footer .col { display: flex; flex-direction: column; gap: 9px; }
.footer .col .meta { margin-bottom: 4px; }
.footer .col a { font-size: 15px; }
.footer .sig { font-family: var(--mono); font-size: 11px; letter-spacing: 0.1em;
               color: var(--muted); }
.footer .tag-line { font-size: 15px; color: var(--muted); max-width: 34ch; }

/* ------------------------------------------------- spacing utilities -----
   These exist because the CSP has no 'unsafe-inline': a style="" attribute on
   the page is blocked outright, so every offset lives here instead. */
.section-lede { margin-bottom: 38px; }
.contact-alt  { margin-top: 26px; }
.footer-fine  { margin-top: 40px; }
.footer-fine .meta { margin-top: 20px; }
.footer .tag-line { margin-top: 12px; }

/* -------------------------------------------------------- scroll reveal -
   CSS-only, via scroll-driven animations. Wrapped in @supports so that a
   browser without them simply shows the content - no JS, no FOUC, and
   nothing is ever left invisible if the feature is missing.                 */

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .reveal {
      animation: reveal-in linear both;
      animation-timeline: view();
      animation-range: entry 5% cover 26%;
    }
    @keyframes reveal-in {
      from {
        opacity: 0;
        transform: translateY(14px);
        text-shadow: -0.03em 0 0 var(--r), 0.03em 0 0 var(--b);
      }
      to {
        opacity: 1;
        transform: none;
        text-shadow: 0 0 0 transparent, 0 0 0 transparent;
      }
    }
  }
}

/* ------------------------------------------------------------------ print */

@media print {
  .masthead, .hero-actions, form, .footer .cols { display: none; }
  html, body { background: #fff; color: #000; }
}
