/* Charge — First Crack Coffee Roasters.
   Photography speaks, the chrome doesn't.
   White canvas, one gray, pills, flat cards, 8px grid, one red word.
   Shared tokens + components for index.html / beans.html / about.html. */

/* ---------- Fonts: self-hosted woff2 only. No font CDN. ---------- */

@font-face {
  font-family: "Bebas Neue";
  src: url("./assets/fonts/bebas-neue-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("./assets/fonts/inter-variable.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("./assets/fonts/inter-variable.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

/* ---------- Tokens ---------- */

:root {
  /* palette */
  --ink: #111111;
  --canvas: #ffffff;
  --soft-cloud: #f5f5f5;
  --charcoal: #39393b;
  --ash: #4b4b4d;
  --mute: #707072;
  --stone: #9e9ea0;
  --hairline: #cacacb;
  --hairline-soft: #e5e5e5;
  --signal: #d30005;

  /* radius */
  --r-none: 0px;
  --r-md: 24px;
  --r-lg: 30px;
  --r-full: 9999px;

  /* spacing — 8px base unit */
  --s-2: 2px;
  --s-4: 4px;
  --s-8: 8px;
  --s-12: 12px;
  --s-16: 16px;
  --s-24: 24px;
  --s-32: 32px;
  --s-48: 48px;

  /* type */
  --f-campaign: "Bebas Neue", "Arial Narrow", sans-serif;
  --f-chrome: "Inter", system-ui, sans-serif;
  --t-lockup: 96px;
  --lockup-track: -0.005em;
  --t-section: 32px;

  /* layout */
  --rhythm: 48px;
  --gutter: 8px;
  --pad: 32px;
  --nav-h: 64px;
}

@media (max-width: 1023px) {
  :root {
    --t-lockup: 64px;
    --lockup-track: -0.0025em;
    --t-section: 28px;
    --rhythm: 32px;
  }
}

@media (max-width: 960px) {
  :root {
    --nav-h: 56px;
  }
}

@media (max-width: 599px) {
  :root {
    --t-lockup: 48px;
    --lockup-track: 0em;
    --t-section: 26px;
    --rhythm: 24px;
    --gutter: 4px;
    --pad: 24px;
  }
}

@media (min-width: 1920px) {
  :root {
    --pad: 80px;
  }
}

/* ---------- Reset ---------- */

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

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

body {
  margin: 0;
  background: var(--canvas);
  color: var(--ink);
  font-family: var(--f-chrome);
  font-weight: 400;
  font-size: 16px;
  line-height: 1.5;
  letter-spacing: 0;
  -webkit-font-smoothing: antialiased;
}

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

[hidden] {
  display: none !important;
}

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

a {
  color: inherit;
}

h1,
h2,
h3,
p,
figure,
ul,
dl,
dt,
dd {
  margin: 0;
  padding: 0;
}

dd {
  margin-inline-start: 0;
}

ul {
  list-style: none;
}

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

.on-dark :focus-visible,
.tile :focus-visible {
  outline-color: var(--canvas);
}

.skip {
  position: absolute;
  left: -9999px;
}

.skip:focus {
  left: var(--s-8);
  top: var(--s-8);
  z-index: 60;
  background: var(--canvas);
  padding: var(--s-8) var(--s-16);
}

/* ---------- Type roles ---------- */

.lockup {
  font-family: var(--f-campaign);
  font-weight: 400;
  font-size: var(--t-lockup);
  line-height: 0.9;
  letter-spacing: var(--lockup-track);
  text-transform: uppercase;
}

.section-header {
  font-family: var(--f-chrome);
  font-weight: 500;
  font-size: var(--t-section);
  line-height: 1.2;
  letter-spacing: 0;
  color: var(--ink);
}

.body {
  font-size: 16px;
  line-height: 1.5;
  font-weight: 400;
}

.body-strong {
  font-size: 16px;
  line-height: 1.5;
  font-weight: 500;
}

.row-label {
  font-size: 16px;
  line-height: 1.75;
  font-weight: 500;
}

.caption {
  font-size: 14px;
  line-height: 1.5;
  font-weight: 500;
}

.chip-text {
  font-size: 12px;
  line-height: 1.5;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.fine {
  font-size: 12px;
  line-height: 1.3;
  font-weight: 400;
}

.prose {
  font-size: 16px;
  line-height: 1.5;
  color: var(--charcoal);
}

.prose + .prose {
  margin-top: var(--s-16);
}

.prose a {
  color: var(--ink);
  text-decoration: underline;
  transition: color 120ms ease-out;
}

.prose a:hover {
  color: var(--charcoal);
}

.num {
  font-variant-numeric: tabular-nums;
}

.signal {
  color: var(--signal);
}

/* The freshness signal at Caption size — bare text, never a container. */
.signal-caption {
  font-size: 14px;
  line-height: 1.5;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--signal);
  white-space: nowrap;
}

/* ---------- Layout ---------- */

.container {
  max-width: 1440px;
  margin: 0 auto;
  padding-left: var(--pad);
  padding-right: var(--pad);
}

.section {
  margin-top: var(--rhythm);
}

.section__rule {
  border-top: 1px solid var(--hairline);
  padding-top: var(--s-16);
}

.section__lede {
  margin-top: var(--s-16);
  max-width: 62ch;
}

/* ---------- Utility bar ---------- */

.utility {
  height: 36px;
  background: var(--soft-cloud);
  border-radius: var(--r-none);
  display: flex;
  align-items: center;
}

.utility__inner {
  width: 100%;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: var(--s-8);
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
}

/* `.utility__signal` and `.utility__sep--last` are layout hooks only: at ≤599px
   the signal drops onto its own line so it can never be clipped. Colour comes
   from `.signal`. */

/* ---------- Primary nav ---------- */

/* Not sticky. The nav's black pill spends the hero fold's one black; if the nav
   travelled it would put a second black surface into the CTA band's fold. */
.nav {
  background: var(--canvas);
  border-bottom: 1px solid var(--hairline);
  border-radius: var(--r-none);
}

.nav__inner {
  height: var(--nav-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-16);
}

.nav__wordmark {
  font-family: var(--f-campaign);
  font-weight: 400;
  font-size: 20px;
  line-height: 1;
  text-transform: uppercase;
  color: var(--ink);
  text-decoration: none;
}

.nav__links {
  display: flex;
  align-items: center;
  gap: var(--s-24);
}

.nav__link {
  font-size: 16px;
  line-height: 1.5;
  font-weight: 500;
  color: var(--ink);
  text-decoration: none;
  padding-bottom: var(--s-4);
  border-bottom: 2px solid transparent;
  transition: color 120ms ease-out;
}

.nav__link[aria-current="page"] {
  border-bottom-color: var(--ink);
}

.nav__right {
  display: flex;
  align-items: center;
  gap: var(--s-8);
}

/* Scoped so it outranks `.icon-btn { display: inline-flex }` regardless of source
   order — the toggle is desktop-hidden and only the ≤960px rule may reveal it. */
.nav .nav__toggle {
  display: none;
}

/* ---------- Pills ---------- */

.pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  line-height: 1.5;
  font-weight: 500;
  letter-spacing: 0;
  text-decoration: none;
  border-radius: var(--r-lg);
  transition: opacity 120ms ease-out;
}

.pill--primary {
  background: var(--ink);
  color: var(--canvas);
  padding: 16px 32px;
  height: 48px;
}

.pill--secondary {
  background: var(--soft-cloud);
  color: var(--ink);
  padding: 16px 32px;
  height: 48px;
}

.pill--on-image {
  background: var(--canvas);
  color: var(--ink);
  padding: 12px 24px;
}

.pill:active,
.chip:active,
.icon-btn:active {
  transform: scale(0.97);
  opacity: 0.5;
  transition: transform 100ms ease-out, opacity 100ms ease-out;
}

/* ---------- Circular icon button ---------- */

.icon-btn {
  width: 40px;
  height: 40px;
  padding: 4px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--r-full);
  background: var(--soft-cloud);
  color: var(--ink);
  flex: 0 0 auto;
}

.icon-btn svg {
  width: 20px;
  height: 20px;
  display: block;
}

/* ---------- Drawer (≤960px) ---------- */

.drawer {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: none;
}

.drawer[data-open="true"] {
  display: block;
}

.drawer__scrim {
  position: absolute;
  inset: 0;
  background: rgba(17, 17, 17, 0.4);
}

.drawer__panel {
  position: absolute;
  inset: 0 auto 0 0;
  width: min(320px, 84vw);
  height: 100%;
  background: var(--canvas);
  border-right: 1px solid var(--hairline);
  border-radius: var(--r-none);
  display: flex;
  flex-direction: column;
  padding: 0 var(--s-24);
}

.drawer__head {
  height: var(--nav-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1px solid var(--hairline);
}

.drawer__row {
  padding: var(--s-24) 0;
  border-bottom: 1px solid var(--hairline);
  font-size: 16px;
  line-height: 1.5;
  font-weight: 500;
  color: var(--ink);
  text-decoration: none;
  display: block;
}

/* No CTA pill in the drawer: the nav keeps its black `Order beans` pill at every width,
   so a drawer pill would be both a duplicate and a second black in the same fold. */

/* ---------- Campaign tile ---------- */

.tile {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: var(--r-none);
  padding: 0;
  overflow: hidden;
  background: var(--soft-cloud);
}

.tile__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

.tile__lockup {
  position: absolute;
  top: var(--s-32);
  left: var(--s-32);
  max-width: 40%;
  margin: 0;
}

.tile__lockup--lower {
  top: auto;
  bottom: 96px;
}

.tile__lockup--ink {
  color: var(--ink);
}

.tile__lockup--canvas {
  color: var(--canvas);
}

.tile__pill {
  position: absolute;
  left: var(--s-32);
  bottom: var(--s-32);
}

/* CTA band — the one full-bleed ink surface per page */
.tile--ink {
  background: var(--ink);
  aspect-ratio: auto;
  padding: var(--s-48) 0;
}

.tile--ink__inner {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--s-24);
}

.tile--ink .tile__lockup,
.tile--ink .tile__pill {
  position: static;
  max-width: none;
}

.cta__note {
  color: var(--stone);
  max-width: 46ch;
}

.bleed {
  margin-top: var(--rhythm);
}

/* ---------- Product card (origin card) ---------- */

.cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--gutter);
  margin-top: var(--s-16);
}

.card {
  background: var(--canvas);
  border-radius: var(--r-none);
  padding: 0;
  border: 0;
  box-shadow: none;
  display: flex;
  flex-direction: column;
  gap: var(--s-8);
}

.card__img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  background: var(--soft-cloud);
  border-radius: var(--r-none);
}

.card__dots {
  display: flex;
  align-items: center;
  gap: var(--s-8);
}

.dot {
  width: 12px;
  height: 12px;
  border-radius: var(--r-full);
  flex: 0 0 auto;
}

.dot--light {
  background: var(--hairline-soft);
  border: 1px solid var(--hairline);
}

.dot--medium {
  background: var(--mute);
}

.dot--dark {
  background: var(--ink);
}

.dot--selected {
  box-shadow: 0 0 0 2px var(--canvas), 0 0 0 4px var(--ink);
}

.card__name {
  font-size: 16px;
  line-height: 1.5;
  font-weight: 500;
  color: var(--ink);
}

.card__sub {
  font-size: 14px;
  line-height: 1.5;
  font-weight: 500;
  color: var(--mute);
}

/* Card metadata is never right-aligned to the card edge: with an 8px gutter, a
   right-aligned value lands within 8px of the neighbouring card's label and the row of
   cards reads as one continuous table. The freshness note sits immediately after the
   elevation instead, and every value keeps clear of the card's right edge. */
.card__fresh {
  display: flex;
  align-items: baseline;
  gap: var(--s-16);
  flex-wrap: wrap;
}

.card__elev {
  font-size: 16px;
  line-height: 1.5;
  font-weight: 500;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

/* The roast day on a card is stated in --mute, not --signal: three cards in one grid
   would otherwise fire the signal three times in a single fold. The red is spent once
   per fold, below the grid (.grid-signal). */
.card__fresh-note {
  font-size: 14px;
  line-height: 1.5;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--mute);
  white-space: nowrap;
}

.card__specs {
  margin-top: var(--s-8);
}

.spec-row {
  display: grid;
  grid-template-columns: 88px 1fr;
  gap: var(--s-16);
  align-items: baseline;
  padding: var(--s-8) 0;
  border-bottom: 1px solid var(--hairline);
}

.spec-row__label {
  color: var(--mute);
}

/* Tabular figures live on .num, not on every value: Inter's tabular set also swaps the
   hyphen for a wide tabular minus, which turns "Wet-hulled" and "Medium-fine" into
   "Wet - hulled". Only the values that must align down a column carry .num. */
.spec-row__value {
  color: var(--ink);
  text-align: left;
  padding-right: var(--s-16);
}

/* The fold's single red run: stated once, under the origins grid. */
.grid-signal {
  display: flex;
  align-items: baseline;
  gap: var(--s-12);
  flex-wrap: wrap;
  margin-top: var(--s-16);
}

.grid-signal__note {
  color: var(--mute);
}

/* ---------- Disclosure rows ---------- */

.rows {
  margin-top: var(--s-16);
}

.row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-24);
  padding: var(--s-24) 0;
  border-bottom: 1px solid var(--hairline);
}

.row__label {
  font-size: 16px;
  line-height: 1.75;
  font-weight: 500;
  color: var(--ink);
  flex: 0 0 auto;
}

.row__value {
  font-size: 16px;
  line-height: 1.5;
  font-weight: 400;
  color: var(--charcoal);
  text-align: right;
}

.row__value--ink {
  color: var(--ink);
}

/* ---------- FAQ rows ---------- */

.faq {
  margin-top: var(--s-16);
}

.faq__item {
  border-bottom: 1px solid var(--hairline);
}

.faq__q {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-24);
  padding: var(--s-24) 0;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 500;
  color: var(--ink);
}

.faq__q::-webkit-details-marker {
  display: none;
}

.faq__chevron svg {
  transition: transform 120ms ease-out;
}

.faq__item[open] .faq__chevron svg {
  transform: rotate(180deg);
}

.faq__a {
  padding: 0 0 var(--s-24) 0;
  max-width: 62ch;
  color: var(--charcoal);
}

/* ---------- Sub-nav strip (beans) ---------- */

.subnav {
  background: var(--canvas);
  border-radius: var(--r-none);
  box-shadow: inset 0 -1px 0 var(--hairline-soft);
}

.subnav__inner {
  min-height: 64px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-16);
  padding-top: var(--s-8);
  padding-bottom: var(--s-8);
  flex-wrap: wrap;
}

.crumb {
  color: var(--mute);
}

/* ---------- Filter chips ---------- */

.chips {
  display: flex;
  align-items: center;
  gap: var(--s-8);
  flex-wrap: wrap;
}

.chip {
  height: 40px;
  padding: 8px 16px;
  display: inline-flex;
  align-items: center;
  border-radius: var(--r-lg);
  background: var(--canvas);
  border: 1px solid var(--hairline);
  color: var(--ink);
  font-size: 12px;
  line-height: 1.5;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  transition: background-color 120ms ease-out, color 120ms ease-out,
    border-color 120ms ease-out;
}

.chip[aria-pressed="true"] {
  background: var(--ink);
  color: var(--canvas);
  border-color: var(--ink);
}

/* ---------- Two-column split (text + plate) ---------- */

/* The Class B plate is 1:1 at every width — binding it to the text column's height turned it
   into a ~2:1 crop (not a plate the system owns) and shrank the subject inside its gray field.
   The plate keeps its square instead, and the row is built so the square fits: the figure gets
   its own narrow column, the text column is capped at a readable measure, and the two are
   centred against each other on the cross axis. Both columns stay flush to the container edges
   (space-between), so the plate's right edge lines up with the cards grid below it. */
/* Start-aligned, never centered: centering the copy against the taller square plate
   opens an empty band between the section headline and its first line, and the system
   forbids air above a headline. Copy begins on the plate's top edge. */
/* The plate stays a square (Class B is 1:1, never a stretched crop), so its height is
   its width. A 400px track keeps that square close to the height of the copy beside it
   instead of towering 300px past it. */
.split {
  display: grid;
  grid-template-columns: minmax(0, 72ch) minmax(0, 400px);
  justify-content: space-between;
  gap: var(--s-48);
  align-items: start;
  margin-top: var(--s-16);
}

.split__figure {
  position: relative;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  background: var(--soft-cloud);
  border-radius: var(--r-none);
}

.split__plate {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: var(--r-none);
}

.split__body {
  display: flex;
  flex-direction: column;
  gap: var(--s-16);
}

.split__actions {
  display: flex;
  gap: var(--s-8);
  flex-wrap: wrap;
  margin-top: var(--s-8);
}

/* ---------- Roast schedule (about) ---------- */

.schedule__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-24);
  padding: var(--s-24) 0;
  border-bottom: 1px solid var(--hairline);
}

.schedule__days {
  display: flex;
  align-items: baseline;
  gap: var(--s-12);
  flex: 0 0 auto;
}

/* ---------- Footer ---------- */

.footer {
  margin-top: var(--rhythm);
  background: var(--canvas);
  border-top: 1px solid var(--hairline);
  border-radius: var(--r-none);
  padding-top: var(--s-32);
  padding-bottom: var(--s-32);
}

.footer__cols {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--s-24);
}

.footer__head {
  font-size: 16px;
  line-height: 1.5;
  font-weight: 500;
  color: var(--ink);
  margin-bottom: var(--s-8);
}

.footer__list li + li {
  margin-top: var(--s-8);
}

.footer__link {
  font-size: 14px;
  line-height: 1.5;
  font-weight: 500;
  color: var(--mute);
  text-decoration: none;
  transition: color 120ms ease-out;
}

.footer__link:hover {
  color: var(--ink);
}

.footer__item {
  font-size: 14px;
  line-height: 1.5;
  font-weight: 500;
  color: var(--mute);
}

.footer__rule {
  border-top: 1px solid var(--hairline);
  margin-top: var(--s-32);
  padding-top: var(--s-16);
}

.footer__fine {
  color: var(--mute);
}

/* ---------- Responsive ---------- */

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

  .tile__lockup {
    max-width: 52%;
  }

  .tile__lockup--lower {
    bottom: 88px;
  }
}

@media (max-width: 960px) {
  .nav__links {
    display: none;
  }

  .nav .nav__toggle {
    display: inline-flex;
  }

  /* The black pill stays: hiding it left the mobile hero fold with no primary CTA at
     all, only the low-contrast white on-image pill. It only loses horizontal padding. */
  .nav__cta {
    padding: 12px 20px;
  }
}

@media (max-width: 599px) {
  .cards {
    grid-template-columns: 1fr;
  }

  /* Stacked: one column, and the 48px cross-axis gap drops to the mobile rhythm. The plate
     needs no override — it is 1:1 at every width now. */
  .split {
    grid-template-columns: 1fr;
    gap: var(--s-24);
  }

  .footer__cols {
    grid-template-columns: 1fr;
  }

  /* The bar stays one 36px right-aligned line at every width — it is chrome, not content.
     It cannot scroll (an overflow-x strip cut the red signal mid-word with no affordance)
     and it must not wrap, so on mobile it drops the shipping chip instead: the roast day
     and the signal are what the bar is for, and they fit. */
  .utility__ship,
  .utility__sep--ship {
    display: none;
  }

  .utility__inner {
    overflow: visible;
  }

  /* Class A tiles are art-directed to 4:5 on mobile so the subject stays
     centred and the lockup keeps its burn-in zone. */
  .tile:not(.tile--ink) {
    aspect-ratio: 4 / 5;
  }

  .tile__img {
    object-position: var(--focal, center);
  }

  .tile__lockup,
  .tile__pill {
    left: var(--s-24);
  }

  .tile__lockup {
    top: var(--s-24);
    max-width: 72%;
  }

  .tile__lockup--lower {
    top: auto;
    bottom: 84px;
  }

  .tile__pill {
    bottom: var(--s-24);
  }

  .row,
  .schedule__row,
  .faq__q {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--s-8);
  }

  .row__value {
    text-align: left;
  }

  .faq__q {
    flex-direction: row;
    align-items: center;
  }
}

/* Per-tile mobile focal points. The 4:5 crop shows a 45%-wide band of a 16:9 frame, so
   each value is checked against the real photograph: the subject must stay in the band
   AND the lockup's corner must stay tonally clean. */
.tile--hero {
  /* hopper + falling beans in frame; upper-left stays white wall for the ink lockup */
  --focal: 35% center;
}

.tile--process {
  /* The frame sets the black drum face and the trier cascade side by side across the middle,
     so one 4:5 window holds both. At 45% the crop keeps hand, scoop, cascade and tray, and
     the white lockup still sits on flat black (0.057 mean, p95 0.070). From 48% the daylit
     wall starts entering the lockup's last glyphs. */
  --focal: 45% center;
}

.tile--brew {
  /* the frame is right-weighted: panning left lost the dripper entirely and left the
     ink lockup floating on empty wall. 65% keeps the dripper and water column in frame
     while the lower-left stays a clean pale counter. */
  --focal: 65% center;
}

.tile--space {
  /* roaster in frame; upper-left stays dark concrete for the white lockup */
  --focal: 32% center;
}

/* ---------- Reduced motion ---------- */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition: none !important;
    transform: none !important;
    animation: none !important;
  }

  .pill:active,
  .chip:active,
  .icon-btn:active {
    opacity: 0.5;
  }
}
