/* ============================================================
   Appify — layout and components
   No hex values here. Everything comes from tokens.css.
   ============================================================ */

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--page);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--fs-base);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

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

a { color: inherit; }

:where(a, button, summary, [tabindex]):focus-visible {
  outline: 3px solid var(--signal);
  outline-offset: 3px;
  border-radius: 2px;
}

.skip {
  position: absolute; left: var(--sp-4); top: var(--sp-4);
  transform: translateY(-200%);
  background: var(--signal); color: var(--plum-deep);
  font-family: var(--font-body); font-weight: 600;
  padding: var(--sp-3) var(--sp-5); border-radius: var(--radius-sm);
  z-index: 50; transition: transform .15s ease;
}
.skip:focus { transform: none; }

/* ---------- shared layout ---------- */

.shell { max-width: var(--page-max); margin-inline: auto; padding-inline: var(--gutter); }

.section { padding-block: clamp(var(--sp-9), 9vw, var(--sp-11)); }
.section + .section { border-top: 1px solid var(--rule); }

.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  color: var(--ink-muted);
  margin: 0 0 var(--sp-4);
}

h1, h2, h3 { font-family: var(--font-display); margin: 0; text-wrap: balance; }
h1 { font-weight: 800; font-size: var(--fs-3xl); line-height: var(--lh-tight); letter-spacing: var(--track-tight); }
h2 { font-weight: 600; font-size: var(--fs-2xl); line-height: var(--lh-snug); letter-spacing: var(--track-head); }
h3 { font-weight: 600; font-size: var(--fs-lg); line-height: var(--lh-snug); letter-spacing: var(--track-head); }

p { margin: 0 0 var(--sp-4); max-width: var(--measure); }
p:last-child { margin-bottom: 0; }

.lede { font-size: var(--fs-md); color: var(--ink-muted); }

/* ---------- header ---------- */

.masthead {
  position: relative; z-index: 5;
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-5);
  padding-block: var(--sp-5);
}

.wordmark {
  font-family: var(--font-display); font-weight: 800;
  /* 26px on a phone, 31px on a laptop. Capped at 1.9rem on purpose: rule 05 says
     no mis-registration below ~32px, and the header wordmark is the flat one —
     staying under the threshold keeps that decision unambiguous. */
  font-size: clamp(1.625rem, 1.45rem + 0.55vw, 1.9rem);
  letter-spacing: -0.05em; line-height: 1;
  color: var(--stock); text-decoration: none;
}
.wordmark .dot { color: var(--signal); }

.nav ul { display: flex; gap: clamp(var(--sp-4), 3vw, var(--sp-7)); list-style: none; margin: 0; padding: 0; }
.nav a {
  font-family: var(--font-mono); font-size: var(--fs-xs);
  letter-spacing: var(--track-mono); text-transform: uppercase;
  color: var(--stock-quiet); text-decoration: none;
  padding-block: var(--sp-2);
}
.nav a:hover, .nav a[aria-current="page"] { color: var(--stock); }

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

.hero {
  position: relative;
  overflow: hidden;
  background:
    radial-gradient(72% 92% at 20% 4%,  var(--hero-bloom) 0%, transparent 60%),
    radial-gradient(54% 70% at 92% 98%, var(--hero-pool)  0%, transparent 64%),
    var(--plum);
  color: var(--stock);
}

.hero__inner { position: relative; padding-bottom: clamp(var(--sp-8), 7vw, var(--sp-10)); }

/* The topology is anchored to the SHELL, not the viewport, and its scale comes
   from its own height. Two consequences, both deliberate:

   1. The pane sits at a fixed place on the drawing at every desktop width. Size
      the drawing off the viewport instead and the pane slides across it as the
      window widens — which is how the fan-out ended up behind the glass.
   2. Because scale is height-driven and the viewBox carries 1050 units of
      runway on the left and ~6100 on the right, the entry line always starts
      off the left edge and the exit line always reaches the right edge, up to a
      4K window. No width cap to stop it short.

   left = (pane's left edge) − 1050 units × scale, and scale = --topo-h / 300. */
.hero__topology {
  position: absolute;
  left: calc(var(--gutter) - var(--topo-h) * var(--topo-anchor));
  top: 47%;
  height: var(--topo-h);
  width: calc(var(--topo-h) * 26.6667);   /* the viewBox's own 8000/300 ratio */
  transform: translateY(-50%);
  filter: saturate(1.08) brightness(1.14);
  pointer-events: none;
}
.hero__topology :where(svg, img) { width: 100%; height: 100%; }

.pane {
  position: relative; z-index: 3;
  /* 1.7 × the topology height ≈ 510 drawing units. Tying the pane's width to the
     drawing's scale is what keeps the "everything past unit 1560 is clear"
     contract true on narrower desktops as well. */
  max-width: min(40rem, calc(var(--topo-h) * 1.7));
  margin-top: clamp(var(--sp-6), 5vw, var(--sp-8));
  padding: clamp(var(--sp-6), 4vw, var(--sp-8));
  border-radius: var(--radius-lg);
  background: var(--pane-sheen), var(--pane-shade), var(--pane-bg);
  -webkit-backdrop-filter: blur(var(--pane-blur)) saturate(var(--pane-sat)) brightness(var(--pane-bright));
          backdrop-filter: blur(var(--pane-blur)) saturate(var(--pane-sat)) brightness(var(--pane-bright));
  border: 1px solid var(--pane-border);
  box-shadow: 0 1.5rem 4rem -1.75rem rgba(10, 5, 16, .55),
              inset 0 1px 0 rgba(255, 255, 255, .18),
              inset 0 -1px 0 rgba(27, 21, 34, .05);
  color: var(--plum-deep);
}

/* Contrast on the pane is measured, not assumed: the darkest true background
   pixel inside it is ~RGB 171, so body copy uses plum (6.0:1), not a lighter
   grey. Measure the worst patch, not the average. */
.pane h1 em { font-style: normal; color: var(--relay-ink); }
.pane .lede { color: var(--plum); margin-top: var(--sp-5); }

/* Glass has to be able to disappear. Both fallbacks land on Direction A —
   a solid stock panel — which is why that had to work on its own. */
@supports not ((backdrop-filter: blur(2px)) or (-webkit-backdrop-filter: blur(2px))) {
  .pane { background: var(--pane-sheen), var(--pane-shade), var(--stock); }
}
@media (prefers-reduced-transparency: reduce) {
  .pane {
    background: var(--pane-sheen), var(--pane-shade), var(--stock);
    -webkit-backdrop-filter: none; backdrop-filter: none;
  }
}

.btn {
  display: inline-block;
  margin-top: var(--sp-6);
  background: var(--signal);
  color: var(--plum-deep);
  font-family: var(--font-body); font-weight: 600; font-size: var(--fs-base);
  text-decoration: none;
  padding: var(--sp-3) var(--sp-6);
  border-radius: var(--radius-sm);
  transition: transform .12s ease, filter .12s ease;
}
.btn:hover { filter: brightness(1.06); transform: translateY(-1px); }
@media (prefers-reduced-motion: reduce) { .btn { transition: none; } .btn:hover { transform: none; } }

/* ---------- steps ---------- */

.steps { display: grid; gap: var(--sp-7); grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); margin-top: var(--sp-7); }
.step .k {
  display: block; font-family: var(--font-mono); font-size: var(--fs-xs);
  letter-spacing: var(--track-mono); text-transform: uppercase;
  color: var(--label); margin-bottom: var(--sp-3);
}
.step h3 { margin-bottom: var(--sp-2); }
.step p { color: var(--ink-muted); max-width: 34ch; }

/* ---------- work ---------- */

.cases { display: grid; gap: var(--sp-5); grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr)); margin-top: var(--sp-7); }
.case {
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: var(--sp-6);
  display: flex; flex-direction: column; gap: var(--sp-3);
}
.case .sector {
  font-family: var(--font-mono); font-size: var(--fs-xs);
  letter-spacing: var(--track-mono); text-transform: uppercase; color: var(--label);
}
.case p { color: var(--ink-muted); font-size: var(--fs-sm); max-width: none; }
.case .stack {
  margin-top: auto; padding-top: var(--sp-3);
  font-family: var(--font-mono); font-size: var(--fs-xs);
  letter-spacing: .06em; color: var(--label-quiet);
}

/* ---------- writing ---------- */

.posts { list-style: none; margin: var(--sp-7) 0 0; padding: 0; }
.posts li { border-top: 1px solid var(--rule); }
.posts li:last-child { border-bottom: 1px solid var(--rule); }
.posts a {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2) var(--sp-5);
  padding-block: var(--sp-5); text-decoration: none;
}
.posts a:hover .title { text-decoration: underline; text-underline-offset: 3px; }
.posts .title { font-family: var(--font-display); font-weight: 600; font-size: var(--fs-lg); letter-spacing: var(--track-head); flex: 1 1 20rem; }
.posts .date { font-family: var(--font-mono); font-size: var(--fs-xs); letter-spacing: .06em; color: var(--ink-muted); }

/* ---------- about + contact ---------- */

.about { display: grid; gap: var(--sp-7); grid-template-columns: minmax(0, 1fr); margin-top: var(--sp-6); }
@media (min-width: 52rem) { .about { grid-template-columns: 1.15fr .85fr; gap: var(--sp-9); } }
.facts { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-4); align-content: start; }
.facts li { display: grid; gap: var(--sp-1); }
.facts .k { font-family: var(--font-mono); font-size: var(--fs-xs); letter-spacing: var(--track-mono); text-transform: uppercase; color: var(--ink-muted); }
.facts .v { font-family: var(--font-display); font-weight: 600; font-size: var(--fs-base); }

.contact { background: var(--plum); color: var(--stock); border-radius: var(--radius); padding: clamp(var(--sp-7), 6vw, var(--sp-9)); margin-top: var(--sp-7); }
.contact h2 { color: var(--stock); }
.contact p { color: var(--stock-muted); }
.contact .lines { display: grid; gap: var(--sp-3); margin-top: var(--sp-6); font-family: var(--font-mono); font-size: var(--fs-base); }
.contact .lines a { color: var(--stock); text-decoration-color: var(--relay); text-underline-offset: 4px; }
.contact .lines a:hover { color: var(--signal); }

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

.foot { border-top: 1px solid var(--rule); padding-block: var(--sp-7) var(--sp-9); }
.foot .row { display: flex; flex-wrap: wrap; gap: var(--sp-3) var(--sp-5); justify-content: space-between; align-items: center; }
.foot p { font-family: var(--font-mono); font-size: var(--fs-xs); letter-spacing: .06em; color: var(--ink-muted); margin: 0; max-width: none; }

/* ---------- narrow screens ---------- */

@media (max-width: 46rem) {
  .pane { max-width: none; }
  /* The pane is full width here, so nothing can clear it. Pick the crop
     instead: shift to the aggregate end so the merge node, the alert and the
     line running off the edge are what shows through the glass. */
  .hero__topology { --topo-h: 400px; --topo-anchor: 5.6; top: 46%; }
  .nav ul { gap: var(--sp-4); }
  .nav a { font-size: 0.6875rem; }
}

/* ---------- page head (every page except the home page) ----------
   The same plum ground and the same drawing, cropped somewhere else. Each page
   sets --topo-anchor to a different multiple, so the strip you see on Work is
   not the strip you see on About — the diagram is a fragment of a real system
   and it should look like one. */

.pagehead {
  position: relative;
  overflow: hidden;
  background:
    radial-gradient(72% 92% at 20% 4%,  var(--hero-bloom) 0%, transparent 60%),
    radial-gradient(54% 70% at 92% 98%, var(--hero-pool)  0%, transparent 64%),
    var(--plum);
  color: var(--stock);
}
/* The drawing gets its own band along the BOTTOM of the plum area, not the
   space behind the type. The first attempt centred it like the home hero and
   the exit line — a 3.9-unit stroke in stock — ran straight through the
   headline. There is no crop that avoids that: the centre line spans the whole
   viewBox, so any horizontal offset still puts it at the same height. Moving
   it vertically is the only fix, and being cut off by the section boundary is
   exactly what the diagram is supposed to do. */
.pagehead { --topo-h: clamp(170px, 15vw, 210px); }
.pagehead .hero__topology {
  top: auto; bottom: var(--sp-5);
  transform: none;
  opacity: .75;
  /* Viewport-anchored, not shell-anchored. The home hero has to hold a fixed
     relationship to the glass pane; a page-head strip has nothing on top of it,
     so it should simply bleed edge to edge. The extra term is the shell's own
     left offset, subtracted back out. */
  left: calc(var(--gutter) - var(--topo-h) * var(--topo-anchor) - (100vw - 100%) / 2);
}
.pagehead__inner {
  position: relative;
  padding-bottom: calc(var(--topo-h) + var(--sp-7));
}
.pagehead__body {
  position: relative; z-index: 3;
  max-width: 42rem;
  padding-top: clamp(var(--sp-6), 4vw, var(--sp-8));
}
.pagehead h1 {
  font-weight: 800; font-size: var(--fs-2xl);
  line-height: var(--lh-tight); letter-spacing: var(--track-tight);
  margin-bottom: var(--sp-4);
}
.pagehead .lede { color: var(--stock-muted); }

.eyebrow--on-plum { color: var(--stock-quiet); }

/* One drawing, four crops. The unit sitting at the shell's left edge is
   300 x --topo-anchor, so these are chosen fragments, not random offsets:
   work starts at the fan-out, about at the parse node, contact at the merge,
   and the 404 gets the long dull entry line, which felt right. */
.pagehead--work    { --topo-anchor: 4.35; }   /* the whole story, from the parse node */
.pagehead--about   { --topo-anchor: 5.15; }   /* interpolate, merge, the alert branch */
.pagehead--contact { --topo-anchor: 5.85; }   /* what leaves — the aggregates, running off */
.pagehead--lost    { --topo-anchor: 2.60; }   /* mostly the long dull line in */

/* ---------- "and there's more this way" ---------- */

.more { margin-top: var(--sp-6); }
.more a {
  font-family: var(--font-mono); font-size: var(--fs-xs);
  letter-spacing: var(--track-mono); text-transform: uppercase;
  color: var(--label);
  text-decoration: none;
  border-bottom: 1px solid var(--rule);
  padding-bottom: var(--sp-1);
}
.more a::after { content: " →"; }
.more a:hover { color: var(--ink); border-bottom-color: currentColor; }

/* ---------- long-form case entries (work) ---------- */

.entry { padding-block: clamp(var(--sp-8), 6vw, var(--sp-10)); }
.entry + .entry { border-top: 1px solid var(--rule); }
.entry > .sector {
  font-family: var(--font-mono); font-size: var(--fs-xs);
  letter-spacing: var(--track-mono); text-transform: uppercase;
  color: var(--label); display: block; margin-bottom: var(--sp-3);
}
.entry h2 { margin-bottom: var(--sp-5); }
.entry__grid { display: grid; gap: var(--sp-7); grid-template-columns: minmax(0, 1fr); }
@media (min-width: 56rem) { .entry__grid { grid-template-columns: 1.4fr .6fr; gap: var(--sp-9); } }
.entry h3 {
  font-size: var(--fs-base); font-weight: 600; font-family: var(--font-mono);
  letter-spacing: var(--track-mono); text-transform: uppercase;
  color: var(--label); margin: var(--sp-6) 0 var(--sp-3);
}
.entry h3:first-child { margin-top: 0; }
.entry p { color: var(--ink-muted); }

/* ---------- article (for when there are posts) ---------- */

.article { max-width: var(--measure); }
.article > * { max-width: none; }
.article h2 { font-size: var(--fs-xl); margin: var(--sp-8) 0 var(--sp-4); }
.article h3 { font-size: var(--fs-lg); margin: var(--sp-7) 0 var(--sp-3); }
.article p, .article li { color: var(--ink-muted); }
.article ul, .article ol { padding-left: 1.2rem; margin: 0 0 var(--sp-4); }
.article li { margin-bottom: var(--sp-2); }
.article blockquote {
  margin: var(--sp-6) 0; padding-left: var(--sp-5);
  border-left: 3px solid var(--signal);
}
.article blockquote p { color: var(--ink); }
.article pre {
  background: var(--card); border: 1px solid var(--rule); border-radius: var(--radius-sm);
  padding: var(--sp-5); overflow-x: auto;
  font-family: var(--font-mono); font-size: var(--fs-sm); line-height: 1.55;
}
.article code { font-family: var(--font-mono); font-size: 0.92em; }
.article :not(pre) > code { background: var(--page-2); padding: .1em .35em; border-radius: 2px; }
.article time {
  display: block; font-family: var(--font-mono); font-size: var(--fs-xs);
  letter-spacing: .06em; color: var(--ink-muted); margin-bottom: var(--sp-6);
}

/* ---------- 404 ---------- */

.lost { display: grid; place-items: start; min-height: 58vh; align-content: center; }
.lost .mark { width: 4.5rem; margin-bottom: var(--sp-6); }
.lost h1 { font-size: var(--fs-2xl); font-weight: 800; letter-spacing: var(--track-tight); margin-bottom: var(--sp-4); }
.lost p { color: var(--stock-muted); }
