/* ===== src/app/apply/apply.module.css  →  .m-apply-* ===== */
/*
 * /apply — the Contact us section, repainted for a white sheet.
 *
 * Nothing is removed or rearranged here. The page renders the very same
 * `ApplySection` that /consultant and /recruit render — same Contact us title,
 * same two-line lead, same 지원 안내 column with its copy, SNS badges and
 * 대표번호, same form column, same grid, same spacing. Only `tone="light"`
 * differs, which drops the photograph and its scrim and lets the rules below
 * re-tint the palette.
 *
 * Why the overrides live here rather than in globals.css: the .apply-* rules
 * are shared with the two dark pages, and this is the only surface on the site
 * that is white. Scoping them under this module's .page wrapper means the dark
 * pages cannot be reached by them. Each selector is one class deeper than the
 * Tailwind utility it has to beat (.text-white on the title and the rule, the
 * badge utilities), so no !important is needed anywhere.
 */

.m-apply-page {
  --apply-ink: #0f1b33;      /* headings, phone, title            */
  --apply-body: #3d4757;     /* body copy                         */
  --apply-muted: #6b7686;    /* captions                          */
  --apply-line: rgba(15, 27, 51, 0.14);
  background: #fff;
}

/* ---------------------------------------------------------------- surface */

.m-apply-page .apply-section--light {
  background: #fbfbfc;
}

/* ------------------------------------------------------------------ title */

.m-apply-page .apply-section--light .contact-display {
  color: var(--apply-ink);
}

.m-apply-page .apply-section--light .apply-lead {
  color: var(--apply-body);
}

/* ------------------------------------------------------- 지원 안내 column */

.m-apply-page .apply-section--light .apply-side-title {
  color: var(--apply-ink);
}

.m-apply-page .apply-section--light .apply-side-copy {
  color: var(--apply-body);
}

.m-apply-page .apply-section--light .rule {
  color: var(--apply-ink);
}

.m-apply-page .apply-section--light .apply-contact {
  border-top-color: var(--apply-line);
}

/* 대표번호는 Footer 의 것과 같은 타이포로 읽히게 한다 (클라이언트 지시):
   Footer 의 번호는 `.footer-details p` 안의 평범한 본문 한 줄이라 body 의
   Pretendard 스택 · weight 500 · 13px 로 그려진다. 여기 기본값이던 serif
   34px 를 그 세 값으로만 맞춘다 — 색·간격·hover 는 이 페이지 것을 유지한다.

   크기만 Footer 기준 13px 에서 14.5px 로 한 번 더 올렸다 (+11.5%). 왼쪽 안내
   영역은 Footer 보다 여백이 넓어 같은 13px 이 실제로는 더 작아 보였다.
   font-family · weight · color 와 두 줄 사이 간격(`.apply-phone-note` 의
   margin-top 6px)은 그대로다 — 간격을 px 로 두었으므로 글자만 커지고 두 줄이
   붙어 보이는 지금의 리듬은 유지된다. */
.m-apply-page .apply-section--light .apply-phone {
  color: var(--apply-ink);
  font-family: inherit;
  font-weight: 500;
  font-size: 14.5px;
}

.m-apply-page .apply-section--light .apply-phone-note {
  color: var(--apply-muted);
  font-size: 14.5px;
}

/* ------------------------------------------------------------ SNS badges */

.m-apply-page .apply-section--light .apply-badges a,
.m-apply-page .apply-section--light .apply-badges span {
  border-color: var(--apply-line);
  color: var(--apply-ink);
}

.m-apply-page .apply-section--light .apply-badges a:hover {
  background: var(--apply-ink);
  color: #fff;
}

/* ------------------------------------------------------------ submit pill */

.m-apply-page .apply-section--light .btn-pill {
  border-color: #090909;
  background: #090909;
  color: #fff;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

@media (min-width: 991px) {
  .m-apply-page .apply-section--light .btn-pill:hover {
    background: transparent;
    color: #090909;
  }
}

/* ===== src/app/home.module.css  →  .m-home-* ===== */
/* HOME — TAESHIN COLOR SYSTEM, and the page's scroll staircase. Page-scoped.
 *
 * This file was colour-only, and most of it still is: everything from the
 * METRICS section down sets `background` and `color` and stops there.
 *
 * It now also carries HOME's STACKING GEOMETRY — the sticky ranges and stop
 * positions that make the hero, Metrics and the 01·02·03 set climb over one
 * another. That lives here for the same reason the colours do: the class names
 * it reaches (`.metrics-section`, `.why-section`) are declared globally and
 * shared, so pinning them from `globals.css` would change every page that uses
 * them. Reached through `:global()` from the HOME wrapper, nothing outside
 * `<main>` on `/` can see any of it, and globals.css is untouched.
 *
 * WHY THIS FILE EXISTS
 *
 * The navy HOME was painted in came from `:root` (`--bg-navy`, `--bg-deep`,
 * `--bg-carbon`) and from global selectors that other pages share:
 *
 *   .why-wrap / .why-section / .why-media-scrim   also used by /support
 *   .portfolio-section                            declared beside .gallery-section
 *   .metrics-section / .home-hero                 HOME only, but declared globally
 *
 * Re-pointing the variables would have repainted every page on the site, and
 * editing the global blocks would have repainted /support. So the whole colour
 * system is applied from ONE class on a HOME wrapper instead, reaching the
 * existing class names through `:global()`. Nothing outside `<main>` on `/`
 * can see any of it, and globals.css is untouched.
 *
 * THE PALETTE
 *
 *   MAIN NAVY    #102A3A   body / dark sections
 *   DEEP NAVY    #091A26   hero
 *   LIGHT NAVY   #19394A   lift tone — surfaces and the light-scene eyebrow
 *   WARM OFF-WHITE #F4F0E8 portfolio scene
 *   WARM IVORY   #FFF8EF   type on the copper scene (see RecruitCta.module.css)
 *   COPPER       #B8613F   recruit scene (see RecruitCta.module.css)
 *
 * The navy system is deliberately TWO section values, not four. The old ladder
 * (#000a20 / #020411 / #030616) spent three near-identical values on three
 * sections and bought no visible separation with any of them. Hero is deep,
 * the body is main, and that is the whole system.
 */

/* Ground behind the whole page, so nothing that is briefly uncovered — an
   overscroll, the moment a sticky section hands over — falls back to the old
   `body` navy. `body` itself is shared with every other page and is not
   touched. */
.m-home-theme {
  background: #102a3a;
}

/* --- THE STACKING SET ---------------------------------------------------- */

/* Bounds the sticky range of the hero and Metrics, and nothing else — no
 * colour, no geometry, no spacing.
 *
 * The hero is pinned so the star field stays behind Metrics while Metrics rises
 * over it; without a wrapper its sticky context would be `.theme`, which spans
 * the whole page, and the canvas would still be pinned and animating under
 * Portfolio. Ending the context after the 01·02·03 set unpins both once the set
 * has fully covered them.
 *
 * Metrics' own pin is not changed by this, only bounded: it still pins at the
 * top and is still covered by the set the same way. Portfolio and RecruitCta
 * are outside and are not affected. */
.m-home-stack {
  position: relative;
}

/* There is deliberately NO SPACER between Metrics and the set.
 *
 * A viewport-tall one was tried, to stop 01 showing under the band the moment
 * it seated. `.metricsPin` solves that on its own: the pin is a full viewport
 * tall, so the set's first panel sits exactly at the bottom edge of the screen
 * when the pin tops out — out of view, and already the next thing to move. The
 * spacer only added an empty scroll with nothing happening in it. */

/* --- WHERE METRICS STOPS ------------------------------------------------- */

/* NOT AT THE TOP OF THE SCREEN.
 *
 * `.sticky-stack` pins Metrics to `top: 0`, which took the band all the way up
 * and left the star field with nothing above it. Metrics is 611px against a
 * 950px viewport, and the finished frame is the band sitting in the LOWER part
 * of the screen with the hero still open above it.
 *
 * `bottom: 0` on the band itself was tried first and is wrong: a sticky box may
 * be shifted anywhere inside its containing block, so the constraint dragged
 * Metrics up into view at scroll position ZERO — measured at top=339 on a page
 * that had not been scrolled.
 *
 * THE PIN IS A WRAPPER INSTEAD. `.metricsPin` is a full-viewport box that pins
 * at `top: 0` with the band held against its bottom edge, so when it seats, the
 * band is at the bottom of the screen and the space above it is whatever the
 * viewport has left — correct at any window height, and it never sets or caps
 * the band's own height. The wrapper has no background, so what shows above the
 * band is the pinned hero. */
.m-home-metricsPin {
  position: sticky;
  top: 0;
  height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}

/* The band no longer pins itself — the wrapper does it. */
.m-home-theme .metrics-section {
  position: static;
}

/* --- 01·02·03 : THE SET CATCHES ONCE, AT ITS OWN START -------------------- */

/* ONLY 01 PINS, AND IT PINS AS THE SET'S START.
 *
 * 01 is the first panel of the set, so catching it at the top is catching the
 * SET at the top — which is the hand-off from Metrics. 02 and 03 are
 * deliberately left in normal flow and carry no rule at all: once 01 is held,
 * they simply scroll up over it as continuous content, which is how the trio
 * was composed to read.
 *
 * A pass of this pinned all three, and that was wrong — it turned one
 * composition into three steps and gave 01→02→03 the same weight of transition
 * as the hand-off between the big sets.
 *
 * So the page catches at exactly two places:
 *
 *   01              the start of the 01·02·03 SET
 *   태신 프로젝트     the section that covers the set
 *
 * and nowhere else. `:first-child` rather than a class, so nothing in
 * WhyTaeshin.tsx has to change and 02/03 cannot pick the rule up. */
.m-home-theme .why-section:first-child {
  position: sticky;
  top: 0;
}

/* --- 태신 프로젝트, AND THE LAST STEP ------------------------------------ */

/* Portfolio is a panel in the staircase too, not something the page flows past.
 * It climbs over the last 01·02·03 panel, reaches the top and holds there —
 * same `position: sticky; top: 0` as every step before it, nothing new.
 *
 * Recruit is the step that covers it, and it needs no rule of its own: it is
 * the next block in flow with its own opaque copper ground, which is exactly
 * how every panel in this staircase covers the one under it. Adding a pin to it
 * as well would only leave it stuck under the footer.
 *
 * The sticky range is `.theme`, which ends with Recruit, so Portfolio releases
 * at the bottom of the page rather than being held under anything that follows
 * `<main>`. */
.m-home-theme .portfolio-section {
  position: sticky;
  top: 0;
}

/* --- HERO — DEEP NAVY ---------------------------------------------------- */

/* Base colour only. The StarField canvas is `absolute inset-0` and covers the
   whole section, so this is what shows before the canvas paints and behind it
   afterwards. The canvas itself — the particles, its own gradient, the
   composition and every bit of motion — is NOT touched. */
.m-home-theme .home-hero {
  background: #091a26;
}

/* The veil is a flat colour wash over the star field, not part of it: same
   radial geometry, same three stops, same alphas — only the tint moves from
   the old #020411 to TAESHIN deep navy. This is the one place the hero's deep
   navy is actually visible, since the canvas covers the base colour above. */
.m-home-theme .home-hero-veil {
  background: radial-gradient(
    120% 68% at 50% 52%,
    rgba(9, 26, 38, 0.44) 0%,
    rgba(9, 26, 38, 0.1) 46%,
    rgba(9, 26, 38, 0.5) 100%
  );
}

/* --- METRICS — GLASS OVER THE STAR FIELD --------------------------------- */

/* Metrics used to paint its own ground: #0C2432, a shade under MAIN NAVY, so it
 * separated from the 01·02·03 set by depth. It is now a sheet of glass instead,
 * because the hero is pinned behind it — the star field is still running under
 * this band and is meant to be seen through it.
 *
 * WHERE THE GREY WAS COMING FROM: `saturate(0.4)`. Draining the blue out of the
 * star field is exactly what turns it grey, and combined with 5px of blur and a
 * 0.045 fill the band read as a tinted panel rather than as a window. The
 * saturate is gone entirely — clear glass does not recolour what is behind it,
 * so the field keeps its own blue and simply shows through.
 *
 * What is left is deliberately almost nothing: a 0.014 white fill, 2px of blur,
 * and a 1-in-4px horizontal striation at 0.016 for the faintest blind texture.
 * The blur is low enough that the streaks stay legible as streaks instead of
 * smearing into a wash.
 *
 * No navy, no grey and no white opaque ground anywhere in it.
 *
 * The band's own content, layout, figures, PartnerMarquee and its pin are
 * untouched — its type is white and its rules are white-alpha, which is what
 * they already were over the old navy, and the star field behind is dark enough
 * that none of them lost contrast. */
.m-home-theme .metrics-section {
  background:
    repeating-linear-gradient(
      180deg,
      rgba(255, 255, 255, 0.016) 0px,
      rgba(255, 255, 255, 0.016) 1px,
      rgba(255, 255, 255, 0) 1px,
      rgba(255, 255, 255, 0) 4px
    ),
    rgba(255, 255, 255, 0.014);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
}

/* --- 01·02·03 — ONE SET, ONE GROUND — MAIN NAVY -------------------------- */

/* The three features are a single SECTION SET, not three sections that happen
   to be adjacent, so they take ONE background between them. There is
   deliberately no per-chapter tint, no alternating ground and no variation of
   any kind inside the set: every `.why-section` resolves to the same value, and
   the only thing that changes from 01 to 03 is which side the photograph is on.
 *
 * THE VALUE IS THE ONE THE CEO MESSAGE'S 사업 수행 시스템 SECTION ACTUALLY
 * RENDERS, not a new colour picked to look like it. `.ceo-system` in globals.css
 * is `var(--bg-deep)`, and that section measured live on /greeting computes to
 * `rgb(2, 4, 17)` — #020411. The same literal is used here.
 *
 * The wrapper takes it too, so the ground is continuous behind the whole set
 * rather than three separately painted panels that happen to match.
 *
 * The staircase — the pin, the slide, the order it stacks in — is the set's one
 * motion language and is not touched here. */
.m-home-theme .why-wrap,
.m-home-theme .why-section {
  background: #020411;
}

/* LIGHT NAVY as a lift tone: the ground a photo frame sits on, visible only
   as the letterbox edge and while an image is still loading. */
.m-home-theme .why-media-frame {
  background: #19394a;
}

/* The 01·02·03 photo scrims, retinted and NOTHING else. Same two gradients,
   same directions, same stops, same alphas — #020411 becomes MAIN NAVY so the
   photographs still dissolve into the ground they sit on. The flipped mirror
   has to be restated because the global rule for it is more specific than the
   base one. */
.m-home-theme .why-media-scrim {
  background:
    linear-gradient(
      to right,
      rgba(16, 42, 58, 0.3) 0%,
      rgba(16, 42, 58, 0.06) 42%,
      rgba(16, 42, 58, 0.5) 100%
    ),
    linear-gradient(
      to bottom,
      rgba(16, 42, 58, 0.28) 0%,
      rgba(16, 42, 58, 0.04) 30%,
      rgba(16, 42, 58, 0.04) 70%,
      rgba(16, 42, 58, 0.28) 100%
    );
}

.m-home-theme .why-grid.is-flipped .why-media-scrim {
  background:
    linear-gradient(
      to left,
      rgba(16, 42, 58, 0.3) 0%,
      rgba(16, 42, 58, 0.06) 42%,
      rgba(16, 42, 58, 0.5) 100%
    ),
    linear-gradient(
      to bottom,
      rgba(16, 42, 58, 0.28) 0%,
      rgba(16, 42, 58, 0.04) 30%,
      rgba(16, 42, 58, 0.04) 70%,
      rgba(16, 42, 58, 0.28) 100%
    );
}

/* --- PORTFOLIO — LIGHT SCENE --------------------------------------------- */

/* WARM OFF-WHITE. The one light scene on HOME, and the reason the navy above
   it reads as a passage rather than as the whole page.
 *
 * Carousel mechanics are untouched: the 26px/s drift, the 420px card, the
 * 320/241 ratio, `imagePosition`, the duplicated track, the segment maths and
 * the indicator's markup all still come from ProjectRenderingCarousel.tsx and
 * globals.css exactly as before. Only the colours the block is drawn in change,
 * and the renderings themselves are not filtered, tinted or masked.
 *
 * Every value below was checked against #F4F0E8 for WCAG AA:
 *
 *   heading  #102A3A  13.1:1      eyebrow  #19394A  10.7:1
 *   body     #55656F   5.3:1      year     #5F6D76   4.7:1
 */
.m-home-theme .portfolio-section {
  background: #f4f0e8;
}

/* Restrained navy — LIGHT NAVY is a step off the heading rather than a grey,
   so the label belongs to the same family as the type under it. */
.m-home-theme .pf-home-eyebrow {
  color: #19394a;
}

.m-home-theme .pf-home-title,
.m-home-theme .pf-home-name {
  color: #102a3a;
}

.m-home-theme .pf-home-lead {
  color: #55656f;
}

/* Muted, but still AA at 20px. */
.m-home-theme .pf-home-year {
  color: #5f6d76;
}

/* The empty-slot ground behind a rendering, inverted from a white wash to a
   navy one so it reads as a recess on the light scene instead of a glow. */
.m-home-theme .pf-home-shot {
  background: rgba(16, 42, 58, 0.07);
}

/* Same interaction grammar as the dark version — translucent at rest, solid on
   hover, the two colours swapping — with the light scene's polarity. */
.m-home-theme .pf-home-cta {
  color: #102a3a;
  background: rgba(16, 42, 58, 0.09);
}

.m-home-theme .pf-home-cta:hover,
.m-home-theme .pf-home-cta:focus-visible {
  color: #fff8ef;
  background: #102a3a;
}

/* The divided hairline. Geometry, width, count and markup are unchanged; the
   line simply inverts from white-on-navy to navy-on-off-white. Orange stays
   out of it — the indicator is not the place to spend the signature colour. */
.m-home-theme .pf-home-dot::before {
  background: rgba(16, 42, 58, 0.22);
}

.m-home-theme .pf-home-dot.is-on::before {
  background: #102a3a;
}

/* Focus rings are defined globally as white, which vanishes on the light
   scene. Navy here, same 2px, same offset behaviour. */
.m-home-theme .portfolio-section :is(a, button):focus-visible {
  outline-color: #102a3a;
}

/* --- Metrics number row: alignment only -------------------------------- */

/*
 * The three figures read as a left-leaning clump. Measured at 1600px: the
 * grid is already three equal columns inside `.page-container` (75~1525,
 * the same span the 주요 고객사 block below uses), but each `.stat-value` is
 * a block filling its column with its text flush left. So the middle figure
 * sits at 572 rather than on the 800 centre axis, and the third ends at
 * 1068 instead of reaching the 1525 right edge.
 *
 * Fixed by aligning each column to the edge it is supposed to answer to:
 * first to the container's left, last to its right, middle to the page
 * centre. The label above each figure follows the same alignment so the pair
 * stays a unit.
 *
 * Alignment only. Size, weight, colour, motion, spacing, the grid itself and
 * the 고객사 content are all untouched — and this lives here rather than in
 * globals.css so it cannot reach any other page.
 */
.m-home-theme .home-stats > .home-stat:nth-child(2) {
  text-align: center;
}

.m-home-theme .home-stats > .home-stat:nth-child(3) {
  text-align: right;
}

/* ===== src/components/Footer.module.css  →  .m-footer-* ===== */
/*
 * Footer — alignment, scale and spacing only.
 *
 * Measured at 1600 before changing anything: the container runs 75~1525, the
 * five menu columns each took a full 264px of it, and the bottom row left a
 * 557px hole between a 386px wordmark and a 507px block of company details.
 * That gap is what read as "leaning left" — nothing was actually off-centre.
 *
 * Every rule here hangs off `.root`, so the base `.footer-*` declarations stay
 * in globals.css untouched and nothing outside the footer can be reached.
 * Menu names and company details are not touched at all — only how they sit.
 */

/* Top and bottom opened up a little, and the difference between them closed:
   80/64 read as a block that had been cropped at the bottom. */
.m-footer-root {
  padding: clamp(72px, 7vw, 100px) 0 clamp(64px, 6vw, 80px);
}

/* --- menu row ------------------------------------------------------------ */

/*
 * Four equal intervals between the first anchor and the last — not five tracks.
 *
 * Five 1fr tracks put the titles on 75/365/655/945/1235 and left a whole 290px
 * track sitting empty past 연락처. What is wanted is the two outer titles
 * pinned to the two edges and the span between them cut into four:
 *
 *     (1525 − 75) / 4 = 362.5
 *     75 · 437.5 · 800 · 1162.5 · 1525
 *
 * So the first four columns are 25% tracks — their left edges land on the
 * first four anchors — and 연락처 is lifted out of the flow and pinned to the
 * right edge, where its anchor is the right side of its text rather than the
 * left. That is the fifth anchor, and the interval from 인재채용 to it is the
 * same 362.5 as the rest.
 *
 * Sub-items inherit their column's alignment, so each follows its own title.
 */
.m-footer-root .m-footer-footerTop {
  position: relative;
  grid-template-columns: repeat(4, 25%);
  column-gap: 0;
}

.m-footer-root .m-footer-footerTop > :last-child {
  position: absolute;
  top: 0;
  right: 0;
  text-align: right;
}

/* --- divider -------------------------------------------------------------- */

/* Same left and right as everything else — it is inside the container, so this
   only rebalances the space above and below it. */
.m-footer-root .m-footer-footerLine {
  margin: clamp(44px, 4.5vw, 64px) 0 clamp(40px, 4vw, 56px);
}

/* --- bottom row ----------------------------------------------------------- */

/* 40 / 60, as a grid rather than `space-between`, so the split is a stated
   ratio instead of whatever is left over after two blocks of unequal content. */
/*
 * The wordmark only needs the width it occupies (317px), so the 40% it used to
 * hold left the details column starting at 703 — a long way from the logo.
 * Sizing the left track to its content and letting the details take the rest
 * brings the two blocks into one band instead of two islands.
 */
.m-footer-root .m-footer-footerIdentity {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: clamp(28px, 3vw, 48px);
  align-items: start;
}

/* 56px -> 46px, an 18% reduction. It is a sign-off, and at 386px wide it was
   competing with the company details rather than closing the page. */
.m-footer-root .m-footer-footerLogoMark {
  height: clamp(32px, 3.3vw, 46px);
}

.m-footer-root .m-footer-footerTagline {
  margin-top: 16px;
}

/*
 * The details were 13px on a 22.75px line and ran to a 760px cap — small and
 * tight, and narrower than the column now holding them. Bigger type, more
 * leading, and the cap lifted so the four lines use the 60% they are given.
 */
.m-footer-root .m-footer-footerDetails {
  max-width: none;
}

/* Right-aligned so every line — including the copyright — finishes on the
   same vertical as 연락처 and the divider. Left-aligned, the block reached the
   right edge but its text did not, which is what read as sitting too far in. */
.m-footer-root .m-footer-footerDetails {
  text-align: right;
}

.m-footer-root .m-footer-footerDetails p {
  margin: 0 0 10px;
  font-size: 14px;
  line-height: 1.9;
  word-break: keep-all;
}

/* The separators carried no space of their own, so 회사명|대표|번호 ran
   together. This is spacing, not a change to what is written. */
/* Wider separators. This is the one thing that actually lengthens the lines
   without touching the type or the wording, so the right-aligned text starts
   further left and the hole in the middle closes a little. */
.m-footer-root .m-footer-footerDetails .sep {
  margin: 0 14px;
}

/* Copyright is the last line and belongs a step away from the details above
   it, not stacked flush against them. */
.m-footer-root .m-footer-footerCopy {
  margin-top: 18px !important;
}

@media (max-width: 860px) {
  .m-footer-root .m-footer-footerIdentity {
    grid-template-columns: 1fr;
  }
  .m-footer-root .m-footer-footerTop {
    grid-template-columns: repeat(2, auto);
    justify-content: start;
    column-gap: clamp(32px, 12vw, 90px);
    row-gap: 36px;
  }
  /* Stacked, there is no shared right edge to line up with, and the last
     column rejoins the flow. */
  .m-footer-root .m-footer-footerTop > :last-child {
    position: static;
    text-align: left;
  }
  .m-footer-root .m-footer-footerDetails {
    text-align: left;
  }
}

/* ------------------------------------------------------------- 공식 채널 --
   회사 정보 아래 한 줄. PC·모바일이 같은 마크업이고 크기만 다르다. */
.m-footer-root .m-footer-footerSns {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 20px 0 0;
  padding: 0;
  list-style: none;
}

.m-footer-root .m-footer-footerSnsLink {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* 손가락으로 눌러야 하므로 44px 아래로 내리지 않는다. */
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.35);
  color: rgba(255, 255, 255, 0.86);
  transition: background-color 0.25s ease, color 0.25s ease, border-color 0.25s ease;
}

.m-footer-root .m-footer-footerSnsLink svg {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.m-footer-root .m-footer-footerSnsLink:hover,
.m-footer-root .m-footer-footerSnsLink:focus-visible {
  background: #fff;
  border-color: #fff;
  color: #111;
}

/* --------------------------------------------------------------- 모바일 --
   카테고리 줄은 감춘다.
   같은 목록이 햄버거 메뉴에 이미 있고, 모바일 푸터에서는 회사 정보에 닿기
   전에 지나가야 하는 긴 목록일 뿐이었다. 회사 정보 블록(로고·태그라인·주소·
   대표번호·사업자정보·저작권)은 그대로 남는다. PC 는 영향 없다. */
@media (max-width: 767px) {
  .m-footer-root .m-footer-footerTop {
    display: none;
  }

  /* 카테고리 줄이 사라지면 그 아래 구분선은 아무것도 나누지 않는다. */
  .m-footer-root .m-footer-footerLine {
    display: none;
  }

  /* 남은 것은 회사 정보 하나뿐이라 가운데로 세운다. */
  .m-footer-root .m-footer-footerIdentity {
    justify-items: center;
    text-align: center;
    padding-top: 4px;
  }

  .m-footer-root .m-footer-footerDetails {
    text-align: center;
  }

  /* 로고가 46px 까지 커져 주소 블록을 눌렀다. 비율은 height 만 줄이면
     그대로 유지된다 — 워드마크는 폭이 자동이다.
     22px 에서 한 번 더 20% 줄였다. */
  .m-footer-root .m-footer-footerLogoMark {
    height: 18px;
    /* 워드마크가 감싼 <p> 보다 좁아 왼쪽에 붙어 있었다. 블록으로 두고
       좌우 auto 로 실제 가운데에 세운다. */
    display: block;
    margin-inline: auto;
  }

  .m-footer-root .m-footer-footerTagline {
    margin-top: 8px;
    font-size: 12.5px;
  }

  /* 회사 정보는 한 줄씩 고정된 행이 아니라 이어지는 문장이다.
     flex + wrap 이라 항목이 화면 폭 안에서 자연스럽게 넘어가고 그 사이는
     gap 이 벌린다. 세로 막대는 감춘다 — 줄이 넘어갈 때 막대만 앞 줄 끝에
     혼자 남아 회색 막대처럼 보였다(대표이사 뒤, FAX 뒤).
     flex 컨테이너는 요소 사이의 공백 텍스트를 항목으로 만들지 않으므로
     막대를 감춰도 여분의 공백이 남지 않는다. PC 는 그대로 inline 흐름이다. */
  .m-footer-root .m-footer-footerDetails .footer-facts {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: baseline;
    gap: 2px 14px;
  }

  .m-footer-root .m-footer-footerDetails .sep {
    display: none;
  }

  /* 줄 간격과 단락 사이를 함께 줄여 푸터가 길어지지 않게 한다. */
  .m-footer-root .m-footer-footerDetails p {
    margin-bottom: 6px;
    line-height: 1.7;
  }

  /* 주소와 긴 신고번호는 폭에 따라 끊기게 둔다 — 억지로 한 줄에 붙이면
     좌우가 잘린다. */
  .m-footer-root .m-footer-footerDetails .footer-facts > * {
    word-break: keep-all;
  }

  .m-footer-root .m-footer-footerSns {
    justify-content: center;
    margin-top: 18px;
  }

  .m-footer-root .m-footer-footerSnsLink {
    width: 40px;
    height: 40px;
  }

  .m-footer-root .m-footer-footerSnsLink svg {
    width: 18px;
    height: 18px;
  }
  /* 고정 dock 보정용으로 두었던 190px 하단 여백은 제거했다 — 모바일에서는
     dock 자체가 없어졌고, 남겨 두면 푸터 아래에 검은 빈 공간이 생긴다.
     휴대폰 홈 인디케이터를 위한 최소 여백만 더한다. */
  .m-footer-root {
    padding-bottom: calc(clamp(56px, 8vw, 72px) + env(safe-area-inset-bottom, 0px));
  }
}

/* ===== src/components/Header.module.css  →  .m-header-* ===== */
/*
 * Header — GNB centring only.
 *
 * `.site-header-inner` is `justify-content: space-between`, so the nav landed
 * in the middle of the space LEFT OVER by the logo and the actions rather than
 * in the middle of the screen. With the logo at 103px and the actions at
 * 225px, that put it (225 − 103) / 2 = 61px to the left of centre — measured
 * at both 1600 and 1920, the same 61px each time, which is what confirmed the
 * cause rather than a coincidence.
 *
 * Taking the nav out of the flex flow and pinning it to the middle of the bar
 * makes its position independent of what sits on either side of it. The logo
 * and the actions do not move: `space-between` keeps the first item at the
 * start and the last at the end, and those are still exactly what they were.
 *
 * Nothing else is touched — the gap between the items, the type, the active
 * underline and the hover behaviour all stay in globals.css untouched. This
 * file exists so the header's own stylesheet is not edited for one rule.
 */

/*
 * Only from the width the nav is actually shown at. `.site-nav` is
 * `display: none` below 1180 and this must not resurrect it there, nor apply
 * to the layout that replaces it.
 */
@media (min-width: 1180px) {
  .m-header-navCenter {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
  }
}

/* ===== src/components/LeadershipSignature.module.css  →  .m-leadership-signature-* ===== */
/*
 * CEO MESSAGE — the sign-off line only.
 *
 * 주식회사 태신디앤씨 대표이사 stays exactly as it was. What changes is the
 * line under it: the name is now set as text with the signature image beside
 * it, on one baseline, rather than the signature standing alone.
 *
 * Scoped here rather than added to globals.css so nothing else in the
 * showcase — its background, its type, its layout — can be reached by it.
 */

/* ---------------------------------------------------------------------------
 * 서명 블록 — 클라이언트 참고 이미지(docs/reference/씨이오메세지-서명)를
 * 픽셀로 재서 그 비율을 그대로 옮겼다.
 *
 *   주식회사 태신디앤씨   글자높이 52  폭 475   (이름 대비 0.72)
 *   대표이사             글자높이 37  폭 150   (이름 대비 0.51)
 *   진 세 권             글자높이 72, 음절 간격 53
 *   두 줄 세로 여백       46px = 1줄 글자높이의 0.88배
 *   좌측 시작            두 줄 모두 x=91 (일치)
 *   우측 끝              565 / 569 (일치)
 *   권 → 서명 이미지      41px
 *
 * 모든 값을 `--sig`(이름 글자 크기) 기준의 calc 로 적어 두었다. 화면이 좁아져
 * --sig 가 줄면 나머지가 같은 비율로 따라 줄어들고, 음절 간격과 양끝 정렬은
 * 그대로 유지된다.
 * ------------------------------------------------------------------------- */

.m-leadership-signature-block {
  /* --sig 는 부모(.leadership-signature)가 정한다 — 서명 이미지와 함께 쓴다.
     내용만큼만 넓다 — 그 폭을 회사명 줄이 정하고, 아래 줄이 거기에 맞춘다. */
  display: inline-block;
}

.m-leadership-signature-company {
  margin: 0;
  font-size: calc(var(--sig) * 0.72);
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: -0.01em;
  color: rgba(255, 255, 255, 0.82);
  white-space: nowrap;
}

/* 좌우 끝을 맞추는 곳. 왼쪽 끝은 회사명과 같은 시작점, 오른쪽 끝은
   space-between 이 이름을 묶음의 오른쪽 변에 붙여 만든다. */
.m-leadership-signature-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  /* 두 줄 사이 여백. 아래에서 실측으로 맞춘 값이다. */
  margin: calc(var(--sig) * 0.42) 0 0;
}

.m-leadership-signature-role {
  font-size: calc(var(--sig) * 0.51);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.01em;
  color: rgba(255, 255, 255, 0.8);
  white-space: nowrap;
  /* 참고 이미지에서 직책이 이름 기준선보다 살짝 위에 앉아 있다. 기준선
     정렬만으로도 일부 올라가므로 나머지만 더한다. */
  position: relative;
  top: calc(var(--sig) * -0.04);
}

/* 음절 사이는 letter-spacing 이 아니라 gap 으로 벌린다. letter-spacing 은
   마지막 글자 뒤에도 공백을 더해서, 그만큼 오른쪽 끝이 밀려 양끝 정렬이
   어긋난다. */
.m-leadership-signature-name {
  display: inline-flex;
  gap: calc(var(--sig) * 0.54);
  font-size: var(--sig);
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0;
  color: #fff;
  white-space: nowrap;
}

/*
 * 서명 이미지. 글자 묶음 바깥에 서므로 두 줄의 폭에 영향을 주지 않는다.
 *
 * 참고 이미지에서 서명의 획 높이는 이름 글자높이의 1.69배다. PNG 안에서
 * 획이 차지하는 비율이 0.81 이므로 상자 높이는 그보다 커야 한다 —
 * 1.69 × (이름글자높이/--sig = 0.92) ÷ 0.81 ≈ 1.91.
 */
.m-leadership-signature-mark {
  display: block;
  width: auto;
  height: calc(var(--sig) * 1.91);
  opacity: 0.92;
  /* 참고 이미지에서 서명의 세로 중심이 이름 글자의 중심보다 조금 위에 있다.
     아래 변 기준으로 세운 뒤 그만큼만 끌어올린다. */
  position: relative;
  bottom: calc(var(--sig) * 0.1);
}

/* ===== src/components/ProjectRenderingCarousel.module.css  →  .m-project-rendering-carousel-* ===== */
/*
 * HOME 태신 프로젝트 track — size, corner and the scrubber.
 *
 * Scoped to this component rather than appended to globals.css: the `.pf-home-*`
 * base rules stay exactly where they are, and everything here is reached only
 * through `.root`, so no other page can be touched by it.
 *
 * Only three things change about the existing card: it is larger, its corner is
 * rounder, and the row of indicator bars underneath is now a real control. The
 * layout, the caption typography, the full-bleed track and the drift mechanism
 * are all as they were.
 */

/* --- card ---------------------------------------------------------------- */

/* 420 -> 472, a 12.4% increase, keeping the reference's 1.328 ratio and the
   gap-to-card proportion it was built on. */
.m-project-rendering-carousel-root .pf-home-card,
.m-project-rendering-carousel-root .pf-home-shot {
  width: 472px;
}

.m-project-rendering-carousel-root .pf-home-shot {
  /* Was 4px. The renderings are the subject of this block and a near-square
     corner made them read as UI tiles. */
  border-radius: 18px;
}

@media (max-width: 639px) {
  .m-project-rendering-carousel-root .pf-home-card,
  .m-project-rendering-carousel-root .pf-home-shot {
    width: 338px;
  }
  .m-project-rendering-carousel-root .pf-home-shot {
    border-radius: 16px;
  }
}

/* --- scrubber ------------------------------------------------------------ */

/*
 * Replaces the row of separate bars. Same visual weight as before — a thin
 * hairline centred under the track — but it is now the scroll position itself:
 * the thumb IS the viewport's share of the list, it tracks the drift live, it
 * can be dragged, and the rail can be clicked to jump.
 */
.m-project-rendering-carousel-scrubber {
  position: relative;
  width: min(450px, calc(100% - 40px));
  margin: 20px auto 0;
  padding: 14px 0;
  border: 0;
  background: none;
  cursor: pointer;
  touch-action: none;
  display: block;
}

.m-project-rendering-carousel-rail {
  position: relative;
  height: 2px;
  background: rgba(255, 255, 255, 0.22);
  border-radius: 2px;
}

.m-project-rendering-carousel-thumb {
  position: absolute;
  top: 0;
  height: 2px;
  border-radius: 2px;
  background: #fff;
  /* Driven from rAF alongside the drift, so it never disagrees with the
     track. No transition — a transition would make it lag the scroll. */
  will-change: transform, width;
}

.m-project-rendering-carousel-scrubber:focus-visible {
  outline: none;
}

.m-project-rendering-carousel-scrubber:focus-visible .m-project-rendering-carousel-rail {
  outline: 2px solid #fff;
  outline-offset: 6px;
}

/* Grows a little while it is being worked, so the control acknowledges the
   pointer without changing the resting design. */
.m-project-rendering-carousel-scrubber:hover .m-project-rendering-carousel-rail,
.m-project-rendering-carousel-scrubber[data-dragging="true"] .m-project-rendering-carousel-rail,
.m-project-rendering-carousel-scrubber:hover .m-project-rendering-carousel-thumb,
.m-project-rendering-carousel-scrubber[data-dragging="true"] .m-project-rendering-carousel-thumb {
  height: 3px;
}

@media (prefers-reduced-motion: reduce) {
  .m-project-rendering-carousel-thumb {
    will-change: auto;
  }
}

/* ===== src/components/gallery/PhotoWall.module.css  →  .m-photo-wall-* ===== */
/*
 * LOUNGE photo wall — page-scoped.
 *
 * Deliberately almost styleless: the only job here is to get UI out of the way
 * so the photographs are what the page is. No card, no padding, no border, no
 * shadow, no caption row. Gap is 8px so the wall reads as one surface rather
 * than a set of separate tiles.
 *
 * Kept out of globals.css — the approved dark pages share that file and none
 * of this should be reachable from them. The old `.gallery-*` rules there are
 * left untouched.
 */

.m-photo-wall-page {
  background: #fff;
}

/* Nearly full-bleed on purpose. The photographs are the page, so the wall
   takes the width rather than sitting inside the site's 1450px text measure. */
.m-photo-wall-wrap {
  width: min(calc(100% - 24px), 1920px);
  margin-inline: auto;
  padding: clamp(48px, 5vw, 84px) 0 clamp(80px, 9vw, 140px);
}

/* Multi-column, so each photo keeps its own aspect ratio and the columns fall
   where they will. With mixed portrait/landscape sources this is masonry; with
   today's uniform 16:9 stand-ins it reads as even rows. */
/* Exactly three across on desktop. Four made each photograph small enough
   that the wall read as thumbnails; three fills the width and lets a face be
   a face. */
.m-photo-wall-wall {
  columns: 3;
  column-gap: 10px;
}

@media (max-width: 1024px) {
  .m-photo-wall-wall {
    columns: 2;
  }
}

@media (max-width: 640px) {
  .m-photo-wall-wall {
    columns: 1;
  }
}

/* A button, because each photo opens the lightbox — but with every trace of
   button chrome removed. */
.m-photo-wall-tile {
  display: block;
  width: 100%;
  margin: 0 0 10px;
  padding: 0;
  border: 0;
  border-radius: 20px;
  background: #eef0f3;
  overflow: hidden;
  cursor: zoom-in;
  /* Stops a column breaking a photo across two columns. */
  break-inside: avoid;
  -webkit-column-break-inside: avoid;
}

.m-photo-wall-tile:focus-visible {
  outline: 2px solid #1b2f6b;
  outline-offset: 2px;
}

.m-photo-wall-shot {
  display: block;
  width: 100%;
  height: auto;
  transition: transform 0.5s cubic-bezier(0.25, 1, 0.5, 1), filter 0.4s ease;
}

/* The whole hover treatment: a touch closer and a touch brighter. No overlay,
   no caption, no text. */
@media (hover: hover) {
  .m-photo-wall-tile:hover .m-photo-wall-shot {
    transform: scale(1.015);
    filter: brightness(1.04);
  }
}

@media (prefers-reduced-motion: reduce) {
  .m-photo-wall-shot {
    transition: none;
  }
  .m-photo-wall-tile:hover .m-photo-wall-shot {
    transform: none;
  }
}

/* ------------------------------------------------------------- lightbox */

.m-photo-wall-lightbox {
  position: fixed;
  inset: 0;
  z-index: 9000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(16px, 4vw, 56px);
  background: rgba(8, 10, 16, 0.94);
  animation: m-photo-wall-fade 0.24s ease;
  cursor: zoom-out;
}

@keyframes m-photo-wall-fade {
  from {
    opacity: 0;
  }
}

.m-photo-wall-stage {
  margin: 0;
  max-width: min(1400px, 92vw);
  max-height: 88vh;
  cursor: default;
}

.m-photo-wall-full {
  display: block;
  width: auto;
  height: auto;
  max-width: min(1400px, 92vw);
  max-height: 88vh;
  object-fit: contain;
}

.m-photo-wall-nav,
.m-photo-wall-close {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 0;
  background: transparent;
  color: rgba(255, 255, 255, 0.75);
  cursor: pointer;
  transition: color 0.25s ease;
}

.m-photo-wall-nav:hover,
.m-photo-wall-close:hover,
.m-photo-wall-nav:focus-visible,
.m-photo-wall-close:focus-visible {
  color: #fff;
}

.m-photo-wall-nav {
  top: 50%;
  transform: translateY(-50%);
  width: clamp(44px, 5vw, 64px);
  height: clamp(64px, 8vw, 96px);
  font-size: clamp(38px, 4vw, 54px);
  line-height: 1;
}

.m-photo-wall-prev {
  left: clamp(4px, 2vw, 28px);
}

.m-photo-wall-next {
  right: clamp(4px, 2vw, 28px);
}

.m-photo-wall-close {
  top: clamp(10px, 2vw, 26px);
  right: clamp(10px, 2vw, 26px);
  width: 48px;
  height: 48px;
  font-size: 34px;
  line-height: 1;
}

.m-photo-wall-counter {
  position: absolute;
  left: 50%;
  bottom: clamp(14px, 2.5vw, 30px);
  transform: translateX(-50%);
  margin: 0;
  font-size: 13px;
  letter-spacing: 0.1em;
  color: rgba(255, 255, 255, 0.55);
}

@media (max-width: 640px) {
  .m-photo-wall-nav {
    top: auto;
    bottom: clamp(10px, 3vw, 22px);
    transform: none;
    height: 48px;
  }
  .m-photo-wall-counter {
    bottom: 24px;
  }
}

/* 관리자가 등록한 사진이 0장일 때. 임시 사진을 대신 채우지 않으므로 이 페이지는
   빈 상태를 스스로 말해야 한다. 벽과 같은 폭 안에 한 줄만 놓고, 위아래로 충분히
   띄워 히어로 바로 아래가 허전하게 비지 않게 한다.

   벽(.wall)의 규칙은 건드리지 않았다 — 사진이 한 장이라도 등록되면 기존
   레이아웃·간격·hover·라이트박스가 그대로 돌아온다. */
.m-photo-wall-empty {
  margin: clamp(60px, 8vw, 110px) 0;
  text-align: center;
  font-size: 15px;
  /* 값을 직접 쓴다. `--ink-faint` 를 쓰려다 흰 배경에 흰 글씨가 됐는데, 그
     토큰은 NEWSROOM 모듈의 `.page` 안에서만 선언된 지역 변수라 이 페이지에서는
     풀리지 않는다. 이 벽은 배경이 #fff 이므로 그 위에서 읽히는 회색을 쓴다. */
  color: #8a94a6;
}

@media (max-width: 767px) {
  .m-photo-wall-wrap {
    padding-top: 44px;
    padding-bottom: 56px;
  }
}

/* ===== src/components/inquiry/Inquiry.module.css  →  .m-inquiry-* ===== */
/*
 * 대행문의 (/inquiry) — only what /apply has no equivalent of.
 *
 * Everything shared with /apply is taken from the real thing rather than
 * restated here: the section, container, grid and light palette come from the
 * `.apply-*` classes plus `app/apply/apply.module.css`, and every form control
 * takes its classes from `RecruitForm`'s exported tone maps. What is left
 * below is the three-up structure this form has and that one does not — the
 * paired rows, the 첨부자료 button and the 현장상태 row — plus the left column's
 * label/value pairs.
 */

/* Two fields per row on desktop, stacking below the same 700px the rest of the
   form's measure starts to crowd at. */
.m-inquiry-pair {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 28px;
}

@media (max-width: 700px) {
  .m-inquiry-pair {
    grid-template-columns: 1fr;
  }
}

/* --------------------------------------------------------------- 첨부자료 */

.m-inquiry-file {
  display: block;
  margin-top: 8px;
}

.m-inquiry-fileInput {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

/* Matches the input row it sits beside: same height, radius and border tone
   as `fieldClassByTone.light`, so the pair reads as one row. */
.m-inquiry-fileButton {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  max-width: 100%;
  height: 53px;
  padding: 14px 20px;
  border: 1px solid rgba(0, 0, 0, 0.15);
  border-radius: 4px;
  background: rgba(0, 0, 0, 0.02);
  font-size: 15px;
  font-weight: 500;
  line-height: 22.5px;
  color: #525252;
  cursor: pointer;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  transition: border-color 0.2s ease, color 0.2s ease;
}

.m-inquiry-fileInput:focus-visible + .m-inquiry-fileButton,
.m-inquiry-fileButton:hover {
  border-color: rgba(0, 0, 0, 0.45);
  color: #171717;
}

/* --------------------------------------------------------------- 현장상태 */

.m-inquiry-statusSet {
  margin: 0;
  padding: 0;
  border: 0;
}

.m-inquiry-statusRow {
  margin-top: 14px;
  display: flex;
  flex-wrap: wrap;
  gap: 14px 34px;
}

/* ------------------------------------------------------------ left column */

/* The label/value pairs mirror /apply's secondary system: the caption takes
   `.apply-phone-note`'s size and colour, the values `.apply-side-copy`'s, and
   the phone keeps `.apply-phone`'s serif display treatment. */
.m-inquiry-metaList {
  margin-top: 40px;
  padding-top: 24px;
  border-top: 1px solid rgba(15, 27, 51, 0.14);
  display: grid;
  gap: 22px;
}

.m-inquiry-metaRow {
  display: grid;
  gap: 4px;
}

/* Exactly `.apply-phone-note` — 13px/500/19.5px, ls normal, #6b7686 — so the
   captions in this column compute to the same values as the caption under
   /apply's phone number. */
.m-inquiry-metaLabel {
  font-size: 13px;
  font-weight: 500;
  line-height: 19.5px;
  letter-spacing: normal;
  color: rgb(107, 118, 134);
}

/* Exactly `.apply-side-copy` — 15px/500/27.75px, ls -0.3px, #3d4757 — the
   value type in /apply's left block. */
.m-inquiry-metaValue {
  font-size: 15px;
  font-weight: 500;
  line-height: 27.75px;
  letter-spacing: -0.3px;
  color: rgb(61, 71, 87);
  word-break: break-all;
  transition: color 0.3s ease;
}

a.m-inquiry-metaValue:hover {
  color: #0f1b33;
}

/* ===== src/components/newsroom/Newsroom.module.css  →  .m-newsroom-* ===== */
/*
 * NEWSROOM — list and article, page-scoped.
 *
 * An editorial news layout rather than the numbered table a Korean corporate
 * board usually is: a card per post, thumbnail first, and an article page set
 * to a reading measure. Kept out of globals.css so nothing here can reach the
 * approved pages.
 */

.m-newsroom-page {
  --ink: #101828;
  --ink-soft: #475467;
  --ink-faint: #8a94a6;
  --point: #1b2f6b;
  --line: #e3e7ee;
  --paper: #ffffff;

  background: var(--paper);
  color: var(--ink);
}

.m-newsroom-wrap {
  width: min(calc(100% - 40px), 1450px);
  margin-inline: auto;
  padding: clamp(72px, 8vw, 130px) 0 clamp(96px, 11vw, 170px);
}

/* --- list: a board, not a card wall --------------------------------------
 *
 * Rows of 번호 / 구분 / 제목 / 작성일 separated by hairlines. No thumbnails, no
 * cards, no rounded image tiles — the title carries the row and the picture
 * belongs inside the article. What keeps it from looking like a 2005 table is
 * the spacing and the weight, not decoration.
 */

.m-newsroom-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 24px;
  padding-bottom: clamp(20px, 2.4vw, 32px);
}

.m-newsroom-label {
  margin: 0;
  font-size: clamp(19px, 1.8vw, 25px);
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--ink);
}

.m-newsroom-count {
  margin: 0;
  font-size: 14px;
  color: var(--ink-faint);
}

/* One grid for the header row and every row under it, so the columns line up
   without a table. */
.m-newsroom-board {
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 2px solid var(--ink);
}

.m-newsroom-colHead,
.m-newsroom-row {
  display: grid;
  grid-template-columns: 84px 120px minmax(0, 1fr) 120px;
  align-items: center;
  gap: 20px;
}

.m-newsroom-colHead {
  padding: 16px 12px;
  border-bottom: 1px solid var(--line);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--ink-faint);
}

.m-newsroom-rowItem {
  border-bottom: 1px solid var(--line);
}

.m-newsroom-row {
  padding: clamp(18px, 2vw, 26px) 12px;
  color: inherit;
  transition: background-color 0.2s ease;
}

/* The whole row responds, and only just — a tint, no lift, no shadow. */
@media (hover: hover) {
  .m-newsroom-rowItem:hover .m-newsroom-row {
    background: rgba(27, 47, 107, 0.035);
  }
  .m-newsroom-rowItem:hover .m-newsroom-rowTitle {
    color: var(--point);
  }
}

.m-newsroom-row:focus-visible {
  outline: 2px solid var(--point);
  outline-offset: -2px;
}

.m-newsroom-num {
  font-size: 14px;
  letter-spacing: 0.04em;
  color: var(--ink-faint);
  text-align: center;
}

.m-newsroom-cat {
  font-size: 13px;
  font-weight: 700;
  color: var(--point);
  text-align: center;
}

.m-newsroom-rowTitle {
  margin: 0;
  min-width: 0;
  font-size: clamp(15px, 1.2vw, 17px);
  font-weight: 600;
  line-height: 1.6;
  letter-spacing: -0.01em;
  word-break: keep-all;
  color: var(--ink);
  transition: color 0.2s ease;
  /* One line on the board; the article carries the rest. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.m-newsroom-date {
  font-size: 14px;
  color: var(--ink-faint);
  text-align: center;
}

/* Phones drop the number and the column header, and stack 구분·날짜 under the
   title — a four-column board does not survive 390px, and shrinking the type
   to force it would be worse than changing the structure. */
@media (max-width: 720px) {
  .m-newsroom-colHead {
    display: none;
  }
  .m-newsroom-row {
    grid-template-columns: 1fr;
    gap: 8px;
    padding: 20px 4px;
  }
  .m-newsroom-num {
    display: none;
  }
  .m-newsroom-rowTitle {
    white-space: normal;
    order: -1;
  }
  .m-newsroom-cat,
  .m-newsroom-date {
    display: inline;
    text-align: left;
    font-size: 13px;
  }
  .m-newsroom-metaRow {
    display: flex;
    align-items: center;
    gap: 10px;
  }
}

.m-newsroom-empty {
  margin: clamp(60px, 8vw, 110px) 0;
  text-align: center;
  font-size: 15px;
  color: var(--ink-faint);
}

/* --- article ------------------------------------------------------------- */

/* A reading measure, centred. Wide enough for a photograph, narrow enough that
   a paragraph does not run away from the eye. */
.m-newsroom-article {
  width: min(calc(100% - 40px), 760px);
  margin-inline: auto;
  padding: clamp(64px, 7vw, 110px) 0 clamp(88px, 10vw, 150px);
}

.m-newsroom-back {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  font-weight: 600;
  color: var(--ink-faint);
  transition: color 0.25s ease;
}

.m-newsroom-back:hover {
  color: var(--point);
}

.m-newsroom-articleHead {
  margin-top: clamp(28px, 3vw, 44px);
  padding-bottom: clamp(28px, 3vw, 44px);
  border-bottom: 1px solid var(--line);
}

.m-newsroom-articleTitle {
  margin: 14px 0 0;
  font-size: clamp(26px, 3vw, 40px);
  font-weight: 700;
  line-height: 1.4;
  letter-spacing: -0.02em;
  word-break: keep-all;
  text-wrap: balance;
  color: var(--ink);
}

.m-newsroom-lead {
  position: relative;
  margin-top: clamp(32px, 4vw, 52px);
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: 12px;
  background: #eef1f5;
}

.m-newsroom-lead img {
  object-fit: cover;
}

.m-newsroom-body {
  margin-top: clamp(36px, 4.5vw, 60px);
}

.m-newsroom-body > * + * {
  margin-top: 26px;
}

.m-newsroom-h {
  margin-top: clamp(44px, 5vw, 66px);
  font-size: clamp(19px, 1.7vw, 24px);
  font-weight: 700;
  line-height: 1.5;
  letter-spacing: -0.01em;
  word-break: keep-all;
  color: var(--ink);
}

.m-newsroom-p {
  font-size: 16px;
  line-height: 1.95;
  word-break: keep-all;
  text-wrap: pretty;
  color: var(--ink-soft);
}

/* Bold inside a paragraph, set by the admin. */
.m-newsroom-p strong,
.m-newsroom-p b {
  font-weight: 700;
  color: var(--ink);
}

.m-newsroom-figure {
  margin: clamp(36px, 4vw, 52px) 0 0;
}

.m-newsroom-figureShot {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: 10px;
  background: #eef1f5;
}

.m-newsroom-figureShot img {
  object-fit: cover;
}

.m-newsroom-caption {
  margin: 12px 0 0;
  font-size: 13.5px;
  line-height: 1.7;
  word-break: keep-all;
  color: var(--ink-faint);
}

/* Image beside text, stacking on a narrow screen rather than squeezing. */
.m-newsroom-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(20px, 3vw, 34px);
  align-items: center;
  margin-top: clamp(36px, 4vw, 52px);
}

.m-newsroom-splitRight .m-newsroom-splitShot {
  order: 2;
}

.m-newsroom-splitShot {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-radius: 10px;
  background: #eef1f5;
}

.m-newsroom-splitShot img {
  object-fit: cover;
}

.m-newsroom-splitText {
  margin: 0;
  font-size: 15.5px;
  line-height: 1.9;
  word-break: keep-all;
  text-wrap: pretty;
  color: var(--ink-soft);
}

@media (max-width: 640px) {
  .m-newsroom-split {
    grid-template-columns: 1fr;
  }
  .m-newsroom-splitRight .m-newsroom-splitShot {
    order: 0;
  }
}

/* After an image-beside-text block the next thing sat right under the picture
   and read as its caption. Give whatever follows the same air the block itself
   opens with. */
.m-newsroom-split + * {
  margin-top: clamp(36px, 4vw, 52px) !important;
}

.m-newsroom-list {
  margin: 0;
  padding-left: 20px;
}

.m-newsroom-list li {
  font-size: 16px;
  line-height: 1.95;
  word-break: keep-all;
  color: var(--ink-soft);
}

.m-newsroom-list li + li {
  margin-top: 6px;
}

/* An external link, shown by its label rather than its URL. */
.m-newsroom-link {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-top: clamp(28px, 3vw, 40px);
  padding: 14px 24px;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 15px;
  font-weight: 600;
  color: var(--point);
  transition: border-color 0.25s ease, background 0.25s ease;
  word-break: break-all;
}

.m-newsroom-link:hover {
  border-color: var(--point);
  background: rgba(27, 47, 107, 0.04);
}

/* --- article foot: board navigation -------------------------------------- */

.m-newsroom-articleFoot {
  margin-top: clamp(60px, 7vw, 96px);
  border-top: 2px solid var(--ink);
}

/* 이전 글 / 다음 글 as board rows, so the article ends the way the list looks. */
.m-newsroom-nav {
  margin: 0;
  padding: 0;
  list-style: none;
}

.m-newsroom-navItem {
  border-bottom: 1px solid var(--line);
}

.m-newsroom-navRow {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr);
  align-items: center;
  gap: 16px;
  padding: clamp(16px, 1.8vw, 22px) 12px;
  color: inherit;
  transition: background-color 0.2s ease;
}

@media (hover: hover) {
  a.m-newsroom-navRow:hover {
    background: rgba(27, 47, 107, 0.035);
  }
  a.m-newsroom-navRow:hover .m-newsroom-navTitle {
    color: var(--point);
  }
}

.m-newsroom-navLabel {
  font-size: 13px;
  font-weight: 700;
  color: var(--ink-faint);
}

.m-newsroom-navTitle {
  margin: 0;
  min-width: 0;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.6;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  transition: color 0.2s ease;
}

/* An end of the board. Kept in place rather than removed so the pair of
   controls does not change shape on the first and last post. */
.m-newsroom-navEmpty .m-newsroom-navTitle {
  color: var(--ink-faint);
  font-weight: 500;
}

.m-newsroom-toList {
  display: flex;
  justify-content: center;
  margin-top: clamp(32px, 4vw, 48px);
}

.m-newsroom-toListBtn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 14px 40px;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 15px;
  font-weight: 600;
  color: var(--ink);
  transition: border-color 0.25s ease, background 0.25s ease;
}

.m-newsroom-toListBtn:hover {
  border-color: var(--point);
  color: var(--point);
  background: rgba(27, 47, 107, 0.04);
}

@media (max-width: 640px) {
  .m-newsroom-navRow {
    grid-template-columns: 74px minmax(0, 1fr);
    gap: 12px;
  }
}

/* --- gallery block ------------------------------------------------------- */

/* Sized by how many pictures the block actually holds, so the admin decides
   the count and the layout follows — rather than the layout deciding and the
   admin filling slots. */
.m-newsroom-gallery {
  display: grid;
  gap: 12px;
}

.m-newsroom-gallery[data-count="2"] {
  grid-template-columns: repeat(2, 1fr);
}

.m-newsroom-gallery[data-count="3"] {
  grid-template-columns: repeat(3, 1fr);
}

.m-newsroom-galleryShot {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-radius: 10px;
  background: #eef1f5;
}

.m-newsroom-galleryShot img {
  object-fit: cover;
}

@media (max-width: 640px) {
  .m-newsroom-gallery[data-count="2"],
  .m-newsroom-gallery[data-count="3"] {
    grid-template-columns: 1fr;
  }
}

/* --- button link --------------------------------------------------------- */

.m-newsroom-buttonWrap {
  display: flex;
  justify-content: center;
}

.m-newsroom-button {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 15px 38px;
  border: 1px solid var(--point);
  border-radius: 999px;
  background: var(--point);
  font-size: 15px;
  font-weight: 700;
  color: #fff;
  transition: background 0.25s ease, color 0.25s ease;
}

.m-newsroom-button:hover {
  background: transparent;
  color: var(--point);
}

@media (max-width: 767px) {
  .m-newsroom-wrap {
    padding-top: 52px;
    padding-bottom: 60px;
  }
}

/* ===== src/components/sections/HeroArchitectural.module.css  →  .m-hero-architectural-* ===== */
/* EXPERIMENT — HOME Architectural Light hero.
 *
 * Component-scoped. Nothing here reaches outside this section: the star-field
 * hero's `.home-hero*` rules in globals.css are untouched and still live, and
 * this file introduces no global selector of its own.
 *
 * ONE HERO = ONE STRONG MOTION. The star hero's motion was perpetual — a canvas
 * of drifting particles that never stops. This one has a single event: a wide,
 * soft light passes once across the facade, the scene lifts out of the dark as
 * it goes, and then the hero rests. There is no parallax, no zoom, no flare, no
 * second direction and nothing that loops.
 */

/* --- the frame ----------------------------------------------------------- */

/* Fills the first screen, with no ceiling.
 *
 * The star hero is `clamp(640px, 100svh, 1000px)`, and the 1000px cap is a real
 * bug on a tall monitor: at a 1440px-tall viewport that hero is 1000px and 440px
 * of Metrics is already on screen before anyone scrolls. The cap is deliberately
 * not carried over — the requirement here is that the first screen is the hero
 * and nothing else.
 *
 * `100vh` first as the floor for browsers without the new units, `100svh` after
 * it for everything current. `dvh` is NOT used: on desktop it resolves to the
 * same number, and on mobile it re-measures as the URL bar hides and shows,
 * which resizes the hero mid-scroll. Mobile is out of scope this round; if the
 * dvh behaviour is wanted later it is a one-line addition here.
 *
 * `isolation: isolate` keeps the grading blend below contained in this section
 * so it can never reach the sections underneath. */
.m-hero-architectural-scene {
  position: relative;
  isolation: isolate;
  display: flex;
  align-items: center;
  min-height: 100vh;
  min-height: 100svh;
  padding-top: calc(var(--header-h) + 90px);
  padding-bottom: 120px;
  overflow: hidden;
  background: #091a26;
}

/* --- the photograph ------------------------------------------------------ */

.m-hero-architectural-media {
  position: absolute;
  inset: 0;
  z-index: -3;
}

.m-hero-architectural-media img {
  object-fit: cover;
  /* The tower's apex sits high in the frame and the facade runs down-left. Held
     a touch above centre so the apex stays in shot as the frame gets taller. */
  object-position: center 42%;
}

/* --- cinematic grading --------------------------------------------------- */

/* Hue only.
 *
 * `mix-blend-mode: color` takes the hue and chroma from this layer and keeps the
 * LUMINANCE of the photograph underneath, which is exactly what grading toward a
 * brand navy needs: the picture's own teal cast becomes TAESHIN navy while every
 * mullion, glass edge and lit window keeps the brightness that makes it legible
 * as structure. A flat scrim would have done the opposite — shifted nothing and
 * flattened everything. */
/* Two things are being balanced here, and the first pass got both wrong.
 *
 * `color` blending replaces the hue AND the saturation of every pixel, so at a
 * high opacity the whole frame collapses to one flat tone — the first attempt
 * ran #0E2C3E at 0.74 and the result was a grey slate photograph with no navy
 * in it and no warmth left in the lit windows. Two changes fix it: a navy with
 * real chroma in it rather than a near-grey one, and an opacity low enough that
 * the warm interior lights keep about half of their own colour and still read as
 * lights. */
.m-hero-architectural-grade {
  position: absolute;
  inset: 0;
  z-index: -2;
  background: #0a3552;
  mix-blend-mode: color;
  opacity: 0.56;
  pointer-events: none;
}

/* Depth, and the half of the reveal that belongs to the whole frame.
 *
 * It opens heavy — the building is present but sunk — and settles back as the
 * light crosses, which is what makes the structure appear rather than simply be
 * there. Darkest at top and bottom so the centre stays clear for the headline;
 * the middle band never goes past 0.2 even at the opening. */
.m-hero-architectural-depth {
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(
    180deg,
    rgba(5, 15, 24, 0.62) 0%,
    rgba(5, 15, 24, 0.2) 40%,
    rgba(5, 15, 24, 0.34) 68%,
    rgba(5, 15, 24, 0.76) 100%
  );
  opacity: 1;
  pointer-events: none;
  animation: m-hero-architectural-heroSettle 2600ms var(--ease-hero) 400ms both;
}

@keyframes m-hero-architectural-heroSettle {
  from {
    opacity: 1;
  }
  to {
    opacity: 0.52;
  }
}

/* --- THE light reveal ---------------------------------------------------- */

/* One pass, and then it is gone.
 *
 * A single band, far wider than it needs to be and with no hard edge anywhere in
 * it, tilted to rake along the facade rather than cut across it square. It
 * travels left to right once and finishes off-frame, so the resting state of the
 * hero has no light layer in it at all — `both` holds that final position and
 * nothing repeats.
 *
 * The alphas are restrained, but the first pass took that too far: at a 0.14
 * peak under 26px of blur, over a photograph this dark, the pass was invisible —
 * there was no moment where the facade lit up. 0.26 is where the mullion lines
 * and the window reflections actually rise as the band crosses them, and it is
 * still nowhere near a flare: the band has no hard edge anywhere in it, it is
 * more than half the frame wide, and it leaves no bright streak behind. */
.m-hero-architectural-sweep {
  position: absolute;
  top: -40%;
  left: 0;
  z-index: -1;
  width: 56%;
  height: 180%;
  transform: rotate(14deg) translate3d(-140%, 0, 0);
  background: linear-gradient(
    100deg,
    rgba(214, 232, 255, 0) 0%,
    rgba(214, 232, 255, 0.08) 26%,
    rgba(232, 243, 255, 0.26) 50%,
    rgba(214, 232, 255, 0.08) 74%,
    rgba(214, 232, 255, 0) 100%
  );
  filter: blur(18px);
  pointer-events: none;
  animation: m-hero-architectural-heroSweep 2600ms var(--ease-hero) 400ms both;
}

@keyframes m-hero-architectural-heroSweep {
  from {
    transform: rotate(14deg) translate3d(-140%, 0, 0);
  }
  to {
    transform: rotate(14deg) translate3d(300%, 0, 0);
  }
}

/* --- content ------------------------------------------------------------- */

/* Untouched from the star hero: the headline, the sub-copy and the two pills
   are the same components with the same global classes, so the only thing that
   differs between the two heroes is the background and its motion. */
.m-hero-architectural-inner {
  position: relative;
  z-index: 1;
  text-align: center;
}

/* --- reduced motion ------------------------------------------------------ */

/* No pass at all. The scene is simply already revealed — the settled depth, no
   light band — rather than a still of its opening frame. */
@media (prefers-reduced-motion: reduce) {
  .m-hero-architectural-depth {
    animation: none;
    opacity: 0.52;
  }
  .m-hero-architectural-sweep {
    animation: none;
    opacity: 0;
  }
}

/* ===== src/components/sections/HeroGalaxy.module.css  →  .m-hero-galaxy-* ===== */
/* EXPERIMENT — HOME cinematic galaxy hero.
 *
 * Component-scoped. The star hero (`sections/Hero.tsx` + `StarField.tsx`) and
 * the Architectural Light experiment (`HeroArchitectural.*`) are both untouched
 * and still in the tree; this shares no class name with either, and globals.css
 * is not modified.
 *
 * ONE HERO = ONE CINEMATIC SCENE. The contrast the whole thing is built on:
 *
 *   the architecture   stable — it moves once, on entry, and then stops
 *   the night sky      alive — and it never stops
 *
 * NOTHING here is a video. One high-resolution still carries the building, the
 * Milky Way and the source star field; everything that moves is a transparent
 * layer composited over it, and the photograph itself is never scaled down,
 * filtered, blurred or degraded.
 *
 * EVERY animated property is `opacity` or `transform`. Both are handled on the
 * compositor, so no frame of this costs a layout or a repaint and idle CPU is
 * effectively zero. There is no canvas and no requestAnimationFrame loop.
 */

/* --- the frame ----------------------------------------------------------- */

/* Fills the first screen with no ceiling — the star hero's 1000px cap is
   deliberately not reproduced, because at a 1400px-tall viewport it leaves
   440px of Metrics on screen before anyone scrolls. */
.m-hero-galaxy-scene {
  position: relative;
  isolation: isolate;
  display: flex;
  align-items: center;
  min-height: 100vh;
  min-height: 100svh;
  padding-top: calc(var(--header-h) + 90px);
  padding-bottom: 120px;
  overflow: hidden;
  background: #060f1a;
}

/* --- PHASE A — the entry push-in ----------------------------------------- */

/* One slow move, and then the building is done moving.
 *
 * It settles at 1.035 and STAYS there (`forwards`) — the camera does not drift
 * back and nothing re-triggers it. 4.6s across 3.5% of scale is slow enough that
 * no edge of the building reads as travelling; it registers as a camera easing
 * closer, which is the whole intent.
 *
 * The replay rule is handled by mounting, not by script. A CSS animation runs
 * when its element is created, so:
 *
 *   scrolling down and back up    the element was never unmounted -> no replay
 *   leaving HOME and coming back  the page remounts -> plays from the start
 *
 * which is exactly the behaviour asked for, with no observer, no session flag
 * and no scroll listener involved. (After a browser back/forward restore the DOM
 * can come back intact and the intro will not replay; that reads correctly, so
 * it is left alone.)
 *
 * This one is NOT paused when the hero scrolls away — see the pause rule at the
 * bottom. Pausing it mid-move would make it resume minutes later, which would
 * look like a second push-in. */
.m-hero-galaxy-media {
  position: absolute;
  inset: 0;
  z-index: -6;
  transform: scale(1);
  animation: m-hero-galaxy-heroPushIn 4600ms cubic-bezier(0.16, 0.68, 0.3, 1) both;
  will-change: transform;
}

.m-hero-galaxy-media img {
  object-fit: cover;
  object-position: center 38%;
}

@keyframes m-hero-galaxy-heroPushIn {
  from {
    transform: scale(1);
  }
  to {
    transform: scale(1.035);
  }
}

/* --- the Milky Way ------------------------------------------------------- */

/* The source image's galaxy is NOT moved — moving it would move the building
   with it. This is a separate, very faint haze laid over the sky along the same
   diagonal the photographed band runs on, drifting slowly enough that it reads
   as the sky having time in it rather than as a moving object. 210s one way, and
   `alternate` so the loop has no seam to snap at.
 *
 * `screen` so it only ever adds light — it can lift the galaxy's glow but can
 * never darken or flatten the photograph underneath. */
.m-hero-galaxy-galaxy {
  position: absolute;
  inset: -6%;
  z-index: -5;
  background:
    radial-gradient(
      52% 34% at 30% 18%,
      rgba(148, 176, 226, 0.2) 0%,
      rgba(148, 176, 226, 0) 70%
    ),
    radial-gradient(
      40% 30% at 63% 34%,
      rgba(196, 176, 214, 0.17) 0%,
      rgba(196, 176, 214, 0) 72%
    ),
    radial-gradient(
      34% 24% at 84% 15%,
      rgba(132, 168, 220, 0.14) 0%,
      rgba(132, 168, 220, 0) 74%
    );
  mix-blend-mode: screen;
  pointer-events: none;
  animation: m-hero-galaxy-galaxyDrift 210s ease-in-out infinite alternate;
}

@keyframes m-hero-galaxy-galaxyDrift {
  from {
    transform: translate3d(-0.9%, 0.5%, 0) scale(1.02);
  }
  to {
    transform: translate3d(1.1%, -0.7%, 0) scale(1.05);
  }
}

/* --- depth --------------------------------------------------------------- */

/* Sits UNDER the added stars on purpose. It darkens the photograph for the
   headline's sake and the star layers above it keep their full strength — which
   is what lets the sky read as the loudest thing on screen without the type
   losing contrast. */
/* Two gradients. The vertical one gives the frame its top and bottom weight; the
   ellipse is a soft pool of shadow behind the copy block.
 *
 * The ellipse is load-bearing. The Milky Way's brightest core lands almost
 * exactly behind the headline, and "Beyond the" is set in the site's dimmed grey
 * — over the bare galaxy it very nearly disappeared. Darkening the whole frame
 * to fix that would have cost the sky the presence this hero exists for, so the
 * shadow is local, wide and heavily feathered: the type sits on it, and the
 * galaxy keeps its brightness everywhere the type is not. The star hero solves
 * the same problem the same way — see `.home-hero-veil` in globals.css. */
.m-hero-galaxy-depth {
  position: absolute;
  inset: 0;
  z-index: -4;
  background:
    radial-gradient(
      62% 44% at 50% 52%,
      rgba(4, 10, 18, 0.4) 0%,
      rgba(4, 10, 18, 0.16) 46%,
      rgba(4, 10, 18, 0) 72%
    ),
    linear-gradient(
      180deg,
      rgba(4, 10, 18, 0.42) 0%,
      rgba(4, 10, 18, 0.1) 34%,
      rgba(4, 10, 18, 0.28) 62%,
      rgba(4, 10, 18, 0.66) 100%
    );
  pointer-events: none;
}

/* --- the star field ------------------------------------------------------ */

/* 274 added stars across SIX layers, and the number of layers is the point.
 *
 * A single layer sharing one opacity animation is a room of lights on one
 * switch: every star pulses together and it reads as mechanical blinking, which
 * is the one thing this must not do. Six layers, each with its own period and
 * its own negative offset, put six independent phases on screen at once, so
 * neighbouring stars are never in step. The periods are deliberately
 * incommensurate — 6.7 / 8.3 / 9.7 / 11.9 / 14.3 / 17.1s — so the combination
 * does not visibly repeat either.
 *
 * The layers differ in kind, not only in timing: s1 is the faint dust, s6 the
 * sparse near stars, with size, alpha and swing all rising through the set.
 * Small stars shimmer; larger ones swing hard.
 *
 * Positions are percentages, so they follow the viewport, and every one was
 * generated outside the tower's silhouette — the added light lands on sky, not
 * on the building.
 *
 * Cost: each layer is ONE element and one paint. The gradients rasterise once
 * and are composited from then on; only `opacity` and `transform` animate. */
.m-hero-galaxy-field {
  position: absolute;
  inset: 0;
  z-index: -3;
  pointer-events: none;
}

.m-hero-galaxy-field span {
  position: absolute;
  inset: 0;
  display: block;
  background-repeat: no-repeat;
}

.m-hero-galaxy-s1 {
  background-image:
    radial-gradient(0.7px 0.7px at 59.86% 24.85%, rgba(255,238,216,0.59) 0%, rgba(255,238,216,0) 100%),
    radial-gradient(0.8px 0.8px at 76.41% 10.01%, rgba(255,255,255,0.50) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.8px 0.8px at 5.17% 36.36%, rgba(212,230,255,0.48) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.0px 1.0px at 32.30% 29.13%, rgba(255,255,255,0.54) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.0px 1.0px at 92.21% 46.16%, rgba(255,255,255,0.36) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.8px 0.8px at 10.62% 60.18%, rgba(212,230,255,0.37) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.7px 0.7px at 58.86% 11.77%, rgba(212,230,255,0.54) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.0px 1.0px at 46.90% 32.26%, rgba(212,230,255,0.43) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.7px 0.7px at 88.59% 13.08%, rgba(255,255,255,0.54) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.9px 0.9px at 88.45% 8.52%, rgba(212,230,255,0.52) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.8px 0.8px at 38.42% 27.07%, rgba(255,238,216,0.48) 0%, rgba(255,238,216,0) 100%),
    radial-gradient(0.7px 0.7px at 51.79% 16.01%, rgba(212,230,255,0.54) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.9px 0.9px at 92.04% 23.08%, rgba(255,255,255,0.50) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.0px 1.0px at 96.06% 39.77%, rgba(212,230,255,0.40) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.6px 0.6px at 8.57% 7.94%, rgba(255,255,255,0.51) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.7px 0.7px at 43.82% 26.86%, rgba(212,230,255,0.38) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.8px 0.8px at 85.81% 61.75%, rgba(255,255,255,0.53) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.7px 0.7px at 4.66% 30.48%, rgba(255,255,255,0.60) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.7px 0.7px at 38.99% 22.02%, rgba(212,230,255,0.52) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.9px 0.9px at 30.75% 33.09%, rgba(212,230,255,0.57) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.7px 0.7px at 1.49% 49.98%, rgba(212,230,255,0.52) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.8px 0.8px at 7.12% 47.55%, rgba(255,255,255,0.38) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.8px 0.8px at 44.30% 4.58%, rgba(212,230,255,0.50) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.9px 0.9px at 70.44% 11.64%, rgba(255,255,255,0.43) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.8px 0.8px at 53.57% 27.32%, rgba(255,255,255,0.58) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.7px 0.7px at 96.74% 39.85%, rgba(212,230,255,0.57) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.0px 1.0px at 82.78% 59.16%, rgba(255,255,255,0.52) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.8px 0.8px at 42.35% 12.55%, rgba(255,255,255,0.58) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.0px 1.0px at 97.48% 24.34%, rgba(255,255,255,0.50) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.0px 1.0px at 42.83% 14.37%, rgba(255,255,255,0.53) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.9px 0.9px at 91.87% 35.72%, rgba(255,255,255,0.40) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.7px 0.7px at 91.37% 21.13%, rgba(212,230,255,0.48) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.8px 0.8px at 74.68% 56.12%, rgba(212,230,255,0.51) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.7px 0.7px at 65.25% 0.56%, rgba(255,255,255,0.44) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.6px 0.6px at 93.85% 22.97%, rgba(212,230,255,0.52) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.6px 0.6px at 85.40% 35.89%, rgba(212,230,255,0.57) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.8px 0.8px at 86.88% 13.28%, rgba(255,255,255,0.44) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.9px 0.9px at 32.39% 2.40%, rgba(255,255,255,0.58) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.7px 0.7px at 96.18% 38.17%, rgba(255,238,216,0.39) 0%, rgba(255,238,216,0) 100%),
    radial-gradient(0.6px 0.6px at 63.96% 25.96%, rgba(255,255,255,0.35) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.6px 0.6px at 85.06% 44.96%, rgba(255,255,255,0.62) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.9px 0.9px at 99.56% 60.02%, rgba(212,230,255,0.61) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.0px 1.0px at 32.60% 19.08%, rgba(255,255,255,0.37) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.7px 0.7px at 45.94% 27.81%, rgba(212,230,255,0.53) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.9px 0.9px at 41.50% 5.67%, rgba(255,255,255,0.45) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.7px 0.7px at 10.70% 25.79%, rgba(255,238,216,0.52) 0%, rgba(255,238,216,0) 100%),
    radial-gradient(0.9px 0.9px at 18.54% 9.39%, rgba(255,238,216,0.48) 0%, rgba(255,238,216,0) 100%),
    radial-gradient(0.9px 0.9px at 35.43% 7.44%, rgba(212,230,255,0.36) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.0px 1.0px at 17.75% 25.60%, rgba(212,230,255,0.55) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.8px 0.8px at 7.14% 6.92%, rgba(255,255,255,0.53) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.7px 0.7px at 69.06% 53.46%, rgba(212,230,255,0.48) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.9px 0.9px at 3.77% 43.46%, rgba(212,230,255,0.58) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.9px 0.9px at 88.66% 44.07%, rgba(212,230,255,0.44) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.9px 0.9px at 1.71% 8.26%, rgba(212,230,255,0.55) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.8px 0.8px at 66.66% 31.33%, rgba(255,238,216,0.44) 0%, rgba(255,238,216,0) 100%),
    radial-gradient(0.9px 0.9px at 77.80% 47.73%, rgba(212,230,255,0.42) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.7px 0.7px at 82.48% 26.99%, rgba(255,238,216,0.40) 0%, rgba(255,238,216,0) 100%),
    radial-gradient(0.9px 0.9px at 2.36% 40.14%, rgba(255,255,255,0.44) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.9px 0.9px at 72.98% 22.21%, rgba(255,255,255,0.48) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.8px 0.8px at 31.35% 5.72%, rgba(212,230,255,0.41) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.9px 0.9px at 81.62% 50.38%, rgba(212,230,255,0.37) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.6px 0.6px at 32.80% 28.53%, rgba(212,230,255,0.53) 0%, rgba(212,230,255,0) 100%);
}

.m-hero-galaxy-s2 {
  background-image:
    radial-gradient(1.1px 1.1px at 90.60% 59.69%, rgba(212,230,255,0.62) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.9px 0.9px at 41.05% 33.83%, rgba(212,230,255,0.60) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.1px 1.1px at 40.57% 17.32%, rgba(212,230,255,0.52) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.9px 0.9px at 79.59% 42.75%, rgba(255,255,255,0.40) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.0px 1.0px at 28.29% 17.25%, rgba(212,230,255,0.51) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.8px 0.8px at 60.66% 28.32%, rgba(255,238,216,0.52) 0%, rgba(255,238,216,0) 100%),
    radial-gradient(1.1px 1.1px at 53.51% 19.74%, rgba(255,238,216,0.52) 0%, rgba(255,238,216,0) 100%),
    radial-gradient(0.9px 0.9px at 0.62% 45.65%, rgba(212,230,255,0.61) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.8px 0.8px at 38.96% 15.51%, rgba(255,255,255,0.46) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.0px 1.0px at 34.94% 23.47%, rgba(255,255,255,0.47) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.8px 0.8px at 11.11% 9.72%, rgba(255,255,255,0.52) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.7px 0.7px at 32.34% 6.49%, rgba(212,230,255,0.69) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.1px 1.1px at 87.11% 18.85%, rgba(255,255,255,0.45) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.1px 1.1px at 37.09% 19.10%, rgba(255,255,255,0.44) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.1px 1.1px at 5.81% 8.32%, rgba(255,255,255,0.64) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.0px 1.0px at 37.75% 8.22%, rgba(255,255,255,0.44) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.1px 1.1px at 35.87% 2.68%, rgba(212,230,255,0.69) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.9px 0.9px at 26.36% 32.94%, rgba(212,230,255,0.69) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.1px 1.1px at 1.24% 27.32%, rgba(255,255,255,0.70) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.8px 0.8px at 14.31% 7.78%, rgba(255,238,216,0.49) 0%, rgba(255,238,216,0) 100%),
    radial-gradient(0.8px 0.8px at 69.63% 2.37%, rgba(212,230,255,0.62) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.1px 1.1px at 76.66% 0.76%, rgba(212,230,255,0.72) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.0px 1.0px at 71.64% 57.01%, rgba(255,255,255,0.44) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.8px 0.8px at 87.41% 26.45%, rgba(212,230,255,0.72) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.1px 1.1px at 31.61% 27.77%, rgba(212,230,255,0.61) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.8px 0.8px at 66.71% 6.34%, rgba(212,230,255,0.44) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.9px 0.9px at 74.37% 57.18%, rgba(255,255,255,0.54) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.7px 0.7px at 93.63% 46.84%, rgba(212,230,255,0.62) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.9px 0.9px at 96.55% 55.53%, rgba(255,255,255,0.44) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.8px 0.8px at 6.09% 45.18%, rgba(212,230,255,0.48) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.0px 1.0px at 82.20% 6.88%, rgba(255,255,255,0.41) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.1px 1.1px at 79.40% 8.38%, rgba(212,230,255,0.55) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.8px 0.8px at 18.62% 6.59%, rgba(255,255,255,0.71) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.8px 0.8px at 72.62% 20.60%, rgba(255,238,216,0.40) 0%, rgba(255,238,216,0) 100%),
    radial-gradient(0.7px 0.7px at 83.98% 31.64%, rgba(255,255,255,0.54) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.0px 1.0px at 87.33% 1.80%, rgba(255,255,255,0.53) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.2px 1.2px at 82.85% 38.90%, rgba(212,230,255,0.46) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.8px 0.8px at 83.00% 57.68%, rgba(255,255,255,0.48) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.1px 1.1px at 38.00% 30.15%, rgba(212,230,255,0.49) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.1px 1.1px at 61.69% 9.02%, rgba(212,230,255,0.63) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.2px 1.2px at 53.97% 17.04%, rgba(212,230,255,0.51) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.8px 0.8px at 78.95% 33.85%, rgba(212,230,255,0.44) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.1px 1.1px at 4.11% 26.84%, rgba(212,230,255,0.44) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.2px 1.2px at 1.73% 43.60%, rgba(255,255,255,0.58) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.9px 0.9px at 4.31% 56.88%, rgba(255,255,255,0.52) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.0px 1.0px at 67.67% 33.09%, rgba(255,255,255,0.68) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.7px 0.7px at 98.57% 44.06%, rgba(212,230,255,0.52) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.8px 0.8px at 71.77% 36.74%, rgba(255,255,255,0.57) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.1px 1.1px at 15.95% 29.36%, rgba(255,255,255,0.48) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.9px 0.9px at 72.52% 50.48%, rgba(255,255,255,0.58) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.0px 1.0px at 18.71% 5.04%, rgba(255,255,255,0.47) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.0px 1.0px at 49.20% 0.70%, rgba(255,255,255,0.59) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(0.8px 0.8px at 29.28% 28.49%, rgba(212,230,255,0.50) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.9px 0.9px at 94.63% 11.80%, rgba(255,255,255,0.64) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.1px 1.1px at 93.94% 35.44%, rgba(212,230,255,0.71) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.7px 0.7px at 86.02% 1.06%, rgba(212,230,255,0.57) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.8px 0.8px at 45.36% 31.59%, rgba(255,238,216,0.58) 0%, rgba(255,238,216,0) 100%),
    radial-gradient(0.8px 0.8px at 91.36% 49.08%, rgba(212,230,255,0.61) 0%, rgba(212,230,255,0) 100%);
}

.m-hero-galaxy-s3 {
  background-image:
    radial-gradient(1.2px 1.2px at 27.36% 26.22%, rgba(212,230,255,0.68) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.0px 1.0px at 82.59% 2.84%, rgba(212,230,255,0.74) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.0px 1.0px at 53.01% 31.48%, rgba(255,255,255,0.56) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.3px 1.3px at 83.66% 39.26%, rgba(212,230,255,0.76) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.0px 1.0px at 45.55% 32.77%, rgba(255,238,216,0.64) 0%, rgba(255,238,216,0) 100%),
    radial-gradient(1.0px 1.0px at 79.38% 24.42%, rgba(212,230,255,0.58) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.4px 1.4px at 85.89% 15.04%, rgba(255,255,255,0.79) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.4px 1.4px at 50.31% 18.59%, rgba(255,255,255,0.51) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.4px 1.4px at 75.69% 43.22%, rgba(255,255,255,0.65) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.2px 1.2px at 87.31% 16.91%, rgba(212,230,255,0.66) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.0px 1.0px at 37.82% 26.38%, rgba(255,255,255,0.72) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.0px 1.0px at 50.72% 5.74%, rgba(212,230,255,0.73) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.1px 1.1px at 41.28% 28.10%, rgba(255,255,255,0.77) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.0px 1.0px at 64.41% 24.18%, rgba(255,255,255,0.52) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.1px 1.1px at 81.25% 55.29%, rgba(212,230,255,0.81) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.5px 1.5px at 17.20% 25.01%, rgba(255,255,255,0.78) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.1px 1.1px at 26.32% 11.82%, rgba(255,238,216,0.67) 0%, rgba(255,238,216,0) 100%),
    radial-gradient(1.4px 1.4px at 2.68% 35.44%, rgba(255,255,255,0.69) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.4px 1.4px at 6.85% 25.65%, rgba(212,230,255,0.72) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.0px 1.0px at 34.00% 30.38%, rgba(212,230,255,0.78) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.9px 0.9px at 98.95% 5.22%, rgba(255,255,255,0.77) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.3px 1.3px at 2.75% 37.70%, rgba(212,230,255,0.63) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.3px 1.3px at 16.23% 26.87%, rgba(212,230,255,0.61) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.9px 0.9px at 82.85% 53.73%, rgba(212,230,255,0.53) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.1px 1.1px at 88.89% 37.04%, rgba(212,230,255,0.71) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.3px 1.3px at 78.54% 19.93%, rgba(255,255,255,0.68) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.0px 1.0px at 82.62% 48.76%, rgba(212,230,255,0.67) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.9px 0.9px at 12.85% 33.43%, rgba(255,255,255,0.69) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.1px 1.1px at 75.50% 18.68%, rgba(255,255,255,0.51) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.1px 1.1px at 52.57% 12.73%, rgba(255,238,216,0.51) 0%, rgba(255,238,216,0) 100%),
    radial-gradient(1.0px 1.0px at 11.76% 10.55%, rgba(255,255,255,0.57) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.0px 1.0px at 51.05% 6.18%, rgba(212,230,255,0.56) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.2px 1.2px at 8.80% 43.63%, rgba(255,255,255,0.73) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.2px 1.2px at 61.83% 22.23%, rgba(212,230,255,0.60) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.1px 1.1px at 83.45% 26.73%, rgba(255,255,255,0.73) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.4px 1.4px at 87.08% 24.90%, rgba(255,255,255,0.51) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.3px 1.3px at 7.37% 48.23%, rgba(212,230,255,0.75) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.4px 1.4px at 77.98% 42.79%, rgba(212,230,255,0.53) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.5px 1.5px at 85.50% 30.59%, rgba(255,255,255,0.70) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.1px 1.1px at 56.58% 15.70%, rgba(255,255,255,0.52) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.0px 1.0px at 78.46% 10.01%, rgba(255,255,255,0.61) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.1px 1.1px at 50.63% 14.80%, rgba(255,238,216,0.66) 0%, rgba(255,238,216,0) 100%),
    radial-gradient(0.9px 0.9px at 53.04% 0.78%, rgba(255,255,255,0.60) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.1px 1.1px at 0.02% 25.90%, rgba(212,230,255,0.70) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.1px 1.1px at 9.36% 35.90%, rgba(212,230,255,0.77) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.3px 1.3px at 76.20% 55.68%, rgba(212,230,255,0.74) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.5px 1.5px at 5.76% 30.20%, rgba(212,230,255,0.55) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.5px 1.5px at 69.60% 43.01%, rgba(255,255,255,0.75) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.2px 1.2px at 22.30% 30.19%, rgba(212,230,255,0.81) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.0px 1.0px at 14.47% 12.67%, rgba(212,230,255,0.58) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.9px 0.9px at 56.78% 0.47%, rgba(212,230,255,0.59) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(0.9px 0.9px at 46.31% 20.85%, rgba(255,255,255,0.81) 0%, rgba(255,255,255,0) 100%);
}

.m-hero-galaxy-s4 {
  background-image:
    radial-gradient(1.2px 1.2px at 82.06% 9.83%, rgba(212,230,255,0.57) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.6px 1.6px at 7.90% 37.78%, rgba(255,255,255,0.62) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.8px 1.8px at 82.80% 8.15%, rgba(255,255,255,0.87) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.6px 1.6px at 24.63% 5.93%, rgba(212,230,255,0.84) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.7px 1.7px at 72.55% 20.15%, rgba(255,255,255,0.90) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.5px 1.5px at 90.83% 50.47%, rgba(212,230,255,0.77) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.9px 1.9px at 11.30% 37.89%, rgba(255,255,255,0.84) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.7px 1.7px at 9.15% 46.98%, rgba(255,255,255,0.57) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.2px 1.2px at 88.97% 8.19%, rgba(212,230,255,0.81) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.7px 1.7px at 1.44% 43.04%, rgba(255,255,255,0.74) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.3px 1.3px at 95.19% 17.29%, rgba(212,230,255,0.89) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.3px 1.3px at 21.99% 29.27%, rgba(255,255,255,0.88) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.6px 1.6px at 78.09% 16.01%, rgba(255,255,255,0.86) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.4px 1.4px at 90.76% 17.68%, rgba(212,230,255,0.73) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.5px 1.5px at 33.52% 1.64%, rgba(255,255,255,0.57) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.7px 1.7px at 7.58% 25.50%, rgba(212,230,255,0.69) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.8px 1.8px at 78.81% 40.69%, rgba(255,238,216,0.56) 0%, rgba(255,238,216,0) 100%),
    radial-gradient(1.8px 1.8px at 10.91% 8.58%, rgba(212,230,255,0.57) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.3px 1.3px at 15.89% 12.26%, rgba(212,230,255,0.65) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.3px 1.3px at 4.26% 32.00%, rgba(212,230,255,0.89) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.9px 1.9px at 9.69% 51.64%, rgba(255,255,255,0.79) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.5px 1.5px at 38.27% 8.94%, rgba(255,238,216,0.59) 0%, rgba(255,238,216,0) 100%),
    radial-gradient(1.6px 1.6px at 8.53% 3.58%, rgba(212,230,255,0.81) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.5px 1.5px at 76.46% 6.73%, rgba(212,230,255,0.67) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.9px 1.9px at 67.88% 32.80%, rgba(212,230,255,0.81) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.6px 1.6px at 71.45% 46.56%, rgba(255,255,255,0.72) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.8px 1.8px at 61.11% 2.45%, rgba(212,230,255,0.76) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.5px 1.5px at 7.70% 43.09%, rgba(255,255,255,0.83) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.5px 1.5px at 96.51% 31.65%, rgba(255,238,216,0.82) 0%, rgba(255,238,216,0) 100%),
    radial-gradient(1.4px 1.4px at 0.41% 16.52%, rgba(212,230,255,0.85) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.8px 1.8px at 13.67% 6.37%, rgba(212,230,255,0.58) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.7px 1.7px at 98.95% 0.45%, rgba(255,255,255,0.84) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.9px 1.9px at 80.04% 12.70%, rgba(255,255,255,0.80) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.8px 1.8px at 11.10% 23.20%, rgba(212,230,255,0.88) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.8px 1.8px at 97.24% 28.34%, rgba(255,255,255,0.74) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.4px 1.4px at 55.45% 26.84%, rgba(212,230,255,0.84) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.4px 1.4px at 79.21% 40.61%, rgba(255,238,216,0.74) 0%, rgba(255,238,216,0) 100%),
    radial-gradient(1.3px 1.3px at 34.54% 15.57%, rgba(255,255,255,0.89) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.6px 1.6px at 12.90% 19.81%, rgba(212,230,255,0.90) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.6px 1.6px at 7.06% 38.29%, rgba(255,255,255,0.86) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.4px 1.4px at 49.90% 13.38%, rgba(255,255,255,0.89) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.4px 1.4px at 91.35% 18.19%, rgba(212,230,255,0.72) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.6px 1.6px at 7.03% 21.27%, rgba(212,230,255,0.83) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.9px 1.9px at 97.73% 26.92%, rgba(255,238,216,0.65) 0%, rgba(255,238,216,0) 100%);
}

.m-hero-galaxy-s5 {
  background-image:
    radial-gradient(1.6px 1.6px at 23.67% 30.39%, rgba(255,255,255,0.92) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(2.1px 2.1px at 21.99% 32.66%, rgba(212,230,255,0.96) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(2.4px 2.4px at 83.50% 47.78%, rgba(212,230,255,0.87) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(2.4px 2.4px at 31.35% 25.06%, rgba(212,230,255,0.91) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(2.4px 2.4px at 47.20% 1.27%, rgba(212,230,255,0.92) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.8px 1.8px at 69.88% 46.78%, rgba(212,230,255,0.95) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(2.3px 2.3px at 12.40% 4.59%, rgba(255,255,255,0.88) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.7px 1.7px at 60.40% 22.49%, rgba(212,230,255,0.93) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.9px 1.9px at 17.44% 27.92%, rgba(255,255,255,0.95) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(2.1px 2.1px at 78.64% 39.68%, rgba(255,255,255,0.91) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.7px 1.7px at 30.97% 6.65%, rgba(255,255,255,0.84) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.8px 1.8px at 22.45% 16.02%, rgba(212,230,255,0.65) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.7px 1.7px at 19.05% 31.43%, rgba(212,230,255,0.87) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(2.4px 2.4px at 89.44% 5.04%, rgba(255,238,216,0.90) 0%, rgba(255,238,216,0) 100%),
    radial-gradient(2.1px 2.1px at 64.21% 21.79%, rgba(255,255,255,0.81) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.6px 1.6px at 92.49% 32.19%, rgba(255,255,255,0.90) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(2.4px 2.4px at 50.64% 18.46%, rgba(255,255,255,0.77) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(2.2px 2.2px at 80.60% 42.78%, rgba(255,255,255,0.83) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.7px 1.7px at 89.31% 45.01%, rgba(255,255,255,0.75) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.9px 1.9px at 10.27% 30.87%, rgba(212,230,255,0.66) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.9px 1.9px at 87.33% 13.77%, rgba(255,238,216,0.77) 0%, rgba(255,238,216,0) 100%),
    radial-gradient(2.0px 2.0px at 53.91% 12.67%, rgba(212,230,255,0.81) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(2.4px 2.4px at 75.29% 1.88%, rgba(255,255,255,0.90) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(2.3px 2.3px at 18.78% 11.69%, rgba(255,238,216,0.91) 0%, rgba(255,238,216,0) 100%),
    radial-gradient(1.7px 1.7px at 85.71% 25.04%, rgba(255,238,216,0.86) 0%, rgba(255,238,216,0) 100%),
    radial-gradient(1.7px 1.7px at 96.94% 42.98%, rgba(212,230,255,0.82) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(2.4px 2.4px at 32.86% 29.61%, rgba(212,230,255,0.71) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(2.2px 2.2px at 91.74% 6.38%, rgba(255,255,255,0.70) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.8px 1.8px at 68.61% 18.30%, rgba(212,230,255,0.77) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.9px 1.9px at 66.91% 14.46%, rgba(255,238,216,0.92) 0%, rgba(255,238,216,0) 100%),
    radial-gradient(2.0px 2.0px at 67.12% 19.50%, rgba(255,255,255,0.74) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(1.9px 1.9px at 95.72% 45.43%, rgba(212,230,255,0.84) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(1.8px 1.8px at 41.17% 26.23%, rgba(212,230,255,0.92) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(2.5px 2.5px at 3.24% 35.71%, rgba(212,230,255,0.84) 0%, rgba(212,230,255,0) 100%);
}

.m-hero-galaxy-s6 {
  background-image:
    radial-gradient(3.0px 3.0px at 69.62% 20.66%, rgba(212,230,255,0.91) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(2.6px 2.6px at 91.64% 4.13%, rgba(255,255,255,0.84) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(3.1px 3.1px at 67.74% 15.87%, rgba(212,230,255,0.72) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(2.4px 2.4px at 99.25% 2.53%, rgba(255,255,255,0.99) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(2.5px 2.5px at 67.02% 7.30%, rgba(255,255,255,0.92) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(2.5px 2.5px at 38.02% 15.96%, rgba(212,230,255,0.88) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(2.6px 2.6px at 31.80% 16.94%, rgba(212,230,255,0.91) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(2.1px 2.1px at 18.54% 26.44%, rgba(212,230,255,0.78) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(3.2px 3.2px at 53.83% 8.67%, rgba(255,238,216,0.73) 0%, rgba(255,238,216,0) 100%),
    radial-gradient(2.9px 2.9px at 35.66% 1.68%, rgba(255,255,255,0.88) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(2.4px 2.4px at 91.77% 38.57%, rgba(255,238,216,0.73) 0%, rgba(255,238,216,0) 100%),
    radial-gradient(3.2px 3.2px at 87.61% 41.78%, rgba(212,230,255,0.70) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(3.2px 3.2px at 2.51% 28.88%, rgba(255,238,216,0.94) 0%, rgba(255,238,216,0) 100%),
    radial-gradient(2.4px 2.4px at 86.26% 1.69%, rgba(212,230,255,0.86) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(3.2px 3.2px at 13.41% 19.67%, rgba(212,230,255,0.93) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(2.5px 2.5px at 93.96% 30.27%, rgba(212,230,255,0.96) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(2.6px 2.6px at 25.30% 0.32%, rgba(255,255,255,0.99) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(3.0px 3.0px at 86.34% 30.34%, rgba(212,230,255,0.99) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(3.1px 3.1px at 10.69% 25.51%, rgba(212,230,255,0.78) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(3.2px 3.2px at 16.86% 9.14%, rgba(212,230,255,0.95) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(3.2px 3.2px at 81.14% 13.32%, rgba(255,255,255,0.86) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(3.2px 3.2px at 96.63% 26.39%, rgba(212,230,255,0.77) 0%, rgba(212,230,255,0) 100%),
    radial-gradient(2.6px 2.6px at 51.93% 3.66%, rgba(255,255,255,0.86) 0%, rgba(255,255,255,0) 100%),
    radial-gradient(2.3px 2.3px at 87.72% 45.99%, rgba(255,255,255,0.96) 0%, rgba(255,255,255,0) 100%);
}

/* Swing climbs with the layer: the dust barely breathes, the near stars swing
   hard. `alternate` throughout, so nothing ever jumps. */
.m-hero-galaxy-s1 {
  animation:
    m-hero-galaxy-tw1 6700ms ease-in-out -1400ms infinite alternate,
    m-hero-galaxy-drift1 170s ease-in-out infinite alternate;
}
.m-hero-galaxy-s2 {
  animation:
    m-hero-galaxy-tw2 8300ms ease-in-out -3100ms infinite alternate,
    m-hero-galaxy-drift2 190s ease-in-out infinite alternate;
}
.m-hero-galaxy-s3 {
  animation:
    m-hero-galaxy-tw3 9700ms ease-in-out -600ms infinite alternate,
    m-hero-galaxy-drift1 150s ease-in-out infinite alternate;
}
.m-hero-galaxy-s4 {
  animation:
    m-hero-galaxy-tw4 11900ms ease-in-out -5200ms infinite alternate,
    m-hero-galaxy-drift2 165s ease-in-out infinite alternate;
}
.m-hero-galaxy-s5 {
  animation:
    m-hero-galaxy-tw5 14300ms ease-in-out -2400ms infinite alternate,
    m-hero-galaxy-drift1 200s ease-in-out infinite alternate;
}
.m-hero-galaxy-s6 {
  animation:
    m-hero-galaxy-tw6 17100ms ease-in-out -7900ms infinite alternate,
    m-hero-galaxy-drift2 230s ease-in-out infinite alternate;
}

@keyframes m-hero-galaxy-tw1 {
  from { opacity: 0.5; }
  to { opacity: 0.95; }
}
@keyframes m-hero-galaxy-tw2 {
  from { opacity: 0.42; }
  to { opacity: 1; }
}
@keyframes m-hero-galaxy-tw3 {
  from { opacity: 0.36; }
  to { opacity: 1; }
}
@keyframes m-hero-galaxy-tw4 {
  from { opacity: 0.3; }
  to { opacity: 1; }
}
@keyframes m-hero-galaxy-tw5 {
  from { opacity: 0.24; }
  to { opacity: 1; }
}
@keyframes m-hero-galaxy-tw6 {
  from { opacity: 0.18; }
  to { opacity: 1; }
}

/* The whole field creeps. Under a percent over three minutes — invisible as
   movement, but the sky is not the same sky two minutes later. */
@keyframes m-hero-galaxy-drift1 {
  from { transform: translate3d(-0.45%, 0.2%, 0); }
  to { transform: translate3d(0.5%, -0.3%, 0); }
}
@keyframes m-hero-galaxy-drift2 {
  from { transform: translate3d(0.4%, -0.25%, 0); }
  to { transform: translate3d(-0.55%, 0.3%, 0); }
}

/* --- the sparkles -------------------------------------------------------- */

/* Ten stars that are meant to be SEEN doing it.
 *
 * These are the drama. Each is a real element with its own size, period, offset
 * and peak, so they never coincide: brightness ramps up fast and falls away
 * slowly, and a four-point diffraction cross opens across it at the peak — the
 * way a bright star reads through a lens, not the way a particle system looks.
 *
 * Ten, not fifty. The restraint is what keeps this on the right side of the line
 * between cinematic and cheap. */
.m-hero-galaxy-sparks {
  position: absolute;
  inset: 0;
  z-index: -2;
  pointer-events: none;
}

.m-hero-galaxy-spark {
  position: absolute;
  width: var(--s);
  height: var(--s);
  margin: calc(var(--s) / -2) 0 0 calc(var(--s) / -2);
  border-radius: 50%;
  background: radial-gradient(
    circle,
    rgba(255, 255, 255, 1) 0%,
    rgba(216, 233, 255, 0.85) 22%,
    rgba(180, 210, 255, 0.35) 46%,
    rgba(150, 190, 255, 0) 72%
  );
  opacity: 0.16;
  animation: m-hero-galaxy-sparkPulse var(--d) ease-in-out var(--w) infinite;
}

/* The cross. Two hairlines, scaled and faded on the same clock as the core. */
.m-hero-galaxy-spark::before,
.m-hero-galaxy-spark::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  opacity: 0;
  box-shadow: 0 0 6px rgba(190, 216, 255, 0.5);
  animation: m-hero-galaxy-sparkCross var(--d) ease-in-out var(--w) infinite;
}

.m-hero-galaxy-spark::before {
  width: calc(var(--s) * 5.2);
  height: 1px;
  margin: 0 0 0 calc(var(--s) * -2.6);
  background: linear-gradient(
    90deg,
    rgba(214, 232, 255, 0) 0%,
    rgba(255, 255, 255, 0.9) 50%,
    rgba(214, 232, 255, 0) 100%
  );
}

.m-hero-galaxy-spark::after {
  width: 1px;
  height: calc(var(--s) * 5.2);
  margin: calc(var(--s) * -2.6) 0 0 0;
  background: linear-gradient(
    180deg,
    rgba(214, 232, 255, 0) 0%,
    rgba(255, 255, 255, 0.9) 50%,
    rgba(214, 232, 255, 0) 100%
  );
}

/* Fast up, slow down — 12% of the cycle to reach peak, the rest to fall away.
   That asymmetry is what makes it read as a star catching the light rather than
   as something switching on and off. */
@keyframes m-hero-galaxy-sparkPulse {
  0% {
    opacity: 0.16;
    transform: scale(0.82);
  }
  12% {
    opacity: var(--p);
    transform: scale(1.28);
  }
  46% {
    opacity: 0.34;
    transform: scale(0.96);
  }
  100% {
    opacity: 0.16;
    transform: scale(0.82);
  }
}

@keyframes m-hero-galaxy-sparkCross {
  0% {
    opacity: 0;
    transform: scale(0.3);
  }
  12% {
    opacity: 0.95;
    transform: scale(1.1);
  }
  40% {
    opacity: 0.22;
    transform: scale(0.7);
  }
  100% {
    opacity: 0;
    transform: scale(0.3);
  }
}

/* Placement. Ten spots spread across the sky, none close to another, each with
   its own size, period, offset and peak so no two ever fire together. */
.m-hero-galaxy-spark:nth-child(1) { left: 8.5%; top: 12%; --s: 8.5px; --d: 8.62s; --w: -8.75s; --p: 0.98; }
.m-hero-galaxy-spark:nth-child(2) { left: 21%; top: 26%; --s: 12.8px; --d: 7.63s; --w: -1.25s; --p: 0.99; }
.m-hero-galaxy-spark:nth-child(3) { left: 34%; top: 8%; --s: 12.2px; --d: 6.48s; --w: -5.33s; --p: 0.88; }
.m-hero-galaxy-spark:nth-child(4) { left: 52%; top: 17%; --s: 11px; --d: 9.97s; --w: -4.48s; --p: 0.97; }
.m-hero-galaxy-spark:nth-child(5) { left: 66%; top: 27%; --s: 9.3px; --d: 8.79s; --w: -2.84s; --p: 0.96; }
.m-hero-galaxy-spark:nth-child(6) { left: 78%; top: 9%; --s: 12.7px; --d: 5.86s; --w: -4.98s; --p: 0.89; }
.m-hero-galaxy-spark:nth-child(7) { left: 88%; top: 21%; --s: 10.6px; --d: 8.09s; --w: -4.12s; --p: 0.87; }
.m-hero-galaxy-spark:nth-child(8) { left: 15%; top: 44%; --s: 12px; --d: 10.06s; --w: -1.72s; --p: 0.99; }
.m-hero-galaxy-spark:nth-child(9) { left: 72%; top: 45%; --s: 9.6px; --d: 6.43s; --w: -8.24s; --p: 0.86; }
.m-hero-galaxy-spark:nth-child(10) { left: 93%; top: 37%; --s: 7.6px; --d: 7.44s; --w: -7.24s; --p: 0.85; }

/* --- the glass ----------------------------------------------------------- */

/* Starlight crossing the facade, and nothing more.
 *
 * The building never moves after the push-in. What it gets is one very wide,
 * very soft, very low band that passes over it and is gone — 26s per cycle, of
 * which it is visible for about four. No flare, no hard edge, no bloom, nothing
 * that reads as a light source switching on. */
.m-hero-galaxy-glass {
  position: absolute;
  left: -30%;
  top: 18%;
  z-index: -2;
  width: 46%;
  height: 96%;
  transform: rotate(9deg) translate3d(0, 0, 0);
  background: linear-gradient(
    100deg,
    rgba(198, 222, 255, 0) 0%,
    rgba(198, 222, 255, 0.045) 40%,
    rgba(214, 234, 255, 0.085) 50%,
    rgba(198, 222, 255, 0.045) 60%,
    rgba(198, 222, 255, 0) 100%
  );
  filter: blur(22px);
  opacity: 0;
  pointer-events: none;
  animation: m-hero-galaxy-glassPass 26s ease-in-out infinite;
}

@keyframes m-hero-galaxy-glassPass {
  0% {
    transform: rotate(9deg) translate3d(0, 0, 0);
    opacity: 0;
  }
  6% {
    opacity: 1;
  }
  22% {
    opacity: 1;
  }
  30% {
    transform: rotate(9deg) translate3d(300%, 0, 0);
    opacity: 0;
  }
  100% {
    transform: rotate(9deg) translate3d(300%, 0, 0);
    opacity: 0;
  }
}

/* --- content ------------------------------------------------------------- */

/* Carried over from the star hero unchanged — same components, same global
   classes, same wording, same destinations. No text animation was added: the
   sky is the only thing allowed to be loud. */
.m-hero-galaxy-inner {
  position: relative;
  z-index: 1;
  text-align: center;
}

/* --- cost when nobody is looking ----------------------------------------- */

/* One IntersectionObserver flips this attribute and every looping layer stops.
   The push-in is deliberately excluded — it is a one-shot that has to be allowed
   to finish, or it would resume minutes later and look like a second move. */
.m-hero-galaxy-scene[data-rest="1"] .m-hero-galaxy-galaxy,
.m-hero-galaxy-scene[data-rest="1"] .m-hero-galaxy-field span,
.m-hero-galaxy-scene[data-rest="1"] .m-hero-galaxy-spark,
.m-hero-galaxy-scene[data-rest="1"] .m-hero-galaxy-spark::before,
.m-hero-galaxy-scene[data-rest="1"] .m-hero-galaxy-spark::after,
.m-hero-galaxy-scene[data-rest="1"] .m-hero-galaxy-glass {
  animation-play-state: paused;
}

/* --- reduced motion ------------------------------------------------------ */

/* Nothing moves and nothing pulses. The scene is simply the photograph, settled,
   with the added stars held at a fixed brightness — still a night sky, just not
   an animated one. */
@media (prefers-reduced-motion: reduce) {
  .m-hero-galaxy-media {
    animation: none;
    transform: scale(1.035);
  }
  .m-hero-galaxy-galaxy,
  .m-hero-galaxy-field span,
  .m-hero-galaxy-glass {
    animation: none;
  }
  .m-hero-galaxy-field span {
    opacity: 0.8;
  }
  .m-hero-galaxy-glass {
    opacity: 0;
  }
  .m-hero-galaxy-spark {
    animation: none;
    opacity: 0.7;
  }
  .m-hero-galaxy-spark::before,
  .m-hero-galaxy-spark::after {
    animation: none;
    opacity: 0.45;
    transform: scale(1);
  }
}

/* ===== src/components/sections/HeroShowAndProve.module.css  →  .m-hero-show-and-prove-* ===== */
/* HOME hero — the state signed off on /hero-lab.
 *
 * Component-scoped on purpose: nothing here is appended to globals.css, so no
 * screen that does not render this component can be affected by it.
 *
 * Two rules, and both come straight from the approved lab. The star field and
 * the veil bring their own styling — `StarField` paints its own ground and
 * `.home-hero-veil` is the original global class at its original strength — so
 * there is nothing to restate for either.
 */

/* The frame.
 *
 * `.home-hero`, which `sections/Hero.tsx` uses, floors at
 * `clamp(640px, 100svh, 1000px)`. The cap is the one thing deliberately not
 * carried over: on a tall monitor it left the hero at 1000px with the next
 * section already on screen. This is uncapped, so the first screen is the hero
 * and nothing else — which is the state that was approved.
 *
 * `100vh` first as the floor for browsers without the newer units, `100svh`
 * after it. `dvh` is NOT used: on mobile it re-measures as the URL bar hides
 * and shows, which would resize the hero mid-scroll.
 *
 * The paddings are load-bearing — they are what put the copy block where it was
 * measured rather than at the true vertical centre. */
/* Pinned, so the star field is still there behind Metrics as it rises over the
   top. The sticky range is bounded by `.stack` in home.module.css — see the
   note there. */
.m-hero-show-and-prove-scene {
  position: sticky;
  top: 0;
  display: flex;
  align-items: center;
  min-height: 100vh;
  min-height: 100svh;
  padding-top: calc(var(--header-h) + 90px);
  padding-bottom: 120px;
  overflow: hidden;
  /* The original hero's own fallback ground, so nothing flashes a different
     colour before the canvas paints its first frame. */
  background: #03081c;
}

/* The copy block. Width, gutters and centring come from the global
   `.page-container` it also carries; this only lifts it above the canvas. */
.m-hero-show-and-prove-inner {
  position: relative;
  z-index: 1;
  text-align: center;
  will-change: transform, opacity;
}

/* ===== src/components/sections/HeroVideoBackdrop.module.css  →  .m-hero-video-backdrop-* ===== */
/*
 * HOME hero video backdrop.
 *
 * ---------------------------------------------------------------------------
 * 2026-08-27 — 워터마크 크롭 해제
 * ---------------------------------------------------------------------------
 * 배경 영상이 1920×1080 H.264(`hero-company-1080.mp4`)로 교체되면서
 * `width: 116%` 를 100% 로 되돌렸다.
 *
 * 116% 는 이전 영상(1280×720)의 우하단 Gemini 워터마크를 화면 밖으로 밀어내려고
 * 넣었던 값이다. 픽셀 격자 판독과 20프레임 시간축 검출로 x 1143–1181,
 * y 584–617 에 고정되어 있는 것을 확인하고, 우측 13.8% 를 항상 잘라내도록
 * 잡았던 것이다.
 *
 * 새 영상에는 그 워터마크가 없다 — 같은 자리를 4개 시점에서 확대해 확인했다.
 * 그래서 116% 는 지킬 것이 없는 크롭이 되었고, 오히려 화면 중앙에 와야 할 해를
 * 오른쪽으로 밀어내고 있었다. 100% 로 되돌리면 컨테이너와 정확히 같은 크기가
 * 되어 `object-fit: cover` 가 화면비 차이만큼만 자른다.
 */

.m-hero-video-backdrop-videoLayer {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: #0a1526;
  z-index: 0;
}

.m-hero-video-backdrop-video {
  position: absolute;
  top: 0;
  left: 0;
  /* Tailwind preflight 의 `video { max-width: 100% }` 를 덮는다. 지금은 폭이
     100% 라 클램프되어도 결과가 같지만, 값을 다시 올릴 일이 생겼을 때 조용히
     무시되는 것을 막으려고 남겨 둔다. */
  max-width: none;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* 2026-08-27: 0% → 50%. 왼쪽 정렬은 이전 영상의 우하단 워터마크를 잘라내려고
     쓰던 값이라, 남는 폭을 전부 오른쪽에서 떼어냈다. 새 영상에는 워터마크가
     없고 구도가 좌우 대칭이라 가운데를 기준으로 반씩 나누는 편이 맞다.
     16:9 화면(예: 1920×1080)에서는 남는 폭이 0 이라 값과 무관하게 결과가
     같고, 16:10 처럼 세로가 짧은 화면에서만 차이가 난다. */
  object-position: 50% 50%;
  pointer-events: none;
}

/* 세로 화면은 무엇을 하든 가로가 크게 잘린다. 어디를 남길지가 전부다.
   2026-08-27 배경 영상 교체에 맞춰 40% → 50% 로 옮겼다.

   40% 는 이전 영상의 워터마크를 화면 밖으로 밀어내려고 잡았던 값이다. 새
   영상에는 워터마크가 없고(우하단 4개 시점 확대 확인), 대신 그 값을 그대로
   두면 화면 중앙에 와야 할 해가 오른쪽 끝에서 잘렸다.

   실측 기준 390px 폭에서: 영상이 1501px 로 스케일되고 실제로 보이는 폭은
   390px 다. 해는 영상 가로의 48% 지점(720px)에 있으므로, 그것을 가시 영역
   한가운데(195px)에 두려면 앵커가 (720-195)/(1501-452) = 50% 여야 한다.

   가로 화면(901px 이상)은 이 값이 듣지 않는다. 아래 width:116% 때문에 영상이
   폭 기준으로 cover 되어 가로 여유가 0 이고, object-position 의 X 는 남는
   공간을 나눌 때만 쓰이기 때문이다. 그쪽은 해가 중앙에서 약간 오른쪽에
   놓이는데 구도상 문제가 없어 그대로 둔다. */
@media (max-width: 900px) {
  .m-hero-video-backdrop-video {
    object-position: 50% 50%;
  }
}

/* ===== src/components/sections/RecruitCta.module.css  →  .m-recruit-cta-* ===== */
/* HOME 마지막 구간 — Recruit CTA. Component-scoped.
 *
 * Deliberately NOT the reference's closing beat. That one centres an oversized
 * serif display over a photograph; this one holds the site's own left baseline,
 * sets the bridge line as the headline and keeps the ask to a single button.
 * The composition is TAESHIN's: left-aligned, no serif display, no second CTA.
 *
 * globals.css is untouched. The only global classes used are the page
 * container, the two approved wrapping utilities and the site's own pill.
 */

/* ---------------------------------------------------------------------------
 * COLOUR — the copper signature scene.
 *
 * This section is the one place on the site that spends TAESHIN's copper, and
 * it spends all of it here rather than sprinkling the hue through the page as
 * an accent. Everything below is a colour change; the composition, the copy,
 * the single 입사 지원하기 link and every measurement in this file are as they
 * were.
 * ------------------------------------------------------------------------ */

.m-recruit-cta-section {
  position: relative;
  isolation: isolate;
  padding-top: clamp(120px, 14vw, 210px);
  padding-bottom: clamp(120px, 14vw, 210px);
  background: #a95739;
}

.m-recruit-cta-bg {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
}

/* Copper, deeper under the copy and opening toward the signature value at the
   right edge. Same 100deg, same three stops, same "darker where the type is"
   idea the navy version had — only the hue and the alphas move.
 *
 * The alphas are HIGHER than the navy version's 0.92 → 0.52 for a concrete
 * reason: the photograph underneath (sec-apply.webp) is a near-black night
 * skyline, so at 0.52 the copper was dragged down to a muddy brown and the
 * scene stopped reading as copper at all. At 0.97 → 0.90 the picture survives
 * as texture — the city lights still glimmer through the right-hand side — and
 * the section reads as one deliberate colour rather than a tinted photo. The
 * image, its file, its crop and its `object-cover` are untouched.
 *
 * The left stop is also the accessibility floor. Ivory #FFF8EF on the section
 * colour alone is 4.6:1, which is marginal for the 17px lead; on the deeper
 * copper the copy actually sits on it lands at about 7:1.
 *
 * DEPTH PASS. The scene opened at #B8613F, which photographed as a bright
 * terracotta — closer to salmon than to the substantial, architectural copper
 * this section is meant to close the page on. Every stop here is one step
 * deeper, taken by dropping value only: hue holds at ~16° and saturation at
 * ~66%, so the family is identical and the colour has not slid toward brown or
 * toward brick red. It is the same copper, lit less. */
.m-recruit-cta-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    100deg,
    rgba(138, 65, 38, 0.97) 0%,
    rgba(152, 75, 47, 0.94) 45%,
    rgba(169, 87, 57, 0.9) 100%
  );
}

.m-recruit-cta-inner {
  position: relative;
  z-index: 1;
}

/* Warm ivory throughout, at three levels of presence. 0.78 rather than the
   navy version's 0.45: on copper the same alpha fell to 2.4:1 and the label
   disappeared, and 0.78 is where an 18px bold line clears AA (4.5:1). */
.m-recruit-cta-eyebrow {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 18px;
  font-weight: 700;
  line-height: 1.2;
  color: rgba(255, 248, 239, 0.78);
}

/* The bridge from 성과 to 사람 is the headline, not a footnote — it is the
   whole reason the page is allowed to end on a recruiting ask. */
.m-recruit-cta-title {
  margin: 34px 0 0;
  max-width: 22ch;
  font-size: clamp(28px, 3.2vw, 46px);
  font-weight: 800;
  line-height: 1.4;
  letter-spacing: -0.8px;
  color: #fff8ef;
}

.m-recruit-cta-lead {
  margin: 28px 0 0;
  max-width: 44ch;
  font-size: 17px;
  font-weight: 500;
  line-height: 1.85;
  color: rgba(255, 248, 239, 0.92);
}

.m-recruit-cta-action {
  margin-top: 52px;
}

/* The button keeps the site's `.btn-pill` — same component, same padding, same
   radius, same 0.35s transition, same destination. Only its colours are
   restated for this ground, and only inside this section: the global rule is
   untouched, so the hero's two pills are unaffected.
 *
 * The grammar is the one `.btn-pill` already has — translucent at rest, solid
 * on hover, foreground and background trading places. Here it runs in ivory
 * and copper instead of white and black. */
.m-recruit-cta-section .btn-pill {
  color: #fff8ef;
  border-color: rgba(255, 248, 239, 0.55);
  background: rgba(255, 248, 239, 0.16);
}

/* Matches the breakpoint the global hover rule is written at, so touch devices
   keep the rest state. */
@media (min-width: 991px) {
  .m-recruit-cta-section .btn-pill:hover {
    color: #7e3e23;
    border-color: #fff8ef;
    background: #fff8ef;
  }
}

/* The global focus ring is white; on copper it is legible but flat. Ivory ties
   it to the scene without losing contrast. */
.m-recruit-cta-section .btn-pill:focus-visible {
  outline-color: #fff8ef;
}

@media (max-width: 767px) {
  .m-recruit-cta-title {
    letter-spacing: -0.4px;
  }
  .m-recruit-cta-lead {
    font-size: 16px;
  }
  .m-recruit-cta-action {
    margin-top: 40px;
  }
}

/* ---------------------------------------------------------------- 모바일 밀도 -- */
@media (max-width: 767px) {
  .m-recruit-cta-title {
    font-size: 22px;
  }
}

@media (max-width: 767px) {
  /* 120/120 은 화면 하나를 여백으로만 쓰는 크기였다. */
  .m-recruit-cta-section {
    padding-top: 56px;
    padding-bottom: 60px;
  }
}

/* ===== src/components/sections/StrategyToExecution.module.css  →  .m-strategy-to-execution-* ===== */
/* HOME 흰 배경 에디토리얼 — Strategy to Execution.
 *
 * Component-scoped. Next.js hashes every class below, so nothing here can
 * reach another page and nothing on another page can reach in. globals.css is
 * not touched by this section at all.
 *
 * Spacing follows the rhythm measured on the reference and already used by the
 * Portfolio block: section padding 158, eyebrow → heading 36, heading → copy
 * 30. Only the global design tokens (--navy, --font-serif) are borrowed.
 */

.m-strategy-to-execution-section {
  background: #fff;
  padding-top: 158px;
  padding-bottom: 158px;
}

.m-strategy-to-execution-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.86fr);
  align-items: center;
  gap: clamp(48px, 6vw, 110px);
}

.m-strategy-to-execution-eyebrow {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 18px;
  font-weight: 700;
  line-height: 1.2;
  color: var(--navy, #1b2f6b);
}

.m-strategy-to-execution-title {
  margin: 36px 0 0;
  font-size: clamp(28px, 2.6vw, 41px);
  font-weight: 800;
  line-height: 1.5;
  letter-spacing: -0.5px;
  color: #0f0f0f;
}

/* One word carries the brand colour, the way the reference marks the subject
   of its own heading. */
.m-strategy-to-execution-accent {
  color: var(--navy, #1b2f6b);
}

.m-strategy-to-execution-lead {
  margin: 30px 0 0;
  max-width: 560px;
  font-size: 15px;
  font-weight: 500;
  line-height: 27px;
  color: rgba(11, 15, 28, 0.66);
}

.m-strategy-to-execution-figure {
  justify-self: end;
  width: 100%;
  max-width: 522px;
}

.m-strategy-to-execution-diagram {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

.m-strategy-to-execution-ring {
  fill: none;
  stroke-width: 18;
}

/* Three stages, three weights of the same navy — the sequence reads as a
   gradient of commitment before any label is read. */
.m-strategy-to-execution-ring1 {
  stroke: #0f1b3d;
}
.m-strategy-to-execution-ring2 {
  stroke: var(--navy, #1b2f6b);
}
.m-strategy-to-execution-ring3 {
  stroke: #3f6098;
}

.m-strategy-to-execution-link {
  stroke: rgba(11, 15, 28, 0.14);
  stroke-width: 1.5;
}

.m-strategy-to-execution-label {
  text-anchor: middle;
  font-size: 15px;
  font-weight: 800;
  letter-spacing: 1.2px;
  fill: #0f1b3d;
}

.m-strategy-to-execution-ko {
  text-anchor: middle;
  font-size: 15px;
  font-weight: 600;
  fill: rgba(11, 15, 28, 0.5);
}

@media (max-width: 1023px) {
  .m-strategy-to-execution-section {
    padding-top: clamp(90px, 12vw, 158px);
    padding-bottom: clamp(90px, 12vw, 158px);
  }
  .m-strategy-to-execution-grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 56px;
  }
  .m-strategy-to-execution-figure {
    justify-self: start;
    max-width: 420px;
  }
}

/* ===== src/components/sections/WhyTaeshin.module.css  →  .m-why-taeshin-* ===== */
/* HOME 01·02·03 — component-scoped typography, proportion and rhythm.
 *
 * Values come from the read-only measurement of the reference's matching trio
 * at a 1600 viewport:
 *
 *   image : text   58 : 42, and the IMAGE keeps the larger mass on every row
 *   heading        36px, restrained weight, generous leading
 *   heading → body 125px
 *   body → CTA      61px
 *
 * globals.css is not touched. `.feature-index`, `.feature-title`, `.why-desc`
 * and `.btn-ghost` keep their existing definitions for /support, /recruit and
 * the other sections that use them; this section overrides only for itself,
 * scoping under `.copy` so the compound selector wins on specificity rather
 * than on stylesheet order.
 */

/* --- one rhythm across all three ---------------------------------------- */

/* The reference runs 01–03 as a single composition on a strict rule:
 *
 *   image height          730px, identical in all three
 *   image → next image    150px, identical in both intervals
 *   image top → text top  227px, identical in all three
 *   first section         flush with the one above it (no lead-in)
 *   sections              butt together, no gaps
 *
 * TAESHIN was not doing this. Its images were vertically CENTRED in each
 * section, so the interval was whatever the leftover space happened to be:
 * 01 and 02 were both exactly as tall as their images and the two pictures
 * TOUCHED (0px), while 03 — held to a full screen by `.sticky-stack` — floated
 * its image with 130px above and below. Three sections, three different
 * intervals.
 *
 * The fix is the reference's rule: pin the image to the TOP of every section
 * and put the interval in as a lead-in on every section except the first. */

.m-why-taeshin-grid.m-why-taeshin-rhythm {
  align-items: start;
  /* 03 is a `.sticky-stack`, which at desktop is a column flex box holding a
     full screen and centring its child. That centring silently added 55px on
     top of the lead-in and pushed the 02→03 interval to 205. An auto bottom
     margin hands the leftover space to the bottom instead, so the lead-in is
     the only thing above the image in every section. The pin itself — the
     `position: sticky` that lets the next section slide over — is untouched. */
  margin-bottom: auto;
}

/* 150px, the reference's own interval. Not on 01 — its image sits flush
   against the section above, exactly as the reference's first one does. */
.m-why-taeshin-grid.m-why-taeshin-lead {
  padding-top: 150px;
}

/* Fixed, so the interval can never be absorbed by a taller row. */
.m-why-taeshin-rhythm .m-why-taeshin-media {
  height: 640px;
  min-height: 640px;
}

/* Hover zoom timing.
 *
 * The zoom itself already exists site-wide (`.img-zoom:hover > img` scales to
 * 1.05 inside `.img-frame`, which is `overflow: hidden`) — the frame never
 * moves and only the picture grows, which is the behaviour asked for. What is
 * wrong for this section is the SPEED: the global transition is 1s, and the
 * reference does the same move in 0.4s ease-out. Measured on it:
 *
 *   rest   transform: none
 *   hover  transform: scale(1.1)   transition: transform 0.4s ease-out
 *   leave  returns to none
 *
 * Only the duration and easing are taken. The reference's 1.1 is a larger jump
 * than this site wants on a corporate block, so the existing 1.05 stays — no
 * bounce, no spring, and nothing outside the frame moves.
 */
.m-why-taeshin-rhythm .m-why-taeshin-media img {
  transition: transform 0.4s ease-out;
}

/* The reference puts 227px between the top of the image and the top of the
   heading, identically in all three. `.headGroup` already contributes 84 of
   that as the band the numeral occupies, so the column carries the remaining
   143 — set them both and the heading lands 311px down instead.
   The global rule's flat 80px was measured against a centred row, which is
   why the text drifted whenever a section changed height. */
.m-why-taeshin-rhythm .m-why-taeshin-copy {
  padding-top: 143px;
  padding-bottom: 0;
}

/* --- proportion ---------------------------------------------------------- */

/* The global rule sets 7fr 5fr for every row, and flipping only reorders the
   children — so on flipped rows the TEXT was taking the 7fr and the image was
   left with 5fr. That is why 02 read as text-heavy while 01 and 03 did not.
   Two classes here beat the single-class global, so the ratio inverts with the
   order and the image keeps the larger share on all three. */
.m-why-taeshin-grid.m-why-taeshin-flip {
  grid-template-columns: 5fr 7fr;
}

/* Scoping handle. Every override below is written as `.copy X` so it wins
   against a same-specificity global without needing !important. */
.m-why-taeshin-copy {
  position: relative;
}

/* --- number + heading as one composition -------------------------------- */

.m-why-taeshin-copy .m-why-taeshin-headGroup {
  position: relative;
  padding-top: 84px;
}

/* Serif index numeral, on its OWN line above the heading.
 *
 * It used to be a 140px ghost at 14% opacity, pulled 76px out of the column so
 * that the heading crossed it about 60% of the way along — heading in front,
 * numeral behind, the two overlapping. That overlap was the single most
 * recognisable borrowing from the reference on this page, so it is gone: the
 * numeral now sits flush with the heading's own left edge, entirely above it,
 * and nothing crosses anything.
 *
 * What is deliberately KEPT is the large serif numeral itself — that is this
 * site's own register, and shrinking it to a small label would have taken the
 * weight out of the text column. 68px against the heading's 36px holds the
 * proportion; 0.24 replaces 0.14 because at half the size the old value would
 * have disappeared.
 *
 * Still `position: absolute`, and that is load-bearing. The numeral is out of
 * flow, so it cannot push anything below it: the heading stays exactly 227px
 * under the top of the image, the 125px heading→body interval is untouched,
 * and the section keeps its height. `.headGroup`'s 84px padding is the band
 * the numeral occupies, and it is unchanged at every breakpoint.
 *
 * `aria-hidden` on the element stays. The numeral is ordering decoration, not
 * content — nothing here promotes it to something a screen reader should read.
 */
.m-why-taeshin-copy .m-why-taeshin-num {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 0;
  margin: 0;
  font-family: var(--font-serif);
  font-size: 68px;
  font-weight: 300;
  line-height: 1;
  letter-spacing: -2px;
  color: rgba(255, 255, 255, 0.24);
  pointer-events: none;
  user-select: none;
}

/* Sits below the numeral now, not over it, and flush with it on the left.
   Weight, size, leading and tracking are all unchanged — the heading itself
   was never the thing that resembled the reference. */
.m-why-taeshin-copy .m-why-taeshin-title {
  position: relative;
  z-index: 1;
  margin: 0;
  font-size: 36px;
  font-weight: 700;
  line-height: 1.35;
  letter-spacing: -0.2px;
  color: #fff;
}

/* --- rhythm -------------------------------------------------------------- */

.m-why-taeshin-copy .m-why-taeshin-body {
  margin: 125px 0 0;
  font-size: 16px;
  font-weight: 500;
  line-height: 1.55;
  letter-spacing: -0.2px;
  color: rgba(255, 255, 255, 0.86);
  max-width: none;
}

/* One sentence per line. Each is its own block, so the structure is set at
   meaning boundaries — not by a <br> inside a sentence, and not by the column
   deciding where a thought ends. */
.m-why-taeshin-copy .m-why-taeshin-line {
  display: block;
  word-break: keep-all;
  text-wrap: pretty;
}

@media (max-width: 1279px) {
  /* Held to the same 0.81 of the band the desktop value uses, so the numeral
     keeps its relationship to the heading at every width. No `left` override
     any more — it is flush with the heading on all three breakpoints. */
  .m-why-taeshin-copy .m-why-taeshin-num {
    font-size: 54px;
    letter-spacing: -1.6px;
  }
  .m-why-taeshin-copy .m-why-taeshin-headGroup {
    padding-top: 68px;
  }
  .m-why-taeshin-copy .m-why-taeshin-title {
    font-size: 32px;
  }
  .m-why-taeshin-copy .m-why-taeshin-body {
    margin-top: 88px;
  }
}

@media (max-width: 1023px) {
  /* Stacked at this width, so none of the desktop rhythm applies: no lead-in
     between images, no fixed image height, and the copy goes back to a normal
     block padding instead of the 227px offset. */
  .m-why-taeshin-grid.m-why-taeshin-flip {
    grid-template-columns: minmax(0, 1fr);
  }
  .m-why-taeshin-grid.m-why-taeshin-lead {
    padding-top: 0;
  }
  .m-why-taeshin-rhythm .m-why-taeshin-media {
    height: auto;
    min-height: 0;
  }
  .m-why-taeshin-rhythm .m-why-taeshin-copy {
    padding-top: 64px;
    padding-bottom: 64px;
  }
}

@media (max-width: 767px) {
  .m-why-taeshin-copy .m-why-taeshin-num {
    font-size: 40px;
    letter-spacing: -1.2px;
  }
  .m-why-taeshin-copy .m-why-taeshin-headGroup {
    padding-top: 50px;
  }
  .m-why-taeshin-copy .m-why-taeshin-title {
    font-size: 27px;
  }
  .m-why-taeshin-copy .m-why-taeshin-body {
    margin-top: 56px;
  }
}

/* ---------------------------------------------------------------- 모바일 밀도 --
   40px 짜리 숫자가 모바일에서 제목보다 크게 서 있었다. 위계를 되돌린다. */
@media (max-width: 767px) {
  .m-why-taeshin-copy .m-why-taeshin-num {
    font-size: 30px;
  }

  .m-why-taeshin-copy .m-why-taeshin-title {
    font-size: 21px;
  }
}

/* ===== src/components/whatwedo/WhatWeDo.module.css  →  .m-what-we-do-* ===== */
/*
 * 우리가 하는 일은 (/what-we-do) — page-scoped styling.
 *
 * A light editorial page, deliberately not the dark ladder the rest of the
 * site uses. Everything lives here rather than in globals.css so that the
 * approved dark pages cannot be reached by any of it, and so the palette can
 * be light without fighting the global tokens.
 *
 * Point colour is the site's own light-section accent, --navy (#1b2f6b), used
 * only on chapter numbers, rules, active states and the CTA. Backgrounds run
 * white → warm white → very light gray, with a single dark navy beat at
 * Reward & Growth so the payoff lands, then back to light for the close.
 */

.m-what-we-do-body {
  --ink: #101828;
  --ink-soft: #475467;
  --ink-faint: #8a94a6;
  --point: #1b2f6b;
  --point-deep: #101f4d;
  --line: #e6e8ee;
  --paper: #ffffff;
  --paper-warm: #faf9f7;
  --paper-cool: #f4f6f9;

  background: var(--paper);
  color: var(--ink);
}

/* ------------------------------------------------------------- primitives */

.m-what-we-do-wrap {
  width: min(calc(100% - 40px), 1450px);
  margin-inline: auto;
}

.m-what-we-do-chapter {
  display: flex;
  align-items: baseline;
  gap: 14px;
  margin: 0;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.m-what-we-do-chapterNo {
  font-family: var(--font-serif);
  font-size: 15px;
  letter-spacing: 0.08em;
  color: var(--point);
}

.m-what-we-do-h2 {
  margin: 22px 0 0;
  font-size: clamp(30px, 3.6vw, 52px);
  font-weight: 700;
  line-height: 1.28;
  letter-spacing: -0.02em;
  word-break: keep-all;
  text-wrap: balance;
  color: var(--ink);
}

.m-what-we-do-lead {
  margin: 26px 0 0;
  max-width: 46ch;
  font-size: clamp(16px, 1.25vw, 19px);
  line-height: 1.9;
  word-break: keep-all;
  text-wrap: pretty;
  color: var(--ink-soft);
}

/* =============================================== 01  WHAT THEY DO ======= */

.m-what-we-do-intro {
  padding: clamp(80px, 9vw, 150px) 0 clamp(60px, 7vw, 110px);
  background: var(--paper);
}

.m-what-we-do-introGrid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(40px, 6vw, 96px);
  align-items: center;
}

.m-what-we-do-introVisual {
  position: relative;
  aspect-ratio: 4 / 3;
  border-radius: 4px;
  overflow: hidden;
  background: var(--paper-cool);
}

.m-what-we-do-introVisual img {
  object-fit: cover;
}

@media (max-width: 900px) {
  .m-what-we-do-introGrid {
    grid-template-columns: 1fr;
  }
  .m-what-we-do-introVisual {
    aspect-ratio: 3 / 2;
  }
}

/* ============================================== 01-2  A DAY ON SITE ===== */

.m-what-we-do-day {
  padding: clamp(70px, 8vw, 120px) 0 clamp(90px, 10vw, 160px);
  background: var(--paper-warm);
}

.m-what-we-do-dayHead {
  max-width: 46ch;
}

/* 카드 스트립.
 *
 * 예전에는 스크롤 위치가 활성 카드를 정했고, 그 계산이 매 스크롤마다 폭을 다시
 * 그려 세로 스크롤이 버벅였다. 지금 이 스트립을 움직이는 것은 hover 하나뿐이고,
 * 그것도 전부 아래 transition 이 처리한다 — JS 는 어느 카드가 열렸는지만 알려
 * 준다.
 *
 * 감속 곡선 `cubic-bezier(0.22, 1, 0.36, 1)` 을 폭·사진·텍스트가 함께 쓴다.
 * 앞부분이 빠르게 튀어나가고 끝에서 길게 잦아드는 모양이라, 포인터에는 즉시
 * 반응하면서 마지막에 스스로 내려앉는다. 넓어지는 카드와 좁아지는 카드가 같은
 * 곡선을 쓰므로 둘이 따로 노는 느낌이 생기지 않고, 되돌아올 때도 같은 곡선을
 * 그대로 탄다. 튕김(bounce)이나 스프링 계열은 쓰지 않는다.
 *
 * 지속시간은 층을 둔다: 폭 0.46s → 사진 0.6s. 사진이 카드보다 조금 늦게
 * 따라오면 판이 열리고 그 안에서 화면이 밀려드는 것처럼 읽힌다. 텍스트는
 * 0.3s 로 가장 짧다 — 글자는 오래 흐려져 있으면 읽는 것을 방해한다. */
.m-what-we-do-dayStrip {
  margin-top: clamp(40px, 5vw, 72px);
  display: flex;
  gap: 12px;
  height: clamp(360px, 48vw, 520px);
}

.m-what-we-do-dayPanel {
  position: relative;
  /* 기본 상태는 네 장이 같은 폭. 열린 카드가 없어도 스트립이 가득 찬다. */
  flex: 1 1 0;
  min-width: 0;
  border-radius: 4px;
  overflow: hidden;
  background: #dfe3ea;
  transition: flex-grow 0.46s cubic-bezier(0.22, 1, 0.36, 1);
}

.m-what-we-do-dayPanel[data-active="true"] {
  flex-grow: 4.6;
}

.m-what-we-do-dayPanel img {
  object-fit: cover;
  transition: transform 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}

.m-what-we-do-dayPanel[data-active="true"] img {
  transform: scale(1.03);
}

.m-what-we-do-dayVeil {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to top,
    rgba(10, 16, 30, 0.82) 0%,
    rgba(10, 16, 30, 0.42) 45%,
    rgba(10, 16, 30, 0.18) 100%
  );
  transition: opacity 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}

.m-what-we-do-dayPanel[data-active="false"] .m-what-we-do-dayVeil {
  opacity: 0.92;
}

/* 카드를 덮는 투명 버튼. 좁은 화면에서만 나타난다(아래 900px 블록). */
.m-what-we-do-dayToggle {
  display: none;
  position: absolute;
  inset: 0;
  z-index: 2;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.m-what-we-do-dayCaption {
  position: absolute;
  inset: auto 0 0 0;
  padding: clamp(18px, 2vw, 32px);
  color: #fff;
}

.m-what-we-do-dayStep {
  display: block;
  font-family: var(--font-serif);
  font-size: 14px;
  letter-spacing: 0.12em;
  color: rgba(255, 255, 255, 0.72);
}

.m-what-we-do-dayTitle {
  margin: 10px 0 0;
  font-size: clamp(17px, 1.5vw, 23px);
  font-weight: 700;
  line-height: 1.35;
  white-space: nowrap;
  /* 접힌 카드는 16px, 열린 카드는 위 clamp 값이다. 그 사이를 끊어서 건너뛰면
     카드가 부드럽게 열리는 동안 제목만 딱 끊겨 튄다. 폭과 같은 곡선·같은
     길이로 함께 간다. */
  transition: font-size 0.46s cubic-bezier(0.22, 1, 0.36, 1);
}

.m-what-we-do-dayDesc {
  margin: 12px 0 0;
  max-width: 40ch;
  font-size: 15px;
  line-height: 1.8;
  word-break: keep-all;
  text-wrap: pretty;
  color: rgba(255, 255, 255, 0.86);
  opacity: 0;
  transform: translateY(10px);
  /* 카드가 벌어지기 시작한 뒤에 글이 올라오도록 아주 짧게만 늦춘다. 0.06s 는
     폭 전환이 눈에 보이기 시작하는 지점이고, 그보다 길면 0.46s 안에서 글이
     지각한 것처럼 읽힌다. */
  transition:
    opacity 0.3s cubic-bezier(0.22, 1, 0.36, 1) 0.06s,
    transform 0.3s cubic-bezier(0.22, 1, 0.36, 1) 0.06s;
}

.m-what-we-do-dayPanel[data-active="true"] .m-what-we-do-dayDesc {
  opacity: 1;
  transform: none;
}

/* Collapsed panels keep only the step number and a vertical title. */
.m-what-we-do-dayPanel[data-active="false"] .m-what-we-do-dayTitle {
  font-size: 16px;
}

/* 모션을 줄여 달라고 한 독자에게는 전환만 끈다. 배치는 그대로다 — 02 가 펼쳐진
   비대칭 구성이 이 스트립의 디자인이고, 모션 설정이 그것을 바꿔서는 안 된다.
   hover 는 여전히 동작하며 애니메이션 없이 즉시 바뀐다. */
@media (prefers-reduced-motion: reduce) {
  .m-what-we-do-dayPanel,
  .m-what-we-do-dayPanel img,
  .m-what-we-do-dayVeil,
  .m-what-we-do-dayTitle,
  .m-what-we-do-dayDesc {
    transition: none;
  }
}

@media (max-width: 900px) {
  .m-what-we-do-dayStrip {
    flex-direction: column;
    height: auto;
  }
  /* 높이는 열리든 닫히든 같다. 눌렀을 때 카드가 자라면 그만큼 페이지가
     밀려서, 손가락을 뗀 자리와 화면이 어긋난다. */
  .m-what-we-do-dayPanel,
  .m-what-we-do-dayPanel[data-active="true"] {
    flex: none;
    height: 260px;
  }

  /* hover 가 없는 기기에서는 data-active 가 뜻을 갖지 않는다. 기본값으로
     02 만 사진이 확대되고 나머지 셋이 어두워지던 것을 되돌린다. */
  .m-what-we-do-dayPanel[data-active="true"] img,
  .m-what-we-do-dayPanel[data-active="false"] img {
    transform: none;
  }

  /* 기본은 사진이 선명하게 보이는 정도. 번호·제목이 읽힐 만큼만 아래를
     어둡게 깔고, 위쪽은 거의 비운다. */
  .m-what-we-do-dayVeil,
  .m-what-we-do-dayPanel[data-active="false"] .m-what-we-do-dayVeil,
  .m-what-we-do-dayPanel[data-active="true"] .m-what-we-do-dayVeil {
    opacity: 1;
    background: linear-gradient(
      to top,
      rgba(10, 16, 30, 0.72) 0%,
      rgba(10, 16, 30, 0.28) 38%,
      rgba(10, 16, 30, 0) 68%
    );
  }

  /* 눌렀을 때 덮이는 반투명 판. 번호와 제목은 이 위에서도 계속 읽힌다. */
  .m-what-we-do-dayPanel[data-mopen="true"] .m-what-we-do-dayVeil,
  .m-what-we-do-dayPanel[data-active="true"][data-mopen="true"] .m-what-we-do-dayVeil {
    background: linear-gradient(
      to top,
      rgba(8, 13, 26, 0.9) 0%,
      rgba(8, 13, 26, 0.78) 55%,
      rgba(8, 13, 26, 0.62) 100%
    );
  }

  /* 기본 상태에서는 설명이 없다. visibility 까지 끄는 것은 화면에서 안 보이는
     글을 스크린 리더가 읽지 않게 하기 위해서다. */
  .m-what-we-do-dayDesc,
  .m-what-we-do-dayPanel[data-active="true"] .m-what-we-do-dayDesc {
    opacity: 0;
    visibility: hidden;
    transform: translateY(8px);
    transition:
      opacity 0.26s ease,
      transform 0.26s ease,
      visibility 0s linear 0.26s;
  }

  .m-what-we-do-dayPanel[data-mopen="true"] .m-what-we-do-dayDesc,
  .m-what-we-do-dayPanel[data-active="true"][data-mopen="true"] .m-what-we-do-dayDesc {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    transition:
      opacity 0.26s ease,
      transform 0.26s ease,
      visibility 0s;
  }

  .m-what-we-do-dayToggle {
    display: block;
  }

  .m-what-we-do-dayToggle:focus-visible {
    outline: 2px solid #fff;
    outline-offset: -4px;
  }
  .m-what-we-do-dayTitle,
  .m-what-we-do-dayPanel[data-active="false"] .m-what-we-do-dayTitle {
    white-space: normal;
    font-size: 20px;
  }
}

/* =================================================== 02  WHO FITS ======= */

.m-what-we-do-fits {
  padding: clamp(80px, 9vw, 150px) 0 clamp(60px, 7vw, 100px);
  background: var(--paper);
}

/* Asymmetric on purpose — three equal cards is what made this read as a
   brochure. Large lead, medium, small, each with its own weight. */
.m-what-we-do-fitGrid {
  margin-top: clamp(44px, 5vw, 76px);
  display: grid;
  grid-template-columns: 1.55fr 1fr;
  grid-template-rows: auto auto;
  gap: clamp(20px, 2.4vw, 34px);
}

.m-what-we-do-fitItem {
  margin: 0;
}

.m-what-we-do-fitItem:nth-child(1) {
  grid-row: span 2;
}

.m-what-we-do-fitShot {
  position: relative;
  overflow: hidden;
  border-radius: 4px;
  background: var(--paper-cool);
}

.m-what-we-do-fitItem:nth-child(1) .m-what-we-do-fitShot {
  aspect-ratio: 4 / 5;
}
.m-what-we-do-fitItem:nth-child(2) .m-what-we-do-fitShot {
  aspect-ratio: 16 / 10;
}
.m-what-we-do-fitItem:nth-child(3) .m-what-we-do-fitShot {
  aspect-ratio: 16 / 10;
}

.m-what-we-do-fitShot img {
  object-fit: cover;
  transition: transform 0.8s var(--ease-card, cubic-bezier(0.25, 1, 0.5, 1));
}

@media (hover: hover) {
  .m-what-we-do-fitItem:hover .m-what-we-do-fitShot img {
    transform: scale(1.02);
  }
}

.m-what-we-do-fitCaption {
  padding: 20px 2px 0;
}

.m-what-we-do-fitNo {
  font-family: var(--font-serif);
  font-size: 14px;
  letter-spacing: 0.1em;
  color: var(--point);
}

.m-what-we-do-fitTitle {
  margin: 10px 0 0;
  font-size: clamp(19px, 1.7vw, 25px);
  font-weight: 700;
  line-height: 1.4;
  word-break: keep-all;
  color: var(--ink);
}

.m-what-we-do-fitDesc {
  margin: 12px 0 0;
  max-width: 44ch;
  font-size: 15px;
  line-height: 1.85;
  word-break: keep-all;
  text-wrap: pretty;
  color: var(--ink-soft);
}

@media (max-width: 900px) {
  .m-what-we-do-fitGrid {
    grid-template-columns: 1fr;
  }
  .m-what-we-do-fitItem:nth-child(1) {
    grid-row: auto;
  }
  .m-what-we-do-fitItem:nth-child(1) .m-what-we-do-fitShot,
  .m-what-we-do-fitItem:nth-child(2) .m-what-we-do-fitShot,
  .m-what-we-do-fitItem:nth-child(3) .m-what-we-do-fitShot {
    aspect-ratio: 16 / 10;
  }
}

/* ============================================ 02-2  MISCONCEPTIONS ====== */

.m-what-we-do-myths {
  padding: clamp(60px, 7vw, 110px) 0 clamp(80px, 9vw, 140px);
  background: var(--paper-cool);
}

.m-what-we-do-mythList {
  margin: clamp(36px, 4vw, 60px) 0 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--line);
}

.m-what-we-do-mythRow {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: clamp(20px, 4vw, 64px);
  align-items: baseline;
  padding: clamp(26px, 3vw, 42px) 0;
  border-bottom: 1px solid var(--line);
}

.m-what-we-do-mythStatement {
  margin: 0;
  font-size: clamp(18px, 1.6vw, 24px);
  font-weight: 600;
  line-height: 1.5;
  word-break: keep-all;
  color: var(--ink-faint);
}

.m-what-we-do-mythCorrection {
  margin: 0;
  font-size: clamp(18px, 1.6vw, 24px);
  font-weight: 700;
  line-height: 1.5;
  word-break: keep-all;
  text-wrap: pretty;
  color: var(--point);
}

.m-what-we-do-mythArrow {
  display: inline-block;
  margin-right: 10px;
  color: var(--point);
}

.m-what-we-do-mythNote {
  margin: 12px 0 0;
  max-width: 48ch;
  font-size: 14.5px;
  line-height: 1.85;
  word-break: keep-all;
  text-wrap: pretty;
  color: var(--ink-soft);
}

@media (max-width: 760px) {
  .m-what-we-do-mythRow {
    grid-template-columns: 1fr;
    gap: 10px;
  }
}

/* ========================================= 03  REWARD & GROWTH ========== */

/* The one dark beat on the page. It carries the payoff, so it earns the
   contrast — and it is information graphic, not photography. */
.m-what-we-do-reward {
  padding: clamp(90px, 10vw, 160px) 0;
  background: #0d1730;
  color: #fff;
}

.m-what-we-do-reward .m-what-we-do-chapter {
  color: rgba(255, 255, 255, 0.5);
}
.m-what-we-do-reward .m-what-we-do-chapterNo {
  color: #96a9dd;
}
.m-what-we-do-reward .m-what-we-do-h2 {
  color: #fff;
}
.m-what-we-do-reward .m-what-we-do-lead {
  color: rgba(255, 255, 255, 0.72);
}

.m-what-we-do-tracks {
  margin-top: clamp(52px, 6vw, 90px);
  display: grid;
  gap: clamp(40px, 4.5vw, 68px);
}

/* Label ~22%, then the chain at its natural width, then the copy taking the
   rest. Laying the three out across the row is what removes the dead strip on
   the right — a two-column split left the short content stranded mid-page. */
.m-what-we-do-track {
  border-top: 1px solid rgba(255, 255, 255, 0.16);
  padding-top: clamp(24px, 2.6vw, 38px);
  display: grid;
  /* Fixed tracks rather than `auto`: each row is its own grid, so an
     auto-sized graphic column made every row start its copy at a different
     x. 40% clears the widest chain (PROJECT 01 → 02 → 03, ~560px at the
     1450px container) without wrapping. */
  grid-template-columns: 22% 40% minmax(0, 1fr);
  gap: clamp(20px, 2.2vw, 40px);
  align-items: start;
}

.m-what-we-do-trackLabel {
  margin: 0;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: #96a9dd;
}

.m-what-we-do-trackGraphic {
  min-width: 0;
}

/* One sentence per line — the two statements are separate points, and running
   them together read as a paragraph the eye skipped. */
.m-what-we-do-trackDesc {
  margin: 0;
  padding-top: 9px;
  /* No measure cap: the 46ch limit stopped this column 41px short of the
     container's right edge (1484 against 1525), which is what put it out of
     line with the section below. The column itself is the measure now. */
  font-size: 15.5px;
  line-height: 1.8;
  word-break: keep-all;
  text-wrap: pretty;
  color: rgba(255, 255, 255, 0.72);
}

.m-what-we-do-trackDesc p {
  margin: 0;
}

.m-what-we-do-trackDesc p + p {
  margin-top: 6px;
}

/* The stage line: a hairline that draws itself, with each stage lighting up
   in order once the track scrolls into view. */
/* inline-flex so the box — and therefore the hairline behind it — ends at the
   last stage instead of stretching to the edge of the column. */
.m-what-we-do-stages {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: clamp(10px, 1.6vw, 22px);
  flex-wrap: wrap;
  max-width: 100%;
}

.m-what-we-do-stageLine {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 1px;
  background: rgba(255, 255, 255, 0.16);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 1.1s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.m-what-we-do-stages[data-drawn="true"] .m-what-we-do-stageLine {
  transform: scaleX(1);
}

.m-what-we-do-stage {
  position: relative;
  z-index: 1;
  padding: 12px clamp(14px, 1.6vw, 24px);
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 999px;
  background: #0d1730;
  font-size: clamp(14px, 1.15vw, 17px);
  font-weight: 600;
  white-space: nowrap;
  color: rgba(255, 255, 255, 0.55);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.5s ease, transform 0.5s ease, color 0.5s ease,
    border-color 0.5s ease;
}

.m-what-we-do-stages[data-drawn="true"] .m-what-we-do-stage {
  opacity: 1;
  transform: none;
}

.m-what-we-do-stage[data-lit="true"] {
  color: #fff;
  border-color: #96a9dd;
}

.m-what-we-do-stageArrow {
  position: relative;
  z-index: 1;
  font-size: 14px;
  color: rgba(255, 255, 255, 0.35);
}

/* Below this the chain and the copy can no longer sit side by side, so the
   copy drops under the graphic and the label keeps its own column. */
@media (max-width: 1180px) {
  .m-what-we-do-track {
    grid-template-columns: 22% minmax(0, 1fr);
    row-gap: 16px;
  }
  .m-what-we-do-trackDesc {
    grid-column: 2;
    padding-top: 0;
  }
}

@media (max-width: 860px) {
  .m-what-we-do-track {
    grid-template-columns: 1fr;
    gap: 14px;
  }
  .m-what-we-do-trackDesc {
    grid-column: auto;
  }
  /* The chain wraps at this width, so the hairline would cut across two rows. */
  .m-what-we-do-stageLine {
    display: none;
  }
}

/* ================================================= 04  FIRST STEP ======= */

/* Deliberately still. The page has been moving for four chapters; this one
   stops, opens up, and asks. */
.m-what-we-do-first {
  padding: clamp(100px, 11vw, 180px) 0 clamp(110px, 12vw, 190px);
  background: var(--paper);
}

/*
 * The same grid lines the dark section above uses.
 *
 * `.track` runs 22% / 40% / 1fr on a clamp(20px, 2.2vw, 40px) gap, which at
 * 1600 puts its columns at 75, 429 and 1044 and ends at 1525. This grid is
 * declared identically and the headline simply spans the first two tracks, so
 * the two sections start and end on the same lines instead of on two
 * different splits (they were 75~798 / 910~1110 against 75~394 / 1044~1484).
 */
.m-what-we-do-firstGrid {
  display: grid;
  grid-template-columns: 22% 40% minmax(0, 1fr);
  gap: clamp(20px, 2.2vw, 40px);
  align-items: start;
  /* Holds the scene open now that the left column is only three elements. */
  min-height: clamp(300px, 30vw, 420px);
}

.m-what-we-do-firstLead {
  grid-column: 1 / 3;
}

/* The lead paragraph and the phone line are gone, so the button carries the
   whole left column. It sits further down and the scene keeps its height —
   the closing beat should feel open, not compacted to fit less text. */
.m-what-we-do-firstCta {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-top: clamp(44px, 5vw, 76px);
  padding: 17px 40px;
  border-radius: 999px;
  background: var(--point);
  color: #fff;
  font-size: 16px;
  font-weight: 700;
  transition: background 0.3s ease;
}

.m-what-we-do-firstCta:hover {
  background: var(--point-deep);
}

/* The labels are two characters now, so a full-width rule under each one read
   as a divider across the column rather than an underline belonging to the
   step. Shrinking the list to its content pulls the rules back to the text;
   the min-width keeps them from collapsing to the width of 면접. */
/*
 * Compact rules, pinned to the right-hand grid line.
 *
 * The list sits in the third track, which ends where the dark section's
 * description column ends — so `margin-left: auto` puts the right edge of
 * every rule on that same line while the rules themselves stay only as wide
 * as the text they belong to. `fit-content` also makes all four identical by
 * construction: the widest row sets the width and the rest follow, so no row
 * can end up longer than another.
 */
.m-what-we-do-steps {
  /* 왼쪽 auto 가 블록을 오른쪽 끝으로 민다. 그대로 두면 리스트의 오른쪽 변이
     wrap 의 우측 경계에 정확히 붙어(여백 0) 화면 가장자리에 걸린 것처럼
     읽혔다. 오른쪽에 60px 을 두어 그만큼 안으로 당긴다.

     블록 전체를 옮기는 값이라 안쪽에는 아무 영향이 없다 — 숫자와 라벨의 정렬,
     행 높이, 항목 간격, 밑줄 길이(width: fit-content 로 내용이 정한다), 폰트,
     색은 전부 그대로다. 왼쪽 제목과 CTA 도 다른 그리드 칼럼이라 움직이지
     않는다.

     모바일은 아래 860px 미디어쿼리에서 0 으로 되돌린다. 거기서는 리스트가
     왼쪽 정렬이라 오른쪽 여백이 레이아웃을 어긋나게 만든다. */
  margin: 0 60px 0 auto;
  padding: 0;
  list-style: none;
  width: fit-content;
  min-width: clamp(112px, 9vw, 140px);
  border-top: 1px solid var(--line);
}

.m-what-we-do-stepRow {
  display: flex;
  align-items: baseline;
  /* Fixed, not fluid: the four rows must read as one column and a clamp that
     moves with the viewport made the number-to-word distance drift. */
  gap: 26px;
  padding: clamp(20px, 2.2vw, 30px) 0;
  border-bottom: 1px solid var(--line);
}

.m-what-we-do-stepNo {
  font-family: var(--font-serif);
  font-size: clamp(15px, 1.2vw, 18px);
  letter-spacing: 0.08em;
  color: var(--point);
}

.m-what-we-do-stepLabel {
  font-size: clamp(16px, 1.35vw, 20px);
  font-weight: 600;
  word-break: keep-all;
  color: var(--ink);
}

@media (max-width: 860px) {
  .m-what-we-do-firstGrid {
    grid-template-columns: 1fr;
  }
  .m-what-we-do-firstLead {
    grid-column: auto;
  }
  .m-what-we-do-steps {
    /* 한 칼럼으로 쌓이는 배치라 리스트가 왼쪽에 붙는다. 데스크톱에서 준
       오른쪽 여백도 여기서는 필요 없다.

       `width: fit-content` 는 데스크톱에서 밑줄을 글자 길이에 맞추려던 값인데,
       한 칼럼이 되면 리스트가 화면 왼쪽 3분의 1만 쓰고 오른쪽이 통째로 비었다.
       좁은 화면에서는 콘텐츠 폭을 그대로 쓴다 — 그러면 번호·단계명·구분선이
       같은 좌우 기준선을 공유한다. */
    width: 100%;
    min-width: 0;
    margin-left: 0;
    margin-right: 0;
  }

  /* 번호 칸을 32px 로 고정해 두 시작선을 맞춘다 — 번호와 단계명이 모든
     행에서 같은 x 에서 시작하고, 둘 사이 간격도 한 값이다. 그룹은 왼쪽에
     붙는다. */
  .m-what-we-do-stepRow {
    display: grid;
    grid-template-columns: 32px auto;
    justify-content: start;
    column-gap: 14px;
    align-items: baseline;
    padding: 0;
    /* 행 사이의 밑줄은 없앤다. 다섯 줄짜리 짧은 목록에서 선은 정보를
       나누기보다 표처럼 보이게 만들었다. 나누는 일은 아래 여백이 한다.
       목록 위의 선(`.steps` 의 border-top)은 섹션 경계라 그대로 둔다. */
    border-bottom: 0;
  }

  .m-what-we-do-stepRow + .m-what-we-do-stepRow {
    margin-top: 22px;
  }

  .m-what-we-do-steps {
    padding-top: 22px;
  }

  .m-what-we-do-stepNo {
    text-align: left;
  }

  .m-what-we-do-stepLabel {
    text-align: left;
    white-space: nowrap;
  }
}

/* Tone normalisation for the day strip.
 *
 * Measured across the four source frames: colour temperature is already tight
 * (B−R spread 4.8), but day-contract sits ~30 luma points brighter than the
 * other three (209 vs 176–183), which is enough to read as a different shoot.
 * Corrected here with a scoped filter rather than by re-grading the files —
 * those same images are shared with /consultant, whose look must not change.
 */
.m-what-we-do-dayPanel:nth-child(4) img {
  filter: brightness(0.88);
}

/* ---------------------------------------------------------------- 모바일 밀도 --
   390px 에서 섹션마다 상하 70~110px 을 쓰고 있어 한 화면에 한 덩어리만 들어왔다.
   여백과 제목만 줄인다 — 본문 크기와 순서·문구는 그대로다. PC 는 영향 없다. */
@media (max-width: 767px) {
  .m-what-we-do-intro,
  .m-what-we-do-fits {
    padding-top: 52px;
    padding-bottom: 44px;
  }

  .m-what-we-do-day {
    padding-top: 48px;
    padding-bottom: 56px;
  }

  .m-what-we-do-myths {
    padding-top: 44px;
    padding-bottom: 52px;
  }

  .m-what-we-do-reward {
    padding-top: 56px;
    padding-bottom: 56px;
  }

  .m-what-we-do-first {
    padding-top: 60px;
    padding-bottom: 64px;
  }

  .m-what-we-do-h2 {
    font-size: 23px;
  }

  .m-what-we-do-dayTitle {
    font-size: 17px;
  }

  /* 터치 높이는 44px 아래로 내리지 않는다. */
  .m-what-we-do-firstCta {
    min-height: 48px;
    padding: 13px 30px;
    font-size: 14.5px;
  }
}

/* 위 블록의 `.dayTitle` 은 `.dayPanel[data-active="false"] .dayTitle` 보다
   특정도가 낮아 접힌 패널에는 닿지 않았다. 두 경우를 함께 잡는다. */
@media (max-width: 767px) {
  .m-what-we-do-dayTitle,
  .m-what-we-do-dayPanel[data-active="false"] .m-what-we-do-dayTitle {
    font-size: 17px;
  }
}

/* ===== src/components/whoweare/WhoWeAre.module.css  →  .m-who-we-are-* ===== */
/*
 * WHO WE ARE (/who-we-are) — page-scoped styling.
 *
 * The page is one tall stage with a single sticky photograph pinned behind it.
 * White panels sit on top and are fully opaque, so nothing shows through while
 * anything is being read; the gaps between them are transparent, and that is
 * the only place the photograph appears. Reading and looking are kept apart on
 * purpose — a panel is never a place where the background is competing.
 *
 * Motion runs one step quieter than HOME: a line that draws itself, a stagger,
 * and a calm text reveal. Nothing pins but the photograph, and it never moves
 * with the pointer.
 *
 * Page-scoped rather than added to globals.css: the approved dark pages share
 * that file and none of this should be able to reach them.
 */

.m-who-we-are-page {
  --ink: #101828;
  --ink-soft: #475467;
  --ink-faint: #8a94a6;
  --point: #1b2f6b;
  --line: #dde1e8;
  --paper: #ffffff;
  --paper-warm: #fbfaf8;

  background: var(--paper);
  color: var(--ink);
}

/* ---------------------------------------------------------------- staging */

/*
 * Background layering, taken from how miraein.co.kr does it — the principle,
 * not the design.
 *
 * Measured there: each section owns an absolutely-positioned background layer,
 * and the one photographic section sets `background-attachment: fixed`. Its
 * box scrolls normally (top ran 50 -> -936 across the pass) while
 * `background-position` never leaves `50% 50%`. No sticky, no transform, no
 * JS. The section becomes a WINDOW travelling over a picture that never moves,
 * and the opaque section following it wipes the window shut from the bottom
 * with a hard edge.
 *
 * So: no sticky layer and no transparent spacer DOM here either. The bands
 * below are real sections; their own height is the whole of the exposure, and
 * the white panels above and below them are what close it.
 */

.m-who-we-are-stage {
  position: relative;
}

/* The photograph. Empty by design — this is a visual break, not a slide: no
   copy, no label, no ornament sits on it. */
.m-who-we-are-band {
  position: relative;
  height: 92vh;
  background-image: var(--band-image);
  background-repeat: no-repeat;
  background-size: cover;
  /* The whole effect. Painted against the viewport, so the picture holds
     still and only the window moves. */
  background-attachment: fixed;
  background-position: 50% 50%;
  background-color: #eef1f5;
}

/* The wash that lifts and returns with scroll — driven from `Band.tsx`. It is
   what makes the photograph emerge out of the white panel above it instead of
   simply appearing once the panel has passed. Tonal only: the panel edges
   below stay hard. */
.m-who-we-are-bandVeil {
  position: absolute;
  inset: 0;
  background: var(--paper);
  will-change: opacity;
}

/* Opaque, always, and hard-edged. The wipe reads as an edge arriving rather
   than a fade, which is what makes the break feel deliberate. */
.m-who-we-are-panel {
  position: relative;
  z-index: 1;
  background: var(--paper);
}

.m-who-we-are-panel:nth-of-type(2) {
  background: var(--paper-warm);
}

/*
 * Angled edges.
 *
 * This is the piece the first pass missed, and it is most of what makes the
 * reference read as layers sliding past each other rather than as bars
 * stacking up. There it is baked into the section background PNGs — one of
 * them is a navy block with a slanted bottom and transparency below it. Here
 * it is `clip-path` instead, so it works with any photograph and stays
 * editable.
 *
 * Both cuts fall the same way, so the exposed photograph is a parallelogram
 * ribbon of constant depth rather than a wedge. The angle is about 2.5° at
 * desktop width — enough to be felt, not enough to look like a graphic device.
 */
.m-who-we-are-panel {
  --cut: clamp(34px, 4vw, 72px);
}

.m-who-we-are-cutBottom {
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--cut)), 0 100%);
}

.m-who-we-are-cutTop {
  clip-path: polygon(0 var(--cut), 100% 0, 100% 100%, 0 100%);
}

.m-who-we-are-cutBoth {
  clip-path: polygon(
    0 var(--cut),
    100% 0,
    100% calc(100% - var(--cut)),
    0 100%
  );
}

/* The cut eats into the panel's own padding, so give the affected edges a
   little more room and nothing lands in the sliver. */
.m-who-we-are-cutTop .m-who-we-are-wrap,
.m-who-we-are-cutBoth .m-who-we-are-wrap {
  padding-top: calc(clamp(88px, 10vw, 168px) + var(--cut));
}

.m-who-we-are-cutBottom .m-who-we-are-wrap,
.m-who-we-are-cutBoth .m-who-we-are-wrap {
  padding-bottom: calc(clamp(88px, 10vw, 168px) + var(--cut));
}

.m-who-we-are-wrap {
  width: min(calc(100% - 40px), 1450px);
  margin-inline: auto;
  padding: clamp(88px, 10vw, 168px) 0;
}

/*
 * Mobile fallback.
 *
 * `background-attachment: fixed` is ignored outright by iOS Safari and repaints
 * badly on Android, which is why the reference site ships separate desktop and
 * mobile sections rather than trying to keep it. Same conclusion here, reached
 * with CSS instead of a second DOM: the band falls back to a normal scrolling
 * background and shortens, so a 16:9 photograph is not cropped to a slot on a
 * portrait screen.
 */
@media (max-width: 900px) {
  .m-who-we-are-band {
    /* svh 는 브라우저 주소창이 접혔다 펴져도 값이 변하지 않는다. vh 를 쓰면
       그때마다 밴드 높이가 다시 계산되어 아래 내용이 밀린다. */
    height: 54svh;
    background-attachment: scroll;
    background-position: 62% 50%;
    /* 화면에 들어올 때 한 번만 부드럽게. 스크롤 위치를 읽지 않는다. */
    opacity: 0;
    transition: opacity 0.6s ease;
  }

  .m-who-we-are-band[data-in="true"] {
    opacity: 1;
  }

  /* 스크롤 연동 베일은 좁은 화면에서 쓰지 않는다(Band.tsx 의 flat). */
  .m-who-we-are-bandVeil {
    display: none;
  }
  /* A 4vw rise across a narrow screen is a steep wedge, so it flattens. */
  .m-who-we-are-panel {
    --cut: 20px;
  }
}

/* Some desktop browsers also stutter on a fixed background; anyone who has
   asked for less motion gets the stable version. */
@media (prefers-reduced-motion: reduce) {
  .m-who-we-are-band {
    background-attachment: scroll;
  }
}

/* ------------------------------------------------------------- section head */

.m-who-we-are-label {
  margin: 0;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--point);
}

.m-who-we-are-kicker {
  margin: 18px 0 0;
  font-size: clamp(15px, 1.2vw, 17px);
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink-faint);
}

.m-who-we-are-headline {
  margin: 12px 0 0;
  max-width: 24ch;
  font-size: clamp(26px, 3vw, 44px);
  font-weight: 700;
  line-height: 1.38;
  letter-spacing: -0.02em;
  word-break: keep-all;
  text-wrap: balance;
  color: var(--ink);
}

/* ============================================== 01  ORGANIZATION ========= */

.m-who-we-are-chart {
  margin-top: clamp(64px, 8vw, 128px);
  display: flex;
  flex-direction: column;
  align-items: center;
}

.m-who-we-are-node {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.7s ease, transform 0.7s ease;
}

.m-who-we-are-node[data-on="true"] {
  opacity: 1;
  transform: none;
}

.m-who-we-are-nodeTop {
  font-size: clamp(19px, 1.9vw, 26px);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.m-who-we-are-nodeMid {
  font-size: clamp(17px, 1.6vw, 22px);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--point);
}

/* Hairlines that draw themselves. No boxes, no shadows — the structure is
   carried by alignment and by the lines, not by cards. */
.m-who-we-are-vline {
  width: 1px;
  height: clamp(56px, 7vw, 96px);
  background: var(--line);
  transform: scaleY(0);
  transform-origin: top center;
  transition: transform 0.65s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.m-who-we-are-vline[data-on="true"] {
  transform: scaleY(1);
}

.m-who-we-are-branch {
  position: relative;
  /* Clear of 관리사업부 — without this the horizontal run grazes the baseline
     and reads as a strikethrough. */
  margin-top: clamp(18px, 2.2vw, 32px);
  width: min(100%, 1040px);
  height: clamp(56px, 7vw, 96px);
}

/* The horizontal run, opening from the middle outwards. */
.m-who-we-are-branchBar {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--line);
  transform: scaleX(0);
  transform-origin: center;
  transition: transform 0.8s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.m-who-we-are-branch[data-on="true"] .m-who-we-are-branchBar {
  transform: scaleX(1);
}

/* Three drops, one per 본부, at the thirds. */
.m-who-we-are-branchDrop {
  position: absolute;
  top: 0;
  width: 1px;
  height: 100%;
  background: var(--line);
  transform: scaleY(0);
  transform-origin: top center;
  transition: transform 0.5s cubic-bezier(0.22, 0.61, 0.36, 1) 0.42s;
}

.m-who-we-are-branch[data-on="true"] .m-who-we-are-branchDrop {
  transform: scaleY(1);
}

.m-who-we-are-branchDrop:nth-of-type(2) {
  left: 16.666%;
}
.m-who-we-are-branchDrop:nth-of-type(3) {
  left: 50%;
}
.m-who-we-are-branchDrop:nth-of-type(4) {
  left: 83.333%;
}

.m-who-we-are-units {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  width: min(100%, 1040px);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* 세 본부는 같은 등급이다 — 같은 크기, 같은 무게, 같은 폭, 그리고 함께 나타난다.
   넓은 화면에서는 분기선이 내려온 자리 바로 아래 가운데로 선다. 좁은 화면에서는
   구분선으로 나뉜 행이 된다.
   담당자 이름과 부문 아이콘은 2026-08-29 요청으로 뺐다 — 남는 것은 본부명과
   업무영역 두 줄이고, 그래서 아이콘 자리만큼의 여백도 함께 사라졌다. */
.m-who-we-are-unit {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
  padding: 6px 10px 0;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}

.m-who-we-are-unit[data-on="true"] {
  opacity: 1;
  transform: none;
}

.m-who-we-are-unitTitle {
  font-size: clamp(16px, 1.5vw, 21px);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.m-who-we-are-unitDesc {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  justify-content: center;
  gap: 6px;
  font-size: clamp(13px, 1.05vw, 15px);
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: -0.01em;
  color: var(--point);
  /* 부문명과 업무영역은 각각 하나의 의미 단위다. 어절 중간에서 갈라지지 않게. */
  word-break: keep-all;
}

.m-who-we-are-unitDot {
  color: color-mix(in srgb, var(--point) 45%, transparent);
}

/* Three short labels stay side by side further down than the prose columns
   do — the hierarchy is easier to read across than stacked. Below 720px it
   rebuilds vertically rather than being squeezed. */
@media (max-width: 720px) {
  .m-who-we-are-branch {
    height: 40px;
  }
  .m-who-we-are-branchBar,
  .m-who-we-are-branchDrop {
    display: none;
  }
  .m-who-we-are-units {
    grid-template-columns: 1fr;
    gap: 0;
  }

  /* 좁은 화면에서는 구분선으로 나뉜 행이 된다. 본부명과 업무영역이 왼쪽
     기준선에 맞춰 서고, 선이 카드 간격을 대신해 위계를 만든다. */
  /* 조직도는 대표이사에서 한 줄기로 내려오는 그림이라, 그 축이 화면 한가운데를
     지나야 구조로 읽힌다. 위의 대표이사·관리사업부가 이미 가운데이므로 본부
     카드도 가운데로 맞춘다 — 왼쪽 정렬이면 축이 중간에서 꺾여 보였다.
     구분선은 `.units` 의 폭을 그대로 쓰므로 좌우 여백이 자동으로 같다. */
  .m-who-we-are-unit {
    align-items: center;
    text-align: center;
    gap: 5px;
    padding: 16px 2px;
    border-top: 1px solid var(--line);
  }
  .m-who-we-are-unit:last-child {
    border-bottom: 1px solid var(--line);
  }

  .m-who-we-are-unitTitle {
    font-size: 17px;
  }

  .m-who-we-are-unitDesc {
    justify-content: center;
    font-size: 13.5px;
  }
}

/* ========================================= 02  WORKING STRUCTURE ========= */

.m-who-we-are-roles {
  margin-top: clamp(56px, 7vw, 104px);
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0;
  border-top: 1px solid var(--line);
}

.m-who-we-are-role {
  padding: clamp(30px, 3.4vw, 52px) clamp(20px, 2.4vw, 40px)
    clamp(38px, 4vw, 62px) 0;
  border-right: 1px solid var(--line);
  transition: background 0.35s ease;
}

.m-who-we-are-role:last-child {
  border-right: 0;
}

.m-who-we-are-role:not(:first-child) {
  padding-left: clamp(20px, 2.4vw, 40px);
}

@media (hover: hover) {
  .m-who-we-are-role:hover {
    background: rgba(27, 47, 107, 0.03);
  }
}

.m-who-we-are-roleNo {
  display: block;
  font-family: var(--font-serif);
  font-size: clamp(30px, 3.2vw, 46px);
  line-height: 1;
  letter-spacing: 0.02em;
  color: var(--point);
}

.m-who-we-are-roleName {
  margin: clamp(18px, 2vw, 28px) 0 0;
  font-size: clamp(18px, 1.6vw, 23px);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.m-who-we-are-roleDesc {
  margin: 12px 0 0;
  max-width: 26ch;
  font-size: clamp(14.5px, 1.1vw, 16px);
  line-height: 1.8;
  word-break: keep-all;
  text-wrap: pretty;
  color: var(--ink-soft);
}

.m-who-we-are-roleKeys {
  margin: clamp(18px, 2vw, 26px) 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
}

.m-who-we-are-roleKeys li {
  font-size: 13px;
  letter-spacing: 0.02em;
  color: var(--ink-faint);
}

/* Prose needs a usable measure. At 900px three columns were 286px wide, which
   is not a column — it is a squeeze. Stacked from 1024px down. */
@media (max-width: 1024px) {
  .m-who-we-are-roles {
    grid-template-columns: 1fr;
  }
  .m-who-we-are-role {
    border-right: 0;
    border-bottom: 1px solid var(--line);
    padding: 34px 0;
  }
  .m-who-we-are-role:not(:first-child) {
    padding-left: 0;
  }
  .m-who-we-are-role:last-child {
    border-bottom: 0;
  }
}

/* ============================================ 03  OUR DIRECTION ========== */

.m-who-we-are-direction {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.92fr);
  gap: clamp(40px, 6vw, 110px);
  align-items: start;
}

.m-who-we-are-directionLead {
  margin: 26px 0 0;
  font-size: clamp(24px, 2.6vw, 38px);
  font-weight: 700;
  line-height: 1.45;
  letter-spacing: -0.02em;
  word-break: keep-all;
  text-wrap: balance;
  color: var(--ink);
}

.m-who-we-are-directionBody {
  padding-top: clamp(8px, 1.6vw, 26px);
}

.m-who-we-are-directionBody p {
  margin: 0;
  max-width: 40ch;
  font-size: clamp(15px, 1.2vw, 17px);
  line-height: 1.95;
  word-break: keep-all;
  text-wrap: pretty;
  color: var(--ink-soft);
}

.m-who-we-are-directionBody p + p {
  margin-top: 18px;
}

.m-who-we-are-closeRule {
  margin-top: clamp(52px, 6vw, 92px);
  height: 1px;
  background: var(--line);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 1.4s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.m-who-we-are-closeRule[data-on="true"] {
  transform: scaleX(1);
}

@media (max-width: 860px) {
  .m-who-we-are-direction {
    grid-template-columns: 1fr;
    gap: 30px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .m-who-we-are-node,
  .m-who-we-are-unit {
    opacity: 1;
    transform: none;
    transition: none;
  }
  .m-who-we-are-vline,
  .m-who-we-are-branchBar,
  .m-who-we-are-branchDrop,
  .m-who-we-are-closeRule {
    transform: none;
    transition: none;
  }
}

/* ---------------------------------------------------------------- 모바일 밀도 --
   제목만 한 단계 낮춘다. 조직도 카드와 본문 크기는 그대로다. PC 는 영향 없다. */
@media (max-width: 767px) {
  .m-who-we-are-headline {
    font-size: 21px;
  }

  .m-who-we-are-directionLead {
    font-size: 19px;
  }
}

@media (max-width: 767px) {
  /* 세 블록이 88~108px 을 쓰고 있었다. 모바일에서는 리듬의 차이가 읽히지
     않으므로 하나의 값으로 모아 밀도를 올린다. */
  .m-who-we-are-wrap,
  .m-who-we-are-cutTop .m-who-we-are-wrap,
  .m-who-we-are-cutBottom .m-who-we-are-wrap,
  .m-who-we-are-cutBoth .m-who-we-are-wrap {
    padding-top: 56px;
    padding-bottom: 60px;
  }

  /* 사선 컷이 있는 블록은 그 높이만큼을 더해 둔다 — 컷 자체(--cut)는 그대로다. */
  .m-who-we-are-cutTop .m-who-we-are-wrap,
  .m-who-we-are-cutBoth .m-who-we-are-wrap {
    padding-top: calc(56px + var(--cut));
  }

  .m-who-we-are-cutBottom .m-who-we-are-wrap,
  .m-who-we-are-cutBoth .m-who-we-are-wrap {
    padding-bottom: calc(60px + var(--cut));
  }
}
