@charset "utf-8";

/* ============================================================
   HSM Media — site styles
   Phase 1. Derived from design/HSM Media Site.dc.html.
   Design-tool syntax (x-dc / sc-for / {{ }} / style-hover) removed.
   Grey ramp re-cut so every text tier clears 4.5:1 on both
   --bg and --surface. Accent red split into a decorative token
   and a text-safe token.
   ============================================================ */

/* ---------- tokens ---------- */
:root {
  /* surfaces */
  --bg:          #0C0C0E;
  --surface:     #111114;

  /* ink ramp — all >= 4.5:1 on --bg AND --surface */
  --ink:         #F2F2F0;  /* 17.43 / 16.82 */
  --ink-2:       #E4E4E8;  /* 15.41 / 14.87 */
  --ink-3:       #D4D4D9;  /* 13.23 / 12.76 */
  --ink-4:       #C6C6CB;  /* 11.48 / 11.08 */
  --ink-5:       #B4B4BA;  /*  9.47 /  9.14 */
  --ink-6:       #9A9AA0;  /*  6.98 /  6.74 */
  --ink-7:       #8E8E94;  /*  6.00 /  5.79 */
  --ink-8:       #82828C;  /*  5.14 /  4.96 — floor */

  /* accent — two tokens on purpose */
  --accent:      #E8241C;  /* logo cross red. DECORATION ONLY (4.37:1) */
  --accent-text: #FF3B30;  /* text-safe red (5.51 / 5.31) */

  /* hairlines (decorative, not text) */
  --line:        rgba(255, 255, 255, .12);
  --line-soft:   rgba(255, 255, 255, .08);
  --line-card:   rgba(255, 255, 255, .10);
  --line-strong: rgba(255, 255, 255, .20);
  --line-btn:    rgba(255, 255, 255, .26);

  /* rhythm — mobile first */
  --gutter:      20px;
  --section-gap: 88px;
  --rule-gap:    28px;

  /* type */
  --font-sans:    'IBM Plex Sans KR', system-ui, -apple-system, 'Malgun Gothic', sans-serif;
  --font-display: 'Archivo', 'Arial Narrow', system-ui, sans-serif;
  --font-mono:    'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
}

@media (min-width: 768px) {
  :root { --gutter: 40px; --section-gap: 130px; --rule-gap: 34px; }
}

/* ---------- base ---------- */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
  font-weight: 400;
  overflow-x: hidden;
}

::selection { background: var(--accent-text); color: var(--bg); }

a { color: var(--ink); text-decoration: none; }
a:hover { color: var(--accent-text); }

img { display: block; max-width: 100%; height: auto; }

:focus-visible {
  outline: 2px solid var(--accent-text);
  outline-offset: 3px;
  border-radius: 2px;
}

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  padding: 10px 16px; background: var(--ink); color: var(--bg);
  font-size: 14px; font-weight: 600;
}
.skip:focus { left: var(--gutter); top: 10px; color: var(--bg); }

.wrap { padding-inline: var(--gutter); }

/* ---------- shared type ---------- */
.eyebrow {
  margin: 0 0 18px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .2em;
  color: var(--accent-text);
  text-transform: uppercase;
}

.h2 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 900;
  font-stretch: 112%;
  font-size: clamp(30px, 3.6vw, 54px);
  line-height: 1;
  letter-spacing: -.03em;
  text-transform: uppercase;
}

.meta {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ink-8);
}

.section { padding-bottom: var(--section-gap); }

.section__head {
  display: flex; flex-wrap: wrap;
  align-items: flex-end; justify-content: space-between;
  gap: 32px;
  border-top: 1px solid var(--line);
  padding-top: var(--rule-gap);
}

/* hairline grid: 1px gap over the page ground reads as a rule */
.cardgrid { display: grid; gap: 1px; background: var(--bg); }
.card { background: var(--surface); outline: 1px solid var(--line-card); padding: 22px; }

.card__label {
  margin: 0 0 8px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .16em;
  color: var(--ink-7);
  text-transform: uppercase;
}

/* 16:9 spec placeholders carried over from the mockup */
.ph {
  position: relative;
  aspect-ratio: 16 / 9;
  border: 1px solid var(--line-strong);
  background: rgba(255, 255, 255, .02);
}
.ph__tag {
  position: absolute;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .14em;
  color: var(--ink-7);
}
.ph__tag--tl { top: 12px; left: 14px; }
.ph__tag--bl { bottom: 12px; left: 14px; letter-spacing: .12em; color: var(--ink-8); }
.ph__tag--tr { top: 12px; right: 14px; color: var(--ink-8); }

/* ---------- header ---------- */
.brand {
  flex: none;
  display: inline-flex; align-items: center; gap: 10px;
  min-width: 0;
}
.brand__mark { width: 26px; height: auto; }
.brand__name {
  font-family: var(--font-display);
  font-weight: 800; font-stretch: 108%;
  font-size: 14px; letter-spacing: .02em;
  text-transform: uppercase; white-space: nowrap;
  color: var(--ink);
}
.brand:hover .brand__name { color: var(--accent-text); }

.header {
  position: sticky; top: 0; z-index: 50;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 14px var(--gutter);
  background: rgba(12, 12, 14, .78);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line-soft);
}

.nav { display: flex; align-items: center; gap: 16px; min-width: 0; }

.nav__links {
  display: flex; align-items: center; gap: 20px;
  min-width: 0; overflow-x: auto;
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .14em;
  scrollbar-width: none;
}
.nav__links::-webkit-scrollbar { display: none; }
.nav__links a { color: var(--ink-7); white-space: nowrap; }
.nav__links a:hover { color: var(--accent-text); }

.nav__cta {
  flex: none;
  display: inline-flex; align-items: center; gap: 8px;
  color: var(--ink);
  border: 1px solid var(--line-btn); border-radius: 999px;
  padding: 8px 16px;
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .14em;
  white-space: nowrap;
}
.nav__cta:hover { color: var(--accent-text); border-color: var(--accent-text); }

@media (min-width: 768px) { .nav { gap: 28px; } .nav__links { gap: 28px; } }

/* ---------- hero ---------- */
.hero { position: relative; padding-inline: var(--gutter); overflow: hidden; }

/* Three glow layers, moved at different rates by motion.js.
   --a keeps the mockup's rainbow untouched; --b and --c are new washes
   pulled from the logo hues and desaturated so they read as light, not
   as colour blocks. */
.hero__glow { position: absolute; pointer-events: none; filter: blur(130px); }
.hero__glow--a {
  inset: auto -10% -34% -10%; height: 74%;
  background: linear-gradient(100deg, #E8241C, #F5A623, #D8E832, #3FD16A, #2FB8E8, #7B4BE8);
  opacity: .24;
}
.hero__glow--b {
  inset: auto -24% -46% 26%; height: 66%;
  background: linear-gradient(210deg, #3E8F63, #2F7E96);
  opacity: .20; filter: blur(150px);
}
.hero__glow--c {
  inset: -18% 18% auto -22%; height: 62%;
  background: linear-gradient(40deg, #6B4E96, #8C4A76);
  opacity: .18; filter: blur(160px);
}
.hero__fade {
  position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(120% 80% at 50% 120%, rgba(12, 12, 14, 0) 0%, var(--bg) 74%);
}

.hero__grid {
  position: relative;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr));
  gap: 40px;
  align-items: center;
  padding: 52px 0 72px;
}
.hero__copy { min-width: 0; display: flex; flex-direction: column; gap: 26px; }
.hero__media { min-width: 0; }

/* The hero h1 IS the lockup image — one asset carries mark and wordmark.
   The h1 (markwrap) takes the entrance transform and the img inside takes
   the scroll scrub, so the two never fight over the same transform. */
.hero__markwrap { margin: 0; line-height: 0; }
.hero__mark { width: min(100%, 300px); height: auto; }

.hero__sub {
  margin: 0; max-width: 520px;
  font-size: 15px; line-height: 1.75; color: var(--ink-6);
  text-wrap: pretty;
}
.hero__actions { display: flex; flex-wrap: wrap; gap: 10px; }

@media (min-width: 768px) {
  .hero__grid { gap: 56px; padding: 76px 0 104px; }
  .hero__copy { gap: 34px; }
  .hero__mark { width: min(100%, 420px); }
}

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; gap: 10px;
  border: 1px solid var(--line-btn); border-radius: 999px;
  padding: 13px 22px;
  font-size: 14px; font-weight: 500; color: var(--ink);
}
.btn:hover { color: var(--accent-text); border-color: var(--accent-text); }
.btn__arrow { font-family: var(--font-mono); }

.btn--primary {
  background: var(--ink); color: var(--bg);
  border-color: var(--ink); font-weight: 600;
}
.btn--primary:hover { background: #FFF; border-color: #FFF; color: var(--bg); }

/* ---------- ticker ---------- */
.ticker {
  border-top: 1px solid var(--line-soft);
  border-bottom: 1px solid var(--line-soft);
  overflow: hidden; padding: 16px 0;
}
.ticker__track {
  display: flex; width: max-content; gap: 56px;
  font-family: var(--font-display); font-weight: 800; font-stretch: 112%;
  font-size: 15px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-8);
  animation: hsmMarquee 34s linear infinite;
  will-change: transform;
}
.ticker__dot { color: var(--accent-text); }

@keyframes hsmMarquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

/* ---------- about ---------- */
.about { display: grid; gap: 34px; padding-block: var(--section-gap); }
.about__body {
  display: flex; flex-direction: column; gap: 26px;
  max-width: 760px;
  font-size: 16px; line-height: 1.85; color: var(--ink-5);
  text-wrap: pretty;
}
.about__body p { margin: 0; }
.about__body strong { color: var(--ink); font-weight: 600; }

.about__h2 {
  margin: 0;
  font-family: var(--font-display); font-weight: 900; font-stretch: 112%;
  font-size: clamp(34px, 4vw, 60px); line-height: .94; letter-spacing: -.03em;
  text-transform: uppercase;
}

.about__cards {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 190px), 1fr));
  margin-top: 14px;
}
.about__name {
  margin: 0;
  font-family: var(--font-display); font-weight: 800; font-stretch: 108%;
  font-size: 20px; color: var(--ink);
}
.about__val { margin: 6px 0 0; font-size: 13px; color: var(--ink-6); }
.about__val--tight { margin: 0; font-size: 14px; line-height: 1.65; color: var(--ink-4); }

.mail-link { font-size: 14px; color: var(--ink); border-bottom: 1px solid rgba(232, 36, 28, .6); }
.mail-link:hover { color: var(--accent-text); border-bottom-color: var(--accent-text); }

@media (min-width: 900px) {
  .about { grid-template-columns: minmax(200px, .5fr) minmax(0, 1fr); gap: 56px; }
}

/* ---------- what we do ---------- */
.services {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
  margin-top: 52px;
}
.services .card {
  display: flex; flex-direction: column; gap: 16px;
  padding: 34px 30px 38px;
}
.services__num { margin: 0; font-family: var(--font-mono); font-size: 11px; color: var(--accent-text); }
.services__title {
  margin: 0;
  font-family: var(--font-display); font-weight: 800; font-stretch: 108%;
  font-size: 24px; letter-spacing: -.02em; text-transform: uppercase;
}
.services__body { margin: 0; font-size: 14px; line-height: 1.8; color: var(--ink-6); text-wrap: pretty; }

.work__h2 { max-width: 900px; }

/* ---------- works ---------- */
.works {
  display: grid; gap: 26px; margin-top: 52px;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
}
.work-card { display: flex; flex-direction: column; gap: 16px; }
.work-card__text { display: flex; flex-direction: column; gap: 8px; }
.work-card__kindrow { display: flex; align-items: center; gap: 10px; }
.work-card__dot { display: inline-block; width: 6px; height: 6px; background: var(--accent); }
.work-card__kind {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .14em; color: var(--ink-7);
}
.work-card__title {
  margin: 0;
  font-family: var(--font-display); font-weight: 800; font-stretch: 106%;
  font-size: 21px; letter-spacing: -.02em;
}
.work-card__desc { margin: 0; font-size: 13.5px; line-height: 1.7; color: var(--ink-7); }
.work-card .ph { border-color: rgba(255, 255, 255, .18); }

.work-detail {
  display: grid; gap: 32px; align-items: start;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr));
  margin-top: 72px;
  border-top: 1px solid var(--line);
  padding-top: var(--rule-gap);
}
.work-detail__title {
  margin: 0 0 16px;
  font-family: var(--font-display); font-weight: 800; font-stretch: 108%;
  font-size: 28px; letter-spacing: -.02em;
}
.work-detail__lede { margin: 0 0 26px; font-size: 14px; line-height: 1.8; color: var(--ink-6); }
.spec { display: flex; flex-direction: column; gap: 1px; background: var(--bg); }
.spec__row {
  display: flex; gap: 20px;
  background: var(--surface); outline: 1px solid var(--line-card);
  padding: 14px 18px;
}
.spec__key {
  min-width: 76px;
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .14em; color: var(--ink-7);
}
.spec__val { font-size: 13.5px; color: var(--ink-3); }

@media (min-width: 768px) { .work-detail { gap: 48px; margin-top: 104px; } }

/* ---------- news ---------- */
.news { margin-top: 44px; display: flex; flex-direction: column; }
.news__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 40px;
  column-gap: 28px; row-gap: 6px;
  align-items: center;
  padding: 22px 4px;
  border-top: 1px solid var(--line-card);
}
.news__row:hover { background: var(--surface); }
.news__date { grid-column: 1; font-family: var(--font-mono); font-size: 12px; color: var(--ink-7); }
.news__title { grid-column: 1; font-size: 17px; font-weight: 500; color: var(--ink); }
.news__arrow {
  grid-column: 2; grid-row: 1 / 3; justify-self: end;
  font-family: var(--font-mono); font-size: 13px; color: var(--ink-7);
}
.news__end { border-top: 1px solid var(--line-card); }

@media (min-width: 768px) {
  .news__row { grid-template-columns: 150px minmax(0, 1fr) 40px; row-gap: 0; padding: 26px 4px; }
  .news__date { grid-column: 1; }
  .news__title { grid-column: 2; }
  .news__arrow { grid-column: 3; grid-row: auto; }
}

/* ---------- vision ---------- */
.vision__inner { border-top: 1px solid var(--line); padding-top: var(--rule-gap); }
.vision .eyebrow { margin-bottom: 44px; }
.vision__body {
  margin: 0; max-width: 1000px;
  font-size: clamp(21px, 2.3vw, 32px);
  line-height: 1.55; letter-spacing: -.02em; font-weight: 400;
  color: var(--ink); text-wrap: pretty;
}
/* footnote: smaller and quieter than the body, but still 5.14:1 */
.vision__note { margin: 26px 0 0; font-size: 13px; color: var(--ink-8); }

/* ---------- contact ---------- */
.contact__inner { border-top: 1px solid var(--line); padding-top: var(--rule-gap); }
.contact__h2 { margin-bottom: 20px; }
.contact__lede { margin: 0 0 46px; font-size: 16px; line-height: 1.8; color: var(--ink-6); }
.contact__mail {
  display: block;
  font-family: var(--font-display); font-weight: 900; font-stretch: 100%;
  font-size: clamp(30px, 6.6vw, 104px);
  line-height: 1; letter-spacing: -.04em;
  color: var(--ink); word-break: break-word;
}
.contact__mail:hover { color: var(--accent-text); }
.contact__cards {
  margin-top: 64px;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 210px), 1fr));
}
.contact__val { margin: 0; font-size: 14px; line-height: 1.6; color: var(--ink-2); }
a.contact__val:hover { color: var(--accent-text); }

/* ---------- footer ---------- */
/* The business record lives here now — provenance, not a pitch. */
.footer { padding-bottom: 44px; border-top: 1px solid var(--line-card); }

.footer__top { display: grid; gap: 28px; padding-top: 40px; }
.footer__brand { display: flex; align-items: center; gap: 12px; }
.footer__mark { width: 34px; height: auto; }
.footer__name {
  font-family: var(--font-display);
  font-weight: 800; font-stretch: 108%;
  font-size: 15px; letter-spacing: .02em;
  text-transform: uppercase; color: var(--ink-3);
}

.footer__biz {
  margin: 0;
  display: grid; gap: 1px; background: var(--bg);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr));
}
.bizrow { background: var(--surface); outline: 1px solid var(--line-card); padding: 18px 20px; }
.bizrow__key {
  margin: 0 0 6px;
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--ink-7);
}
.bizrow__val { margin: 0; font-size: 14px; line-height: 1.6; color: var(--ink-2); }
.bizrow__val a { color: var(--ink-2); }
.bizrow__val a:hover { color: var(--accent-text); }

.footer__bottom {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 20px;
  margin-top: 36px; padding-top: 24px;
  border-top: 1px solid var(--line-card);
}
.footer__copy { font-family: var(--font-mono); font-size: 11px; color: var(--ink-7); }
.footer__links {
  display: flex; flex-wrap: wrap; gap: 22px;
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .1em;
}
.footer__links a { color: var(--ink-7); }
.footer__links a:hover { color: var(--accent-text); }

@media (min-width: 768px) {
  .footer__top { grid-template-columns: auto minmax(0, 1fr); gap: 48px; align-items: start; }
}

/* ============================================================
   motion
   Everything that starts hidden is scoped to .has-js, so with
   JavaScript off the page renders fully visible. transform and
   opacity only.
   ============================================================ */

/* Shared motion values. Everything reveals with the same distance,
   duration and easing so the page reads as one system. */
:root {
  --rise:  36px;
  --dur:   .9s;
  --ease:  cubic-bezier(.16, 1, .3, 1);
  --step:  90ms;
}

/* ---- 1. hero entrance ---- */
.has-js .hero__copy > * {
  opacity: 0;
  transform: translateY(var(--rise)) scale(.96);
  transition:
    opacity   var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}
.has-js .hero.is-in .hero__copy > * { opacity: 1; transform: none; }

/* lockup h1 -> sub -> button, 90ms apart; the 16:9 slot follows at 270ms.
   nth-child(4) is kept for the case a fourth block returns to the column. */
.has-js .hero__copy > *:nth-child(1) { transition-delay: calc(0 * var(--step)); }
.has-js .hero__copy > *:nth-child(2) { transition-delay: calc(1 * var(--step)); }
.has-js .hero__copy > *:nth-child(3) { transition-delay: calc(2 * var(--step)); }
.has-js .hero__copy > *:nth-child(4) { transition-delay: calc(3 * var(--step)); }

/* ---- 2-2-3. logo entrance ----
   The logo does not rise like the rest of the column — it unwinds into
   place. Higher specificity so it beats the generic column rule above. */
.has-js .hero__copy > .hero__markwrap { transform: scale(.7) rotate(-8deg); }
.has-js .hero.is-in .hero__copy > .hero__markwrap { transform: none; }

/* 16:9 slot joins the sequence after the buttons */
.has-js .hero__media {
  opacity: 0;
  transform: translateY(var(--rise)) scale(.96);
  transition:
    opacity   var(--dur) var(--ease),
    transform var(--dur) var(--ease);
  transition-delay: calc(3 * var(--step));   /* 270ms — hero copy now has 3 children */
}
.has-js .hero.is-in .hero__media { opacity: 1; transform: none; }

/* ---- 2. section entrance stagger ----
   Hidden from first paint under .has-js so nothing flashes before the
   observer runs. --d is the per-sibling delay, set by motion.js. */
.has-js #services .services > .card,
.has-js #works .works > .work-card,
.has-js #notices .news__row {
  opacity: 0;
  transform: translateY(var(--rise)) scale(.96);
  transition:
    opacity   var(--dur) var(--ease),
    transform var(--dur) var(--ease);
  transition-delay: var(--d, 0ms);
}
.has-js #services .services > .card.is-in,
.has-js #works .works > .work-card.is-in,
.has-js #notices .news__row.is-in { opacity: 1; transform: none; }

/* ---- 2-2-1. kinetic headlines ----
   Structural rules are NOT scoped to .has-js: once motion.js has split a
   heading the markup must render correctly even if the enhancement is
   later dropped (reduced motion). The animated state is scoped.
   Lines are measured at the FINAL width, so growing 'wdth' back to rest
   can never re-wrap them. */
.kt-line {
  display: block;
  overflow: hidden;
  /* room for descenders inside the mask without changing layout height */
  padding-bottom: .14em;
  margin-bottom: -.14em;
}
.kt-word { display: inline-block; white-space: nowrap; }
.kt-char { display: inline-block; }

.has-js .kt-anim .kt-char {
  transform: translateY(115%);
  font-variation-settings: 'wdth' 85;
  transition:
    transform               var(--dur) var(--ease),
    font-variation-settings var(--dur) var(--ease);
  transition-delay: var(--cd, 0ms);
}
.has-js .kt-anim.is-in .kt-char {
  transform: none;
  font-variation-settings: 'wdth' var(--wdth, 100);
}
/* muted while a heading is being re-measured (font load, resize) */
.kt-nofx .kt-char { transition: none !important; }

/* ---- 4. hover / focus ----
   Plain CSS, deliberately NOT scoped to .has-js: these work with
   JavaScript off. Motion is transform-only; the colour changes were
   already in place and stay instant, per the transform/opacity rule.
   Pointer motion is gated on (hover: hover) so it cannot stick on touch.
   The `.is-in:hover` duplicates exist only to out-specify the reveal
   rule above, which pins `transform` on revealed elements. */
.nav__links a { position: relative; }
.nav__links a::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: -5px; height: 1px;
  background: currentColor;
  transform: scaleX(0); transform-origin: left center;
  transition: transform .28s cubic-bezier(.22, .61, .36, 1);
}
.btn, .nav__cta { transition: transform .25s cubic-bezier(.22, .61, .36, 1); }
.btn__arrow, .news__arrow { display: inline-block; transition: transform .25s cubic-bezier(.22, .61, .36, 1); }
.services .card { position: relative; transition: transform .3s cubic-bezier(.22, .61, .36, 1); }
.work-card .ph, .work-card__title { transition: transform .32s cubic-bezier(.22, .61, .36, 1); }

@media (hover: hover) and (pointer: fine) {
  .nav__links a:hover::after { transform: scaleX(1); }

  .btn:hover { transform: translateY(-2px); }
  .btn:hover .btn__arrow { transform: translateX(3px); }
  .nav__cta:hover { transform: translateY(-1px); }

  .services .card:hover { transform: translateY(-4px); z-index: 1; }
  .has-js #services .services > .card.is-in:hover { transform: translateY(-4px); }

  .work-card:hover .ph { transform: scale(1.02); }
  .work-card:hover .work-card__title { transform: translateX(3px); }

  .news__row:hover .news__arrow { transform: translateX(4px); }
}

/* keyboard parity — outside the hover query so it always applies */
.nav__links a:focus-visible::after { transform: scaleX(1); }
.btn:focus-visible { transform: translateY(-2px); }
.nav__cta:focus-visible { transform: translateY(-1px); }
.work-card:focus-visible .ph { transform: scale(1.02); }

/* ---- 2-2-2. scroll scrub ----
   The ticker is not part of the scrub: it runs purely on its CSS keyframe
   at a constant speed and direction, with or without JavaScript. */
.has-js .hero__mark { will-change: transform, opacity; }

/* ---- 3. background glow drift ----
   Only promoted to its own layer while it is actually drifting
   (desktop). The blur is expensive; no point paying for it on mobile. */
.has-js .hero__glow.is-drifting { will-change: transform; }

/* ---------- reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  .ticker__track { animation: none; }
  .has-js .hero__glow { transform: none !important; will-change: auto; }
  .has-js .hero__copy > * { opacity: 1; transform: none; transition: none; }
  .has-js .hero__copy > .hero__markwrap { transform: none; }
  .has-js .hero__mark { transform: none; opacity: 1; }
  .has-js .hero__media { opacity: 1; transform: none; transition: none; }
  .has-js #services .services > .card,
  .has-js #works .works > .work-card,
  .has-js #notices .news__row { opacity: 1; transform: none; transition: none; }

  /* hover: keep the affordance, drop the movement */
  .nav__links a::after, .btn, .nav__cta, .btn__arrow, .news__arrow,
  .services .card, .work-card .ph, .work-card__title { transition: none; }
  .btn:hover, .btn:focus-visible,
  .nav__cta:hover, .nav__cta:focus-visible,
  .btn:hover .btn__arrow,
  .services .card:hover,
  .has-js #services .services > .card.is-in:hover,
  .work-card:hover .ph, .work-card:focus-visible .ph,
  .work-card:hover .work-card__title,
  .news__row:hover .news__arrow { transform: none; }
  .nav__links a:hover::after, .nav__links a:focus-visible::after { transform: scaleX(1); }

  /* kinetic headlines: show at rest width, no mask travel */
  .has-js .kt-anim .kt-char {
    transform: none;
    font-variation-settings: 'wdth' var(--wdth, 100);
    transition: none;
  }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}
