/* ─── reset + atmosphere ─────────────────────────────────────────────────
   The ground is fully black. Depth comes from a fixed grain plate, a
   vignette, and a hairline registration grid — never from a lighter panel.
   ───────────────────────────────────────────────────────────────────────── */

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

* {
  margin: 0;
  padding: 0;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* The rail's track is deliberately wider than the viewport. `clip` contains
     it without creating a scroll container — `hidden` here would break the
     sticky stage the whole rail depends on. */
  overflow-x: clip;
}

body {
  background: var(--ink);
  color: var(--bone);
  font-family: var(--body);
  font-size: clamp(0.95rem, 1.05vw, 1.06rem);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: clip;
}

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

a {
  color: inherit;
  text-decoration: none;
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: none;
  cursor: pointer;
}

::selection {
  background: var(--lime);
  color: var(--ink);
}

/* ── the grain plate ── fixed so it reads as a property of the screen, not
   of the content scrolling under it. */
.grain {
  position: fixed;
  inset: 0;
  z-index: 900;
  pointer-events: none;
  /* On a pure-black ground an `overlay` blend resolves to black — i.e. no
     grain at all. `screen` at a very low opacity is what actually puts a
     film of light noise over the ink. */
  opacity: 0.055;
  mix-blend-mode: screen;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
}

/* ── vignette ── */
.vignette {
  position: fixed;
  inset: 0;
  z-index: 890;
  pointer-events: none;
  background: radial-gradient(
    ellipse 90% 70% at 50% 45%,
    transparent 40%,
    rgba(0, 0, 0, 0.55) 100%
  );
}

/* ── the registration grid ── four hairlines dividing the page into the same
   columns the section strips use. Porto's chassis, kept very quiet. */
.grid-lines {
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
}

.grid-lines span {
  border-right: var(--rule) solid var(--hair);
}

.grid-lines span:last-child {
  border-right: 0;
}

@media (max-width: 700px) {
  .grid-lines {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* ── shared shell ── */
.shell {
  position: relative;
  z-index: 2;
  padding-inline: var(--gut);
  /* Everything below the card rail is measured content — copy, screenshots,
     a credential. Unboxed, it ran the full width of a 2560px monitor, which
     stretches line lengths and strands the eye in dead space. The gutters sit
     inside the cap, so the reading column is a true 1440. */
  max-width: calc(var(--maxw) + var(--gut) * 2);
  margin-inline: auto;
}

/* The two immersive sections stay full-bleed on purpose: a boxed hero reads
   as a slide, and the rail cap has to line up with a rail that is not boxed. */
.hero.shell,
.rail__cap.shell {
  max-width: none;
  margin-inline: 0;
}

.rule {
  height: var(--rule);
  background: var(--hair);
  border: 0;
}

/* ── the section header ── numbered, Porto-style: index left, label right,
   both in the mono registration voice, separated by a hairline. */
.sec-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding-block: 1.1rem;
  border-top: var(--rule) solid var(--hair-strong);
  color: var(--dim);
}

.sec-head .idx {
  color: var(--bone);
}

section {
  position: relative;
}

/* Skip link — keyboard users land here first. */
.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 1000;
  background: var(--lime);
  color: var(--ink);
  padding: 0.75rem 1rem;
}

.skip:focus {
  left: 0;
}

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