/* ==========================================================================
   Components — header, nav, clock, footer, cards, buttons
   ========================================================================== */

/* ---------- Header ------------------------------------------------------ */

.header {
  position: sticky;
  top: 0;
  z-index: var(--z-nav);
  background-color: var(--color-bg);
  border-bottom: 1px solid var(--color-border);
}

/* mobile: wordmark left, menu button right.
   desktop: three tracks so the nav is optically centred in the viewport
   regardless of how wide the wordmark or clock are. */
.header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  min-height: var(--header-h-mobile);
}

@media (min-width: 768px) {
  .header__inner {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    min-height: var(--header-h);
  }

  .header__inner > .clock {
    justify-self: end;
  }
}

/* wordmark.
   inline-flex + align-items:center makes the anchor a flex box, so the text is
   centred by box metrics rather than by Inter's line-height, which would let
   the uppercase glyphs ride high against the nav and clock. */
.wordmark {
  display: inline-flex;
  align-items: center;
  color: var(--color-accent);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  line-height: 1;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  white-space: nowrap;
}

.wordmark:hover {
  color: var(--color-accent-hover);
}

/* ---------- Nav --------------------------------------------------------- */

.nav {
  display: none;
}

@media (min-width: 768px) {
  .nav {
    display: flex;
    align-items: center;
    gap: var(--space-5);
  }
}

.nav__link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) 0;
  font-size: var(--text-base);
  line-height: 1;
  color: var(--color-text);
}

.nav__link:hover,
.nav__link:focus-visible {
  color: var(--color-accent);
}

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

/* Nav star — a text character, not an icon, so it takes the nav's colour and
   sits on the same baseline as the label.
   One glyph, U+2738, in two treatments: filled for the current page, outlined
   via -webkit-text-stroke for hover.
   The character comes from CSS rather than the markup so the two states can
   swap it. The span is empty in the HTML, which also keeps the header
   byte-identical across pages — the sole per-page difference stays
   aria-current. */
/* Fixed-width box, centred glyph. The filled star is 16px and the outlined one
   12px, so without this the two states take different widths and every nav
   label shifts when you navigate between pages — the nav is centre-aligned, so
   one star changing size moves all three items. Reserving the wider star's
   width means the box never changes and only the glyph inside it does. */
.nav__star {
  display: inline-block;
  width: var(--text-base);
  font-size: var(--text-base);
  line-height: 1;
  text-align: center;
  color: var(--color-accent);
  flex-shrink: 0;
}

.nav__star::before {
  content: "\2738";
}

/* One full turn. Used on the active page's star, which is already visible and
   so has nothing to fade in — the spin is its whole hover response. */
@keyframes nav-star-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

/* Star states, shared by the desktop nav and the mobile menu:
     idle          hidden
     hover         outlined star at 12px, turns into place
     current page  filled star at 16px, always visible; spins once on hover

   No media query needed — .nav is hidden below 768px and .mobile-menu above it,
   so only one of these is ever on screen.
   The star's box is always in the layout at a fixed width, so labels sit
   shifted right at rest and nothing moves — not when hovering, and not when
   navigating between pages. */
.nav__link .nav__star,
.mobile-menu__link .nav__star {
  opacity: 0;
  transform: rotate(-90deg);
  transition:
    opacity var(--duration-base) var(--ease-soft),
    transform var(--duration-base) var(--ease-soft);
}

/* Outlined hover star: the same ✸ glyph hollowed out with text-stroke.
   text-stroke is centred on the glyph edge — CSS has no inside-only stroke for
   text — so a 1px stroke pushes 0.5px past the outline on every side and the
   star grows. Setting it at --text-xs pulls the outer edges back inside the
   filled 16px star's footprint.
   @supports guards it: a browser without text-stroke would paint a transparent,
   invisible star, so it falls back to the filled version. */
@supports (-webkit-text-stroke: 1px currentColor) {
  .nav__link:not([aria-current="page"]) .nav__star,
  .mobile-menu__link:not([aria-current="page"]) .nav__star {
    font-size: var(--text-xs);
    color: transparent;
    -webkit-text-stroke: 1px var(--color-accent);
  }
}

.nav__link:hover .nav__star,
.nav__link:focus-visible .nav__star,
.mobile-menu__link:hover .nav__star,
.mobile-menu__link:focus-visible .nav__star {
  opacity: 1;
  transform: rotate(0deg);
}

.nav__link[aria-current="page"] .nav__star,
.mobile-menu__link[aria-current="page"] .nav__star {
  opacity: 1;
  transform: rotate(0deg);
}

.nav__link[aria-current="page"]:hover .nav__star,
.nav__link[aria-current="page"]:focus-visible .nav__star,
.mobile-menu__link[aria-current="page"]:hover .nav__star,
.mobile-menu__link[aria-current="page"]:focus-visible .nav__star {
  animation: nav-star-spin var(--duration-slow) var(--ease-in-out);
}

/* ---------- Clock ------------------------------------------------------- */

.clock {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-sm);
  line-height: 1;
  color: var(--color-text);
  /* fixed-width digits so the layout doesn't jitter each second */
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.clock__icon {
  width: var(--icon-14);
  height: var(--icon-14);
  flex-shrink: 0;
}

/* hidden until JS fills it, so no empty/incorrect time flashes */
.clock:not(.is-ready) {
  visibility: hidden;
}

/* Reserve width so the header doesn't reflow as the digits change.
   8.5ch fits "11:52:08 AM" in Inter's tabular figures. */
.clock__time {
  min-width: 8.5ch;
}

/* ---------- Mobile menu ------------------------------------------------- */

.nav-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* 44px tap target */
  width: 44px;
  height: 44px;
  margin-right: var(--inset-icon-row);
  color: var(--color-text);
}

.nav-toggle .icon {
  width: var(--icon-20);
  height: var(--icon-20);
}

.nav-toggle:hover {
  color: var(--color-accent);
}

@media (min-width: 768px) {
  .nav-toggle {
    display: none;
  }
}

/* swap the icon shown inside the toggle based on state */
.nav-toggle__close,
.nav-toggle[aria-expanded="true"] .nav-toggle__open {
  display: none;
}

.nav-toggle[aria-expanded="true"] .nav-toggle__close {
  display: block;
}

.mobile-menu {
  position: fixed;
  inset: var(--header-h-mobile) 0 auto 0;
  z-index: var(--z-menu);
  display: flex;
  flex-direction: column;
  /* no block padding or gap — each link's 44px min-height sets the rhythm, so
     the panel ends flush with the last item instead of trailing whitespace */
  padding: 0 var(--gutter);
  background-color: var(--color-bg);
  border-bottom: 1px solid var(--color-border);
  box-shadow: var(--shadow-md);
}

.mobile-menu[hidden] {
  display: none;
}

/* min-height rather than padding for the 44px tap target, so the row height is
   stated directly instead of implied by a value that has to be re-derived if
   the font size changes */
.mobile-menu__link {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 44px;
  font-size: var(--text-base);
  line-height: 1;
}

.mobile-menu__link:hover,
.mobile-menu__link[aria-current="page"] {
  color: var(--color-accent);
}

@media (min-width: 768px) {
  .mobile-menu {
    display: none;
  }
}

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

.footer {
  background-color: var(--color-accent);
  color: var(--color-on-accent);
  padding-block: var(--space-8);
}

.footer__inner {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-6);
  justify-items: center;
  text-align: center;
}

/* three-up row: message left, coffee centered, social right */
@media (min-width: 768px) {
  .footer__inner {
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: var(--space-5);
    text-align: left;
  }

  .footer__message {
    justify-self: start;
  }

  .footer__social {
    justify-self: end;
  }
}

.footer__message {
  font-size: var(--text-base);
  max-width: 32ch;
}

/* coffee — placeholder for the click-to-brew interaction */
.footer__brew {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  color: var(--color-on-accent);
}

.footer__brew-icon {
  width: var(--icon-20);
  height: var(--icon-20);
}

.footer__brew-label {
  font-size: var(--text-xs);
  line-height: 1;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
}

.footer__social {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  /* offset the links' own padding so the outer glyphs align optically with
     the container edge */
  margin-inline: var(--inset-icon-row);
}

/* Hit area is the 20px glyph plus 8px padding = 36px, so the hover reads as
   touching the icon rather than a wide invisible box. Slightly under the 44px
   touch guideline; acceptable for secondary links with space around them. */
.footer__social-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-2);
  color: var(--color-on-accent);
  transition: transform var(--duration-base) var(--ease-soft);
}

.footer__social-link .icon {
  width: var(--icon-20);
  height: var(--icon-20);
}

/* lift on hover — no background plate */
.footer__social-link:hover,
.footer__social-link:focus-visible {
  transform: translateY(-4px);
}

/* ---------- Hero -------------------------------------------------------- */

/* Centred column: coffee mark, then the one-sentence intro. The title's own
   max-width does the measure capping — see .hero__title. */
.hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-6);
  text-align: center;
}

.hero__mark {
  width: var(--hero-mark);
  height: var(--hero-mark);
  border-radius: var(--radius-md);
  background-color: var(--color-surface-subtle);
}

/* 40ch lands the sentence on two lines at desktop. ch units mean the measure
   is tied to the font size, so the break holds as --text-4xl scales. */
.hero__title {
  max-width: 40ch;
  font-size: var(--text-4xl);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-snug);
}

/* ---------- Case study -------------------------------------------------- */

/* Sticky under the sticky site header — --below-header is where content clears
   it. */
@media (min-width: 768px) {
  .case-nav {
    position: sticky;
    top: var(--below-header);
  }
}

.case-nav__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.case-nav__link {
  display: block;
  padding-block: var(--space-1);
  font-size: var(--text-base);
  color: var(--color-text-muted);
}

.case-nav__link:hover,
.case-nav__link:focus-visible {
  color: var(--color-accent);
}

/* Current section. aria-current is set by js/case-nav.js, so the styling is
   keyed off the same attribute a screen reader reads — one source of truth.
   Colour is paired with weight so the state survives a colour-blind read and
   isn't signalled by hue alone. */
.case-nav__link[aria-current="true"] {
  color: var(--color-text);
  font-weight: var(--weight-medium);
}

/* Two levels of spacing, two elements. .case__body separates groups — the header
   block from each section, and sections from each other — so its gap is the
   page's --section-y, the same break as the one under the site header.
   .case__header handles the tight spacing inside the intro group. Keeping the
   two on separate elements is what avoids subtracting one from the other. */
.case__body {
  display: flex;
  flex-direction: column;
  gap: var(--section-y);
}

.case__header {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

/* 16/9 until that would make the image taller than --case-hero-max-h, then the
   height caps and the ratio gives way — the intro and meta rows below stay
   visible rather than being pushed off screen on a wide window.
   Once capped the box is wider than 16/9, so a real <img> inside it needs
   object-fit: cover to fill without distorting. */
.case__hero {
  border-radius: var(--radius-lg);
  background-color: var(--color-surface-subtle);
  aspect-ratio: 16 / 9;
  max-height: var(--case-hero-max-h);
  overflow: hidden;
}

.case__hero img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Title left, one-line summary right, baselines aligned — and the summary drops
   to its own line when the pair no longer fits.
   No breakpoint: flex-wrap decides from the actual text width, which is the
   only thing that matters here. A fixed breakpoint has to guess, and the guess
   is wrong at some window widths — the sentence needs ~435px on one line while
   the body column is only ~432px at 768px, so where it stops fitting depends on
   the copy, not on a round number. */
.case__intro {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2) var(--space-6);
}

.case__title {
  font-size: var(--text-3xl);
  /* takes the leftover width and wraps to two lines if it must. A heading on
     two lines is fine; the summary is the thing that has to stay on one. */
  flex: 1 1 auto;
  min-width: 0;
}

.case__summary {
  color: var(--color-text);
  /* flex-shrink: 0 is the whole fix. The box is sized to the text's one-line
     width and is never squeezed below it, so it can't break mid-sentence — when
     there isn't room beside the title, flex-wrap moves it down whole instead.
     Every earlier attempt let it shrink and then argued about how much. */
  flex: 0 0 auto;
  /* but never wider than the line it's on. flex-shrink: 0 alone would refuse to
     shrink even once wrapped onto its own line, and at 320px the sentence wants
     ~435px against ~288px available — it would overflow the viewport. This caps
     it at the container, so it holds one line whenever one line fits and wraps
     normally on narrow screens. */
  max-width: 100%;
  /* text-wrap: pretty, set on every p in base.css, pulls a word down early to
     avoid a short last line. Once this is wrapping on a narrow screen that
     would break it earlier than necessary. */
  text-wrap: auto;
}

/* Four meta pairs across. auto-fit means they wrap to two-up then one-up on
   narrow screens without a breakpoint of their own. */
.case__meta {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: var(--space-5);
  margin: 0;
}

.case__meta-item {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.case__meta-label {
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-text-muted);
}

.case__meta-value {
  margin: 0;
  font-size: var(--text-base);
}

.case__section-title {
  font-size: var(--text-xl);
  margin-bottom: var(--space-2);
}

/* ---------- See next ---------------------------------------------------- */

.case-more__title {
  font-size: var(--text-xl);
  text-align: center;
  margin-bottom: var(--space-7);
}

/* Two cards, centred, each capped so a pair doesn't stretch across the full
   1728px container the way a three-up row does. */
.case-more__grid {
  justify-content: center;
}

@media (min-width: 768px) {
  .case-more__grid {
    grid-template-columns: repeat(2, minmax(0, 22rem));
  }
}

/* ---------- Coming soon ------------------------------------------------- */

/* Standalone holding page — the only page with no header or footer, so it
   centres in the viewport rather than sitting in the normal page flow.
   min-height uses svh, not vh: on mobile Safari vh measures the viewport with
   the browser UI hidden, which would push the block below the fold. */
.coming {
  display: flex;
  align-items: center;
  min-height: 100svh;
  padding-block: var(--section-y);
}

/* Everything centred, same as the home page hero. text-align centres the lines
   inside the title; align-items centres the children, each of which is only as
   wide as its content.
   No fit-content or margin-inline: auto here — those existed to centre a
   left-aligned block, where the column had to shrink to its text before it could
   be centred. Centred text centres itself inside a full-width box. */
.coming__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-5);
  text-align: center;
}

/* mark, statement and note are one tight group; the social row is separate,
   which is why the gap above it is a step wider */
.coming__statement {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-5);
}

/* The same ✸ (U+2738) as the nav star, at display size. A text character
   rather than an icon, so it inherits the accent colour and needs no sprite
   entry — see .nav__star for the original.
   aria-hidden on the span in the markup keeps it out of the accessibility tree;
   CSS content is ignored by screen readers anyway, but stating it is clearer. */
/* inline-block so rotate has a box to turn — an inline element ignores it.
   js/star.js sets the rotate angle from the cursor position; the transition
   smooths the gap between frames rather than snapping.
   rotate, not transform: a separate property, so nothing here can be clobbered
   by a transform set elsewhere. */
.coming__mark {
  display: inline-block;
  font-size: var(--text-3xl);
  line-height: 1;
  color: var(--color-accent);
  transition: rotate var(--duration-base) var(--ease-soft);
}

.coming__mark::before {
  content: "\2738";
}

/* Size, weight and tracking match .hero__title on the home page — same voice,
   same sentence shape. The measure is narrower (34ch vs 40ch) only because this
   sentence is shorter and 40ch would leave it on one long line.
   ch is tied to the font size, so the break survives --text-4xl scaling.
   A plain ch cap is all that's needed now the text is centred: leftover space in
   the box splits evenly on both sides instead of pooling on the right, so the
   box no longer has to hug the text exactly. The earlier max-content sizing and
   the <br> in the markup existed only to make a left-aligned block centrable.
   34ch holds the sentence to two lines at desktop; text-wrap: balance, on every
   heading in base.css, evens their lengths. */
.coming__title {
  max-width: 34ch;
  font-size: var(--text-4xl);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-snug);
}

/* Inter's real italic cut, not a synthetic slant — coming-soon.html loads the
   ital axis for exactly this. The true italic has designed sidebearings, so the
   last letter of a phrase doesn't lean into the following word the way a sheared
   upright does.
   No colour or weight change: the slant alone marks the phrases, which keeps the
   accent reserved for the mark and the links. */
.coming__title em {
  font-style: italic;
}

.coming__note {
  font-size: var(--text-base);
  color: var(--color-text);
}

/* margin-top, not margin-left, unlike the footer's row: the links carry
   --space-2 of padding for their hit area, and vertically that padding sits
   inside the gap above them — so the flex gap and the sentence above it read
   further apart than the same gap does between two text elements. Pulling the
   row up by the padding makes the visible gap match the one above the sentence.
   No horizontal inset: that one aligns a glyph to left-aligned text, and the
   row is centred here. */
.coming__social {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  margin-top: var(--inset-icon-row);
}

.coming__social-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-2);
  color: var(--color-text);
  transition: transform var(--duration-base) var(--ease-soft);
}

/* A step up from the footer's 20px: these two links are the only interactive
   elements on the page, with no text beside them to set their scale. */
.coming__social-link .icon {
  width: var(--icon-24);
  height: var(--icon-24);
}

.coming__social-link:hover,
.coming__social-link:focus-visible {
  color: var(--color-accent);
  transform: translateY(-4px);
}

/* ---------- Work card --------------------------------------------------- */

.card {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

/* aspect-ratio reserves the space before the image loads, so the titles below
   never jump. Empty for now — the ratio holds the placeholder open. */
.card__media {
  overflow: hidden;
  border-radius: var(--radius-lg);
  background-color: var(--color-surface-subtle);
  aspect-ratio: 16 / 9;
}

/* eyebrow and title are one tight pair, a step closer than the gap to the
   image above them */
.card__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--duration-slow) var(--ease-out);
}

.card:hover .card__media img {
  transform: scale(1.03);
}

.card__eyebrow {
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-text-subtle);
}

/* h2 in the markup for document outline, sized by class per §6 — never pick a
   heading level for its size */
.card__title {
  font-size: var(--text-xl);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-snug);
  transition: color var(--duration-fast) var(--ease-in-out);
}

.card:hover .card__title {
  color: var(--color-accent);
}

.card__desc {
  color: var(--color-text-muted);
}

/* ---------- Button ------------------------------------------------------ */

.button {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-5);
  min-height: 44px;
  border-radius: var(--radius-full);
  font-size: var(--text-base);
  font-weight: var(--weight-medium);
  background-color: var(--color-accent);
  color: var(--color-on-accent);
  transition: background-color var(--duration-fast) var(--ease-in-out);
}

.button:hover {
  background-color: var(--color-accent-hover);
}

.button--ghost {
  background-color: transparent;
  color: var(--color-text);
  border: 1px solid var(--color-border-strong);
}

.button--ghost:hover {
  background-color: transparent;
  border-color: var(--color-accent);
  color: var(--color-accent);
}
