/* ==========================================================================
   Base: reset, fonts, typography, layout primitives.
   Depends on css/tokens.css being loaded first.
   ========================================================================== */

/* -- Font ------------------------------------------------------------------
   Switched to Google Sans Flex 2026-07-26 (client decision) — the open,
   SIL-licensed variable-font alternative to classic Google Sans (which is
   Google's own proprietary font, not legally redistributable here; see
   PROJECT_STATUS.md and BRANDING.md §4 for the full licensing background).

   Loaded live from Google Fonts (same `<link>` pattern already used for
   the Roboto fallback, one `<link>` per page's <head>) rather than
   self-hosted — Google Sans Flex is actually published on Google Fonts,
   unlike classic Google Sans, so there's no file for the client to
   source/place manually. No @font-face needed here; the CDN stylesheet
   provides it, with `font-weight: 100 900` covering the full variable
   range this site's type scale uses (Regular/Medium/Bold). */

/* -- Reset ------------------------------------------------------------------ */
*, *::before, *::after { box-sizing: border-box; }
html, body, h1, h2, h3, h4, p, figure { margin: 0; }
html { -webkit-text-size-adjust: 100%; }
/* Toggled by js/main.js on back/forward-cache page restoration, briefly
   dropping pointer-events (inherited by every descendant, nothing in this
   codebase overrides it back to auto) so the browser is forced to
   re-evaluate :hover from scratch on the next real pointer movement,
   instead of rendering stuck in whatever element the cursor happened to
   sit over when the user last navigated away. See js/main.js comment. */
html.suppress-hover {
  pointer-events: none;
}
body {
  font-family: var(--font-family-base);
  font-weight: var(--font-weight-regular);
  font-optical-sizing: auto;
  /* Google Sans Flex's other 4 variable axes (slant/width/grade/round) —
     pinned to their neutral defaults rather than left to the browser,
     since this design only ever varies weight. No effect on the Roboto
     fallback (a static font, ignores unsupported variation settings). */
  font-variation-settings: "slnt" 0, "wdth" 100, "GRAD" 0, "ROND" 0;
  background: var(--color-bg-page);
  color: var(--color-text-primary);
  line-height: 1.5;
}
img, svg, video { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
ul, ol { margin: 0; padding: 0; list-style: none; }

@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;
  }
}

/* -- Typography --------------------------------------------------------------
   Semantic classes, not bare tag selectors — a heading's visual scale and
   its document-outline level (h1/h2/h3) are two different things on this
   site (e.g. Insights/Case Studies/Contact page titles are <h1> tags that
   render at the H2/Major-headline token, BRANDING.md §4). */
.text-h1 {
  font-weight: var(--font-weight-bold);
  font-size: var(--font-size-h1);
  line-height: var(--line-height-h1);
  letter-spacing: -2%;
}
.text-h2 {
  font-weight: var(--font-weight-bold);
  font-size: var(--font-size-h2);
  line-height: var(--line-height-h2);
}
.text-h3 {
  font-weight: var(--font-weight-medium);
  font-size: var(--font-size-h3);
  line-height: var(--line-height-h3);
}
.text-h4 {
  font-weight: var(--font-weight-medium);
  font-size: var(--font-size-h4);
  line-height: var(--line-height-h4);
}
.text-lead-body {
  font-weight: var(--font-weight-regular);
  font-size: var(--font-size-lead-body);
  line-height: var(--line-height-lead-body);
}
.text-small-body {
  font-weight: var(--font-weight-regular);
  font-size: var(--font-size-small-body);
  line-height: var(--line-height-small-body);
}
.text-eyebrow {
  font-weight: var(--font-weight-bold);
  font-size: var(--font-size-eyebrow);
  line-height: var(--line-height-eyebrow);
  text-transform: uppercase;
}
.text-link {
  font-weight: var(--font-weight-medium);
  font-size: var(--font-size-link);
  line-height: var(--line-height-link);
  color: var(--color-text-link);
}

/* Responsive type scale — confirmed proposal (see project conversation):
   large desktop (≥1400px, base rules above) is signed off and unchanged.
   Small desktop and tablet are new tiers; mobile's eyebrow is the one
   value that changed from what was already live. Breakpoints match
   BRANDING.md §5's `lg`/`md` tokens — same tablet range the text-heavy
   section's column stagger already uses. */
@media (min-width: 992px) and (max-width: 1399px) {
  .text-h1 { font-size: var(--font-size-h1-small-desktop); line-height: var(--line-height-h1-small-desktop); }
  .text-h2 { font-size: var(--font-size-h2-small-desktop); line-height: var(--line-height-h2-small-desktop); }
  .text-h3 { font-size: var(--font-size-h3-small-desktop); line-height: var(--line-height-h3-small-desktop); }
  .text-h4 { font-size: var(--font-size-h4-small-desktop); line-height: var(--line-height-h4-small-desktop); }
  .text-lead-body { font-size: var(--font-size-lead-body-small-desktop); line-height: var(--line-height-lead-body-small-desktop); }
}
@media (min-width: 768px) and (max-width: 991px) {
  .text-h1 { font-size: var(--font-size-h1-tablet); line-height: var(--line-height-h1-tablet); letter-spacing: -1%; }
  .text-h2 { font-size: var(--font-size-h2-tablet); line-height: var(--line-height-h2-tablet); }
  .text-h3 { font-size: var(--font-size-h3-tablet); line-height: var(--line-height-h3-tablet); }
  .text-h4 { font-size: var(--font-size-h4-tablet); line-height: var(--line-height-h4-tablet); }
  .text-lead-body { font-size: var(--font-size-lead-body-tablet); line-height: var(--line-height-lead-body-tablet); }
  .text-eyebrow { font-size: var(--font-size-eyebrow-tablet); line-height: var(--line-height-eyebrow-tablet); }
}
@media (max-width: 767px) {
  .text-h1 { font-size: var(--font-size-h1-mobile); line-height: var(--line-height-h1-mobile); letter-spacing: -1%; }
  .text-h2 { font-size: var(--font-size-h2-mobile); line-height: var(--line-height-h2-mobile); }
  .text-h3 { font-size: var(--font-size-h3-mobile); line-height: var(--line-height-h3-mobile); }
  .text-h4 { font-size: var(--font-size-h4-mobile); line-height: var(--line-height-h4-mobile); }
  .text-lead-body { font-size: var(--font-size-lead-body-mobile); line-height: var(--line-height-lead-body-mobile); }
  .text-eyebrow { font-size: var(--font-size-eyebrow-mobile); line-height: var(--line-height-eyebrow-mobile); }
}

/* -- Layout primitives -------------------------------------------------------- */
.container {
  max-width: var(--container-max-width);
  margin-inline: auto;
  padding-inline: var(--container-edge-padding);
}
@media (min-width: 992px) and (max-width: 1399px) {
  .container { padding-inline: var(--container-edge-padding-small-desktop); }
}
@media (min-width: 768px) and (max-width: 991px) {
  .container { padding-inline: var(--container-edge-padding-tablet); }
}
@media (max-width: 767px) {
  .container { padding-inline: var(--container-edge-padding-mobile); }
}

.section {
  position: relative;
  padding-block: var(--section-padding-desktop-max);
}
@media (min-width: 992px) and (max-width: 1399px) {
  .section { padding-block: var(--section-padding-small-desktop); }
}
@media (min-width: 768px) and (max-width: 991px) {
  .section { padding-block: var(--section-padding-tablet); }
}
@media (max-width: 767px) {
  .section { padding-block: var(--section-padding-mobile); }
}
/* .section--page-header: for a page whose very first section sits
   directly under the fixed header with nothing else above it (Insights,
   Case Studies, Contact, Login — unlike Index, whose first section is a
   full-viewport-height hero with vertically-centered content, so it
   never actually needs this). The header is a fixed bar, ~122px tall at
   every breakpoint (measured — it doesn't scale down with the page's own
   responsive type/spacing tiers), but section padding-top drops to
   100px (tablet) and 64px (mobile) — both less than 122px, so ordinary
   section padding isn't enough there and the page's H1 renders partly or
   fully behind the header (confirmed: Insights' H1 measured at just
   64px from the top on mobile, well inside the header's 0–122px zone).
   Only padding-top needs the override — padding-bottom keeps each
   tier's normal section rhythm from the base rule above. Large desktop
   (150px, reduced 2026-07-25 from 240px — see tokens.css) still clears
   122px on its own and doesn't need this. Small desktop no longer does
   on its own (90px, reduced from 140px in the same pass), so the
   override now extends up through 1399px, not just 991px. */
@media (max-width: 1399px) {
  .section--page-header { padding-top: 150px; }
}
/* No background-color here on purpose — bg-page IS the pattern tile's own
   backdrop color (both are var(--color-bg-page)/midnight-black-900), so an
   opaque fill here would paint over and hide body's pattern layer beneath.
   Leaving it transparent lets the identical-colored pattern show through
   with zero visible difference in the base color. */
.section--bg-page { background: transparent; }
.section--bg-alt { background: var(--color-bg-alt); }

/* Background pattern (WEBSITE_SPECIFICATION.md §5): tiles behind every
   section regardless of section background color, honeycomb-offset (rows
   staggered by half a tile width), not a plain rectangular repeat.
   `UI/image/background/bg_pattern.png` (140x65) was inspected directly —
   its dot sits dead-center of the tile (bbox x:68-71/y:30-33), so a plain
   `background-repeat` of that source file produces a straight rectangular
   grid, not the hex look.
   `bg_pattern_hex.svg` (140x130) reproduces the same honeycomb layout as a
   vector — an earlier PNG version of this tile looked blurry on HiDPI/
   Retina displays (a 1x raster asset upscaled by the browser to match
   actual screen pixel density); SVG has no such scale-dependent blur.
   `background-attachment: fixed` per the Figma prototype: the pattern
   itself stays put in the viewport while foreground content scrolls over
   it, rather than scrolling along with the page. Known limitation: iOS
   Safari doesn't support `fixed` backgrounds — it silently falls back to
   `scroll` there, which just means the pattern scrolls with content on
   iOS instead of staying fixed; not broken, just not this exact effect. */
body {
  background-color: var(--color-bg-page); /* fallback base color, matches the pattern tile's own backdrop exactly */
  background-image: url('../UI/image/background/bg_pattern_hex.svg');
  background-repeat: repeat;
  background-attachment: fixed;
}

/* -- Shared Template: Text-Heavy Section --------------------------------------
   WEBSITE_SPECIFICATION.md §4. Used by Index Sections 2, 4, 5 and (header
   structure only) Contact Section 2. */
.text-heavy-section__header { margin-bottom: var(--space-60); }
.text-heavy-section__lead-body { margin-top: var(--space-18); }

.text-heavy-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  column-gap: var(--space-40);
}
.text-heavy-row + .text-heavy-row { margin-top: var(--space-60); }

.text-heavy-row__col:nth-child(1) { padding-top: 0; }
.text-heavy-row__col:nth-child(2) { padding-top: var(--space-90); }
.text-heavy-row__col:nth-child(3) { padding-top: var(--space-200); } /* 242px ≈ space-200 (12.5rem = 200px); closest token to the spec's 242px, not pixel-exact — flag if pixel-exact fidelity matters */

.text-heavy-row__col h3 { margin-bottom: var(--space-12); }

/* Large-desktop-only bold/spacious pass (client feedback: text-heavy
   sections read as packed despite the section's own generous outer
   padding — bumped separately above). Column width and font sizes are
   untouched (narrowing either would undercut the bold type the client
   specifically likes); every value here only adds *space around* that
   type instead. Scoped to ≥1400px so small desktop/tablet/mobile keep
   their own already-tuned values from the earlier responsive pass:
   - column-gap 40px → 60px: the single biggest lever against the
     3-column "wall of bold text" effect.
   - h3 margin-bottom 12px → 18px: headline breathes before its
     paragraph starts instead of sitting almost stacked on it.
   - row-to-row margin 60px → 90px: gives the 0/135/200px stagger more
     room to read as an intentional cascade, not a packed grid.
   - h3 line-height 44.4px (1.2×) → 48px (~1.3×): columns are narrow
     enough (353px at 1440px) that bold 37px headlines wrap onto 2–3
     lines regardless — since the wrap itself isn't going away, looser
     line-height makes it read as deliberate rather than cramped. Scoped
     to just this selector, not the global --line-height-h3 token, so
     H3 elsewhere (banner headings, case-study card intro) is unaffected. */
@media (min-width: 1400px) {
  .text-heavy-row { column-gap: var(--space-60); }
  .text-heavy-row + .text-heavy-row { margin-top: var(--space-90); }
  .text-heavy-row__col h3 { margin-bottom: var(--space-18); line-height: 48px; }
}

@media (min-width: 768px) and (max-width: 991px) {
  .text-heavy-row { column-gap: var(--column-gutter-tablet); }
  .text-heavy-row__col:nth-child(2) { padding-top: var(--space-60); }
  .text-heavy-row__col:nth-child(3) { padding-top: var(--space-90); }
}

@media (max-width: 767px) {
  .text-heavy-row {
    grid-template-columns: 1fr;
    row-gap: var(--space-40);
  }
  .text-heavy-row__col:nth-child(1),
  .text-heavy-row__col:nth-child(2),
  .text-heavy-row__col:nth-child(3) {
    padding-top: 0;
  }
}

/* Scroll-reveal (BRANDING.md §7 "Text-heavy section reveal"), driven by
   js/main.js toggling .is-revealed via IntersectionObserver.

   Fails safe by design: a .reveal-item is NOT hidden by default — only
   .reveal-pending (added by main.js, only once it has actually reached
   and run that code) makes it opacity:0. If js/main.js fails to load, is
   blocked, or throws partway through an earlier unrelated block (nav
   toggle, active-link detection) before reaching the reveal setup, the
   content simply stays at its default visible state instead of being
   permanently stuck invisible — confirmed as a real risk after Contact's
   9-profile grid briefly appeared to have "all profiles missing" for a
   client testing it live (root cause that time was the animation's
   stagger duration, already fixed separately — but this failure mode
   was real and worth closing regardless of what actually caused that
   report). */
.reveal-item {
  transition: opacity var(--duration-standard) var(--ease-out),
              transform var(--duration-standard) var(--ease-out);
}
.reveal-item.reveal-pending {
  opacity: 0;
  transform: translateY(var(--reveal-translate-y));
}
.reveal-item.is-revealed {
  opacity: 1;
  transform: translateY(0);
}
@media (prefers-reduced-motion: reduce) {
  .reveal-item { transform: none; }
}

/* Visually-hidden but crawlable — CSS clip technique, not display:none
   (search engines discount display:none content per
   WEBSITE_SPECIFICATION.md's Index Section 3 SEO fallback requirement). */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* -- Buttons ------------------------------------------------------------------ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-8);
  /* Medium is the default size (Index Section 1 Part 2's "Let's Explore
     Together" CTA) — confirmed via Figma MCP: uniform space/27 padding,
     bold label-scale (16px/24px) text, no border-radius on any button
     instance checked. */
  padding: var(--space-27);
  font-weight: var(--font-weight-bold);
  font-size: var(--font-size-link);
  line-height: var(--line-height-link);
  transition: background var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out),
              border-color var(--duration-fast) var(--ease-out);
}
.btn--primary {
  background: var(--color-action-primary);
  color: var(--color-action-primary-text);
  border: 3px solid var(--color-action-primary);
}
/* Hover/press fills confirmed via Figma MCP (node 1744:682) — previously
   missing entirely, every .btn was static regardless of interaction state.
   :focus-visible mirrors :hover (same visual affordance for keyboard
   users); :active is the separate, darker "press" fill Figma defines. */
.btn--primary:hover,
.btn--primary:focus-visible {
  background: var(--color-action-primary-hover);
  border-color: var(--color-action-primary-hover);
}
.btn--primary:active {
  background: var(--color-action-primary-press);
  border-color: var(--color-action-primary-press);
}
.btn--secondary {
  background: transparent;
  color: var(--color-action-secondary-text);
  border: 3px solid var(--color-action-secondary-border); /* 3px confirmed via Figma MCP (both header Login and Section 6 "Meet The Team" instances) — was 1px, wrong */
}
/* Figma defines one shared fill for both hover and press on the secondary
   button (unlike primary, which has 3 distinct fills) — border/text stay
   orange throughout, only the background fills in. */
.btn--secondary:hover,
.btn--secondary:focus-visible,
.btn--secondary:active {
  background: var(--color-action-secondary-hover-bg);
}
.btn--secondary:disabled {
  border-color: var(--color-text-disabled);
  color: var(--color-text-disabled);
}
/* Large (Section 6 CTAs): same space/27 padding as the default/medium size,
   but steps up to the H4/sub-headline type scale (28px/42px) and drops to
   medium weight — confirmed via Figma MCP, not a guess. */
.btn--large {
  font-weight: var(--font-weight-medium);
  font-size: var(--font-size-h4);
  line-height: var(--line-height-h4);
}
/* .btn--large tracks H4's responsive tiers the same way .text-h4 does
   (it reads var(--font-size-h4) directly rather than via the .text-h4
   class, so it doesn't inherit the overrides above automatically). Must
   come after the base .btn--large rule above — equal-specificity rules
   are resolved by source order, not by which media query is active, so a
   copy placed earlier in the cascade (e.g. alongside .text-h4's own
   breakpoint rules) gets silently overridden by this base rule instead.
   Left unwired, two .btn--large buttons sharing the Section 6 CTA row
   wrap to two lines once the row narrows to tablet width (confirmed at
   768–991px, where "Explore Our Work →" wraps but "Meet The Team →"
   doesn't, producing a mismatched-height row). */
@media (min-width: 992px) and (max-width: 1399px) {
  .btn--large { font-size: var(--font-size-h4-small-desktop); line-height: var(--line-height-h4-small-desktop); }
}
@media (min-width: 768px) and (max-width: 991px) {
  .btn--large { font-size: var(--font-size-h4-tablet); line-height: var(--line-height-h4-tablet); }
}
@media (max-width: 767px) {
  .btn--large { font-size: var(--font-size-h4-mobile); line-height: var(--line-height-h4-mobile); }
}
/* Small (header Login, case-study card "Read More"): tighter padding,
   fixed minimum width, stays at the bold label scale — confirmed via
   Figma MCP. */
.btn--small {
  padding: var(--space-8) var(--space-18);
  min-width: 120px;
}
.btn--full { flex: 1; }
