/* ─────────────────────────────────────────────────────────────
   indifferentketchup.com

   Page styles for the personal site. Colors, spacing, motion and
   type all resolve to tokens.css; nothing here hardcodes a value
   that already exists as a custom property.

   Two deliberate departures from ketchup-site-design/DESIGN.md,
   both because this is a marketing page rather than a tool or a
   dashboard:

   1. Corners are square, not 12px rounded. The 12px in the radius
      scale shows up here as a *cut* on the primary action and on
      the images instead. One shape rule, applied everywhere.
   2. The contact section is a full-bleed --brand fill, which
      breaks the Rarity Rule's ~10% ceiling for that one viewport.
      It is the single strongest moment on the page and the only
      place red fills a surface. Everywhere else red is reserved
      for exactly one action, per the rule.

   The site is dark-only on purpose: both brand marks are drawn for
   the dark canvas and lose contrast above --bg-surface (see
   brand/BRAND.md), so there is no light theme to fall back to.
   ───────────────────────────────────────────────────────────── */

:root {
  --shell: 1280px;
  --gutter: clamp(20px, 4vw, 48px);
  --topbar-h: 64px;
  --measure: 68ch;

  /* Section rhythm. Wider than the token scale's --section-y, which
     is tuned for dashboard panels rather than page sections. */
  --band-y: clamp(60px, 8vw, 112px);

  /* The one shape rule: 12px off the top-right and bottom-left. */
  --cut: 12px;
  --notch: polygon(
    0 0,
    calc(100% - var(--cut)) 0,
    100% var(--cut),
    100% 100%,
    var(--cut) 100%,
    0 calc(100% - var(--cut))
  );

  --z-sticky: 100;
  --z-scrim: 190;
  --z-drawer: 200;

  /* --border-strong is 2.67:1 on --bg, which is fine for a divider but
     misses WCAG 2.2 SC 1.4.11 (3:1) for the visible boundary of a
     control. Outline buttons and the nav toggle have nothing but that
     boundary to identify them, so they get a derived value instead:
     4.04:1 on --bg, 3.23:1 on --bg-surface. Derived from the tokens
     rather than hardcoded so it still tracks a palette change. */
  --border-control: color-mix(in srgb, var(--border-strong) 70%, var(--text-muted));
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }

body { margin: 0; overflow-x: hidden; }
img { display: block; max-width: 100%; }
figure { margin: 0; }
:where(h1, h2, h3, h4) { text-wrap: balance; }
:where(p) { text-wrap: pretty; }

a { color: var(--brand); text-decoration: none; }
a:hover { color: var(--brand-hover); }

code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  color: var(--text-muted);
}

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

.skiplink {
  position: absolute;
  left: var(--gutter);
  top: -100px;
  z-index: var(--z-drawer);
  padding: var(--sp-3) var(--sp-4);
  background: var(--brand);
  color: var(--brand-ink);
  font-family: var(--font-display);
  font-weight: 600;
  transition: top var(--t-base) var(--ease-out);
}
.skiplink:focus { top: var(--sp-2); }

/* ══ type roles ══════════════════════════════════════════════ */

/* The line break in the headline is authored, not left to wrapping:
   the second line is the punchline and has to land on its own. Scale
   is capped so the first line still fits on one line at desktop. */
h1 {
  margin: var(--sp-5) 0 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(34px, 4.6vw, 58px);
  line-height: 1.06;
  letter-spacing: -0.032em;
  text-wrap: normal;
}

.section-title,
.band-title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(20px, 2.2vw, 28px);
  line-height: 1.2;
  letter-spacing: -0.02em;
}

h3, h4 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.015em;
}

/* Mono is the label/metadata voice everywhere on this page. */
.kicker,
.meta,
.chips li,
.footer,
.feature-links {
  font-family: var(--font-mono);
}

.kicker {
  margin: 0;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--brand);
}

.meta {
  margin: var(--sp-2) 0 0;
  font-size: 12.5px;
  color: var(--text-faint);
}

.deck {
  margin: var(--sp-4) 0 0;
  max-width: var(--measure);
  color: var(--text-muted);
  font-size: 17px;
}

/* ══ buttons ═════════════════════════════════════════════════ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 0 26px;
  border: 1px solid transparent;
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition:
    background-color var(--t-fast) var(--ease-out),
    border-color var(--t-fast) var(--ease-out),
    color var(--t-fast) var(--ease-out),
    transform var(--t-fast) var(--ease-out);
}
.btn:active { transform: translateY(1px); }

.btn-sm { min-height: 38px; padding: 0 16px; font-size: 13.5px; }

/* Filled buttons carry the cut. Outline buttons stay square so the
   hairline reads as a clean rectangle at small sizes. */
.btn-primary,
.btn-dark { clip-path: var(--notch); }

/* clip-path clips anything drawn outside the border box, which takes
   tokens.css's focus outline with it. Draw the ring inside the shape
   instead so the notch survives and the indicator stays visible.

   The ring is white, not --brand-ink. --brand-ink is the same navy as
   the page canvas, so a navy ring on the red button merges with the
   background behind it and reads as the button shrinking rather than
   as focus. White is 3.57:1 on the red fill and 18.56:1 on the dark
   fill, clearing SC 1.4.11's 3:1 against both. */
.btn-primary:focus-visible,
.btn-dark:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 3px var(--text);
}

/* tokens.css focuses with --info, which is only 1.52:1 on the red
   fill. Inside the contact band the ring switches to the ink color
   instead, at 5.19:1. */
.contact :focus-visible { outline-color: var(--brand-ink); }

.btn-primary { background: var(--brand); color: var(--brand-ink); font-weight: 700; }
.btn-primary:hover { background: var(--brand-hover); color: var(--brand-ink); }

.btn-outline { border-color: var(--border-control); color: var(--text); }
.btn-outline:hover { border-color: var(--brand); color: var(--brand); }

.btn-dark { background: var(--bg); color: var(--text); }
.btn-dark:hover { background: var(--bg-surface); color: var(--text); }

.btn-ghost { border-color: rgb(10 20 30 / 0.45); color: var(--brand-ink); }
.btn-ghost:hover {
  border-color: var(--brand-ink);
  background: rgb(10 20 30 / 0.08);
  color: var(--brand-ink);
}

/* ══ topbar ══════════════════════════════════════════════════ */

.topbar {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  display: flex;
  align-items: center;
  gap: var(--sp-6);
  height: var(--topbar-h);
  padding-inline: var(--gutter);
  border-bottom: 1px solid var(--border);
  background: rgb(10 20 30 / 0.9);
  backdrop-filter: blur(10px);
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--text);
}
.brand:hover { color: var(--text); }
/* Height-driven: the mark is about 1:2, so pinning it to a square box
   would crop the bottle or pad it with dead space. */
.brand img { height: 30px; width: auto; }

.navlinks {
  flex: 1;
  display: flex;
  gap: var(--sp-6);
  font-size: 14.5px;
  color: var(--text-muted);
}
.navlinks a { color: inherit; transition: color var(--t-fast) var(--ease-out); }
.navlinks a:hover,
.navlinks a[aria-current="true"] { color: var(--brand); }

/* Scroll position on a long single page. Driven by the scroll
   timeline, so there is no scroll listener behind it. */
.scrollbar {
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 2px;
  background: var(--brand);
  transform: scaleX(0);
  transform-origin: 0 50%;
}

.navtoggle {
  display: none;
  place-items: center;
  width: 44px;
  height: 44px;
  border: 1px solid var(--border-control);
  background: none;
  color: var(--text);
  cursor: pointer;
}
.navtoggle:hover { border-color: var(--brand); color: var(--brand); }
.navtoggle-bars { position: relative; width: 18px; height: 12px; }
.navtoggle-bars::before,
.navtoggle-bars::after {
  content: "";
  position: absolute;
  left: 0;
  width: 18px;
  height: 2px;
  background: currentColor;
  transition:
    top var(--t-fast) var(--ease-out),
    transform var(--t-fast) var(--ease-out);
}
.navtoggle-bars::before { top: 1px; }
.navtoggle-bars::after { top: 9px; }
.navtoggle[aria-expanded="true"] .navtoggle-bars::before { top: 5px; transform: rotate(45deg); }
.navtoggle[aria-expanded="true"] .navtoggle-bars::after { top: 5px; transform: rotate(-45deg); }

.navscrim { display: none; }

/* ══ hero ════════════════════════════════════════════════════ */

/* Both columns size to their content and group at the left gutter, so
   the mark sits just past the end of the copy instead of being shoved
   to the far edge by a 1fr column. Keeps the h1 on the same left edge
   as every section heading below it. */
.hero {
  display: grid;
  grid-template-columns: minmax(0, max-content) minmax(0, max-content);
  justify-content: start;
  align-items: center;
  gap: clamp(24px, 5vw, 88px);
  max-width: var(--shell);
  margin-inline: auto;
  min-height: min(64dvh, 580px);
  padding-inline: var(--gutter);
}

.hero-type {
  width: min(100%, 760px);
  padding-block: clamp(44px, 6vw, 72px);
}
.hero-copy {
  margin: var(--sp-6) 0 0;
  max-width: 46ch;
  font-size: 18px;
  color: var(--text-muted);
}
.hero-ctas {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  margin-top: var(--sp-8);
}

/* No panel and no divider here. A flat --bg-deep block with a hard
   border read as the mark sitting in a box rather than in the hero.
   What replaces it is a wide, very low-contrast tonal falloff in the
   canvas's own hue: enough to keep the bottle from floating on a dead
   flat field, not enough to draw an edge anywhere. It is a vignette,
   not a glow, so it stays inside the no-glow rule. */
.hero-mark {
  position: relative;
  align-self: stretch;
  display: grid;
  place-items: center;
  padding: var(--sp-6);
  background: radial-gradient(
    62% 48% at 52% 50%,
    color-mix(in srgb, var(--bg-surface) 55%, transparent) 0%,
    transparent 70%
  );
}
/* Sized off height, not width: the mark is roughly 1:2, so height is
   what decides whether it fits the hero without overflowing. Kept near
   the height of the copy block rather than the height of the section,
   so the two read as one group instead of a wall of bottle next to
   some text. */
.hero-mark img {
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: min(46dvh, 420px);
}

/* ══ two-column sections (sticky heading in the left rail) ════ */

.section {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(0, 9fr);
  column-gap: var(--sp-8);
  row-gap: var(--sp-6);
  align-items: start;
  max-width: var(--shell);
  margin-inline: auto;
  padding: var(--band-y) var(--gutter);
  scroll-margin-top: var(--topbar-h);
}
.section > .section-title {
  position: sticky;
  top: calc(var(--topbar-h) + var(--sp-6));
}

/* ══ work ════════════════════════════════════════════════════ */

/* The one deployed project gets the full width of the body rail and
   a legible screenshot. Everything after it is a list. */
.feature {
  margin-top: var(--sp-10);
  padding-top: var(--sp-8);
  border-top: 2px solid var(--brand);
}
.feature-shot {
  display: block;
  clip-path: var(--notch);
  background: var(--bg-inset);
  transition: transform var(--t-base) var(--ease-out);
}
.feature-shot:hover { transform: translateY(-3px); }
.feature-shot img { width: 100%; height: auto; }

.feature-copy { margin-top: var(--sp-6); }
.feature-copy h3 { font-size: clamp(26px, 3vw, 36px); }
.feature-copy h3 a { color: var(--text); }
.feature-copy h3 a:hover { color: var(--brand); }
.feature-lede {
  margin: var(--sp-4) 0 0;
  max-width: var(--measure);
  font-size: 17px;
  color: var(--text-muted);
}
.feature-links {
  display: flex;
  gap: var(--sp-5);
  margin: var(--sp-6) 0 0;
  font-size: 13px;
}
.feature-links a { border-bottom: 1px solid var(--brand-border); padding-bottom: 2px; }

/* The other two deployed sites, two-up under the featured one. A 1 + 2
   arrangement rather than three equal tiles: sortof is the one with a
   public URL, a real user base and the most work in it, and the layout
   should say so. */
.sites {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-8);
  margin-top: var(--sp-10);
}
.site-shot {
  display: block;
  clip-path: var(--notch);
  background: var(--bg-inset);
  transition: transform var(--t-base) var(--ease-out);
}
.site-shot:hover { transform: translateY(-3px); }
.site-shot img { width: 100%; height: auto; }

.site h3 {
  margin-top: var(--sp-5);
  font-size: 21px;
}
.site h3 a { color: var(--text); }
.site h3 a:hover { color: var(--brand); }
.site > p:not(.meta):not(.feature-links) {
  margin: var(--sp-3) 0 0;
  color: var(--text-muted);
  font-size: 15px;
}

.group { margin-top: var(--sp-10); }
.group-title {
  font-size: 15px;
  font-weight: 600;
  color: var(--text-faint);
  padding-bottom: var(--sp-3);
  border-bottom: 1px solid var(--border);
}

.repos {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--sp-8) var(--sp-8);
  margin: var(--sp-6) 0 0;
  padding: 0;
  list-style: none;
}
.repos h4 { font-size: 19px; color: var(--text); }
.repos > li > a { display: inline-block; }
.repos > li > a:hover h4 { color: var(--brand); }
.repos > li > p:not(.meta) {
  margin: var(--sp-2) 0 0;
  color: var(--text-muted);
  font-size: 15px;
}

.more { margin: var(--sp-10) 0 0; }
.more a {
  font-family: var(--font-mono);
  font-size: 13.5px;
  border-bottom: 1px solid var(--brand-border);
  padding-bottom: 2px;
}

/* ══ stack band ══════════════════════════════════════════════ */

.band {
  background: var(--bg-surface);
  border-block: 1px solid var(--border);
  padding-block: var(--band-y);
  scroll-margin-top: var(--topbar-h);
}

.stackgrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: var(--sp-8);
  margin-top: var(--sp-10);
}
.stackgrid h3 {
  font-size: 15px;
  color: var(--text);
  padding-bottom: var(--sp-3);
  border-bottom: 1px solid var(--border-strong);
}

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin: var(--sp-4) 0 0;
  padding: 0;
  list-style: none;
}
.chips li {
  padding: 5px 10px;
  border: 1px solid var(--border-strong);
  font-size: 13px;
  color: var(--text-muted);
}

/* ══ background ══════════════════════════════════════════════ */

.lede {
  margin: 0;
  max-width: 26ch;
  font-family: var(--font-display);
  font-size: clamp(23px, 3vw, 36px);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.025em;
}
.section-body > p:not(.lede):not(.deck):not(.more) {
  margin: var(--sp-6) 0 0;
  max-width: var(--measure);
  color: var(--text-muted);
}

.facts { margin: var(--sp-10) 0 0; }
.facts > div {
  display: grid;
  grid-template-columns: minmax(150px, 2fr) 7fr;
  gap: var(--sp-6);
  padding: var(--sp-4) 0;
  border-top: 1px solid var(--border);
}
.facts > div:last-child { border-bottom: 1px solid var(--border); }
.facts dt { font-family: var(--font-mono); font-size: 13px; color: var(--text); }
.facts dd { margin: 0; max-width: var(--measure); color: var(--text-muted); }

/* ══ off the clock ═══════════════════════════════════════════ */

.offclock {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: clamp(32px, 5vw, 80px);
  align-items: center;
  max-width: var(--shell);
  margin-inline: auto;
  padding: var(--band-y) var(--gutter);
  scroll-margin-top: var(--topbar-h);
}
.offclock-photo {
  position: relative;
  clip-path: var(--notch);
  background: var(--bg-inset);
}
.offclock-photo img { width: 100%; height: auto; }

/* The lead item outranks its siblings but stays under the section
   heading, so the ladder reads h2 > lead h3 > sibling h3. */
.offclock-lead { margin-top: var(--sp-8); }
.offclock-lead h3 { font-size: clamp(19px, 1.9vw, 23px); }
.offclock-item {
  margin-top: var(--sp-6);
  padding-top: var(--sp-6);
  border-top: 1px solid var(--border);
}
.offclock-item h3 { font-size: 17px; }
.offclock-copy p {
  margin: var(--sp-3) 0 0;
  max-width: var(--measure);
  color: var(--text-muted);
}

/* ══ contact ═════════════════════════════════════════════════ */

.contact {
  background: var(--brand);
  color: var(--brand-ink);
  padding-block: var(--band-y);
  scroll-margin-top: var(--topbar-h);
}
.contact-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(38px, 7vw, 84px);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.04em;
}
/* Full-strength ink, not a softened alpha: --brand-ink at less than
   100% opacity drops below 4.5:1 against the red fill. */
.contact-copy {
  margin: var(--sp-6) 0 0;
  max-width: 52ch;
  font-size: 18px;
  color: var(--brand-ink);
}
.contact-ctas {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  margin-top: var(--sp-8);
}

/* ══ footer ══════════════════════════════════════════════════ */

.footer {
  border-top: 1px solid var(--border);
  padding-block: var(--sp-6);
  font-size: 13px;
  color: var(--text-faint);
}
.footer-inner {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-4);
  align-items: center;
  justify-content: space-between;
}
.footer p { margin: 0; }

.org-credit {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  color: var(--org-mark);
}
.org-credit img { width: 18px; height: 18px; opacity: 0.9; }
.org-credit:hover { color: var(--org-mark-hover); text-decoration: underline; }

/* ══ motion ══════════════════════════════════════════════════
   Scroll-driven only. Reveals establish the reading order down a
   long single page; the topbar rule reports position within it.
   Both are progressive enhancement: without scroll timelines the
   page renders complete and static.                              */

@keyframes rise {
  from { opacity: 0; transform: translateY(22px); }
  to   { opacity: 1; transform: none; }
}
@keyframes draw {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .feature,
    .group,
    .more,
    .stackgrid > *,
    .facts > div,
    .offclock-photo,
    .offclock-lead,
    .offclock-item {
      animation: rise linear both;
      animation-timeline: view();
      animation-range: entry 8% cover 26%;
    }
  }
}

@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .scrollbar {
      animation: draw linear both;
      animation-timeline: scroll(root);
    }
  }
}

/* ══ responsive ══════════════════════════════════════════════ */

@media (max-width: 1080px) {
  .section {
    grid-template-columns: 1fr;
    row-gap: var(--sp-6);
  }
  .section > .section-title { position: static; }

  .sites { grid-template-columns: 1fr; gap: var(--sp-10); }
  .offclock { grid-template-columns: 1fr; }
  .offclock-photo { max-width: min(100%, 460px); }
  .offclock-lead { margin-top: 0; }
}

@media (max-width: 900px) {
  .topbar { gap: var(--sp-3); }
  .topbar-cta { display: none; }
  .navtoggle { display: grid; margin-left: auto; }

  .navlinks {
    position: fixed;
    top: var(--topbar-h);
    left: 0;
    right: 0;
    z-index: var(--z-drawer);
    flex: none;
    flex-direction: column;
    gap: 0;
    background: var(--bg);
    border-bottom: 1px solid var(--border);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transform: translateY(-8px);
    transition:
      opacity var(--t-base) var(--ease-out),
      transform var(--t-base) var(--ease-out),
      visibility 0s linear var(--t-base);
  }
  .navlinks a {
    display: flex;
    align-items: center;
    min-height: 52px;
    padding-inline: var(--gutter);
    border-bottom: 1px solid var(--border);
  }
  .navscrim {
    position: fixed;
    inset: var(--topbar-h) 0 0;
    z-index: var(--z-scrim);
    width: 100%;
    border: 0;
    background: rgb(5 14 23 / 0.72);
    cursor: pointer;
  }
  body.nav-open .navlinks {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: none;
    transition-delay: 0s;
  }
  body.nav-open .navscrim { display: block; }

  .hero {
    grid-template-columns: 1fr;
    min-height: 0;
    padding-left: 0;
  }
  .hero-type { padding: clamp(40px, 9vw, 64px) var(--gutter); }
  /* No divider here either. Stacked, the mark just sits above the
     type on the same canvas. */
  .hero-mark {
    order: -1;
    padding-block: var(--sp-6);
  }
  .hero-mark img { width: min(52vw, 240px); max-height: none; }

  .facts > div { grid-template-columns: 1fr; gap: var(--sp-2); }
}

@media (max-width: 560px) {
  .btn { width: 100%; }
  .hero-ctas,
  .contact-ctas { flex-direction: column; align-items: stretch; }
}

@media (prefers-reduced-motion: reduce) {
  .btn:active { transform: none; }
  .feature-shot:hover { transform: none; }
  .navlinks { transform: none !important; }
  .scrollbar { display: none; }
}
