/* ==========================================================================
   natemoss — build log
   Warm dark, bone type, one amber accent. Numbers are the heroes.
   Static CSS. No framework. Load speed is a conversion lever here.
   ========================================================================== */

:root {
  /* warm charcoal, deliberately not blue-black and not pure black */
  --ink:        #14120E;
  --ink-2:      #1B1814;
  --ink-3:      #241F1A;

  --bone:       #F4EEE3;
  --bone-dim:   #B8AE9E;
  --bone-faint: #7A7166;

  --amber:      #E9A23B;
  --amber-soft: #F0BE72;

  --rule:       #332C24;

  --sans: 'Archivo', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --serif: 'Fraunces', Georgia, 'Times New Roman', serif;
  --mono: ui-monospace, 'SF Mono', SFMono-Regular, Menlo, Consolas, monospace;

  --gut: clamp(1.25rem, 5vw, 3rem);
  --maxw: 1180px;
  --narrow: 668px;
}

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

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

body {
  background: var(--ink);
  color: var(--bone);
  font-family: var(--sans);
  font-size: clamp(1rem, 0.96rem + 0.22vw, 1.125rem);
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

/* --- atmosphere: a whisper of grain so the flat dark has tooth --------- */
.grain {
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  opacity: .28;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
}

/* --- layout ------------------------------------------------------------ */
.wrap { width: 100%; max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gut); }
.narrow { max-width: var(--narrow); }

/* A narrow measure that keeps the page's single left edge, rather than
   re-centring itself in the viewport and making the margin wander. */
.wrap.narrow { max-width: var(--maxw); }
.wrap.narrow > * { max-width: var(--narrow); }

.sec {
  padding-block: clamp(4.5rem, 11vw, 9rem);
  border-top: 1px solid var(--rule);
}

/* --- type -------------------------------------------------------------- */
.mono {
  font-family: var(--mono);
  font-size: .7rem;
  letter-spacing: .13em;
  text-transform: uppercase;
}
.dim { color: var(--bone-faint); }

h2 {
  font-family: var(--serif);
  font-variation-settings: 'SOFT' 0, 'WONK' 1, 'opsz' 90;
  font-weight: 600;
  font-size: clamp(2rem, 1.4rem + 2.6vw, 3.25rem);
  line-height: 1.02;
  letter-spacing: -.02em;
  margin-bottom: 1.6rem;
}

h3 {
  font-family: var(--serif);
  font-variation-settings: 'SOFT' 0, 'WONK' 1, 'opsz' 40;
  font-weight: 600;
  font-size: clamp(1.35rem, 1.1rem + 1.05vw, 1.9rem);
  line-height: 1.14;
  letter-spacing: -.015em;
  margin-bottom: 1.1rem;
}

p + p { margin-top: 1.05em; }
p { max-width: 62ch; }

.big  { font-size: 1.2em; line-height: 1.5; color: var(--bone); }
.sub  { color: var(--bone-dim); margin-top: -.5rem; }
.emph { color: var(--amber-soft); }

.daymark {
  color: var(--amber);
  margin-bottom: 1rem;
  display: flex;
  align-items: center;
  gap: .8rem;
}
.daymark::after {
  content: "";
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, var(--rule), transparent);
  max-width: 190px;
}

/* --- hero -------------------------------------------------------------- */
/* 54px of that top padding is the fixed topbar, which now sits over the hero. */
.hero { padding-top: calc(54px + clamp(2rem, 5vw, 3.6rem)); padding-bottom: clamp(3rem, 7vw, 5.5rem); }

.hero-id { display: flex; gap: 1.4rem; flex-wrap: wrap; margin-bottom: clamp(3rem, 9vw, 6rem); }
.tag { color: var(--bone); }

.hero-h1 { margin: 0; font-weight: 400; }

.bignum {
  display: block;
  font-family: var(--serif);
  font-variation-settings: 'SOFT' 0, 'WONK' 1, 'opsz' 144;
  font-weight: 700;
  font-size: clamp(6.5rem, 21vw, 17rem);
  line-height: .78;
  letter-spacing: -.055em;
  color: var(--amber);
  margin-left: -.06em;      /* optical: pull the 1 back to the margin */
}

.hero-line {
  display: block;
  font-family: var(--serif);
  font-variation-settings: 'SOFT' 0, 'WONK' 0, 'opsz' 80;
  font-weight: 400;
  font-size: clamp(1.55rem, 1rem + 3.05vw, 3.4rem);
  line-height: 1.1;
  letter-spacing: -.022em;
}
.hero-line:first-of-type { margin-top: .42em; }
.hero-line em { font-style: italic; font-variation-settings: 'WONK' 1; color: var(--amber-soft); margin-right: .1em; }

.lede {
  margin-top: 1.9rem;
  max-width: 46ch;
  font-size: clamp(1.02rem, .97rem + .3vw, 1.24rem);
  color: var(--bone-dim);
}

.hero-cta {
  margin-top: 2.4rem;
  display: flex;
  align-items: center;
  gap: 1.6rem 2rem;
  flex-wrap: wrap;
}

.btn {
  display: inline-block;
  font-family: var(--mono);
  font-size: .78rem;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--ink);
  background: var(--amber);
  padding: .95em 1.5em;
  border-radius: 2px;
  text-decoration: none;
  transition: background .18s ease, transform .18s ease;
}
.btn:hover { background: var(--amber-soft); transform: translateY(-1px); }

.link-plain {
  color: var(--bone);
  text-decoration: none;
  border-bottom: 1px solid var(--rule);
  padding-bottom: 2px;
  transition: border-color .18s ease, color .18s ease;
}
.link-plain:hover { color: var(--amber); border-color: var(--amber); }

/* --- images ------------------------------------------------------------ */
.shot-frame {
  background: var(--ink-2);
  border: 1px solid var(--rule);
  border-radius: 4px;
  overflow: hidden;
}
.shot-frame img,
.shot-frame video { display: block; width: 100%; height: auto; }

.hero-shot { margin-top: clamp(3rem, 7vw, 5rem); }
.hero-shot figcaption { margin-top: .9rem; text-transform: none; letter-spacing: .02em; font-size: .74rem; line-height: 1.5; max-width: 60ch; }

.shots {
  margin-top: 3rem;
  display: grid;
  /* min() keeps the track from overflowing viewports narrower than the minimum */
  grid-template-columns: repeat(auto-fit, minmax(min(340px, 100%), 1fr));
  gap: 1.1rem;
}
.shots figcaption { padding: .7rem .9rem; border-top: 1px solid var(--rule); }

.watch { margin-top: 2.4rem; display: flex; gap: 1rem; align-items: baseline; flex-wrap: wrap; }
.watch .mono { text-transform: none; letter-spacing: .02em; }

/* --- decisions --------------------------------------------------------- */
.decisions .wrap.narrow { margin-top: 3.5rem; }

.decision {
  position: relative;
  padding-top: 2.6rem;
  margin-top: 2.6rem;
  border-top: 1px solid var(--rule);
}
.decision:first-child { border-top: 0; margin-top: 0; padding-top: 0; }

.decision .num {
  color: var(--amber);
  margin-bottom: .7rem;
  font-size: .74rem;
}

.decision .outcome {
  margin-top: 1.3rem;
  padding-left: 1.15rem;
  border-left: 2px solid var(--amber);
  color: var(--bone);
}
/* italic terminals crowd the roman letter that follows, so buy back a hair */
.decision .outcome em { color: var(--amber-soft); font-style: italic; margin-right: .09em; }

/* --- method ------------------------------------------------------------ */
.method { background: var(--ink-2); }

blockquote {
  margin-top: 2rem;
  padding: 1.7rem 1.9rem;
  background: var(--ink-3);
  border-left: 3px solid var(--amber);
  border-radius: 2px;
  font-family: var(--serif);
  font-variation-settings: 'SOFT' 20, 'WONK' 1, 'opsz' 40;
  font-size: clamp(1.08rem, 1rem + .5vw, 1.32rem);
  line-height: 1.42;
  letter-spacing: -.008em;
}

/* --- numbers ----------------------------------------------------------- */
.stats {
  margin: 0 0 3rem;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(215px, 1fr));
  gap: 1px;
  /* container stays --ink so a short final row reads as empty space, not as a
     lit cell. The hairlines come from each cell's ring instead. */
  background: var(--ink);
  border: 1px solid var(--rule);
  border-radius: 3px;
  overflow: hidden;
}
.stats > div {
  background: var(--ink);
  box-shadow: 0 0 0 1px var(--rule);
  padding: 1.4rem 1.5rem;
}
.stats dt { color: var(--bone-faint); margin-bottom: .55rem; line-height: 1.4; }
.stats dd {
  font-family: var(--serif);
  font-variation-settings: 'SOFT' 0, 'WONK' 1, 'opsz' 100;
  font-weight: 600;
  font-size: clamp(2.1rem, 1.6rem + 1.5vw, 3rem);
  line-height: .95;
  letter-spacing: -.03em;
  color: var(--amber);
}
.stats dd span {
  font-family: var(--sans);
  font-size: .85rem;
  font-weight: 400;
  letter-spacing: 0;
  color: var(--bone-faint);
  margin-left: .28em;
}

/* --- day job ----------------------------------------------------------- */
.also {
  margin-top: 2rem;
  padding-top: 1.6rem;
  border-top: 1px solid var(--rule);
  color: var(--bone-dim);
}

/* --- footer ------------------------------------------------------------ */
.foot {
  border-top: 1px solid var(--rule);
  padding-block: clamp(3.5rem, 8vw, 6rem);
  background: var(--ink-2);
}
.foot-cta { margin-bottom: 2rem; }
.foot-links { display: flex; gap: 1.6rem; flex-wrap: wrap; margin-bottom: 1rem; }
.foot-links a { color: var(--bone-dim); text-decoration: none; transition: color .18s ease; }
.foot-links a:hover { color: var(--amber); }

/* --- motion ------------------------------------------------------------ */
.reveal {
  opacity: 0;
  transform: translateY(14px);
  animation: rise .82s cubic-bezier(.22,.61,.36,1) forwards;
  animation-delay: var(--d, 0s);
}
@keyframes rise { to { opacity: 1; transform: none; } }

.sec, .decision, .shots figure {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity .7s cubic-bezier(.22,.61,.36,1), transform .7s cubic-bezier(.22,.61,.36,1);
}
.sec.in, .decision.in, .shots figure.in { opacity: 1; transform: none; }

.shots figure:nth-child(2) { transition-delay: .07s; }
.shots figure:nth-child(3) { transition-delay: .14s; }
.shots figure:nth-child(4) { transition-delay: .21s; }
.shots figure:nth-child(5) { transition-delay: .28s; }
.shots figure:nth-child(6) { transition-delay: .35s; }
.shots figure:nth-child(7) { transition-delay: .42s; }
.shots figure:nth-child(8) { transition-delay: .49s; }
.shots figure:nth-child(9) { transition-delay: .56s; }

@media (prefers-reduced-motion: reduce) {
  .reveal, .sec, .decision, .shots figure { opacity: 1; transform: none; }
}

/* --- home hero --------------------------------------------------------- */
/* The case study keeps the enormous 126. The homepage is about the person, so it
   leads with a statement instead and lets the number belong to the project. */
.home-hero { padding-bottom: clamp(3rem, 8vw, 6rem); }

.home-h1 {
  margin: 0;
  font-family: var(--serif);
  font-variation-settings: 'SOFT' 0, 'WONK' 1, 'opsz' 144;
  font-weight: 600;
  font-size: clamp(2.6rem, 1.2rem + 6.4vw, 6.4rem);
  line-height: .98;
  letter-spacing: -.032em;
  margin-top: .5em;
  /* Reserves the line box so an empty heading mid-type cannot collapse and
     shove the lede upward. */
  min-height: 1em;
}

/* Typed headline. The caret sits on the wrapper so it trails the text as it
   grows. It used to keep blinking after the line finished, which read as a
   promise that the heading was going to backspace and say something else. It
   now retires itself once the last character is in. */
.typeline::after {
  content: "";
  display: inline-block;
  width: .085em;
  height: .72em;
  margin-left: .05em;
  vertical-align: -.02em;
  background: var(--bone-faint);
  animation: caret 1.05s steps(1) infinite;
}

/* Set by the typing script on the last character. The delay holds the caret for
   a beat so it does not disappear on the same frame as the final letter. */
.typeline.is-done::after {
  animation: none;
  opacity: 0;
  transition: opacity .45s ease .4s;
}

@keyframes caret {
  0%, 48% { opacity: 1; }
  49%, 97% { opacity: 0; }
  98%, 100% { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .typeline::after { animation: none; opacity: .45; }
}

/* Portrait sits beside the intro rather than above the headline, so the first
   thing read is still the statement. */
.home-intro {
  display: grid;
  grid-template-columns: minmax(0, 1fr) clamp(210px, 24vw, 310px);
  gap: clamp(1.8rem, 5vw, 4rem);
  align-items: end;
}
.portrait { margin: 0; }
.portrait picture { display: block; }

/* A sticker cutout with its own white outline, so it sits straight on the
   charcoal. No frame and no mask: the artwork carries its own edge. */
.portrait img {
  display: block;
  width: 100%;
  height: auto;
}

@media (max-width: 760px) {
  .home-intro { grid-template-columns: 1fr; align-items: start; }
  .portrait { max-width: 210px; margin-top: .6rem; }
}

/* --- project card ------------------------------------------------------ */
.project {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: clamp(1.6rem, 4vw, 3.4rem);
  align-items: center;
  margin-top: 2.6rem;
  padding: clamp(1.1rem, 2.2vw, 1.7rem);
  border: 1px solid var(--rule);
  border-radius: 6px;
  background: var(--ink-2);
  text-decoration: none;
  color: inherit;
  transition: border-color .25s ease, background .25s ease, transform .25s ease;
}
.project:hover {
  border-color: var(--bone-faint);
  background: var(--ink-3);
  transform: translateY(-2px);
}
.project:focus-visible { outline: 2px solid var(--amber); outline-offset: 4px; }

.project-shot {
  border: 1px solid var(--rule);
  border-radius: 4px;
  overflow: hidden;
  background: var(--ink);
}
.project-shot img,
.project-shot video { display: block; width: 100%; height: auto; }

/* The card is a link and the video has no controls, so nothing inside it should
   ever swallow the tap. Belt and braces for iOS. */
.shot-video { pointer-events: none; }

.project-kicker { margin-bottom: .7rem; }

.project-title {
  font-family: var(--serif);
  font-variation-settings: 'SOFT' 0, 'WONK' 1, 'opsz' 96;
  font-weight: 600;
  font-size: clamp(2rem, 1.2rem + 2.4vw, 3.1rem);
  line-height: 1;
  letter-spacing: -.026em;
  margin: 0 0 .6rem;
}

/* The Poppycal app icon in front of the title. Flex rather than an inline image,
   because an inline image aligns to the baseline and the mark needs to centre on
   the letterforms. Sized in em so it tracks the title's clamp down to phone. */
.project-title.with-mark { display: flex; align-items: center; gap: .32em; }
.title-mark { flex: none; width: auto; height: .8em; }

.project-desc { max-width: 44ch; margin-bottom: 1rem; }
.project-meta { margin-bottom: 1.3rem; text-transform: none; letter-spacing: .04em; }
.project-cta { color: var(--amber); }
.project:hover .project-cta { color: var(--amber-soft); }

@media (max-width: 780px) {
  .project { grid-template-columns: 1fr; }
  .project-body { padding-bottom: .4rem; }
}

/* Secondary work. Deliberately smaller than the featured card: Poppycal is a
   shipped product, these two are not, and flattening them would cost Poppycal
   more than it would gain the others. */
.project-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: 1.1rem;
  margin-top: 1.1rem;
}

.project-sm {
  display: flex;
  flex-direction: column;
  padding: clamp(1rem, 2vw, 1.4rem);
  border: 1px solid var(--rule);
  border-radius: 6px;
  background: var(--ink-2);
  text-decoration: none;
  color: inherit;
  transition: border-color .25s ease, background .25s ease, transform .25s ease;
}
.project-sm:hover {
  border-color: var(--bone-faint);
  background: var(--ink-3);
  transform: translateY(-2px);
}
.project-sm:focus-visible { outline: 2px solid var(--amber); outline-offset: 4px; }
.project-sm .project-shot { margin-bottom: 1.2rem; }
.project-sm .project-body { display: flex; flex-direction: column; flex: 1; }
.project-sm .project-desc { margin-bottom: 1.1rem; }
.project-sm .project-cta { margin-top: auto; }

.project-title.sm {
  font-size: clamp(1.35rem, 1.05rem + .8vw, 1.75rem);
  line-height: 1.08;
  margin-bottom: .55rem;
}

/* The cards reveal as whole objects rather than inheriting the section stagger. */
.project, .project-sm { opacity: 0; transform: translateY(18px); }
.project.in, .project-sm.in { opacity: 1; transform: translateY(0); }
.project-grid .project-sm:nth-child(2) { transition-delay: .08s; }
@media (prefers-reduced-motion: reduce) {
  .project, .project-sm { opacity: 1; transform: none; transition: none; }
}

/* A single screenshot at full wrap width, used on the NateOS page. The NateOS UI
   is near-white, so it needs its own frame padding to sit on the charcoal without
   looking like a hole punched in the page. */
.wide-shot {
  margin-top: 2.4rem;
  padding: clamp(.5rem, 1.4vw, 1rem);
  padding-bottom: 0;
}
.wide-shot img { border-radius: 3px; }
.wide-shot figcaption {
  padding: .85rem .2rem .1rem;
  border-top: 0;
  text-transform: none;
  letter-spacing: .02em;
  font-size: .74rem;
  line-height: 1.5;
  max-width: 60ch;
}
.wide-shot {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity .7s cubic-bezier(.22,.61,.36,1), transform .7s cubic-bezier(.22,.61,.36,1);
}
.wide-shot.in { opacity: 1; transform: translateY(0); }
@media (prefers-reduced-motion: reduce) {
  .wide-shot { opacity: 1; transform: none; transition: none; }
}

/* A second branch heading inside one section needs air above it. */
.branch-h2 { margin-top: clamp(3rem, 7vw, 4.6rem); }

/* Breadcrumb back to the homepage from a case study. */
.crumb { text-decoration: none; border-bottom: 1px solid var(--rule); }
.crumb:hover { color: var(--amber); border-bottom-color: var(--amber); }

/* Visible to screen readers only. A link that hijacks the tab should say so;
   sighted users get the same information from the cursor and the new tab itself. */
.vh {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --- utility bar ------------------------------------------------------- */
/* Hidden until the hero leaves the viewport. The research is explicit that a
   single above-fold CTA outperforms a row of links, so this solves findability
   for readers who already scrolled without touching the opening. */
/* Present from the first paint. It used to slide in once the hero CTA left the
   screen; Nate wanted it there on load, which is what people expect from a
   header. The border only appears once the page has scrolled, so it reads as
   part of the hero at the top and as a bar after that. */
.topbar {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 50;
  background: transparent;
  border-bottom: 1px solid transparent;
  transition: background .3s ease, border-color .3s ease,
              backdrop-filter .3s ease;
}
/* What decides when the bar stops being transparent. It used to watch .hero-cta,
   which meant the bar only filled in once the whole hero had gone by: 628px on
   the Poppycal page, most of a screen, with the wordmark sitting over the 126 the
   entire way down. This is an 8px marker at the top of the document instead, so
   the bar fills the moment the page moves at all. It is still transparent when
   you are parked at the very top, which is the part worth keeping.

   8px rather than 1px only so momentum bounce and sub-pixel scroll positions
   cannot make it flicker. At reading speed it is indistinguishable from zero. */
.topbar-sentinel {
  position: absolute;
  top: 0; left: 0;
  width: 1px; height: 8px;
  pointer-events: none;
}

.topbar.in {
  background: rgba(20, 18, 14, .92);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-bottom-color: var(--rule);
}

/* Wordmark. The same letterform as the favicon: Fraunces at its small optical
   size, which keeps the stems from thinning out the way the display cut does. */
.topbar-mark {
  font-family: var(--serif);
  font-variation-settings: 'SOFT' 0, 'WONK' 1, 'opsz' 9;
  font-weight: 900;
  font-size: 1.6rem;
  line-height: 1;
  color: var(--amber);
  text-decoration: none;
  transition: color .18s ease;
}
.topbar-mark:hover { color: var(--amber-soft); }
.topbar-mark:focus-visible { outline: 2px solid var(--amber); outline-offset: 4px; border-radius: 2px; }

.topbar-in {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 var(--gut);
  height: 54px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.topbar-name,
.topbar-links a {
  font-family: var(--mono);
  font-size: .69rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  text-decoration: none;
}
.topbar-name { color: var(--bone); }
.topbar-links { display: flex; gap: clamp(.9rem, 3vw, 1.9rem); align-items: center; }
.topbar-links a { color: var(--bone-dim); transition: color .18s ease; }
.topbar-links a:hover { color: var(--bone); }
.topbar-links .topbar-cta { color: var(--amber); }

@media (max-width: 460px) {
  .topbar-name { display: none; }
  .topbar-in { justify-content: center; }
}

@media (prefers-reduced-motion: reduce) {
  .topbar { transition: none; }
}

/* --- focus ------------------------------------------------------------- */
a:focus-visible {
  outline: 2px solid var(--amber);
  outline-offset: 3px;
  border-radius: 2px;
}

/* --- print ------------------------------------------------------------- */
@media print {
  .grain, .hero-shot, .shots { display: none; }
  body { background: #fff; color: #000; }
}
