/* AnyBridge homepage, styled from DESIGN.md (Meta-design-analysis).
   Tokens are mirrored as custom properties; components follow the spec's
   button/card/typography definitions. Per the no-hover policy, interactive
   elements define pressed (:active) states only.

   Two deliberate deviations from the spec:
   - Typeface. DESIGN.md specifies Optimistic VF, which is Meta-proprietary and
     not licensable. Inter is the closest available match (same humanist-
     geometric character, same 300-700 range) and is self-hosted in fonts.css
     alongside Noto Sans KR for hangul. The spec's `ss01, ss02` pairing is NOT
     carried over: those stylistic sets mean something different in Inter
     (alternate digits / disambiguation glyphs), so applying them here would
     change the type in ways the spec never intended.
   - Mobile nav. The spec collapses pill tabs into a hamburger drawer below
     768px; this page has exactly two of them, so they simply tighten and stay
     visible. A drawer for two anchors would need JS the page otherwise avoids. */

:root {
  /* colors */
  --canvas: #ffffff;
  --ink-deep: #0a1317;
  --ink: #1c1e21;
  --slate: #4b4c4f;
  --steel: #5d6c7b;
  --hairline: #ced0d4;
  --hairline-soft: #dee3e9;
  --fb-blue: #1876f2;

  --ink-button: #000000;
  --on-ink-button: #ffffff;
  --charcoal: #444950;

  /* The brand blue is #01a2ff (brand/AnyBridge_symbol.svg), but it cannot be used
     as text: 2.76:1 on white, under even the 3:1 large-text floor. This is the
     same hue and chroma with lightness 50% -> 45%, which measures 3.39:1. It is
     the page's only use of the brand colour outside the symbol itself. */
  --brand-text: #0091e6;

  /* the sticky nav's total height, used by the hero to fill exactly one screen.
     Kept as a token so the two can't drift apart. */
  --nav-h: 65px;

  /* rounding */
  --r-xl: 16px;
  --r-xxxl: 32px;
  --r-full: 100px;

  /* spacing */
  --sp-xs: 8px;
  --sp-md: 12px;
  --sp-base: 16px;
  --sp-lg: 20px;
  --sp-xl: 24px;
  --sp-xxl: 32px;
  --sp-xxxl: 40px;
  --sp-section-sm: 48px;
  --sp-section: 64px;
  --sp-section-lg: 80px;
  --sp-hero: 120px;

  /* Inter covers latin, Noto Sans KR covers hangul; each @font-face in
     fonts.css is unicode-range scoped, so the two never compete. */
  --font: Inter, "Noto Sans KR", -apple-system, BlinkMacSystemFont, "Segoe UI",
          Roboto, "Apple SD Gothic Neo", "Malgun Gothic", Helvetica, Arial,
          sans-serif;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  /* the nav is sticky and 65px tall; without this a pill tab parks its target
     section's h2 underneath it, landing the reader on an untitled section */
  scroll-padding-top: var(--sp-section-lg);
}

body {
  background: var(--canvas);
  color: var(--ink-deep);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.5;
  letter-spacing: -0.16px;
}

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

a { color: inherit; text-decoration: none; }

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

/* CSS breaks CJK between any two syllables by default, which splits Korean
   words mid-word at the end of a line ("절감" → "절" / "감"). keep-all breaks
   at spaces only, the way Latin text already behaves. */
[lang="ko"] { word-break: keep-all; }

/* ── typography roles (DESIGN.md scale) ─────────────────────────────────── */

.hero-display {
  font-size: 64px;
  font-weight: 500;
  line-height: 1.16;
  letter-spacing: 0;
}

.heading-lg {
  font-size: 36px;
  font-weight: 500;
  line-height: 1.28;
  letter-spacing: 0;
}

.heading-sm {
  font-size: 24px;
  font-weight: 500;
  line-height: 1.25;
  letter-spacing: 0;
}

/* Each prose role is 1px above DESIGN.md's token (18/16/14). The spec was read
   off a US commerce site; this page carries dense bilingual copy, and hangul at
   14px is genuinely hard to read. The 2px steps between roles are preserved, so
   the hierarchy is unchanged. */
.subtitle-md { font-size: 19px; font-weight: 400; line-height: 1.44; letter-spacing: 0; }
.body-md { font-size: 17px; font-weight: 400; line-height: 1.5; letter-spacing: -0.16px; }
.body-sm { font-size: 15px; font-weight: 400; line-height: 1.43; letter-spacing: -0.14px; }
.caption { font-size: 12px; font-weight: 400; line-height: 1.33; letter-spacing: 0; }

.eyebrow {
  /* 13px, not the 12px caption size: this line carries the Korean card title,
     which is content rather than a label, and hangul needs more size than Latin
     at the same nominal px. Still under .body-sm (15px) so the hierarchy holds. */
  font-size: 13px;
  font-weight: 700;
  line-height: 1.33;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--steel);
}

/* the eyebrow's 0.08em tracking is for Latin caps; hangul with positive letter
   spacing reads as separated characters, so the Korean half resets it */
.eyebrow-ko { letter-spacing: 0; }

/* Line breaking. Left to itself the browser fills every line to the last word
   that fits, so phrases split at meaningless points and the last line is often
   a single stranded word. CSS has native controls for exactly this, no JS and
   no hand-placed <br>: `balance` evens the line lengths across a short block,
   which keeps headings and lead paragraphs breaking near clause boundaries;
   `pretty` leaves longer body copy alone but refuses to end it on an orphan.
   (Korean is handled separately by word-break: keep-all above.) */
.hero-display,
.heading-lg,
.heading-sm,
.hero-sub,
.hero-sub-ko,
.section-intro,
.section-intro-ko,
.contact-sub,
.contact-sub-ko { text-wrap: balance; }

.body-md,
.card-ko { text-wrap: pretty; }

/* ── buttons (pill, per spec) ───────────────────────────────────────────── */

.btn {
  display: inline-block;
  font-size: 14px;
  font-weight: 700;
  line-height: 1.43;
  letter-spacing: -0.14px;
  border-radius: var(--r-full);
  transition: background-color 200ms ease-out, border-color 200ms ease-out;
}

.btn-primary {
  background: var(--ink-button);
  color: var(--on-ink-button);
  padding: 14px 30px;
}
.btn-primary:active { background: var(--charcoal); }


/* DESIGN.md defines no primary for dark surfaces: button-primary is black on
   white and would vanish on ink-deep. This is button-primary inverted. */
.btn-invert {
  background: var(--canvas);
  color: var(--ink-deep);
  padding: 14px 30px;
}
.btn-invert:active { background: var(--hairline-soft); }

.pill-tab {
  display: inline-block;
  background: var(--canvas);
  color: var(--ink);
  font-size: 14px;
  font-weight: 700;
  line-height: 1.43;
  letter-spacing: -0.14px;
  border: 1px solid var(--hairline);
  border-radius: var(--r-full);
  /* DESIGN.md contradicts itself here: button-pill-tab specifies `8px 16px`,
     which on 14px/1.43 text yields a 38px target, but the spec's own Touch
     Targets section says pill buttons "render at 40-44px effective height …
     above the WCAG AAA 44px floor". Following the stated accessibility intent
     over the token: 11px vertical lands the tab at exactly 44px. */
  padding: 11px 16px;
  transition: background-color 200ms ease-out;
}
/* the dark fill replaces the border in the active state, per DESIGN.md */
.pill-tab:active { background: var(--ink-deep); border-color: var(--ink-deep); color: var(--canvas); }

/* ── nav ────────────────────────────────────────────────────────────────── */

.nav {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--canvas);
  border-bottom: 1px solid var(--hairline-soft);
}

.nav-inner {
  height: calc(var(--nav-h) - 1px);   /* the 1px is .nav's bottom border */
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.wordmark {
  display: inline-flex;
  align-items: center;
}

/* the actual brand lockup (Logoguidelines_AnyBridge_2307_signage.pdf),
   traced to vector paths rather than reset in a look-alike webfont */
.wordmark-lockup {
  display: block;
  height: 28px;
  width: auto;
}

.nav-links {
  display: flex;
  align-items: center;
  gap: var(--sp-md);
}

/* ── hero ───────────────────────────────────────────────────────────────── */

.hero {
  /* the first screen shows the hero and nothing else. svh, not vh or dvh: vh is
     measured with the mobile browser chrome hidden so the hero would overflow the
     visible area, and dvh changes as that chrome collapses, which makes the page
     jump while scrolling. svh is the smallest viewport, i.e. exactly what a
     visitor sees on load. min-height, not height, so a short window grows the
     hero instead of clipping it. */
  min-height: calc(100vh - var(--nav-h));
  min-height: calc(100svh - var(--nav-h));
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-block: var(--sp-hero);
  text-align: center;
}

.hero-display span { display: block; }

/* the brand blue on the two "Any"s and on "bridge". A plain span, not <em>:
   this is colour, not emphasis, and <em> would make a screen reader announce
   it. Read in order the three highlights spell the company name. */
.hero-display .hl { display: inline; color: var(--brand-text); }

/* The fourth line is the claim the first three set up, so it stays inside the
   h1 but drops a tier: at display size it needs 1400px and wraps even on the
   widest layout, which reads as a mistake rather than a second thought. Sized
   per breakpoint rather than in em, because an em that keeps this ratio falls
   under the 16px body text once .hero-display steps down to 24px. */
.hero-claim {
  font-size: 40px;
  color: var(--slate);
  margin-top: var(--sp-md);
}

.hero-sub {
  margin-top: var(--sp-xl);
  color: var(--slate);
}

.hero-sub-ko {
  margin-top: var(--sp-md);
  color: var(--steel);
}

.hero-ctas {
  margin-top: var(--sp-xxxl);
  display: flex;
  justify-content: center;
  gap: var(--sp-base);
  flex-wrap: wrap;
}

/* load-in: one orchestrated rise, staggered. The hidden start state lives in
   the keyframe rather than the rule, and fill-mode `both` holds it through the
   stagger delay, so if animations never run at all, the hero renders visible
   instead of invisible. */
.rise {
  animation: rise 500ms ease-out both;
}
.r1 { animation-delay: 0ms; }
.r2 { animation-delay: 90ms; }
.r3 { animation-delay: 180ms; }
.r4 { animation-delay: 320ms; }
.r5 { animation-delay: 440ms; }
.r6 { animation-delay: 560ms; }

@keyframes rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .rise { animation: none; opacity: 1; transform: none; }
}

/* ── dark strip (card-promo-strip) ──────────────────────────────────────── */

.contact-strip {
  background: var(--ink-deep);
  color: var(--canvas);
  border-radius: var(--r-xxxl);
  padding: var(--sp-section);
  text-align: center;
}




/* ── content sections (platform, products) ──────────────────────────────── */

.features,
.careers { padding-bottom: var(--sp-section-lg); }

/* the two section titles carry the brand colour. Scoped to the sections so the
   Join us heading inside the dark strip keeps its white. heading-lg is 36px, so
   the 3:1 large-text floor applies and --brand-text's 3.39:1 clears it. */
.features > .container > h2,
.careers > .container > h2 { color: var(--brand-text); }

/* No measure cap on the section leads. They sit on the open canvas, so a cap
   made them wrap three times with half the container empty to the right. The
   1280px .container is the only bound, which puts the worst case around 135
   characters: long for reading, fine as long as these stay one or two lines.
   Inside the cards and the dark strips the column is genuinely narrow, so the
   caps there stay. */
.section-intro {
  margin-top: var(--sp-base);
  color: var(--ink);
}

.section-intro-ko {
  margin-top: var(--sp-xs);
  color: var(--slate);
}

/* icon is decorative: the eyebrow directly below it is the card's label */
.feature-card-icon { width: 40px; height: 40px; margin-bottom: var(--sp-base); }

.feature-grid {
  margin-top: var(--sp-xxxl);
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--sp-xl);
}

.feature-card {
  background: var(--canvas);
  border: 1px solid var(--hairline-soft);
  border-radius: var(--r-xl);
  padding: var(--sp-xxl);
  container-type: inline-size;
}

/* The <br>s in the mission bodies are authored breaks: they put one clause on
   each line. They only hold while the card is wide enough for the longest of
   those clauses (501px measured); narrower, the clause wraps anyway and the
   forced break just strands a two-word orphan under it, so drop it and let the
   text reflow. This has to be a container query, not a width query: the grid is
   2-col above 1023px and 1-col below, so a card is narrow at 1024px and wide at
   900px. No viewport threshold can express that. */
@container (max-width: 500px) {
  .body-md br { display: none; }
}

.feature-card .heading-sm { margin-top: var(--sp-xs); }
/* that 8px spaces the title below an eyebrow; the work-field cards have no
   eyebrow, so there their title is the card's first line and needs none */
.feature-card > .heading-sm:first-child { margin-top: 0; }
.feature-card .body-md { margin-top: var(--sp-md); color: var(--ink); }
.card-ko { margin-top: var(--sp-md); color: var(--slate); }

/* Only the parked careers cards use .stack (see the comment in index.html).
   Kept so restoring that block needs no CSS work. */
.stack {
  list-style: none;
  margin-top: var(--sp-lg);
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-xs);
}

.stack li {
  /* a pill is one token: never let its label break inside itself */
  white-space: nowrap;
  font-size: 12px;
  font-weight: 700;
  line-height: 1.33;
  color: var(--ink);
  background: var(--canvas);
  border: 1px solid var(--hairline);
  border-radius: var(--r-full);
  padding: 5px 12px;
}

/* ── contact call (inside Careers) ──────────────────────────────────────── */

/* a full section beat, not a card gap: the strip is its own moment, and at
   --sp-xxxl it read as the fifth item in the role grid above it */
.contact-strip { margin-top: var(--sp-section-lg); }

.contact-sub {
  margin-top: var(--sp-md);
  max-width: 52ch;
  margin-inline: auto;
}

.contact-sub-ko {
  margin-top: var(--sp-xs);
  color: rgba(255, 255, 255, 0.72);
}

.contact-strip .btn { margin-top: var(--sp-xl); }

/* ── footer ─────────────────────────────────────────────────────────────── */

.footer {
  border-top: 1px solid var(--hairline-soft);
  padding-block: var(--sp-xxl);
  /* steel, not stone: stone is 3.07:1 on white and fails WCAG AA for the 12px
     legal line. steel is 5.39:1, and is what DESIGN.md's footer-region
     specifies anyway (stone is the disabled/de-emphasized token). */
  color: var(--steel);
}

/* ── responsive (DESIGN.md breakpoints) ─────────────────────────────────── */

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

@media (max-width: 767px) {
  .container { padding-inline: var(--sp-lg); }
  .hero { padding-block: var(--sp-section-lg); }
  .hero-display { font-size: 36px; line-height: 1.28; }
  .hero-claim { font-size: 24px; }
  .contact-strip { padding: var(--sp-section-sm) var(--sp-xl); }
  .heading-lg { font-size: 28px; }
  .feature-card { padding: var(--sp-xl); }
  /* both tabs stay reachable: tightened, not hidden (see the header note).
     Horizontal padding shrinks to fit 320px; vertical padding grows so the tap
     target stays at 44px, the WCAG floor. */
  .nav-links { gap: var(--sp-xs); }
  .pill-tab { padding: 12px; font-size: 13px; }
  .wordmark-lockup { height: 24px; }
}

@media (max-width: 479px) {
  .hero-display { font-size: 24px; line-height: 1.25; }
  .hero-claim { font-size: 18px; }
}

/* A landscape phone has no room for a full-screen hero at display size: the nav
   takes 65px of a 390px viewport and the hero's own content is taller than what
   is left. The min-height above self-gates here (100svh - 65px is the smaller
   number, so content height wins and nothing clips) but the type is still too
   large for the space, so shrink it. Declared after the width queries so it wins
   at equal specificity. */
@media (max-height: 520px) {
  .hero { padding-block: var(--sp-xxl); }
  .hero-display { font-size: 36px; line-height: 1.28; }
}
