/*
  BASE
  Global typography, layout shell, and shared components (nav, footer, buttons,
  cards, glass surfaces). Mobile-first: base rules target small screens,
  min-width media queries scale up at 600px and 1024px.
*/

/* ---------- GLOBAL TYPE / LAYOUT ---------- */

body {
  background-color: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

h1, h2, h3, h4 {
  font-family: var(--font-serif);
  line-height: var(--lh-heading);
  color: var(--color-heading);
}

h1 { font-size: var(--fs-h1); }
h2 { font-size: var(--fs-h2); }
h3 { font-size: var(--fs-h3); }

p {
  max-width: var(--prose-max-width);
}

p + p {
  margin-top: var(--space-3);
}

a {
  color: var(--color-link);
}

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

a:disabled,
a[aria-disabled="true"] {
  color: var(--color-text-disabled);
}

.eyebrow {
  display: inline-block;
  font-family: var(--font-sans);
  font-size: var(--fs-meta);
  font-weight: 600;
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--color-text-muted);
}

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

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  top: -100%;
  left: var(--space-3);
  z-index: 100;
  background: var(--color-text);
  color: var(--color-text-on-dark);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
}

.skip-link:focus {
  top: var(--space-3);
}

/* ---------- LAYOUT SHELL ---------- */

.wrap {
  width: 100%;
  max-width: var(--content-max-width);
  margin-inline: auto;
  padding-inline: var(--space-4);
}

@media (min-width: 600px) {
  .wrap {
    padding-inline: var(--space-6);
  }
}

@media (min-width: 1024px) {
  .wrap {
    padding-inline: var(--space-7);
  }
}

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

.section--alt {
  background-color: var(--color-bg-alt);
}

.section--divided {
  border-top: var(--border-hairline);
}

main {
  display: block;
}

/* ---------- SITE HEADER / NAV ---------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(250, 246, 239, 0.82);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-bottom: var(--border-hairline);
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-block: var(--space-3);
}

@media (min-width: 600px) {
  :root {
    /* Two-row header at this width: logo row + the nav row below it,
       each taller than the single collapsed mobile row. */
    --header-height: 96px;
  }
}

/* Anchor/scroll targets land below the sticky header instead of under
   it — native anchor-scrolling and any JS-driven scrollIntoView() both
   respect scroll-margin-top. +16px is breathing room past the header
   edge, not part of the measured header height. */
#home,
#work,
#about {
  scroll-margin-top: calc(var(--header-height) + 16px);
}

.site-logo {
  font-family: var(--font-serif);
  font-size: 1.35rem;
  font-weight: 600;
  color: var(--color-text);
  text-transform: uppercase;
  letter-spacing: 0.2em;
}

.nav-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-sm);
}

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

.nav-toggle__bars,
.nav-toggle__bars::before,
.nav-toggle__bars::after {
  display: block;
  width: 22px;
  height: 2px;
  background: var(--color-text);
  transition: var(--transition-base);
}

.nav-toggle__bars {
  position: relative;
}

.nav-toggle__bars::before,
.nav-toggle__bars::after {
  content: '';
  position: absolute;
  left: 0;
}

.nav-toggle__bars::before { top: -7px; }
.nav-toggle__bars::after { top: 7px; }

.nav-toggle[aria-expanded="true"] .nav-toggle__bars {
  background: transparent;
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bars::before {
  transform: rotate(45deg);
  top: 0;
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bars::after {
  transform: rotate(-45deg);
  top: 0;
}

.site-nav {
  display: none;
  flex-direction: column;
  gap: var(--space-1);
  padding-block: var(--space-3);
  border-top: var(--border-hairline);
}

.site-nav.is-open {
  display: flex;
}

.site-nav__link {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding-inline: var(--space-2);
  border-radius: var(--radius-sm);
  font-size: 0.95rem;
  font-weight: 400;
  color: var(--color-text);
}

.site-nav__link:hover {
  background: var(--color-accent-blue-100);
  color: var(--color-text-hover);
}

.site-nav__link[aria-current="page"] {
  font-weight: 700;
}

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

  .site-nav {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: var(--space-5);
    border-top: none;
    padding-block: 0;
  }

  .site-nav__link {
    min-height: auto;
    padding-inline: 0;
    border-radius: 0;
  }

  .site-nav__link:hover {
    background: none;
  }
}

/* ---------- SITE FOOTER ---------- */

.site-footer {
  border-top: var(--border-hairline);
  padding-block: var(--space-6);
}

.site-footer__inner {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.site-footer__links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
}

@media (min-width: 600px) {
  .site-footer__inner {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
  }
}

/* ---------- BUTTONS / LINKS ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  min-height: 44px;
  padding-inline: var(--space-4);
  border-radius: var(--radius-pill);
  font-size: 0.95rem;
  font-weight: 600;
  transition: var(--transition-base);
  border: 1px solid transparent;
}

.btn--primary {
  background: var(--color-accent-blue-800);
  color: var(--color-text-on-dark);
}

.btn--primary:hover {
  background: var(--color-accent-blue-900);
  color: var(--color-text-on-dark);
}

.btn--primary:disabled,
.btn--primary[aria-disabled="true"] {
  background: var(--color-accent-ash-300);
  color: var(--color-text-on-dark);
}

.btn--ghost {
  border-color: var(--color-border);
  color: var(--color-text);
}

.btn--ghost:hover {
  border-color: var(--color-accent-blue-900);
  color: var(--color-accent-blue-900);
}

.btn--ghost:disabled,
.btn--ghost[aria-disabled="true"] {
  border-color: var(--color-accent-ash-300);
  color: var(--color-accent-ash-300);
}

.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  font-weight: 600;
}

.link-arrow::after {
  content: '\2192';
  transition: transform var(--transition-base);
}

.link-arrow:hover::after {
  transform: translateX(3px);
}

/* ---------- GLASS SURFACE ---------- */
/* "Layered translucent glass in soft light" — used for cards floating over
   soft-focus background sections. Falls back to a flat tinted surface
   wherever backdrop-filter isn't supported. */

.glass {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-soft);
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .glass {
    backdrop-filter: blur(var(--glass-blur));
    -webkit-backdrop-filter: blur(var(--glass-blur));
  }
}

/* ---------- CARDS ---------- */
/* Used by the homepage Work section's preview list (index.html) — a
   single-column stack of full-width rows, image + content side by side
   at tablet/desktop width, stacked at mobile. .card__title is also reused
   as-is by sfe-work-survey.html's .cs-proof-card for matching typography,
   so it stays a standalone rule even though nothing else here is shared. */

.work-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

.card {
  display: flex;
  flex-direction: column;
  /* No padding here — .card__media needs to sit flush against the card's
     own edge (full-bleed); overflow: hidden clips its square corners to
     the card's own border-radius instead of giving the image its own. */
  overflow: hidden;
  border-radius: var(--radius-md);
  /* --color-bg (cream), not --color-surface (white) — matches the actual
     page background of the case study these cards link to, so the card
     doesn't read lighter than what the visitor lands on after clicking. */
  background: var(--color-bg);
  border: var(--border-hairline);
  transition: transform var(--transition-slow), box-shadow var(--transition-slow);
}

.card:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-lift);
}

.card__media {
  display: block;
  width: 100%;
  height: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

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

/* Pins the CTA to the bottom of the card regardless of blurb length, so
   it lines up across cards with different amounts of copy above it.
   Scoped to this context rather than added to .link-arrow itself, which
   is also used inline elsewhere (e.g. the "next case study" footer nav)
   where that behavior isn't wanted. */
.card__body .link-arrow {
  margin-top: auto;
}

.card__title {
  font-family: var(--font-serif);
  font-size: var(--fs-h3);
}

.card__skills {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
}

.pill {
  display: inline-flex;
  align-items: center;
  /* No spacing token lands exactly on these values (--space-1 is the
     smallest, at 8px) — hardcoded so the pills read quieter/smaller than
     the rest of the card's token-driven spacing, not competing with the
     title. Vertical padding is intentionally asymmetric (3px top, 1.5px
     bottom): at --fs-meta/--lh-tight, Inter's glyph ink sits higher than
     the (correctly flex-centered) line box's own center, so equal padding
     visually reads ~1.6px high — measured via actual rendered glyph
     bounds, not just the CSS box model. This offset compensates for that
     without touching line-height. */
  padding-block: 0.1875rem 0.09375rem;
  padding-inline: 0.375rem;
  border: 1px solid var(--color-text);
  border-radius: var(--radius-pill);
  font-size: var(--fs-meta);
  line-height: var(--lh-tight);
  color: var(--color-text);
}

@media (min-width: 600px) {
  .card {
    flex-direction: row;
  }

  .card__media {
    /* Keeps its aspect-ratio (inherited from the base rule) rather than
       being stretched to match the text column's height — at 45% width
       that ratio-derived height is usually the taller of the two, so it's
       what sets the row's height; .card__body (no aspect-ratio of its
       own) then stretches to match, growing the card as needed instead of
       the image being compressed to fit a shorter, text-driven height. */
    flex: 0 0 45%;
  }

  .card__body {
    flex: 1 1 55%;
  }
}

/* ---------- UTILITIES ---------- */

.flow > * + * {
  margin-top: var(--space-3);
}

.stack-lg > * + * {
  margin-top: var(--space-6);
}

.center-text {
  text-align: center;
  margin-inline: auto;
}

/* ---------- LIGHTBOX ---------- */
/* Shared site-wide component (scripts/main.js builds and controls this
   markup) — click-to-zoom for real case-study images. Not case-study.css
   because the trigger elements live there, but this chrome is generic. */

.is-lightbox-trigger {
  cursor: pointer;
}

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-5);
  /* Plain rgba first as a fallback for browsers without color-mix; the
     token-based color-mix below overrides it everywhere that supports it. */
  background: rgba(15, 26, 41, 0.425);
  background: color-mix(in srgb, var(--color-accent-blue-900) 42.5%, transparent);
}

.lightbox[hidden] {
  display: none;
}

/* Sized (not the image itself) to 90vw/90vh so a transparent-background
   image — e.g. the Guidance Builder flowchart PNG — gets a solid light
   mat behind it instead of showing the dark backdrop through its
   transparent regions. Both this and .lightbox__image use viewport units
   rather than percentages of one another: the frame has no explicit
   width/height (it shrink-wraps to the image plus padding), so a
   percentage-based max-width/height on the image would resolve against
   an indeterminate parent size instead of reliably constraining it. */
.lightbox__frame {
  display: flex;
  flex-direction: column;
  /* Centers the image (or placeholder) when the caption below it is
     narrower — the caption itself opts back out via align-self: stretch
     so its text can sit flush left under the image, matching how
     .cs-media-caption reads inline on the page. */
  align-items: center;
  max-width: 90vw;
  max-height: 90vh;
  padding: var(--space-2);
  background: var(--color-bg);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lift);
}

.lightbox__image {
  display: block;
  max-width: calc(90vw - (var(--space-2) * 2));
  max-height: calc(90vh - (var(--space-2) * 2));
  object-fit: contain;
  /* Nested smaller than the frame's own radius so its corners sit inside
     the mat rather than poking past it. */
  border-radius: var(--radius-sm);
  cursor: default;
}

/* When a caption is showing, it shares the frame's 90vh budget with the
   image — reserve room for it (roughly two lines of --fs-meta text plus
   its own margin-top) rather than letting the two together overflow the
   mat. :has() keys off the caption's own [hidden] state, so this applies
   automatically and only when a caption is actually present — no JS
   class-toggling needed. */
.lightbox__frame:has(.lightbox__caption:not([hidden])) .lightbox__image,
.lightbox__frame:has(.lightbox__caption:not([hidden])) .cs-media--placeholder {
  max-height: calc(90vh - (var(--space-2) * 2) - 4rem);
}

/* Reuses .cs-media-caption's exact type/color/spacing (case-study.css,
   loaded on every page that can show a lightbox) so the caption reads
   identically to how it appears inline on the page itself. Stretches to
   the image's width and keeps .cs-media-caption's left-aligned default —
   [hidden] needs no extra override here since this rule never touches
   display, unlike .lightbox__nav/.lightbox__counter above. */
.lightbox__caption {
  align-self: stretch;
}

.lightbox__close {
  position: fixed;
  top: var(--space-4);
  right: var(--space-4);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-sm);
  /* Icon-only, sitting directly on the dark backdrop rather than inside a
     solid light card — the site's normal light-surface/dark-text button
     styling would read as a bright, disconnected box here, and its dark
     icon would nearly disappear if the background were removed. Cream
     (the same token used for text on dark/accent surfaces elsewhere)
     keeps the × legible against the overlay at any opacity. */
  background: transparent;
  color: var(--color-text-on-dark);
  font-size: 1.5rem;
  line-height: 1;
  transition: var(--transition-base);
}

.lightbox__close:hover {
  background: rgba(247, 242, 232, 0.15);
  background: color-mix(in srgb, var(--color-text-on-dark) 15%, transparent);
}

/* Gallery mode (multiple images per trigger, e.g. a project's image
   stack on work/sfe-work-survey.html) reuses everything above — frame,
   mat, close button — and adds Previous/Next + a position counter. Both
   controls stay hidden (see scripts/main.js) for the single-image path
   used elsewhere (Guidance Builder / Field Guide screenshots), so this
   never shows up outside a gallery. */
.lightbox__nav {
  position: fixed;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-text-on-dark);
  font-size: 1.5rem;
  line-height: 1;
  transition: var(--transition-base);
}

.lightbox__nav:hover {
  background: rgba(247, 242, 232, 0.15);
  background: color-mix(in srgb, var(--color-text-on-dark) 15%, transparent);
}

.lightbox__nav[hidden] {
  display: none;
}

.lightbox__nav--prev {
  left: var(--space-4);
}

.lightbox__nav--next {
  right: var(--space-4);
}

.lightbox__counter {
  position: fixed;
  bottom: var(--space-4);
  left: 50%;
  transform: translateX(-50%);
  font-size: var(--fs-meta);
  color: var(--color-text-on-dark);
  opacity: 0.85;
}

.lightbox__counter[hidden] {
  display: none;
}

/* A gallery item with no real src yet (no photo asset shot for this
   project) falls back to the same striped placeholder look as the page
   itself (.cs-media--placeholder, defined in case-study.css — every page
   that declares a gallery also loads that stylesheet). It has no
   intrinsic size the way a real <img> would, so it needs an explicit
   footprint inside the frame rather than relying on .lightbox__image's
   max-width/height alone. */
.lightbox__frame .cs-media--placeholder {
  width: min(70vw, 640px);
  aspect-ratio: 4 / 3;
}

/* .cs-media--placeholder (case-study.css) sets display: flex as an
   author rule, which beats the browser's built-in [hidden]{display:none}
   regardless of the hidden attribute — author-origin CSS always wins
   over user-agent-origin CSS for the same property. Without this, toggling
   lightboxPlaceholder.hidden in JS had no visual effect: it kept
   rendering full-size, stacked directly below the real <img>, and pushed
   the caption down with it. Same class of fix already applied to
   .lightbox__nav/.lightbox__counter above, just missed for this element
   when gallery mode first shipped. */
.lightbox__frame .cs-media--placeholder[hidden] {
  display: none;
}
