/*
 * Global Styles — Shear Madness Barbering
 * Typography, layout shell, masthead, navigation, footer.
 * Components live in components.css; tokens in variables.css.
 */

/* ---- Base ---- */

html {
  scroll-behavior: smooth;
}

body {
  font-family: var(--font-body);
  font-size: var(--text-base);
  font-stretch: var(--stretch-normal);
  color: var(--color-ink);
  background-color: var(--color-paper);
  line-height: var(--leading-normal);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

::selection {
  background: var(--color-brand);
  color: var(--color-paper-on-dark);
}

/* ---- Skip Link ---- */

.skip-link {
  position: absolute;
  top: -100%;
  left: var(--space-md);
  z-index: 1000;
  padding: var(--space-sm) var(--space-md);
  background: var(--color-ink);
  color: var(--color-paper-on-dark);
  font-weight: var(--weight-semibold);
  text-decoration: none;
  transition: top var(--transition-fast);
}

.skip-link:focus {
  top: 0;
  outline: none;
  box-shadow: var(--focus-ring);
}

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

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

.container--narrow {
  max-width: var(--container-narrow);
}

.container--wide {
  max-width: var(--container-wide);
}

.section {
  padding-block: var(--space-section);
}

.section--shade {
  background: var(--color-paper-shade);
}

/* Class name kept for cross-client consistency, but the dark surface on this
   site is the loft's olive wall, not black. */
.section--ink {
  background: var(--color-brand);
  color: var(--color-paper-on-dark);
}

.section--ink h2,
.section--ink h3,
.section--ink h4 {
  color: var(--color-paper-on-dark);
}

.section--ink p {
  color: var(--color-faint-on-dark);
}

/* ---- Typography ---- */

/* Two registers, per variables.css:
   h1/h2 are SIGN LETTERING — the heavy slab from the shop's badge.
   h3/h4 are SHOP LABELS — plain stack, caps, wide tracking. Mixing the two
   is what keeps a one-weight display face from flattening every heading. */
h1, h2 {
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  text-transform: uppercase;
  letter-spacing: var(--tracking-display);
  color: var(--color-ink);

  /* Never let a heavy slab word be broken across lines. Alfa Slab sets very
     wide, and the browser's last resort for an over-wide word is to break it
     mid-word, which is how the old hero shipped "TRANSFORMATIO / N STARTS
     HERE." The fluid clamps in variables.css keep the longest word inside its
     column; these three declarations make the break impossible even if a
     future edit makes the copy longer. A word that no longer fits will
     overflow visibly instead of silently mangling itself. */
  overflow-wrap: normal;
  word-break: keep-all;
  hyphens: none;

  /* Even out ragged line lengths in display type. Supported everywhere that
     matters; harmless where it is not. */
  text-wrap: balance;
}

h3, h4 {
  font-family: var(--font-body);
  font-weight: var(--weight-bold);
  font-stretch: var(--stretch-label);
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--color-ink);
}

h1 { font-size: var(--display-hero); line-height: var(--leading-tight); }
h2 { font-size: var(--display-section); line-height: var(--leading-tight); }
h3 { font-size: var(--text-base); line-height: 1.35; }
h4 { font-size: var(--text-sm); line-height: 1.35; }

/* A section headline that has to carry a long word (page titles on the
   service pages) drops a step rather than crowding its column. */
h1.display-sub, h2.display-sub { font-size: var(--display-sub); }

/* Painted-sign emphasis: the marked word goes rust. Never italic. */
h1 em, h2 em {
  font-style: normal;
  color: var(--color-signal);
}

p {
  margin-block-end: var(--space-md);
}

p:last-child {
  margin-block-end: 0;
}

a {
  color: var(--color-brand);
  text-decoration: underline;
  text-decoration-thickness: 1.5px;
  text-underline-offset: 3px;
  transition: color var(--transition-fast);
}

a:hover {
  color: var(--color-signal);
}

a:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring-offset);
}

strong {
  font-weight: var(--weight-semibold);
}

/* Kicker — a printed-form section label: small caps riding ON the rule,
   like a fieldset legend. Use inside .section-header. */
/* Kicker — a printed-form section label.
   RATIONED. The old homepage put one above every single section (six of them
   over eight sections), which is the exact rhythm that makes a page read as
   generated: label, slab headline, body, repeat. A section's position on the
   page already says what it is. Budget for this site is at most one kicker
   per three sections; the headline carries the rest alone. */
.kicker {
  display: block;
  font-family: var(--font-body);
  font-weight: var(--weight-bold);
  font-stretch: var(--stretch-label);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--color-signal);
  margin-block-end: var(--space-md);
}

.section--ink .kicker {
  color: var(--color-paper-on-dark);
}

.section-header {
  max-width: 46rem;
  margin-block-end: var(--space-2xl);
}

/* A headline that sits at the right-hand edge of the measure instead of the
   left. Used once, to break the eight-times-repeated left rag. */
.section-header--end {
  max-width: 38rem;
  margin-inline-start: auto;
  text-align: end;
}

/* Headline and its lead paragraph set as a wide two-column band, with the
   paragraph on a real column rather than floating in a corner. */
.section-header--band {
  max-width: none;
  display: grid;
  gap: var(--space-md) var(--space-3xl);
  align-items: end;
}

@media (min-width: 56rem) {
  .section-header--band {
    grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  }

  .section-header--band > :last-child {
    padding-block-end: 0.35em;
  }
}

.section-lede {
  max-width: 52ch;
  font-size: var(--text-lg);
  line-height: var(--leading-snug);
  color: var(--color-ink-soft);
}

.section--ink .section-lede {
  color: var(--color-faint-on-dark);
}

/* ---- Reveal ----
   The one piece of motion on the site, and it earns its place on exactly one
   job: bringing the photographs of the work up as you reach them, so the eye
   lands on the cuts in sequence rather than on a wall of nine at once.
   Driven by IntersectionObserver in main.js, never by a scroll listener.
   Elements start hidden ONLY when JS is present to reveal them, so a no-JS
   or failed-observer visitor sees everything. */
html.js .reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity var(--transition-reveal), transform var(--transition-reveal);
  transition-delay: var(--reveal-delay, 0ms);

  /* Failsafe. The hidden state is gated on html.js, which the inline script in
     <head> sets, but the code that UNDOES it lives in main.js. If main.js ever
     fails to load, that gap would leave the photographs of the work invisible
     for good, which is the worst thing that could quietly happen to this page.
     This reveals anything still hidden after 8s, so a broken script costs the
     animation and nothing else. 8s is long enough that a reader who actually
     reaches the work section still sees the reveal. */
  animation: reveal-failsafe 1ms linear 8s forwards;
}

@keyframes reveal-failsafe {
  to { opacity: 1; transform: none; }
}

html.js .reveal.is-in {
  opacity: 1;
  transform: none;
  animation: none;
}

@media (prefers-reduced-motion: reduce) {
  html.js .reveal {
    opacity: 1;
    transform: none;
    transition: none;
    animation: none;
  }
}

.section-subtitle {
  margin-block-start: var(--space-sm);
  font-size: var(--text-lg);
  color: var(--color-ink-soft);
}

.section--ink .section-subtitle {
  color: var(--color-faint-on-dark);
}

/* ---- Utilities ---- */

.text-center { text-align: center; }
.text-muted { color: var(--color-ink-faint); }
.text-lg { font-size: var(--text-lg); }
.mb-md { margin-block-end: var(--space-md); }
.mb-xl { margin-block-end: var(--space-xl); }
.mt-xl { margin-block-start: var(--space-xl); }

/* Newsprint divider — double rule */
.double-rule {
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--container-padding);
}

.double-rule::before {
  content: '';
  display: block;
  border-block-start: var(--rule-hairline) solid var(--color-rule-faint);
}

/* ---- Utility Strip (top) ---- */

.utility-strip {
  background: var(--color-brand-dark);
  color: var(--color-paper-on-dark);
  font-size: var(--text-sm);
  padding: var(--space-xs) 0;
}

.utility-strip .container {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-xs) var(--space-lg);
}

.utility-strip a {
  color: var(--color-paper-on-dark);
  font-weight: var(--weight-semibold);
}

.utility-strip a:hover {
  color: var(--color-paper-on-dark);
  text-decoration-color: var(--color-signal);
}

/* ---- Masthead ---- */

.site-header {
  background: var(--color-paper);
  border-block-end: var(--rule-hairline) solid var(--color-rule-faint);

  /* Containing block for the mobile nav drawer. Without this there is no
     positioned ancestor, so the absolutely positioned drawer fell back to the
     initial containing block and took its static position as a flex item,
     which put it at top: -66px: above the viewport, covering the logo. */
  position: relative;
}

.site-header .container {
  display: flex;
  align-items: center;
  gap: var(--space-lg);
  padding-block: var(--space-lg);
}

/* The masthead carries the shop's actual flash badge, not a text wordmark
   alone — it is the strongest thing they own. */
.logo {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  text-decoration: none;
  min-width: 0;
}

.logo-badge {
  width: 2.75rem;
  height: 2.75rem;
  flex-shrink: 0;
  object-fit: contain;
}

.logo-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.logo-name {
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  font-size: var(--text-xl);
  text-transform: uppercase;
  letter-spacing: var(--tracking-display);
  color: var(--color-ink);
  line-height: 1.05;
}

.logo-sub {
  font-size: 0.6875rem;
  font-weight: var(--weight-bold);
  text-transform: uppercase;
  color: var(--color-ink-faint);
  letter-spacing: var(--tracking-label);
}

.logo:hover .logo-name {
  color: var(--color-signal);
}

@media (min-width: 48rem) {
  .logo-badge { width: 3.25rem; height: 3.25rem; }
  .logo-name { font-size: var(--text-2xl); }
}

/* ---- Navigation ---- */

.nav-toggle {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 2.5rem;
  height: 2.5rem;
  flex-shrink: 0;
  margin-inline-start: auto;
  padding: var(--space-sm);
  background: none;
  border: var(--rule) solid var(--color-rule);
  cursor: pointer;
}

.nav-toggle:hover {
  background: var(--color-paper-shade);
}

.nav-toggle:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring-offset);
}

.nav-toggle-bar {
  display: block;
  width: 100%;
  height: 2px;
  background: var(--color-ink);
  transition: transform var(--transition-fast), opacity var(--transition-fast);
}

.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}

.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(2) {
  opacity: 0;
}

.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

/* Only hide the nav when JavaScript is there to bring it back. Without JS the
   toggle is inert, so the list stays open and the toggle is removed instead —
   otherwise a no-JS phone has no navigation at all. */
html.js .primary-nav {
  display: none;
}

html:not(.js) .nav-toggle {
  display: none;
}

/*
 * The open state MUST out-specify the rule above it.
 *
 * This was the mobile menu bug: `html.js .primary-nav` is (0,2,1) because of
 * the `html` type selector, while a bare `.primary-nav.is-open` is only
 * (0,2,0). The hidden rule therefore won on specificity no matter what order
 * the two appeared in, and the drawer could never be shown. The script was
 * working the whole time: it added `.is-open` and flipped `aria-expanded` to
 * true, so the button reported an expanded menu that stayed `display: none`.
 * Tapping the hamburger did nothing at all.
 *
 * Adding `html.js` here makes it (0,3,1) and the open state wins.
 */
html.js .primary-nav.is-open {
  display: block;
}

/* The drawer chrome is scoped to the mobile range on purpose. It used to be
   unscoped, so a stale `.is-open` left over from opening the menu on a narrow
   window would keep applying `position: absolute` after a resize past the
   desktop breakpoint, tearing the nav out of the header row. Above 48rem the
   nav is an inline list and needs none of this. */
@media (max-width: 47.9375rem) {
  html.js .primary-nav.is-open {
    position: absolute;
    /* Hang from the bottom edge of the header rather than from wherever the
       flex layout happened to leave the static position.
       The offset is NOT plain 100%: percentages on `top` resolve against the
       containing block's PADDING box, which excludes the header's bottom rule,
       so 100% alone lands the drawer on top of that rule and hides it. */
    top: calc(100% + var(--rule-hairline));
    left: 0;
    right: 0;
    z-index: 100;
    background: var(--color-paper);
    border-block-end: var(--rule-hairline) solid var(--color-rule-faint);
  }
}

.nav-list {
  display: flex;
  flex-direction: column;
}

.nav-list a {
  display: block;
  padding: var(--space-md) var(--container-padding);
  font-family: var(--font-body);
  font-weight: var(--weight-bold);
  font-stretch: var(--stretch-label);
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--color-ink);
  text-decoration: none;
  border-block-end: var(--rule-hairline) solid var(--color-rule-faint);
}

.nav-list a:hover {
  color: var(--color-signal);
}

.nav-list a[aria-current="page"] {
  color: var(--color-brand);
}

.nav-list a:focus-visible {
  outline: none;
  box-shadow: inset var(--focus-ring);
}

/* ---- Breadcrumb ---- */

.breadcrumb {
  padding-block-start: var(--space-sm);
}

.breadcrumb ol {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
  max-width: var(--container-max);
  margin-inline: auto;
  padding: var(--space-sm) var(--container-padding);
  font-size: var(--text-xs);
  color: var(--color-ink-faint);
}

.breadcrumb li:not(:last-child)::after {
  content: '\2192';
  margin-inline-start: var(--space-xs);
  color: var(--color-ink-faint);
}

.breadcrumb a {
  color: var(--color-ink-soft);
  text-decoration: none;
}

.breadcrumb a:hover {
  color: var(--color-signal);
  text-decoration: underline;
}

.breadcrumb [aria-current="page"] {
  color: var(--color-ink);
  font-weight: var(--weight-medium);
}

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

.site-footer {
  background: var(--color-brand-dark);
  color: var(--color-paper-on-dark);
  padding-block: var(--space-4xl) var(--space-2xl);
}

.footer-grid {
  display: grid;
  gap: var(--space-2xl);
}

.footer-wordmark {
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  font-size: var(--text-2xl);
  text-transform: uppercase;
  letter-spacing: var(--tracking-display);
  margin-block-end: var(--space-sm);
}

/* The badge is ink drawn on cream paper -- the paper IS the skin tone -- so it
   is never value-inverted for a dark surface. It carries its own paper instead,
   the way a flash sheet does. A reversed variant turned the face into the
   darkest value on the badge and read badly. See "Never invert the badge"
   in CLAUDE.md before making any dark-surface variant of it. */
.footer-badge {
  height: 5.5rem;
  width: auto;
  margin-block-end: var(--space-md);
  padding: var(--space-sm);
  background: var(--color-paper);
}

.footer-heading {
  font-family: var(--font-body);
  font-weight: var(--weight-bold);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--color-paper-on-dark);
  margin-block-end: var(--space-md);
}

.footer-text {
  color: var(--color-faint-on-dark);
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
}

.footer-nav a {
  display: block;
  padding-block: var(--space-xs);
  color: var(--color-faint-on-dark);
  text-decoration: none;
  font-size: var(--text-sm);
}

.footer-nav a:hover {
  color: var(--color-paper-on-dark);
  text-decoration: underline;
}

.footer-contact-item {
  margin-block-end: var(--space-sm);
  color: var(--color-faint-on-dark);
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
}

.footer-contact-item a {
  color: var(--color-paper-on-dark);
  text-decoration: none;
}

.footer-contact-item a:hover {
  text-decoration: underline;
}

.footer-bottom {
  margin-block-start: var(--space-2xl);
  padding-block-start: var(--space-lg);
  border-block-start: var(--rule-hairline) solid rgba(244, 239, 230, 0.16);
  font-size: var(--text-sm);
  color: var(--color-faint-on-dark);
}

.footer-cities {
  font-size: var(--text-xs);
  margin-block-start: var(--space-sm);
  line-height: var(--leading-relaxed);
}

/* ---- Desktop ---- */

@media (min-width: 48rem) {
  /* h1 and h2 are fluid (see --display-* in variables.css) and deliberately
     have no stepped desktop override; a hard jump at 48rem is what used to
     push the hero headline past its column. */
  h3 { font-size: var(--text-lg); }

  .nav-toggle {
    display: none;
  }

  html.js .primary-nav,
  .primary-nav {
    display: block;
    margin-inline-start: auto;
  }

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

  .nav-list a {
    padding: var(--space-xs) var(--space-md);
    font-size: var(--text-sm);
    border-block-end: none;
  }

  .nav-cta {
    background: var(--color-signal);
    color: var(--color-paper-on-dark) !important;
    margin-inline-start: var(--space-md);
    padding-block: var(--space-sm) !important;
    padding-inline: var(--space-lg) !important;
  }

  .nav-cta:hover,
  .nav-cta[aria-current="page"] {
    background: var(--color-ink);
    color: var(--color-paper-on-dark) !important;
  }

  .footer-grid {
    grid-template-columns: 2fr 1fr 1fr 1.2fr;
  }
}

/* ---- Reduced Motion ---- */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
