/* css/v17.css · v17 component & page styles
 *
 * New components live here (HeroDark, TrustStrip, ProofStrip, TimelineList,
 * IPCard, PressCard, EmptyState, ProductCard, etc.). All consume --ds-*
 * semantic tokens so dark mode flips via [data-theme="dark"] on <html>.
 *
 * Body dark-mode overrides for legacy .gl-section / .gl-region scaffolds
 * are at the bottom of this file.
 */

/* ============================================================
 * HeroDark · fullbleed cinematic dark hero
 * ============================================================ */
.gl-hero-dark {
  position: relative;
  min-height: 92vh;
  /* Header is position:fixed so it doesn't take flow space — hero starts
   * naturally at y=0 and fills the viewport. No margin-top compensation
   * needed; the next section after hero is always at y=100vh, regardless
   * of how the header sizes itself. */
  background: #0A0E1A;
  color: var(--ds-white);
  overflow: hidden;
  display: flex;
  align-items: center;
}
.gl-hero-dark__bg {
  position: absolute;
  inset: 0;
  z-index: 0;
}
.gl-hero-dark__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 400ms var(--ease-out);
}
.gl-hero-dark__video.is-active {
  opacity: 0.7;
}
.gl-hero-dark__overlay {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse at 30% 20%, rgba(0, 102, 255, 0.20), transparent 60%),
    linear-gradient(180deg, rgba(10, 14, 26, 0.55) 0%, rgba(10, 14, 26, 0.85) 70%, #0A0E1A 100%);
}
.gl-hero-dark__content {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: var(--container-max);
  margin: 0 auto;
  padding: 0 var(--container-pad-x);
}
.gl-hero-dark__label {
  display: inline-block;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.18em;
  color: var(--ds-primary-300);
  margin-bottom: 24px;
}
.gl-hero-dark__title {
  font-size: clamp(36px, 5.5vw, 64px);
  line-height: 1.12;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--ds-white);
  margin: 0 0 24px;
  max-width: 880px;
  /* Honor `\n` in i18n strings as a hard line break. */
  white-space: pre-line;
}
/* Language-specific title widths · tuned so KR wraps to 2 lines and EN to 2. */
.gl-hero-dark--lang-kr .gl-hero-dark__title { max-width: 580px; }
.gl-hero-dark--lang-en .gl-hero-dark__title { max-width: 850px; }
.gl-hero-dark__subtitle {
  font-size: clamp(15px, 1.4vw, 18px);
  line-height: 1.7;
  color: rgba(255, 255, 255, 0.75);
  max-width: 640px;
  margin: 0 0 36px;
  /* Honor `\n` in i18n strings as a hard line break. */
  white-space: pre-line;
}
.gl-hero-dark__ctas {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
}
.gl-hero-dark__scroll {
  position: absolute;
  bottom: 32px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 1;
  font-size: 11px;
  letter-spacing: 0.2em;
  color: rgba(255, 255, 255, 0.5);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}
.gl-hero-dark__scroll::after {
  content: '';
  width: 1px;
  height: 28px;
  background: rgba(255, 255, 255, 0.4);
  animation: scrollHint 2s var(--ease-in-out) infinite;
}
@keyframes scrollHint {
  0%, 100% { transform: scaleY(0.4); transform-origin: top; }
  50%      { transform: scaleY(1);   transform-origin: top; }
}

/* ============================================================
 * TrustStrip · auto-marquee partner outlets
 * ============================================================ */
.gl-trust {
  background: var(--ds-bg-surface);
  border-top: 1px solid var(--ds-border-subtle);
  border-bottom: 1px solid var(--ds-border-subtle);
  padding: 28px 0;
  overflow: hidden;
}
.gl-trust__inner {
  display: flex;
  align-items: center;
  gap: 32px;
  max-width: var(--container-max);
  margin: 0 auto;
  padding: 0 var(--container-pad-x);
}
.gl-trust__label {
  flex: 0 0 auto;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.18em;
  color: var(--ds-text-tertiary);
  text-transform: uppercase;
}
.gl-trust__viewport {
  flex: 1;
  position: relative;
  overflow: hidden;
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.gl-trust__track {
  display: flex;
  gap: 96px;
  width: max-content;
  animation: trustMarquee 38s linear infinite;
}
.gl-trust__item {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 24px;
}
.gl-trust__logo {
  display: block;
  height: 100%;
  width: auto;
  max-height: 20px;
  object-fit: contain;
}
/* Dark mode · invert near-black logos to white so they stay visible */
:root[data-theme="dark"] .gl-trust__logo {
  filter: brightness(0) invert(1);
  opacity: 0.85;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gl-trust__logo {
    filter: brightness(0) invert(1);
    opacity: 0.85;
  }
}
@keyframes trustMarquee {
  0%   { transform: translateX(0); }
  100% { transform: translateX(-50%); }
}
@media (max-width: 694px) {
  .gl-trust__inner { flex-direction: column; align-items: flex-start; gap: 16px; }
  .gl-trust__viewport { width: 100%; }
}

/* ============================================================
 * ProofStrip · 4-metric stat row
 * ============================================================ */
.gl-proof {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0;
  border-top: 1px solid var(--ds-border-subtle);
  border-bottom: 1px solid var(--ds-border-subtle);
}
.gl-proof__item {
  padding: 32px 24px;
  border-right: 1px solid var(--ds-border-subtle);
  display: flex;
  flex-direction: column;
  gap: 8px;
}
/* Accordion reveal · the outer wrap collapses to 0 height initially and
 * expands to its natural height when ProofStrip enters the viewport,
 * pushing the timeline below it down as it unfolds. CSS Grid trick:
 * `grid-template-rows: 0fr → 1fr` is one of the few ways to animate
 * height-from-0-to-auto natively without JS measurement. */
.gl-proof-accordion {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 760ms cubic-bezier(0.16, 1, 0.3, 1);
}
.gl-proof-accordion.is-revealed {
  grid-template-rows: 1fr;
}
.gl-proof-accordion__inner {
  overflow: hidden;
  min-height: 0;
  opacity: 0;
  transition: opacity 480ms var(--ease-out) 240ms;
}
.gl-proof-accordion.is-revealed .gl-proof-accordion__inner {
  opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
  .gl-proof-accordion { grid-template-rows: 1fr; transition: none; }
  .gl-proof-accordion__inner { opacity: 1; transition: none; }
}
.gl-proof__item:last-child { border-right: 0; }
.gl-proof__metric {
  font-size: clamp(28px, 3vw, 36px);
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--ds-text-primary);
}
.gl-proof__label {
  font-size: 13px;
  line-height: 1.5;
  color: var(--ds-text-secondary);
  letter-spacing: -0.005em;
}
@media (max-width: 1024px) {
  .gl-proof { grid-template-columns: repeat(2, 1fr); }
  .gl-proof__item:nth-child(2) { border-right: 0; }
  .gl-proof__item:nth-child(-n+2) { border-bottom: 1px solid var(--ds-border-subtle); }
}
@media (max-width: 540px) {
  .gl-proof { grid-template-columns: 1fr; }
  .gl-proof__item { border-right: 0 !important; border-bottom: 1px solid var(--ds-border-subtle); }
  .gl-proof__item:last-child { border-bottom: 0; }
}

/* ============================================================
 * About · Story · proof wrap
 *
 * Group of 3 milestone metrics (특허·제휴·마일스톤) embedded INSIDE the
 * Story section, between the section title and the dated timeline rows.
 * Conceptually a wrap (no own section/heading) so it reads as part of
 * the Story narrative — proof points before the chronological list.
 *
 * Scoped overrides vs the generic .gl-proof component:
 *   · text centered (was left-aligned in the original 4-metric strip)
 *   · metric size reduced to 24px (vs the strip's clamp(28,3vw,36))
 *   · the smaller, centered footprint reads as supporting evidence
 *     under the Story headline rather than a hero stat block
 * ============================================================ */
.gl-about-story__proof {
  margin-bottom: 56px;
}
.gl-about-story__proof .gl-proof__item {
  text-align: center;
}
.gl-about-story__proof .gl-proof__metric {
  font-size: 24px;
}
/* Disable the generic .gl-proof__item:hover lift/bg here — Story's proof
 * is supporting evidence, not a hero stat row, so it stays static. */
.gl-about-story__proof .gl-proof__item,
.gl-about-story__proof .gl-proof__item:hover {
  transform: none;
  background: transparent;
}
@media (max-width: 694px) {
  .gl-about-story__proof { margin-bottom: 40px; }
}

/* ============================================================
 * About · Tabs (WHAT WE DO / PHILOSOPHY & VISION)
 * Pill-style toggle that sits between the page hero and the body.
 * ============================================================ */
.gl-about-tabs {
  display: flex;
  justify-content: center;
  padding: 40px var(--container-pad-x) 0;
  /* Light: white. Dark: black. Forced explicitly so the alternating section
   * bg pattern doesn't bleed into the tab strip. */
  background: var(--ds-white);
}
:root[data-theme="dark"] .gl-about-tabs { background: var(--ds-black); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gl-about-tabs { background: var(--ds-black); }
}
.gl-about-tabs__inner {
  display: inline-flex;
  gap: 4px;
  padding: 4px;
  border: 1px solid #eee;
  border-radius: var(--radius-full);
}
.gl-about-tab {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--ds-text-secondary);
  font-family: inherit;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 10px 20px;
  border-radius: var(--radius-full);
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out),
              box-shadow var(--duration-fast) var(--ease-out);
}
.gl-about-tab:hover { color: var(--ds-text-primary); }
.gl-about-tab.is-active {
  background: var(--ds-bg-base);
  color: var(--ds-text-primary);
  box-shadow: var(--shadow-xs);
}
@media (max-width: 694px) {
  .gl-about-tabs { padding-top: 24px; }
  .gl-about-tab { padding: 8px 14px; font-size: 11px; letter-spacing: 0.06em; }
}

/* ============================================================
 * About · Mission · 2-column (text + decorative wall image)
 * ============================================================ */
.gl-about-mission__grid {
  display: grid;
  grid-template-columns: 1.2fr 1fr;
  gap: 56px;
  align-items: center;
}
.gl-about-mission__visual {
  display: flex;
  justify-content: center;
}
.gl-about-mission__image {
  width: 100%;
  height: auto;
  display: block;
  max-width: 400px;
  border-radius: var(--radius-2xl);
  object-fit: contain;
}
@media (max-width: 1024px) {
  .gl-about-mission__grid { grid-template-columns: 1fr; gap: 40px; }
  .gl-about-mission__image { max-width: 100%; }
}

/* ============================================================
 * TimelineList · About · Story
 * ============================================================ */
.gl-timeline {
  display: grid;
  grid-template-columns: 140px 1fr;
  gap: 0 32px;
  position: relative;
}
.gl-timeline::before {
  content: '';
  position: absolute;
  left: 140px;
  top: 8px;
  bottom: 8px;
  width: 1px;
  background: var(--ds-border-subtle);
}
.gl-timeline__row {
  display: contents;
}
.gl-timeline__date {
  grid-column: 1;
  font-variant-numeric: tabular-nums;
  font-size: 13px;
  font-weight: 600;
  color: var(--ds-text-tertiary);
  padding: 10px 0;
  letter-spacing: 0;
  transition: color var(--duration-base) var(--ease-out),
              font-size var(--duration-base) var(--ease-out),
              font-weight var(--duration-base) var(--ease-out);
}
.gl-timeline__text {
  grid-column: 2;
  font-size: 15px;
  line-height: 1.7;
  color: var(--ds-text-primary);
  padding: 10px 0 10px 24px;
  position: relative;
  letter-spacing: -0.005em;
  transition: color var(--duration-base) var(--ease-out),
              font-size var(--duration-base) var(--ease-out),
              font-weight var(--duration-base) var(--ease-out);
}
.gl-timeline__text::before {
  content: '';
  position: absolute;
  left: -4px;
  top: 18px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--ds-bg-base);
  border: 1.5px solid var(--ds-border-default);
  transition: background var(--duration-base) var(--ease-out),
              border-color var(--duration-base) var(--ease-out),
              transform var(--duration-base) var(--ease-out);
}
.gl-timeline__row:hover .gl-timeline__text::before {
  background: var(--ds-primary-500);
  border-color: var(--ds-primary-500);
  transform: scale(1.2);
}
.gl-timeline__row:hover .gl-timeline__date {
  color: var(--ds-primary-600);
  font-size: 14px;
  font-weight: 700;
}
.gl-timeline__row:hover .gl-timeline__text {
  color: var(--ds-primary-700);
  font-size: 17px;
  font-weight: 700;
}
@media (max-width: 694px) {
  .gl-timeline { grid-template-columns: 72px 1fr; gap: 0 12px; }
  .gl-timeline__date { font-size: 12px; }
  .gl-timeline__text { padding-left: 12px; font-size: 14px; }
  /* Hide both the vertical guide line and the per-row dot indicators on
   * mobile · the narrow date column collides with the line, and the dots
   * cost horizontal space the timeline text needs more. */
  .gl-timeline::before        { display: none; }
  .gl-timeline__text::before  { display: none; }
}

/* ============================================================
 * IPCard · Labs · 3 IP units
 * ============================================================ */
.gl-ipcard {
  border-top: 1px solid var(--ds-border-default);
  padding: 64px 0;
}
.gl-ipcard__head {
  align-items: start;
  margin-bottom: 32px;
}
.gl-ipcard__title {
  font-size: clamp(24px, 2.6vw, 32px);
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--ds-text-primary);
  line-height: 1.25;
  margin: 0;
  /* Honor `\n` injected after sentence-ending periods. */
  white-space: pre-line;
}
.gl-ipcard__body {
  font-size: 16px;
  line-height: 1.75;
  color: var(--ds-text-secondary);
  letter-spacing: -0.005em;
  margin: 0 0 20px;
}
.gl-ipcard__modes {
  list-style: none;
  margin: 0 0 32px;
  padding: 16px 20px;
  background: var(--gray-50);
  border-radius: var(--ds-radius-md);
  font-size: 14px;
  line-height: 1.75;
  color: var(--ds-text-primary);
}
:root[data-theme="dark"] .gl-ipcard__modes { background: rgba(255, 255, 255, 0.12); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gl-ipcard__modes { background: rgba(255, 255, 255, 0.12); }
}
.gl-ipcard__modes li { padding: 2px 0; }
.gl-ipcard__split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 32px;
  border-top: 1px solid var(--ds-border-subtle);
  padding-top: 24px;
}
.gl-ipcard__split-block { display: flex; flex-direction: column; gap: 10px; }
.gl-ipcard__split-label {
  font-size: 11px;
  font-weight: 600;
  color: var(--ds-text-tertiary);
  text-transform: uppercase;
}
.gl-ipcard__split-list {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 14px;
  line-height: 1.7;
  color: var(--ds-text-primary);
}
.gl-ipcard__split-list li {
  padding: 4px 0 4px 14px;
  position: relative;
}
.gl-ipcard__split-list li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 14px;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--ds-text-tertiary);
}
@media (max-width: 1024px) {
  .gl-ipcard { padding: 48px 0; }
  .gl-ipcard__split { grid-template-columns: 1fr; gap: 24px; }
}

/* ============================================================
 * Press cover image · sits between hero and the link list.
 * Full-width inside the section's content frame, rounded corners.
 * ============================================================ */
/* Honor `\n` in the cover title as a hard line break. */
.gl-section__title--prewrap { white-space: pre-line; }
/* Press list / Career empty visually continue the cover section · same white
 * background, no top padding so the cover image and the section below read
 * as one block. Class is doubled to outrank the page-wide alternation rule
 * (e.g. .gl-press section.gl-region:nth-of-type(odd)). */
.gl-press  section.gl-region.gl-press-list.gl-press-list,
.gl-career section.gl-region.gl-career-empty.gl-career-empty {
  background: var(--gray-0);
  padding-top: 0;
}
:root[data-theme="dark"] .gl-press  section.gl-region.gl-press-list.gl-press-list,
:root[data-theme="dark"] .gl-career section.gl-region.gl-career-empty.gl-career-empty {
  background: var(--ds-bg-base);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gl-press  section.gl-region.gl-press-list.gl-press-list,
  :root:not([data-theme="light"]) .gl-career section.gl-region.gl-career-empty.gl-career-empty {
    background: var(--ds-bg-base);
  }
}
.gl-press-cover__image,
.gl-career-cover__image {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 50px;
  object-fit: cover;
}
/* Cover title sits above the image · breathing room between them. */
.gl-press-cover .gl-section__head,
.gl-career-cover .gl-section__head {
  margin-bottom: 32px;
}
@media (max-width: 694px) {
  .gl-press-cover__image,
  .gl-career-cover__image { border-radius: 28px; }
}

/* ============================================================
 * PressCard · external link list
 * ============================================================ */
.gl-press-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;
  border-top: 1px solid var(--ds-border-subtle);
  border-left: 1px solid var(--ds-border-subtle);
  /* Round the outer block · individual card corners are rounded by the
   * per-cell rules below so the visible borders curve, not just the clip. */
  border-top-left-radius: var(--ds-radius-lg);
  border-top-right-radius: var(--ds-radius-lg);
  border-bottom-left-radius: var(--ds-radius-lg);
  border-bottom-right-radius: var(--ds-radius-lg);
  overflow: hidden;
}
/* Per-cell corner radii · 2-column grid.
 * - first child  (idx 0) → top-left
 * - second child (idx 1) → top-right
 * - last child if total is odd (alone on the last row) → bottom-left + bottom-right
 * - last child if total is even (right column of last row) → bottom-right
 *   and the second-to-last child (left column of last row) → bottom-left */
.gl-press-grid > .gl-press-card-wrap:first-child .gl-press-card {
  border-top-left-radius: var(--ds-radius-lg);
}
.gl-press-grid > .gl-press-card-wrap:nth-child(2) .gl-press-card {
  border-top-right-radius: var(--ds-radius-lg);
}
.gl-press-grid > .gl-press-card-wrap:last-child:nth-child(odd) .gl-press-card {
  border-bottom-left-radius: var(--ds-radius-lg);
  border-bottom-right-radius: var(--ds-radius-lg);
}
.gl-press-grid > .gl-press-card-wrap:last-child:nth-child(even) .gl-press-card {
  border-bottom-right-radius: var(--ds-radius-lg);
}
.gl-press-grid > .gl-press-card-wrap:nth-last-child(2):nth-child(odd) .gl-press-card {
  border-bottom-left-radius: var(--ds-radius-lg);
}
/* When total is ODD, the right-column terminal sits at the second-to-last
 * position (even nth-child) — its bottom-right is the visible right edge
 * of the block, so round it too. (idx 9 with 11 total cards.) */
.gl-press-grid > .gl-press-card-wrap:nth-last-child(2):nth-child(even) .gl-press-card {
  border-bottom-right-radius: var(--ds-radius-lg);
}
.gl-press-card-wrap {
  position: relative; height: 100%;
}
.gl-press-card {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 24px 28px;
  border-bottom: 1px solid var(--ds-border-subtle);
  border-right: 1px solid var(--ds-border-subtle);
  text-decoration: none;
  color: inherit;
  transition: background var(--duration-fast) var(--ease-out);
  position: relative;
  /* Stretch to fill the grid row so 1-line and 2-line title cards in the
   * same row align their bottom borders. Wrap has height:100%, card
   * needs to mirror it. */
  height: 100%;
  box-sizing: border-box;
}
/* Link preview popover · OG metadata baked at build time.
 * Floats above the card on hover (desktop only). Class is `.gl-link-preview`
 * (NOT `.gl-press-preview` — that name is taken by the Home press section). */
.gl-link-preview {
  /* Viewport-fixed · follows the mouse cursor. left/top are set inline
   * by the React component on mousemove (rAF-throttled). */
  position: fixed;
  top: 0;
  left: 0;
  z-index: 50;
  width: 320px;
  max-width: 90vw;
  background: var(--ds-bg-base);
  border: 1px solid var(--ds-border-subtle);
  border-radius: var(--radius-xl);
  box-shadow: 0 24px 48px rgba(15, 23, 42, 0.18),
              0 8px 16px rgba(15, 23, 42, 0.10);
  overflow: hidden;
  pointer-events: none;
  animation: gl-link-preview-fade 140ms var(--ease-out);
}
@keyframes gl-link-preview-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.gl-link-preview__media {
  width: 100%;
  height: 150px;
  overflow: hidden;
  background: var(--ds-bg-muted);
}
.gl-link-preview__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
  display: block;
}
.gl-link-preview__body {
  padding: 14px 16px 16px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.gl-link-preview__title {
  font-size: 14px;
  font-weight: 700;
  line-height: 1.4;
  color: var(--ds-text-primary);
  letter-spacing: -0.01em;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.gl-link-preview__desc {
  font-size: 12px;
  line-height: 1.5;
  color: var(--ds-text-secondary);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.gl-link-preview__host {
  font-size: 11px;
  font-weight: 600;
  color: var(--ds-text-tertiary);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 2px;
}
@media (max-width: 694px) {
  /* No hover on touch — hide preview entirely. */
  .gl-link-preview { display: none; }
  /* Press grid · mobile collapses to 5 cards + show-more toggle.
   * Hide the 6th item onward unless `.is-expanded` is on the grid. */
  .gl-press-grid:not(.is-expanded) > .gl-press-card-wrap:nth-child(n+6) {
    display: none;
  }
  /* When collapsed, the visible last card (5th) needs its bottom corners
   * rounded so the block terminates cleanly. Override the desktop's last-
   * child rule which would round a different (now-hidden) card. */
  .gl-press-grid:not(.is-expanded) > .gl-press-card-wrap:nth-child(5) .gl-press-card {
    border-bottom-left-radius: var(--ds-radius-lg);
    border-bottom-right-radius: var(--ds-radius-lg);
  }
}
:root[data-theme="dark"] .gl-link-preview {
  background: var(--ds-bg-surface);
  border-color: rgba(255, 255, 255, 0.10);
  box-shadow: 0 24px 48px rgba(0, 0, 0, 0.55),
              0 8px 16px rgba(0, 0, 0, 0.35);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gl-link-preview {
    background: var(--ds-bg-surface);
    border-color: rgba(255, 255, 255, 0.10);
    box-shadow: 0 24px 48px rgba(0, 0, 0, 0.55),
                0 8px 16px rgba(0, 0, 0, 0.35);
  }
}
.gl-press-card:nth-child(2n) { border-right: 0; }
.gl-press-card:hover { background: var(--ds-neutral-50); }
.gl-press-card__meta {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 12px;
  letter-spacing: 0;
  color: var(--ds-text-tertiary);
}
.gl-press-card__date { font-variant-numeric: tabular-nums; }
.gl-press-card__outlet {
  font-weight: 600;
  color: var(--ds-text-secondary);
}
.gl-press-card__outlet::before {
  content: '·';
  margin-right: 8px;
  color: var(--ds-text-tertiary);
}
.gl-press-card__title {
  font-size: 16px;
  line-height: 1.5;
  font-weight: 500;
  color: var(--ds-text-primary);
  letter-spacing: -0.01em;
  margin: 0;
}
.gl-press-card__arrow {
  position: absolute;
  top: 24px;
  right: 28px;
  font-size: 18px;
  color: var(--ds-text-tertiary);
  transition: transform var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out);
}
.gl-press-card:hover .gl-press-card__arrow {
  color: var(--ds-primary-500);
  transform: translate(2px, -2px);
}
/* Toggle button for the collapse-on-mobile press grid · hidden on
 * tablet/desktop, shown on mobile (≤694px). Always rendered in JSX; CSS
 * controls visibility per breakpoint. */
.gl-press-grid__toggle {
  display: none;
  margin-top: 20px;
  text-align: center;
}
@media (max-width: 694px) {
  .gl-press-grid__toggle { display: block; }
}
@media (max-width: 1024px) {
  .gl-press-grid { grid-template-columns: 1fr; }
  /* Single-column · only first card rounds the top, last card rounds the
   * bottom. Reset the 2-col-specific rules so they don't fight the simpler
   * vertical layout. */
  .gl-press-grid > .gl-press-card-wrap:nth-child(2) .gl-press-card {
    border-top-right-radius: 0;
  }
  .gl-press-grid > .gl-press-card-wrap:nth-last-child(2):nth-child(odd) .gl-press-card {
    border-bottom-left-radius: 0;
  }
  .gl-press-grid > .gl-press-card-wrap:first-child .gl-press-card {
    border-top-right-radius: var(--ds-radius-lg);
  }
  .gl-press-grid > .gl-press-card-wrap:last-child .gl-press-card {
    border-bottom-left-radius: var(--ds-radius-lg);
    border-bottom-right-radius: var(--ds-radius-lg);
  }
}
.gl-press-note {
  margin-top: 16px;
  font-size: 12px;
  color: var(--ds-text-tertiary);
}

/* ============================================================
 * EmptyState · Press / Career fallback
 * ============================================================ */
.gl-empty-state {
  border: 1px solid var(--ds-border-subtle);
  border-radius: var(--ds-radius-lg);
  padding: 48px 40px;
  text-align: center;
  margin: 0 auto;
  background: var(--ds-bg-surface);
}
.gl-empty-state__title {
  font-size: 20px;
  font-weight: 600;
  letter-spacing: -0.015em;
  color: var(--ds-text-primary);
  margin: 0 0 16px;
}
.gl-empty-state__body {
  font-size: 15px;
  line-height: 1.7;
  color: var(--ds-text-secondary);
  margin: 0 0 12px;
  letter-spacing: -0.005em;
}
.gl-empty-state__tail {
  font-size: 14px;
  line-height: 1.6;
  color: var(--ds-text-tertiary);
  margin: 0;
}

/* ============================================================
 * KeyValueList · Labs · R&D + Stack
 * ============================================================ */
.gl-kv {
  display: grid;
  grid-template-columns: 200px 1fr;
  gap: 16px 32px;
}
.gl-kv__row { display: contents; }
.gl-kv__key {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0;
  color: var(--ds-text-tertiary);
  padding: 10px 0;
  border-top: 1px solid var(--ds-border-subtle);
}
.gl-kv__value {
  font-size: 15px;
  line-height: 1.7;
  color: var(--ds-text-primary);
  padding: 10px 0;
  border-top: 1px solid var(--ds-border-subtle);
  letter-spacing: -0.005em;
}
@media (max-width: 694px) {
  .gl-kv { grid-template-columns: 1fr; gap: 0; }
  .gl-kv__key { padding-bottom: 0; border-bottom: 0; }
  .gl-kv__value { padding-top: 4px; border-top: 0; padding-bottom: 16px; border-bottom: 1px solid var(--ds-border-subtle); }
}

/* ============================================================
 * Network · About
 * ============================================================ */
/* ------------------------------------------------------------
 * Network grid · stagger-reveal logo cards with per-cell parallax
 * ----------------------------------------------------------*/
.gl-network-groups {
  display: flex;
  flex-direction: column;
  gap: 40px;
  margin-top: 32px;
}
.gl-network-group {
  gap: 14px;
}
.gl-network-group__label {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ds-text-tertiary);
}
.gl-network-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  align-items: stretch;
  margin: 0 auto;
  padding: 0;
  gap: 40px 32px;
  max-width: 1100px;
}
.gl-network-grid__cell { display: flex; }
.gl-network-grid__card {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: 28px 18px;
  width: 100%;
  height: 100%;
  min-height: 120px;
  transition: transform 240ms var(--ease-out),
              box-shadow 240ms var(--ease-out),
              border-color 240ms var(--ease-out);
}
.gl-network-grid__card:hover {
  transform: translateY(-4px);
}
.gl-network-grid__logo {
  height: 28px;
  width: auto;
  object-fit: contain;
}
/* Affiliate logos · same fixed box height (48px) so the name labels
 * underneath line up across cards. object-fit: contain (inherited)
 * shrinks each image to fit within its width × 48 box without distortion. */
.gl-network-grid__logo[src$="yes24.png"] {
  width: 96px;
  height: 48px;
}
.gl-network-grid__logo[src$="dcinside.png"] {
  width: 140px;
  height: 48px;
}
.gl-network-grid__logo[src$="inavi-v2.png"] {
  width: 120px;
  height: 48px;
}
.gl-network-grid__name {
  font-size: 13px;
  font-weight: 600;
  color: var(--ds-text-secondary);
  letter-spacing: -0.005em;
}
@media (max-width: 1024px) {
  .gl-network-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 694px) {
  .gl-network-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  .gl-network-grid__card { padding: 22px 14px; }
}
:root[data-theme="dark"] .gl-network-grid__card {
  background: rgba(255, 255, 255, 0.04);
  border-color: rgba(255, 255, 255, 0.10);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gl-network-grid__card {
    background: rgba(255, 255, 255, 0.04);
    border-color: rgba(255, 255, 255, 0.10);
  }
}


/* ============================================================
 * About · Info (merged Office + Contact)
 * Left column stacks two text blocks (Office, Contact); right column
 * holds the embedded map filling the full grid row height.
 * ============================================================ */
.gl-about-info__grid {
  display: grid;
  grid-template-columns: 1fr 1.4fr;
  gap: 56px;
  align-items: stretch;
}
.gl-about-info__text {
  display: flex;
  flex-direction: column;
  gap: 48px;
  justify-content: center;
}
.gl-about-info__title {
  font-size: 28px;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--ds-text-primary);
  margin: 0 0 12px;
}
.gl-about-info__body {
  font-size: 16px;
  line-height: 26px;
  color: var(--ds-text-secondary);
  margin: 0;
}
.gl-about-info__cta {
  margin-top: 20px;
}
@media (max-width: 1024px) {
  .gl-about-info__grid { grid-template-columns: 1fr; gap: 32px; }
  .gl-about-info__text { gap: 40px; }
}

/* ============================================================
 * Office · address / transport / map
 * ============================================================ */
.gl-office__address {
  font-size: 18px;
  font-weight: 500;
  color: var(--ds-text-primary);
  letter-spacing: -0.01em;
  margin: 0 0 8px;
}
.gl-office__transport {
  font-size: 14px;
  color: var(--ds-text-secondary);
  margin: 0;
}
.gl-office__map {
  display: block;
  width: 100%;
  height: 480px;
  border: 1px solid var(--ds-border-subtle);
  border-radius: var(--radius-2xl);
  background: var(--ds-bg-subtle);
  box-shadow: var(--shadow-lg);
}
@media (max-width: 1024px) {
  .gl-office__map { height: 360px; }
}
@media (max-width: 694px) {
  .gl-office__map { height: 280px; }
}

/* ============================================================
 * Trademark block · Labs
 * ============================================================ */
.gl-tm {
  display: flex;
  flex-direction: column;
  gap: 20px;
  padding: 28px 32px;
  background: var(--gray-0);
  border-radius: var(--ds-radius-lg);
}
.gl-tm__head { display: flex; align-items: baseline; gap: 16px; flex-wrap: wrap; }
.gl-tm__mark {
  font-size: 22px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--ds-text-primary);
}
.gl-tm__desc {
  font-size: 14px;
  color: var(--ds-text-secondary);
  letter-spacing: -0.005em;
}
.gl-tm__classes {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 4px 16px;
}
.gl-tm__classes li {
  font-size: 13px;
  color: var(--ds-text-primary);
  padding: 6px 0;
  border-top: 1px solid var(--ds-border-subtle);
  letter-spacing: -0.005em;
}
.gl-tm__pending-title {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.12em;
  color: var(--ds-text-tertiary);
  text-transform: uppercase;
  margin: 12px 0 6px;
}
.gl-tm__pending {
  font-size: 14px;
  line-height: 1.7;
  color: var(--ds-text-primary);
  letter-spacing: -0.005em;
  margin: 0;
}
@media (max-width: 694px) { .gl-tm__classes { grid-template-columns: 1fr; } }

/* ============================================================
 * ProductCard · Business
 * ============================================================ */
.gl-product {
  padding: 96px 0;
}
.gl-product__head {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 24px;
  align-items: baseline;
  margin-bottom: 12px;
  border-bottom: 1px solid var(--ds-border-subtle);
  padding-bottom: 16px;
}
.gl-product__name-block {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
}
.gl-product__name {
  font-size: clamp(24px, 2.6vw, 44px);
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--ds-text-primary);
  margin: 0;
}
.gl-product__oneliner {
  font-size: 18px;
  line-height: 1.6;
  font-weight: 500;
  color: var(--ds-text-primary);
  letter-spacing: -0.01em;
  margin: 12px 0 24px;
  max-width: 760px;
}
.gl-product__intro-list {
  list-style: none;
  margin: 0 0 24px;
  padding: 0;
  font-size: 14px;
  line-height: 1.8;
  color: var(--ds-text-secondary);
}
.gl-product__features {
  list-style: none;
  margin: 0 0 24px;
  padding: 0;
}
.gl-product__features li {
  font-size: 15px;
  line-height: 1.7;
  color: var(--ds-text-primary);
  padding: 4px 0 4px 18px;
  position: relative;
  letter-spacing: -0.005em;
}
.gl-product__features li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 14px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--ds-primary-500);
}
.gl-product__meta-grid {
  gap: 24px 32px;
  margin-top: 24px;
}
.gl-product__meta-block { display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px; }
.gl-product__meta-label {
  font-size: 11px;
  font-weight: 600;
  color: var(--ds-text-tertiary);
  text-transform: uppercase;
}
.gl-product__meta-list {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 14px;
  line-height: 1.7;
  color: var(--ds-text-primary);
  letter-spacing: -0.005em;
}
.gl-product__meta-list li { padding: 2px 0; }
.gl-product__subscribe {
  margin: 16px 0 24px;
}
.gl-product__subscribe-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 12px 22px;
  background: var(--gray-900);
  color: var(--gray-0);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: -0.01em;
  border-radius: var(--radius-full);
  text-decoration: none;
  transition: transform 160ms var(--ease-out),
              box-shadow 160ms var(--ease-out),
              background 160ms var(--ease-out);
}
.gl-product__subscribe-btn:hover {
  background: var(--gray-800);
  transform: translateY(-2px);
  box-shadow: 0 8px 18px rgba(15, 23, 42, 0.18);
  opacity: 1;
}
.gl-product__channel-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--ds-text-secondary);
  text-decoration: none;
  transition: color var(--duration-fast) var(--ease-out);
}
.gl-product__channel-link:hover { color: var(--ds-primary-600); opacity: 1; }
.gl-product__channel-icon {
  flex: 0 0 auto;
  display: inline-block;
  vertical-align: middle;
}
/* Behold.so Instagram preview widget · sits below the channel link.
 * Constrain max-width so the widget doesn't overflow the meta column. */
.gl-product__insta {
  margin-top: 12px;
  /* Surface the widget's own CSS variables so it adapts to the brand tone. */
  --behold-grid-gap: 8px;
  --behold-corner-radius: 12px;
  --behold-border-color: var(--ds-border-subtle);
}
.gl-product__insta behold-widget {
  display: block;
  width: 100%;
}
.gl-product__more {
  margin-top: 24px;
}
.gl-product__more-btn {
  appearance: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 10px 16px;
  border-radius: var(--radius-full);
  border: 1px solid var(--ds-border-default);
  background: transparent;
  color: var(--ds-text-secondary);
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: -0.005em;
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out),
              border-color var(--duration-fast) var(--ease-out);
}
.gl-product__more-btn:hover {
  background: var(--ds-bg-muted);
  color: var(--ds-text-primary);
  border-color: var(--ds-border-strong);
}
.gl-product__more-btn::after {
  content: '';
  width: 6px;
  height: 6px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg) translate(-1px, -1px);
  transition: transform var(--duration-fast) var(--ease-out);
}
.gl-product__more-btn[aria-expanded="true"]::after {
  transform: rotate(-135deg) translate(-1px, -1px);
}
/* Accordion panel · grid 0fr→1fr trick gives a smooth height transition
 * (Chrome 117+, Firefox 117+, Safari 17.4+). Inner wrapper handles overflow
 * so children clip during the animation rather than spilling out. */
.gl-product__panel {
  display: grid;
  grid-template-rows: 0fr;
  opacity: 0;
  transition: grid-template-rows 360ms var(--ease-out),
              opacity 240ms var(--ease-out);
}
.gl-product__panel.is-open {
  grid-template-rows: 1fr;
  opacity: 1;
}
.gl-product__panel-inner {
  min-height: 0;
  overflow: hidden;
}
.gl-product__panel-inner > .gl-product__meta-grid {
  /* Add top spacing INSIDE the clipped area so collapsed state has 0 height. */
  margin-top: 24px;
}
/* Gated panel · stack blocks vertically instead of the default 2-column grid. */
.gl-product__meta-grid--gated {
  display: flex;
  flex-direction: column;
  gap: 24px;
}
.gl-product__status {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  font-weight: 600;
  color: var(--green-500);
  /* Sits in .gl-product__head's right column (auto), aligned with title. */
  justify-self: end;
  white-space: nowrap;
}
.gl-product__status::before {
  content: '';
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--green-500);
  box-shadow: 0 0 0 4px rgba(34, 197, 94, 0.15);
}
@media (max-width: 1024px) {
  .gl-product__head { grid-template-columns: 1fr; }
  .gl-product__meta-grid { grid-template-columns: 1fr; gap: 20px; }
}

/* Two-column layout when ProductCard has a visual mockup */
.gl-product__layout {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  gap: 56px;
  align-items: start;
}
.gl-product__text { min-width: 0; }
.gl-product__visual {
  position: sticky;
  top: 96px;
  display: flex;
  align-items: flex-start;
  justify-content: center;
}
.gl-product__visual > * {
  width: 100%;
  max-width: 580px;
}
/* B2C / B2B group titles · toned-down gray so the product cards below
 * carry the visual weight, not the group label. */
.gl-business-b2c > .gl-section__inner > .gl-section__head > .gl-section__title,
.gl-business-b2b > .gl-section__inner > .gl-section__head > .gl-section__title {
  color: var(--fg-quaternary);
}

/* B2C (Newming) — narrower mockup so the iPhone bezel reads at the right scale. */
.gl-business-b2c .gl-product__visual > * {
  max-width: 360px;
}
/* B2C · Newming Weekly — newsletter card uses the standard B2B width so the
 * RSS list has comfortable reading width. Overrides the 360px above. */
#product-newming-weekly .gl-product__visual > * {
  max-width: 480px;
}

/* ============================================================
 * Business · Quick-nav · liquid glass pill bar (sticky on desktop)
 * Sits 10px below the fixed header. Anchors scroll to product-* ids.
 * ============================================================ */
.gl-business__quicknav {
  position: sticky;
  top: calc(var(--header-h, 72px) + 10px);
  z-index: 30;
  /* Negative bottom margin pulls the next B2C section up so the pill sits
   * centered on the boundary (half on intro · half on B2C) and doesn't add
   * vertical space. Sticky behavior takes over once scrolling reaches the
   * top threshold. */
  margin: 0 auto -96px;
  padding: 12px;
  width: max-content;
  max-width: calc(100% - 32px);
  background: rgba(255, 255, 255, 0.62);
  border: 1px solid rgba(255, 255, 255, 0.55);
  border-radius: 20px;
  box-shadow: 0 10px 32px rgba(15, 23, 42, 0.10),
              inset 0 1px 0 rgba(255, 255, 255, 0.7);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
          backdrop-filter: blur(20px) saturate(180%);
}
.gl-quicknav__list {
  display: flex;
  align-items: center;
  gap: 2px;
  margin: 0;
  padding: 0;
  list-style: none;
}
/* B2C ↔ B2B separator · small gray dot between Newming Weekly and Mingo. */
.gl-quicknav__sep {
  width: 4px;
  height: 4px;
  margin: 0 8px;
  border-radius: 50%;
  background: var(--gray-300);
  flex: 0 0 auto;
}
:root[data-theme="dark"] .gl-quicknav__sep { background: rgba(255, 255, 255, 0.25); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gl-quicknav__sep { background: rgba(255, 255, 255, 0.25); }
}
.gl-quicknav__link {
  display: inline-flex;
  align-items: center;
  padding: 8px 16px;
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.005em;
  color: var(--gray-700);
  text-decoration: none;
  border-radius: var(--radius-full);
  white-space: nowrap;
  transition: background 160ms var(--ease-out),
              color 160ms var(--ease-out);
}
.gl-quicknav__link:hover {
  background: rgba(15, 23, 42, 0.08);
  color: var(--gray-900);
  opacity: 1;
}
/* Smooth-scroll offset for anchored product cards · respects header height. */
.gl-product { scroll-margin-top: calc(var(--header-h, 72px) + 80px); }

@media (max-width: 1024px) {
  .gl-business__quicknav { display: none; }
}
/* Dark theme · invert glass tint */
:root[data-theme="dark"] .gl-business__quicknav {
  background: rgba(20, 20, 20, 0.55);
  border-color: rgba(255, 255, 255, 0.10);
  box-shadow: 0 10px 32px rgba(0, 0, 0, 0.45),
              inset 0 1px 0 rgba(255, 255, 255, 0.06);
}
:root[data-theme="dark"] .gl-quicknav__link { color: rgba(255, 255, 255, 0.7); }
:root[data-theme="dark"] .gl-quicknav__link:hover {
  background: rgba(255, 255, 255, 0.10);
  color: var(--gray-0);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gl-business__quicknav {
    background: rgba(20, 20, 20, 0.55);
    border-color: rgba(255, 255, 255, 0.10);
    box-shadow: 0 10px 32px rgba(0, 0, 0, 0.45),
                inset 0 1px 0 rgba(255, 255, 255, 0.06);
  }
  :root:not([data-theme="light"]) .gl-quicknav__link { color: rgba(255, 255, 255, 0.7); }
  :root:not([data-theme="light"]) .gl-quicknav__link:hover {
    background: rgba(255, 255, 255, 0.10);
    color: var(--gray-0);
  }
}
@media (max-width: 1024px) {
  .gl-product__layout { grid-template-columns: 1fr; gap: 32px; }
  .gl-product__visual { position: static; }
}

/* ============================================================
 * Home · Research section · giant "1" background watermark
 * ============================================================ */
.gl-home-research {
  position: relative;
  overflow: hidden;
}
.gl-home-research__numeral {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: clamp(280px, 52vw, 480px);
  font-weight: 700;
  font-family: serif;
  line-height: 0.85;
  letter-spacing: -0.06em;
  color: var(--gray-50);
  pointer-events: none;
  user-select: none;
  z-index: 0;
}
/* Inner content lifts above the watermark. */
.gl-home-research > .gl-section__inner {
  position: relative;
  z-index: 1;
}

/* ============================================================
 * Prose · long-form text blocks (Career)
 * ============================================================ */
.gl-prose { max-width: 720px; }
.gl-prose__title {
  font-size: 44px;
  line-height: 56px;
  font-weight: 700;
  letter-spacing: -0.025em;
  color: var(--ds-text-primary);
  margin: 0 0 24px;
  /* Honor `\n` in i18n strings as a hard line break. */
  white-space: pre-line;
}
/* ============================================================
 * Career · block1 two-column · prose left, value bubbles right
 * ============================================================ */
.gl-career-block-1__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 64px;
  align-items: start;
}
@media (max-width: 1024px) {
  .gl-career-block-1__grid {
    grid-template-columns: 1fr;
    gap: 40px;
  }
}
/* Values block · title above the bubble cloud, sits in the right column. */
.gl-values {
  display: flex;
  flex-direction: column;
  gap: 20px;
  /* Vertically center next to the prose for balance on long copy. */
  align-self: center;
}
.gl-values__title {
  font-size: 18px;
  font-weight: 700;
  letter-spacing: -0.005em;
  color: var(--ds-text-secondary);
  margin: 0;
}
/* Bubble cloud · free scatter (no grid). Each bubble is absolutely
 * positioned by hand-authored % coords inside the relative container.
 * The orbit wrapper carries the cloud-drift animation; the inner span
 * carries the JS-driven mouse-push transform. Two transforms layered on
 * different elements compose without fighting. */
.gl-values__bubbles {
  position: relative;
  width: 100%;
  /* Tall enough that the loose ellipse layout breathes without clipping. */
  min-height: 480px;
}
/* Orbit wrapper · positions the bubble center at left/top, then drifts in
 * a slow looping translate (clouds-floating effect). `translate(-50%, -50%)`
 * inside the keyframes is composed with the drift offset. */
.gl-values__bubble-orbit {
  position: absolute;
  /* left/top set inline · they reference the bubble CENTER. */
  animation: gl-values-drift 14s ease-in-out infinite alternate;
  will-change: transform;
}
@keyframes gl-values-drift {
  0%   { transform: translate(-50%, -50%) translate(0, 0); }
  25%  { transform: translate(-50%, -50%) translate(8px, -10px); }
  50%  { transform: translate(-50%, -50%) translate(-6px, -14px); }
  75%  { transform: translate(-50%, -50%) translate(-10px, 6px); }
  100% { transform: translate(-50%, -50%) translate(6px, 12px); }
}
@media (prefers-reduced-motion: reduce) {
  .gl-values__bubble-orbit { animation: none; }
}
.gl-values__bubble {
  /* Width = height for a perfect circle; size variants below set both. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  font-weight: 700;
  letter-spacing: -0.005em;
  color: var(--ds-text-primary);
  background: var(--gray-0);
  border: 1px solid var(--ds-border-subtle);
  border-radius: 50%;
  user-select: none;
  cursor: default;
  will-change: transform;
  transition: transform 360ms cubic-bezier(0.34, 1.56, 0.64, 1),
              background 200ms var(--ease-out),
              border-color 200ms var(--ease-out),
              box-shadow 200ms var(--ease-out);
  box-shadow: 0 4px 12px rgba(15, 23, 42, 0.06),
              0 1px 3px rgba(15, 23, 42, 0.04);
}
/* Size variants · circular, fixed diameter. lg = strongest emphasis. */
.gl-values__bubble--lg { width: 188px; height: 188px; font-size: 26px; }
.gl-values__bubble--md { width: 116px; height: 116px; font-size: 16px; }
.gl-values__bubble--sm { width: 88px;  height: 88px;  font-size: 13px; }
/* Direct hover · invert to black surface, white label, lifted shadow.
 * Bring the bubble to the front so an overlapped bubble can still claim
 * the spotlight when hovered. */
.gl-values__bubble:hover {
  background: var(--gray-900);
  border-color: var(--gray-900);
  color: var(--gray-0);
  box-shadow: 0 14px 28px rgba(15, 23, 42, 0.28),
              0 4px 10px rgba(15, 23, 42, 0.16);
}
.gl-values__bubble-orbit:hover { z-index: 9; }
@media (max-width: 1024px) {
  .gl-values__bubbles { min-height: 440px; }
  .gl-values__bubble--lg { width: 162px; height: 162px; font-size: 23px; }
  .gl-values__bubble--md { width: 102px; height: 102px; font-size: 15px; }
  .gl-values__bubble--sm { width: 78px;  height: 78px;  font-size: 12px; }
}
@media (max-width: 694px) {
  .gl-values__bubbles { min-height: 380px; }
  .gl-values__bubble--lg { width: 138px; height: 138px; font-size: 20px; }
  .gl-values__bubble--md { width: 90px;  height: 90px;  font-size: 14px; }
  .gl-values__bubble--sm { width: 70px;  height: 70px;  font-size: 11px; }
}
.gl-prose p {
  font-size: 16px;
  line-height: 1.85;
  color: var(--ds-text-primary);
  margin: 0 0 18px;
  letter-spacing: -0.005em;
  /* Honor `\n` in i18n strings as a hard line break. */
  white-space: pre-line;
}
.gl-prose p:last-child { margin-bottom: 0; }

/* ============================================================
 * Body content centered/maxw helpers used in pages
 * ============================================================ */
.gl-content-narrow p {
  font-size: 17px;
  line-height: 1.8;
  color: var(--ds-text-primary);
  letter-spacing: -0.005em;
  margin: 0;
  max-width: 90%;
  /* Honor `\n` in i18n strings as a hard line break. */
  white-space: pre-line;
}
@media (max-width: 694px) {
  .gl-content-narrow p { max-width: 99%; }
}
/* Vertical spacing between consecutive paragraphs in a narrow content block. */
.gl-content-narrow p + p { margin-top: 20px; }
/* Philosophy paragraphs · honor `\n` inside an i18n string as a line break,
 * giving the author 2 levels of rhythm: paragraph break (array boundary) for
 * a large gap, and `\n` for a tight in-paragraph wrap. */
.gl-about-philosophy .gl-content-narrow p,
.gl-about-mission .gl-content-narrow p {
  white-space: pre-line;
}

/* ============================================================
 * Philosophy · "Aura Pulse" pillar cards
 * Each pillar = central core + 2 concentric rings continuously pulsing
 * outward (sonar/signal feel). Per-card scroll parallax (JS) drifts cards
 * at alternating speeds for a wave-like rhythm.
 * ============================================================ */
.gl-philo-pillars {
  list-style: none;
  margin: 80px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 24px;
}
.gl-philo-pillar {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 22px;
  padding: 24px 16px;
}
.gl-philo-pillar__aura {
  position: relative;
  width: 400px;
  height: 400px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.gl-philo-pillar__core {
  width: 200px;
  height: 200px;
  border-radius: 50%;
  background: var(--philo-accent, var(--gray-900));
  color: var(--gray-0);
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  z-index: 2;
  /* Subtle elevation to feel like a node floating on the network line */
  box-shadow: 0 18px 36px rgba(15, 23, 42, 0.12);
  transition: transform 320ms var(--ease-out),
              box-shadow 320ms var(--ease-out);
}
.gl-philo-pillar:hover .gl-philo-pillar__core {
  transform: scale(1.05);
  box-shadow: 0 24px 48px rgba(15, 23, 42, 0.18);
}
.gl-philo-pillar__icon {
  width: 72px;
  height: 72px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.gl-philo-pillar__ring {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 200px;
  height: 200px;
  border-radius: 50%;
  border: 1.5px solid var(--philo-accent, var(--gray-900));
  transform: translate(-50%, -50%) scale(1);
  opacity: 0.45;
  pointer-events: none;
  animation: gl-philo-pulse 4.2s ease-out infinite;
}
.gl-philo-pillar__ring--1 { animation-delay: 0s; }
.gl-philo-pillar__ring--2 { animation-delay: 1.4s; opacity: 0.3; }
@keyframes gl-philo-pulse {
  0%   { transform: translate(-50%, -50%) scale(0.85); opacity: 0.45; }
  70%  { opacity: 0; }
  100% { transform: translate(-50%, -50%) scale(2);    opacity: 0; }
}
.gl-philo-pillar__label {
  font-size: 18px;
  font-weight: 800;
  letter-spacing: 0.02em;
  color: var(--ds-text-primary);
}
.gl-philo-pillar__desc {
  font-size: 14px;
  line-height: 1.7;
  color: var(--ds-text-secondary);
  margin: 0;
  max-width: 240px;
  /* Honor `\n` in i18n strings as line breaks. */
  white-space: pre-line;
}
/* Per-card accent palette · gray/black tones */
.gl-philo-pillar--orange { --philo-accent: var(--gray-900); }
.gl-philo-pillar--teal   { --philo-accent: var(--gray-700); }
.gl-philo-pillar--blue   { --philo-accent: var(--gray-500); }

@media (max-width: 1024px) {
  .gl-philo-pillars { gap: 16px; }
  .gl-philo-pillar__aura { width: 320px; height: 320px; }
  .gl-philo-pillar__core { width: 160px; height: 160px; }
  .gl-philo-pillar__ring { width: 160px; height: 160px; }
  .gl-philo-pillar__icon { width: 60px; height: 60px; }
}
@media (max-width: 694px) {
  .gl-philo-pillars { grid-template-columns: 1fr; gap: 8px; margin-top: 48px; }
  .gl-philo-pillar { padding: 16px; }
  .gl-philo-pillar__aura { width: 280px; height: 280px; }
  .gl-philo-pillar__core { width: 140px; height: 140px; }
  .gl-philo-pillar__ring { width: 140px; height: 140px; }
  .gl-philo-pillar__icon { width: 56px; height: 56px; }
}
/* Dark theme · invert accent palette so cores stay visible on dark */
:root[data-theme="dark"] .gl-philo-pillar__label { color: var(--gray-0); }
:root[data-theme="dark"] .gl-philo-pillar__desc  { color: rgba(255, 255, 255, 0.65); }
:root[data-theme="dark"] .gl-philo-pillar__core { color: var(--gray-900); }
:root[data-theme="dark"] .gl-philo-pillar--orange { --philo-accent: var(--gray-200); }
:root[data-theme="dark"] .gl-philo-pillar--teal   { --philo-accent: var(--gray-400); }
:root[data-theme="dark"] .gl-philo-pillar--blue   { --philo-accent: var(--gray-500); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gl-philo-pillar__label { color: var(--gray-0); }
  :root:not([data-theme="light"]) .gl-philo-pillar__desc  { color: rgba(255, 255, 255, 0.65); }
  :root:not([data-theme="light"]) .gl-philo-pillar__core { color: var(--gray-900); }
  :root:not([data-theme="light"]) .gl-philo-pillar--orange { --philo-accent: var(--gray-200); }
  :root:not([data-theme="light"]) .gl-philo-pillar--teal   { --philo-accent: var(--gray-400); }
  :root:not([data-theme="light"]) .gl-philo-pillar--blue   { --philo-accent: var(--gray-500); }
}
@media (prefers-reduced-motion: reduce) {
  .gl-philo-pillar__ring { animation: none; opacity: 0.3; }
}

/* Home page · center the narrow paragraph horizontally within its container,
 * desktop and mobile alike. */
.gl-home .gl-content-narrow p {
  margin: 0 auto;
  max-width: 70%;
}
@media (max-width: 694px) {
  .gl-home .gl-content-narrow p { max-width: 80%; }
}

/* ============================================================
 * Why-now · Home · simple tabular list
 * ============================================================ */
.gl-whynow {
  list-style: none;
  margin: 0;
  padding: 0;
  max-width: 720px;
}
.gl-whynow li {
  font-size: 17px;
  line-height: 1.7;
  color: var(--ds-text-primary);
  padding: 14px 0;
  border-top: 1px solid var(--ds-border-subtle);
  letter-spacing: -0.005em;
}
.gl-whynow li:first-child { border-top: 0; }

/* ============================================================
 * Closing line · large centered statement (Home / Business)
 * ============================================================ */
.gl-closing {
  text-align: center;
  padding: 80px 0;
}
.gl-closing__title {
  font-size: clamp(28px, 3.6vw, 44px);
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--ds-text-primary);
  line-height: 1.3;
  margin: 0;
  max-width: 720px;
  margin: 0 auto;
}

/* ============================================================
 * Alternating section background pattern (white ↔ gray-50)
 *
 * Per-page scope. nth-of-type counts <section> siblings, so the page-hero
 * (position 1) is excluded by the .gl-region class filter. The alternation
 * starts from the first .gl-region (position 2 = even = white), giving:
 *   pos 2,4,6,8 = white  |  pos 3,5,7 = gray-50
 *
 * Specificity (0,3,2) wins over .gl-region--subtle (0,1,0), so existing
 * --subtle modifiers are harmlessly overridden by the pattern.
 *
 * Dark theme uses --ds-bg-base / --ds-bg-surface for the same alternation.
 * ============================================================ */
.gl-home     section.gl-region:nth-of-type(odd),
.gl-about    section.gl-region:nth-of-type(odd),
.gl-labs     section.gl-region:nth-of-type(odd),
.gl-business section.gl-region:nth-of-type(odd),
.gl-press    section.gl-region:nth-of-type(odd),
.gl-career   section.gl-region:nth-of-type(odd) {
  background: var(--gray-50);
}
.gl-home     section.gl-region:nth-of-type(even),
.gl-about    section.gl-region:nth-of-type(even),
.gl-labs     section.gl-region:nth-of-type(even),
.gl-business section.gl-region:nth-of-type(even),
.gl-press    section.gl-region:nth-of-type(even),
.gl-career   section.gl-region:nth-of-type(even) {
  background: var(--gray-0);
}

:root[data-theme="dark"] .gl-home     section.gl-region:nth-of-type(odd),
:root[data-theme="dark"] .gl-about    section.gl-region:nth-of-type(odd),
:root[data-theme="dark"] .gl-labs     section.gl-region:nth-of-type(odd),
:root[data-theme="dark"] .gl-business section.gl-region:nth-of-type(odd),
:root[data-theme="dark"] .gl-press    section.gl-region:nth-of-type(odd),
:root[data-theme="dark"] .gl-career   section.gl-region:nth-of-type(odd) {
  background: var(--ds-bg-surface);
}
:root[data-theme="dark"] .gl-home     section.gl-region:nth-of-type(even),
:root[data-theme="dark"] .gl-about    section.gl-region:nth-of-type(even),
:root[data-theme="dark"] .gl-labs     section.gl-region:nth-of-type(even),
:root[data-theme="dark"] .gl-business section.gl-region:nth-of-type(even),
:root[data-theme="dark"] .gl-press    section.gl-region:nth-of-type(even),
:root[data-theme="dark"] .gl-career   section.gl-region:nth-of-type(even) {
  background: var(--ds-bg-base);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gl-home     section.gl-region:nth-of-type(odd),
  :root:not([data-theme="light"]) .gl-about    section.gl-region:nth-of-type(odd),
  :root:not([data-theme="light"]) .gl-labs     section.gl-region:nth-of-type(odd),
  :root:not([data-theme="light"]) .gl-business section.gl-region:nth-of-type(odd),
  :root:not([data-theme="light"]) .gl-press    section.gl-region:nth-of-type(odd),
  :root:not([data-theme="light"]) .gl-career   section.gl-region:nth-of-type(odd) {
    background: var(--ds-bg-surface);
  }
  :root:not([data-theme="light"]) .gl-home     section.gl-region:nth-of-type(even),
  :root:not([data-theme="light"]) .gl-about    section.gl-region:nth-of-type(even),
  :root:not([data-theme="light"]) .gl-labs     section.gl-region:nth-of-type(even),
  :root:not([data-theme="light"]) .gl-business section.gl-region:nth-of-type(even),
  :root:not([data-theme="light"]) .gl-press    section.gl-region:nth-of-type(even),
  :root:not([data-theme="light"]) .gl-career   section.gl-region:nth-of-type(even) {
    background: var(--ds-bg-base);
  }
}

/* ============================================================
 * Section vertical rhythm (240px top/bottom)
 *
 * Two scopes:
 *   1. .gl-home .gl-region   — every region on Home gets 240px (the v17 base
 *      sections research/why-now/proof/closing live there).
 *   2. .gl-four-research, .gl-living-lab, .gl-flow-map, .gl-press-preview —
 *      page-agnostic. These showcase sections moved from Home to About;
 *      they keep their generous breathing room wherever they appear.
 * ============================================================ */
.gl-home .gl-region,
.gl-four-research,
.gl-living-lab,
.gl-flow-map,
.gl-press-preview {
  padding-top: 160px;
  padding-bottom: 160px;
}
@media (max-width: 1024px) {
  .gl-home .gl-region,
  .gl-four-research,
  .gl-living-lab,
  .gl-flow-map,
  .gl-press-preview {
    padding-top: 160px;
    padding-bottom: 160px;
  }
}
@media (max-width: 694px) {
  .gl-home .gl-region,
  .gl-four-research,
  .gl-living-lab,
  .gl-flow-map,
  .gl-press-preview {
    padding-top: 80px;
    padding-bottom: 80px;
  }
}

/* ============================================================
 * TypingText · per-character reveal + blinking cursor
 * ============================================================ */
.gl-typing {
  display: inline;
  white-space: pre-wrap;
}
.gl-typing__chars { color: inherit; }
.gl-typing__cursor {
  display: inline-block;
  margin-left: 4px;
  font-weight: 300;
  color: var(--ds-primary-500);
  transform: translateY(-0.04em);
  animation: typingBlink 1s steps(2, start) infinite;
}
.gl-typing__cursor.is-done {
  animation-duration: 1.4s;
}
@keyframes typingBlink {
  to { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .gl-typing__cursor { animation: none; opacity: 0; }
}

/* Note · page-hero shape dark-mode tone tweaks moved to sections.css
 * (see "Dark mode · shape + text + pen color inversions" block) so the
 * full shape system lives in one file. */

/* ============================================================
 * Mobile-only line break utility · `<br className="gl-br-mobile" />`
 * Hidden above 694px, rendered as a hard break on mobile. Used together
 * with the `renderMobileBreaks(text)` helper that splits i18n strings on
 * the `[m-br]` marker. Independent of the existing `\n` + pre-line system.
 * ============================================================ */
.gl-br-mobile { display: none; }
@media (max-width: 694px) {
  .gl-br-mobile { display: inline; }
}

/* ============================================================
 * Reveal · IntersectionObserver-driven entry transition
 * ============================================================ */
.gl-reveal {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 720ms var(--ease-out), transform 720ms var(--ease-out);
  will-change: opacity, transform;
}
.gl-reveal.is-visible { opacity: 1; transform: none; }
/* Directional variants · override the starting transform.
 * --from-left : slides in from the left (used by mission text block)
 * --from-up   : default behaviour, kept for symmetry / explicit intent */
.gl-reveal--from-left { transform: translateX(-40px); }
.gl-reveal--from-up   { transform: translateY(28px); }
@media (prefers-reduced-motion: reduce) {
  .gl-reveal { opacity: 1; transform: none; transition: none; }
}

/* ============================================================
 * HeroDark · center align variant + parallax bg layer hint
 * ============================================================ */
.gl-hero-dark__bg { will-change: transform; }
.gl-hero-dark--center .gl-hero-dark__content {
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.gl-hero-dark--center .gl-hero-dark__title,
.gl-hero-dark--center .gl-hero-dark__subtitle { margin-left: auto; margin-right: auto; }
.gl-hero-dark--center .gl-hero-dark__ctas { justify-content: center; }
@media (prefers-reduced-motion: reduce) {
  .gl-hero-dark__bg,
  .gl-hero-dark__content { transform: none !important; }
}

/* ============================================================
 * Center alignment helpers (used on Home only)
 * ============================================================ */
.gl-content-narrow--center { margin-left: auto; margin-right: auto; text-align: center; }
.gl-whynow--center { margin-left: auto; margin-right: auto; text-align: center; list-style-position: inside; }
.gl-whynow--center li { padding-left: 0; padding-right: 0; }

/* ============================================================
 * NEW A · Four Research (4 IP intro cards · Persona / NounDB / Poll / NewsBlock)
 * ============================================================ */
.gl-four-research__grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 20px;
  margin-top: 56px;
}
.gl-four-research__cta { text-align: center; margin-top: 56px; }
@media (max-width: 1024px) {
  .gl-four-research__grid { grid-template-columns: repeat(2, 1fr); gap: 16px; }
}
@media (max-width: 694px) {
  .gl-four-research__grid { grid-template-columns: repeat(2, 1fr); gap: 12px; }
}

/* Animated conic-gradient outline · uses @property so the angle can be
 * keyframe-animated. (Falls back to a static gradient on engines without
 * @property; visible-only on hover so the static state is unaffected.) */
@property --gl-ipmini-angle {
  syntax: '<angle>';
  initial-value: 0deg;
  inherits: false;
}
.gl-ipmini {
  position: relative;
  padding: 32px 28px 28px;
  border: 1px solid var(--ds-border-subtle);
  border-radius: 25px;
  background: var(--ds-bg-surface);
  display: flex;
  flex-direction: column;
  gap: 12px;
  /* Form a stacking context so ::before(z-index:-1) hides behind the card
   * surface but stays in front of the page beneath. */
  isolation: isolate;
  transition: transform 320ms var(--ease-out),
              border-color 240ms var(--ease-out),
              box-shadow 320ms var(--ease-out),
              background 240ms var(--ease-out);
}
@media (max-width: 694px) {
  .gl-ipmini { padding: 16px 20px 16px; }
}
/* Dark theme · --ds-bg-surface (neutral-800) too close to the section bg.
 * Use a soft white overlay + brighter border for visible separation. */
:root[data-theme="dark"] .gl-ipmini {
  background: rgba(255, 255, 255, 0.05);
  border-color: rgba(255, 255, 255, 0.10);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gl-ipmini {
    background: rgba(255, 255, 255, 0.05);
    border-color: rgba(255, 255, 255, 0.10);
  }
}
/* Hover · Instagram-Story-style animated gradient outline that flows around
 * the card border line itself. The `::before` overlays the card with a 2px
 * padding-box stripe of conic gradient; mask-composite clips out everything
 * but that 2px ring, so the gradient appears ON the border, not behind the
 * card. */
.gl-ipmini::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 2px;
  /* Brand blue + each sub-page hero color · About blue-500, Labs green-700,
   * Business violet-700, Press orange-600, Career gray-900. Loops back to
   * blue so the conic ring connects without a seam. */
  background: conic-gradient(
    from var(--gl-ipmini-angle),
    var(--blue-500),
    #15803D,
    #6D28D9,
    #EA580C,
    var(--gray-900),
    var(--blue-500));
  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
          mask-composite: exclude;
  opacity: 0;
  transition: opacity 240ms var(--ease-out);
  pointer-events: none;
}
.gl-ipmini:hover {
  /* Hide the static gray border so only the gradient ring is visible.
   * No lift / shadow · the moving gradient carries the affordance on its own. */
  border-color: transparent;
}
.gl-ipmini:hover::before {
  opacity: 1;
  animation: gl-ipmini-spin 4s linear infinite;
}
@keyframes gl-ipmini-spin {
  to { --gl-ipmini-angle: 360deg; }
}
@media (prefers-reduced-motion: reduce) {
  .gl-ipmini:hover::before { animation: none; }
}
.gl-ipmini__icon {
  width: 44px; height: 44px;
  display: flex; align-items: center; justify-content: center;
  color: var(--gray-700);
  margin-bottom: 4px;
}
/* Dark theme · lighter neutral so the stroke reads on a dark section. */
:root[data-theme="dark"] .gl-ipmini__icon {
  color: var(--gray-300);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gl-ipmini__icon {
    color: var(--gray-300);
  }
}
.gl-ipmini__name {
  font-size: 22px; font-weight: 700; letter-spacing: -0.018em;
  color: var(--ds-text-primary); margin: 0;
}
.gl-ipmini__tagline {
  font-size: 16px; font-weight: 500; letter-spacing: -0.005em;
  color: var(--ds-text-primary); margin: 0;
}
.gl-ipmini__desc {
  font-size: 14px; line-height: 1.7; letter-spacing: -0.005em;
  color: var(--ds-text-secondary); margin: 0;
}

/* ============================================================
 * NEW B · Living Lab (Newming + floating mockup with tilt)
 * ============================================================ */
.gl-living-lab {
  position: relative;
  overflow: hidden;
  /* Vertical padding controlled by .gl-home .gl-region (240px) at file end. */
}
.gl-living-lab__bg {
  position: absolute; inset: 0;
  background:
    radial-gradient(ellipse 60% 40% at 22% 30%, rgba(0, 102, 255, 0.10), transparent 60%),
    radial-gradient(ellipse 50% 40% at 78% 70%, rgba(0, 102, 255, 0.06), transparent 60%);
  pointer-events: none;
  z-index: 0;
}
.gl-living-lab .gl-section__inner { position: relative; z-index: 1; }
.gl-living-lab__split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 64px;
  align-items: center;
  margin-top: 56px;
}
.gl-living-lab__visual {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 420px;
}
.gl-living-lab__mockup {
  /* Frontal flat presentation · 3D rotate + float animation removed.
   * The Newming mockup itself now plays a user-flow image sequence inside
   * its bezel, which IS the motion — adding tilt would compete with it. */
  filter: drop-shadow(0 32px 64px rgba(0, 0, 0, 0.18));
  transition: transform 600ms var(--ease-out), filter 600ms var(--ease-out);
}
.gl-living-lab__mockup:hover {
  transform: scale(1.03);
  filter: drop-shadow(0 40px 80px rgba(0, 0, 0, 0.24));
}
.gl-living-lab__story {
  display: flex;
  flex-direction: column;
  gap: 22px;
  max-width: 480px;
}
.gl-living-lab__product {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 14px;
}
@media (max-width: 694px) {
  .gl-living-lab__product {
    align-items: center;
  }
}
.gl-living-lab__product-info {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 20px;
}

.gl-living-lab__product-name {
  font-size: 28px; font-weight: 700; letter-spacing: -0.02em;
  color: var(--ds-text-primary); margin: 0;
}
.gl-living-lab__body {
  font-size: 17px; line-height: 1.75; letter-spacing: -0.005em;
  color: var(--ds-text-primary); margin: 0;
}
.gl-living-lab__bullets {
  list-style: none; margin: 0; padding: 16px 0 16px 22px;
  display: flex; flex-direction: column; gap: 10px;
  border-left: 2px solid var(--ds-primary-500);
}
.gl-living-lab__bullets li {
  font-size: 15px; line-height: 1.55; letter-spacing: -0.005em;
  color: var(--ds-text-secondary);
}
.gl-living-lab__meta {
  font-size: 13px; color: var(--ds-text-tertiary); margin: 0;
  letter-spacing: 0;
}
@media (max-width: 1024px) {
  .gl-living-lab__split { grid-template-columns: 1fr; gap: 48px; }
  .gl-living-lab__visual { min-height: 360px; }
  .gl-living-lab__story { max-width: none; align-items: center; text-align: center; }
  .gl-living-lab__bullets { border-left: 0; padding-left: 0; align-items: center; text-align: center; }
}
@media (max-width: 694px) {
  /* iPhone mockup doesn't read at mobile size · hide the visual entirely
   * so the section collapses to story content only (no reserved empty space). */
  .gl-living-lab__visual { display: none; }
  .gl-living-lab__split { gap: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .gl-living-lab__mockup { transform: none; transition: none; }
}

/* ── Newming app icon · theme-aware swap of pre-rendered SVGs ──
 * Two square 1024×1024 SVGs exported from Apple Icon Composer, with
 * gradient + glyph already baked in. CSS only adds:
 *   · 22.37% squircle radius (iOS superellipse approximation)
 *   · drop shadow + subtle inset highlight (suggests glass)
 *   · theme-driven background-image swap:
 *       light theme → newming_logo_dark.svg   (dark icon on light page)
 *       dark theme  → newmung_logo_light.svg  (light icon on dark page)
 *     filename "newmung" is the user's saved spelling — kept as-is. */
.gl-newming-icon {
  flex-shrink: 0;
  border-radius: 22.37%;
  background-image: url('../assets/mockups/newming_logo_dark.svg');
  background-size: cover;
  background-repeat: no-repeat;
  background-position: center;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.18),
    0 0 0 1px rgba(0, 0, 0, 0.06),
    0 8px 24px rgba(0, 0, 0, 0.22);
}
:root[data-theme="dark"] .gl-newming-icon {
  background-image: url('../assets/mockups/newmung_logo_light.svg');
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.18),
    0 0 0 1px rgba(255, 255, 255, 0.10),
    0 8px 24px rgba(0, 0, 0, 0.45);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gl-newming-icon {
    background-image: url('../assets/mockups/newmung_logo_light.svg');
    box-shadow:
      inset 0 1px 0 rgba(255, 255, 255, 0.18),
      0 0 0 1px rgba(255, 255, 255, 0.10),
      0 8px 24px rgba(0, 0, 0, 0.45);
  }
}

/* ── Download badges · Living Lab CTA row ──────────────────────────
 * Renders below bullets, before meta. Currently Google Play only;
 * if App Store badge is added later, just append another <a> with
 * the same .gl-living-lab__download class — the flex row wraps. */
.gl-living-lab__downloads {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 4px;
}
.gl-living-lab__download {
  position: relative;        /* anchor for ::after inset border */
  display: inline-flex;
  border-radius: 8px;
  overflow: hidden;          /* clip both badges to the unified outer radius */
  transition: opacity 200ms var(--ease-out), transform 200ms var(--ease-out);
}
/* Dark theme only · paint inset 1px white stroke over badge to mask
 * the baked-in dark border. Light mode shows the badge as-is. */
:root[data-theme="dark"] .gl-living-lab__download::after {
  content: '';
  position: absolute;
  inset: 0;
  border: 1px solid #fff;
  border-radius: inherit;
  pointer-events: none;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gl-living-lab__download::after {
    content: '';
    position: absolute;
    inset: 0;
    border: 1px solid #fff;
    border-radius: inherit;
    pointer-events: none;
  }
}
.gl-living-lab__download:hover {
  opacity: 0.85;
  transform: translateY(-1px);
}
.gl-living-lab__download img {
  height: 56px;
  width: auto;
  display: block;
}
@media (max-width: 1024px) {
  .gl-living-lab__downloads { justify-content: center; }
}

/* ============================================================
 * NEW C · Research → Operation Flow Map
 * ============================================================ */
/* gl-flow-map · bg controlled by alternating pattern (.gl-home nth-of-type) */
.gl-flow-map { /* base styles only · bg from page alternation */ }

/* Container splits the section into a label row above + a 3-column grid below.
 * Both share the same column track (240px / 1fr / 240px) so labels sit exactly
 * above their respective columns. The grid itself contains only nodes + SVG,
 * giving the connector layer a clean 1:1 height match with the node columns. */
.gl-flow-map__container {
  margin-top: 56px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.gl-flow-map__head-row {
  display: grid;
  grid-template-columns: 240px 1fr 240px;
  gap: 32px;
}
.gl-flow-map__grid {
  display: grid;
  grid-template-columns: 240px 1fr 240px;
  gap: 32px;
  /* Tall enough that `justify-content: space-between` on each column has
   * comfortable room to spread now-taller product nodes (name + desc). */
  min-height: 460px;
  position: relative;
}
.gl-flow-map__label {
  font-size: 11px; font-weight: 700; letter-spacing: 0.16em;
  color: var(--ds-text-tertiary); text-transform: uppercase;
}
.gl-flow-map__label--ip      { text-align: right; }
.gl-flow-map__label--product { text-align: left; }

/* Both columns use space-between so first / last nodes pin to top / bottom
 * edges of the grid. Middle nodes evenly distribute between. SVG path
 * endpoints follow the same distribution (yPos in Home.jsx). */
.gl-flow-map__col {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 0;
}

.gl-flow-map__node {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 18px;
  background: var(--ds-bg-elevated);
  border: 1px solid var(--ds-border-subtle);
  border-radius: var(--ds-radius-md);
  font-size: 14px; font-weight: 600; letter-spacing: -0.005em;
  color: var(--ds-text-primary);
  cursor: default;
  /* Stagger delay (--enter-delay) is applied ONLY to entrance (opacity /
   * transform). Hover-driven properties (border/bg/shadow) react immediately
   * so the interaction never feels laggy. */
  transition: opacity 480ms var(--ease-out) var(--enter-delay, 0s),
              transform 480ms var(--ease-out) var(--enter-delay, 0s),
              border-color 160ms var(--ease-out),
              background 160ms var(--ease-out),
              box-shadow 160ms var(--ease-out);
  opacity: 0;
  transform: translateY(8px);
}
.gl-flow-map__grid.is-revealed .gl-flow-map__node {
  opacity: 1; transform: none;
}
.gl-flow-map__node--ip {
  justify-content: flex-end;
}
.gl-flow-map__node--ip .gl-flow-map__node-icon {
  flex: 0 0 auto;
  color: var(--gray-700);
  width: 28px; height: 28px;
  display: flex; align-items: center; justify-content: center;
}
.gl-flow-map__node--product {
  justify-content: flex-start;
  flex-wrap: wrap;
  row-gap: 4px;
}
/* Product description · subtle gray secondary line under the product name. */
.gl-flow-map__node-desc {
  flex-basis: 100%;
  font-size: 12px;
  font-weight: 500;
  line-height: 1.4;
  color: var(--fg-quaternary);
  letter-spacing: -0.005em;
}
/* Product hover tooltip · sources from business.products[id].oneliner.
 * Positioned BELOW the card so it never clips against the right-side page
 * padding regardless of viewport width. White surface for readability;
 * pointer-events disabled so it never blocks hover. */
.gl-flow-map__node--product { position: relative; }
.gl-flow-map__node-tip {
  position: absolute;
  left: 50%;
  top: calc(100% + 10px);
  transform: translate(-50%, -4px);
  width: max-content;
  max-width: min(280px, 90vw);
  padding: 12px 16px;
  font-size: 14px;
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: -0.005em;
  color: var(--gray-900);
  background: var(--gray-0);
  border: 1px solid var(--ds-border-subtle);
  border-radius: var(--ds-radius-md);
  box-shadow: 0 18px 40px rgba(15, 23, 42, 0.16),
              0 6px 14px rgba(15, 23, 42, 0.08);
  opacity: 0;
  pointer-events: none;
  transition: opacity 160ms var(--ease-out),
              transform 160ms var(--ease-out);
  z-index: 5;
}
/* Arrow points up at the card · matches white surface + subtle border. */
.gl-flow-map__node-tip::before {
  content: '';
  position: absolute;
  top: -5px;
  left: 50%;
  width: 10px; height: 10px;
  background: var(--gray-0);
  border-top: 1px solid var(--ds-border-subtle);
  border-left: 1px solid var(--ds-border-subtle);
  transform: translate(-50%, 0) rotate(45deg);
  border-radius: 2px;
}
/* Invisible bridge over the 10px gap between card and tooltip · so the
 * pointer can travel from card to tooltip (e.g. to click the CTA) without
 * losing :hover on the parent node. Sits above the visible tooltip surface
 * but below the arrow. */
.gl-flow-map__node-tip::after {
  content: '';
  position: absolute;
  top: -12px;
  left: 0; right: 0;
  height: 12px;
}
.gl-flow-map__node--product:hover .gl-flow-map__node-tip,
.gl-flow-map__node--product.is-hi .gl-flow-map__node-tip {
  opacity: 1;
  transform: translate(-50%, 0);
  pointer-events: auto;
}
/* Mobile · the product column hugs the right edge of the viewport, so a
 * center-anchored tooltip clips off the right side. Anchor to the card's
 * right edge instead so the tooltip extends leftward into available space,
 * and reposition the arrow to point at the card's horizontal center. */
@media (max-width: 694px) {
  .gl-flow-map__node-tip {
    left: auto;
    right: 0;
    transform: translateY(-4px);
  }
  .gl-flow-map__node-tip::before {
    left: auto;
    right: 50px;
    transform: rotate(45deg);
  }
  .gl-flow-map__node--product:hover .gl-flow-map__node-tip,
  .gl-flow-map__node--product.is-hi .gl-flow-map__node-tip {
    transform: translateY(0);
  }
}
.gl-flow-map__node-tip-text { display: block; }
/* Text-style CTA button · subtle separator above, brand blue with arrow. */
.gl-flow-map__node-tip-cta {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--ds-border-subtle);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: -0.005em;
  color: var(--ds-primary-500);
  text-decoration: none;
  width: 100%;
  cursor: pointer;
  transition: color 160ms var(--ease-out), gap 160ms var(--ease-out);
}
.gl-flow-map__node-tip-cta:hover {
  color: var(--ds-primary-600, var(--ds-primary-500));
  gap: 8px;
}
/* Dark mode · invert surface so the tooltip stays legible without the
 * harsh white block. */
:root[data-theme="dark"] .gl-flow-map__node-tip {
  color: var(--gray-0);
  background: var(--ds-bg-surface);
  border-color: rgba(255, 255, 255, 0.10);
}
:root[data-theme="dark"] .gl-flow-map__node-tip::before {
  background: var(--ds-bg-surface);
  border-color: rgba(255, 255, 255, 0.10);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gl-flow-map__node-tip {
    color: var(--gray-0);
    background: var(--ds-bg-surface);
    border-color: rgba(255, 255, 255, 0.10);
  }
  :root:not([data-theme="light"]) .gl-flow-map__node-tip::before {
    background: var(--ds-bg-surface);
    border-color: rgba(255, 255, 255, 0.10);
  }
}
.gl-flow-map__group-tag {
  flex: 0 0 auto;
  font-size: 10px; font-weight: 700; letter-spacing: 0.14em;
  color: var(--ds-primary-500);
  background: var(--ds-bg-brand-subtle);
  padding: 3px 8px;
  border-radius: var(--ds-radius-sm);
}
/* IP nodes invert to brand blue · text + icon flip to white. */
.gl-flow-map__node--ip:hover,
.gl-flow-map__node--ip.is-hi {
  border-color: var(--ds-primary-500);
  background: var(--ds-primary-500);
  color: var(--gray-0);
  box-shadow: 0 4px 12px rgba(0, 102, 255, 0.18);
}
.gl-flow-map__node--ip:hover .gl-flow-map__node-icon,
.gl-flow-map__node--ip.is-hi .gl-flow-map__node-icon {
  color: var(--gray-0);
}
/* Product nodes invert to near-black · name + desc flip to white. */
.gl-flow-map__node--product:hover,
.gl-flow-map__node--product.is-hi {
  border-color: var(--gray-900);
  background: var(--gray-900);
  color: var(--gray-0);
  box-shadow: 0 4px 12px rgba(15, 23, 42, 0.22);
}
.gl-flow-map__node--product:hover .gl-flow-map__node-desc,
.gl-flow-map__node--product.is-hi .gl-flow-map__node-desc {
  color: rgba(255, 255, 255, 0.7);
}

.gl-flow-map__connectors-wrap {
  position: relative;
}
.gl-flow-map__connectors {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  pointer-events: none;
  overflow: visible;
}
/* Continuous flow · dashed segments stream from IP (left) toward Product
 * (right) at a steady pace. Negative dashoffset shifts dashes in the +x
 * direction along each path. */
@keyframes gl-flow-stream {
  to { stroke-dashoffset: -85; }
}
.gl-flow-map__edge {
  fill: none;
  stroke: var(--ds-border-default);
  stroke-width: 0.5;
  stroke-linecap: round;
  stroke-dasharray: 1 2;
  animation: gl-flow-stream 11s linear infinite;
  /* Phase-shift each edge by reusing --enter-delay as a NEGATIVE animation
   * offset (multiplied to spread across the full cycle). Negative delays
   * start the animation as if it had already been running, so each edge sits
   * at a different point in the cycle and the lines stop pulsing in unison. */
  animation-delay: calc(-1 * var(--enter-delay, 0ms) * 14);
  /* Entrance fade · staggered via --enter-delay. Hover-driven stroke
   * properties have no delay so they snap on instantly. */
  opacity: 0;
  transition: opacity 600ms var(--ease-out) var(--enter-delay, 0s),
              stroke 160ms var(--ease-out),
              stroke-width 160ms var(--ease-out);
}
.gl-flow-map__grid.is-revealed .gl-flow-map__edge { opacity: 1; }
.gl-flow-map__edge.is-hi {
  stroke: var(--ds-primary-500);
  stroke-width: 0.7;
}
@media (prefers-reduced-motion: reduce) {
  .gl-flow-map__edge { animation: none; }
}

/* Mobile only · keep the symmetrical 3-column layout (IPs · connectors ·
 * Products) so the data-flow visualization survives on small screens. The
 * column tracks shrink, product descriptions are hidden, and paddings are
 * tighter. Tablet keeps the default desktop layout (240/1fr/240). */
@media (max-width: 694px) {
  .gl-flow-map__head-row,
  .gl-flow-map__grid {
    grid-template-columns: 100px 1fr 110px;
    gap: 8px;
  }
  .gl-flow-map__grid { min-height: 340px; }
  /* Hide product description on mobile · just the product name remains so
   * the right column doesn't blow up the layout. */
  .gl-flow-map__node-desc { display: none; }
  .gl-flow-map__node {
    padding: 8px 10px;
    font-size: 12px;
    gap: 6px;
  }
  .gl-flow-map__node--ip .gl-flow-map__node-icon {
    width: 18px; height: 18px;
  }
  .gl-flow-map__label { font-size: 11px; }
}
@media (prefers-reduced-motion: reduce) {
  .gl-flow-map__node { opacity: 1; transform: none; }
  .gl-flow-map__edge { stroke-dashoffset: 0; }
}

/* ============================================================
 * Labs · page-scoped section title size (32px override)
 *
 * Applies to all 4 body sections inside .gl-labs:
 *   핵심 기술 · 연구 인프라 · 등록 상표 · 우리가 연구에 쓰는 기술
 * IP cards use .gl-ipcard__title (different class) so unaffected.
 * page-hero uses .gl-page-hero__title (different class) so unaffected.
 * ============================================================ */
.gl-labs .gl-section__title {
  font-size: 32px;
  line-height: 1.3;
}

/* ============================================================
 * Labs · Core Technology (6 capability cards · 3×2 grid)
 *
 * Each card: visual placeholder (gradient) + name + description.
 * Visuals use distinct radial/linear gradients matching the source theme;
 * swap in real <img> later by replacing the .gl-core-tech__visual div.
 * ============================================================ */
.gl-core-tech__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 56px 32px;
  margin-top: 40px;
}
.gl-core-tech__card {
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.gl-core-tech__visual {
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: var(--ds-radius-md);
  overflow: hidden;
  position: relative;
  background-color: var(--ds-bg-muted);
}
.gl-core-tech__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 600ms var(--ease-out);
}
.gl-core-tech__card:hover .gl-core-tech__img {
  transform: scale(1.04);
}
@media (prefers-reduced-motion: reduce) {
  .gl-core-tech__img { transition: none; }
  .gl-core-tech__card:hover .gl-core-tech__img { transform: none; }
}
.gl-core-tech__name {
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.018em;
  color: var(--ds-text-primary);
  margin: 0;
}
.gl-core-tech__desc {
  font-size: 14px;
  line-height: 1.7;
  color: var(--ds-text-secondary);
  letter-spacing: -0.005em;
  margin: 0;
}
@media (max-width: 1024px) {
  .gl-core-tech__grid { grid-template-columns: repeat(2, 1fr); gap: 40px 24px; }
}
@media (max-width: 694px) {
  .gl-core-tech__grid { grid-template-columns: 1fr; gap: 32px; }
}

/* ============================================================
 * NEW E · Partners (7 outlet logos · grayscale → color on hover)
 * ============================================================ */
/* 4 + 3 layout · flex with center justify · items cluster in the middle
 * (don't spread to fill full width). Fixed-width cells (180px) wrap naturally:
 * 4 fit per row at desktop widths, last 3 center on row 2. */
.gl-partners__grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 40px 56px;
  margin-top: 56px;
}
.gl-partners__cell {
  flex: 0 0 auto;
  width: 180px;
  height: 56px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 8px;
}
.gl-partners__logo {
  display: block;
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  filter: grayscale(100%);
  opacity: 0.55;
  transition: filter 320ms var(--ease-out), opacity 320ms var(--ease-out);
}
.gl-partners__cell:hover .gl-partners__logo {
  filter: grayscale(0);
  opacity: 1;
}
@media (max-width: 1024px) {
  .gl-partners__grid { gap: 32px 32px; }
  .gl-partners__cell { width: 140px; }
}
@media (max-width: 694px) {
  .gl-partners__grid { gap: 24px 16px; }
  .gl-partners__cell { width: 120px; height: 48px; padding: 0 6px; }
}

/* Dark theme · invert near-black logos to white, keep monochrome */
:root[data-theme="dark"] .gl-partners__logo {
  filter: grayscale(100%) brightness(0) invert(1);
  opacity: 0.65;
}
:root[data-theme="dark"] .gl-partners__cell:hover .gl-partners__logo {
  filter: brightness(0) invert(1);
  opacity: 1;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gl-partners__logo {
    filter: grayscale(100%) brightness(0) invert(1);
    opacity: 0.65;
  }
  :root:not([data-theme="light"]) .gl-partners__cell:hover .gl-partners__logo {
    filter: brightness(0) invert(1);
    opacity: 1;
  }
}
@media (prefers-reduced-motion: reduce) {
  .gl-partners__logo { transition: none; }
}

/* ============================================================
 * NEW D · Press Preview (3 cards · standalone grid)
 * ============================================================ */
.gl-press-preview { /* padding via .gl-home .gl-region */ }
.gl-press-preview__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0;
  margin-top: 56px;
  border-top: 1px solid var(--ds-border-subtle);
}
.gl-press-preview__cell {
  border-bottom: 1px solid var(--ds-border-subtle);
  border-right: 1px solid var(--ds-border-subtle);
}
.gl-press-preview__cell:last-child { border-right: 0; }
.gl-press-preview__cell .gl-press-card {
  border: 0;
  height: 100%;
}
.gl-press-preview__cta { text-align: center; margin-top: 40px; }
@media (max-width: 1024px) {
  .gl-press-preview__grid { grid-template-columns: 1fr; }
  .gl-press-preview__cell { border-right: 0; }
}

/* ============================================================
 * Hover micro-interactions · page-agnostic content cards
 * ============================================================ */
.gl-proof__item {
  transition: transform 240ms var(--ease-out), background 240ms var(--ease-out);
}
.gl-proof__item:hover {
  transform: translateY(-3px);
  background: var(--ds-neutral-50);
}
.gl-home .gl-whynow li {
  transition: color 200ms var(--ease-out), padding-left 200ms var(--ease-out);
  cursor: default;
}
.gl-home .gl-whynow li:hover {
  color: var(--ds-text-brand);
}

/* Stagger reveal · proof items via parent .is-revealed marker */
.gl-home .gl-proof__item {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 600ms var(--ease-out),
              transform 600ms var(--ease-out),
              background 240ms var(--ease-out);
}
.gl-home .gl-proof.is-revealed .gl-proof__item {
  opacity: 1; transform: none;
}
@media (prefers-reduced-motion: reduce) {
  .gl-home .gl-proof__item { opacity: 1; transform: none; }
}

/* ============================================================
 * Dark mode · body content overrides for legacy scaffolds
 *
 * Flips .gl-section / .gl-region / .gl-page-hero / .gl-header / .gl-footer
 * from --gray-* primitives to --ds-* semantic tokens.
 *
 * Two parallel branches:
 *   1. :root[data-theme="dark"]      — explicit toggle (tweaks panel)
 *   2. @media (prefers-color-scheme: dark) :root:not([data-theme="light"])
 *      — OS-level preference (auto)
 * Authors can pin light with data-theme="light" to override OS dark.
 * New v17 components above use --ds-* directly so they flip automatically.
 * ============================================================ */
:root[data-theme="dark"] body,
:root[data-theme="dark"] .gl-section,
:root[data-theme="dark"] .gl-region,
:root[data-theme="dark"] .gl-page-hero {
  background: var(--ds-bg-base);
  color: var(--ds-text-primary);
}
:root[data-theme="dark"] .gl-section--subtle,
:root[data-theme="dark"] .gl-region--subtle { background: var(--ds-bg-surface); }
:root[data-theme="dark"] .gl-section--dark,
:root[data-theme="dark"] .gl-region--dark {
  background: var(--ds-neutral-900);
  color: var(--ds-text-primary);
}
:root[data-theme="dark"] .gl-section__title,
:root[data-theme="dark"] .gl-page-hero__title { color: var(--ds-text-primary); }
:root[data-theme="dark"] .gl-section__subtitle { color: var(--ds-text-secondary); }
/* Note · .gl-page-hero__sub dark-theme color is owned by sections.css
 * per-shape rules (#ffffff for every subpage). */
:root[data-theme="dark"] .gl-section__eyebrow,
:root[data-theme="dark"] .gl-page-hero__eyebrow { color: var(--ds-primary-300); }
:root[data-theme="dark"] .gl-region--bordered { border-bottom-color: var(--ds-border-subtle); }

/* Header in dark — solid header (post-hero scroll state) flips to neutral-900 */
:root[data-theme="dark"] .gl-header {
  background: rgba(0, 0, 0, 0.85);
  border-bottom-color: var(--ds-border-subtle);
}
/* Dark scrolled · glass blur · mirrors the light scrolled treatment */
:root[data-theme="dark"] .gl-header.is-scrolled {
  background: rgba(0, 0, 0, 0.55);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
          backdrop-filter: blur(20px) saturate(180%);
  border-bottom-color: rgba(255, 255, 255, 0.08);
}
:root[data-theme="dark"] .gl-header__nav-link { color: var(--ds-text-secondary); }
:root[data-theme="dark"] .gl-header__nav-link.is-active { color: var(--ds-text-primary); }
:root[data-theme="dark"] .gl-header__nav-link:hover { color: var(--ds-text-primary); }
/* Active-nav underline · light theme = --gray-500 (header.css), dark = white */
:root[data-theme="dark"] .gl-header__nav-underline { background: var(--gray-0); }
:root[data-theme="dark"] .gl-lang-toggle { background: rgba(255, 255, 255, 0.06); }
:root[data-theme="dark"] .gl-lang-btn { color: rgba(255, 255, 255, 0.7); }
:root[data-theme="dark"] .gl-lang-btn.is-active {
  background: var(--gray-0);
  color: var(--gray-900);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
}
:root[data-theme="dark"] .gl-theme-toggle { background: rgba(255, 255, 255, 0.06); }
:root[data-theme="dark"] .gl-theme-btn { color: rgba(255, 255, 255, 0.7); }
:root[data-theme="dark"] .gl-theme-btn.is-active {
  background: var(--gray-0);
  color: var(--gray-900);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
}

/* Header nav hover · darker bg for clear contrast in both light/dark */
:root[data-theme="dark"] .gl-header__nav-link:hover {
  color: var(--ds-text-primary);
  background: rgba(255, 255, 255, 0.10);
}

/* Header transparent over hero · is-on-dark / is-on-light always win, even in
 * dark theme. Order matters: this rule sits AFTER the .gl-header /
 * .gl-header.is-scrolled dark overrides above so it wins specificity-tied
 * conflicts. */
:root[data-theme="dark"] .gl-header.is-on-dark,
:root[data-theme="dark"] .gl-header.is-on-light {
  background: transparent;
  -webkit-backdrop-filter: none;
          backdrop-filter: none;
  border-bottom-color: transparent;
}

/* Section / page borders · flip --gray-200 → --ds-border-default in dark */
:root[data-theme="dark"] .gl-page-hero { border-bottom-color: var(--ds-border-default); }
:root[data-theme="dark"] .gl-region--bordered { border-bottom-color: var(--ds-border-default); }
:root[data-theme="dark"] .gl-region--trust {
  border-top-color: var(--ds-border-default);
  border-bottom-color: var(--ds-border-default);
}
:root[data-theme="dark"] .gl-footer__legal { border-top-color: var(--ds-border-default); }
:root[data-theme="dark"] .gl-modal__header { border-bottom-color: var(--ds-border-default); }
:root[data-theme="dark"] .gl-drawer__header,
:root[data-theme="dark"] .gl-drawer__footer { border-color: var(--ds-border-default); }

/* Footer copyright · ensure dark token wins over the .gl-footer__copyright
 * inline gray-400 color rule in footer.css */
:root[data-theme="dark"] .gl-footer__copyright { color: var(--ds-text-tertiary); }
:root[data-theme="dark"] .gl-header__hamburger { color: var(--ds-text-primary); }
:root[data-theme="dark"] .gl-drawer { background: var(--ds-bg-base); color: var(--ds-text-primary); }
:root[data-theme="dark"] .gl-drawer__nav-link { color: var(--ds-text-primary); border-bottom-color: var(--ds-border-subtle); }

/* Footer in dark */
:root[data-theme="dark"] .gl-footer {
  background: var(--ds-neutral-900);
  color: var(--ds-text-secondary);
  border-top-color: var(--ds-border-default);
}
:root[data-theme="dark"] .gl-footer__col-title,
:root[data-theme="dark"] .gl-footer__tagline { color: var(--ds-text-primary); }
:root[data-theme="dark"] .gl-footer__link { color: var(--ds-text-secondary); }
:root[data-theme="dark"] .gl-footer__link:hover { color: var(--ds-text-primary); }
:root[data-theme="dark"] .gl-footer__legal { color: var(--ds-text-tertiary); border-top-color: var(--ds-border-subtle); }

/* Modal in dark */
:root[data-theme="dark"] .gl-modal { background: var(--ds-bg-elevated); color: var(--ds-text-primary); }
:root[data-theme="dark"] .gl-modal__header { border-bottom-color: var(--ds-border-subtle); }
:root[data-theme="dark"] .gl-modal__title { color: var(--ds-text-primary); }
:root[data-theme="dark"] .gl-modal__close { background: var(--ds-bg-muted); color: var(--ds-text-secondary); }
:root[data-theme="dark"] .gl-modal__close:hover { background: var(--ds-bg-surface); }
/* Hover bg overrides in dark mode · light --ds-neutral-50 (#F9F8F5) is too
 * bright on dark page; substitute with the semantic --ds-bg-muted token. */
:root[data-theme="dark"] .gl-press-card:hover,
:root[data-theme="dark"] .gl-proof__item:hover { background: var(--ds-bg-muted); }
:root[data-theme="dark"] .gl-about-story__proof .gl-proof__item:hover { background: transparent; }

/* OS-level preference fallback · same rules under prefers-color-scheme: dark */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) body,
  :root:not([data-theme="light"]) .gl-section,
  :root:not([data-theme="light"]) .gl-region,
  :root:not([data-theme="light"]) .gl-page-hero {
    background: var(--ds-bg-base);
    color: var(--ds-text-primary);
  }
  :root:not([data-theme="light"]) .gl-section--subtle,
  :root:not([data-theme="light"]) .gl-region--subtle { background: var(--ds-bg-surface); }
  :root:not([data-theme="light"]) .gl-section--dark,
  :root:not([data-theme="light"]) .gl-region--dark {
    background: var(--ds-neutral-900);
    color: var(--ds-text-primary);
  }
  :root:not([data-theme="light"]) .gl-section__title,
  :root:not([data-theme="light"]) .gl-page-hero__title { color: var(--ds-text-primary); }
  :root:not([data-theme="light"]) .gl-section__subtitle { color: var(--ds-text-secondary); }
  /* .gl-page-hero__sub owned by sections.css per-shape rules */
  :root:not([data-theme="light"]) .gl-section__eyebrow,
  :root:not([data-theme="light"]) .gl-page-hero__eyebrow { color: var(--ds-primary-300); }
  :root:not([data-theme="light"]) .gl-region--bordered { border-bottom-color: var(--ds-border-subtle); }
  :root:not([data-theme="light"]) .gl-header {
    background: rgba(0, 0, 0, 0.85);
    border-bottom-color: var(--ds-border-subtle);
  }
  :root:not([data-theme="light"]) .gl-header.is-scrolled {
    background: rgba(0, 0, 0, 0.55);
    -webkit-backdrop-filter: blur(20px) saturate(180%);
            backdrop-filter: blur(20px) saturate(180%);
    border-bottom-color: rgba(255, 255, 255, 0.08);
  }
  :root:not([data-theme="light"]) .gl-header__nav-link { color: var(--ds-text-secondary); }
  :root:not([data-theme="light"]) .gl-header__nav-link.is-active,
  :root:not([data-theme="light"]) .gl-header__nav-link:hover { color: var(--ds-text-primary); }
  :root:not([data-theme="light"]) .gl-header__nav-underline { background: var(--gray-0); }
  :root:not([data-theme="light"]) .gl-lang-btn { color: rgba(255, 255, 255, 0.7); }
  :root:not([data-theme="light"]) .gl-lang-btn.is-active { background: var(--gray-0); color: var(--gray-900); }
  :root:not([data-theme="light"]) .gl-theme-toggle { background: rgba(255, 255, 255, 0.06); }
  :root:not([data-theme="light"]) .gl-theme-btn { color: rgba(255, 255, 255, 0.7); }
  :root:not([data-theme="light"]) .gl-theme-btn.is-active { background: var(--gray-0); color: var(--gray-900); }
  :root:not([data-theme="light"]) .gl-header__hamburger { color: var(--ds-text-primary); }
  :root:not([data-theme="light"]) .gl-drawer { background: var(--ds-bg-base); color: var(--ds-text-primary); }
  :root:not([data-theme="light"]) .gl-drawer__nav-link { color: var(--ds-text-primary); border-bottom-color: var(--ds-border-subtle); }
  :root:not([data-theme="light"]) .gl-footer {
    background: var(--ds-neutral-900);
    color: var(--ds-text-secondary);
    border-top-color: var(--ds-border-default);
  }
  :root:not([data-theme="light"]) .gl-footer__col-title,
  :root:not([data-theme="light"]) .gl-footer__tagline { color: var(--ds-text-primary); }
  :root:not([data-theme="light"]) .gl-footer__link { color: var(--ds-text-secondary); }
  :root:not([data-theme="light"]) .gl-footer__link:hover { color: var(--ds-text-primary); }
  :root:not([data-theme="light"]) .gl-footer__legal { color: var(--ds-text-tertiary); border-top-color: var(--ds-border-subtle); }
  :root:not([data-theme="light"]) .gl-modal { background: var(--ds-bg-elevated); color: var(--ds-text-primary); }
  :root:not([data-theme="light"]) .gl-modal__header { border-bottom-color: var(--ds-border-subtle); }
  :root:not([data-theme="light"]) .gl-modal__title { color: var(--ds-text-primary); }
  :root:not([data-theme="light"]) .gl-modal__close { background: var(--ds-bg-muted); color: var(--ds-text-secondary); }
  :root:not([data-theme="light"]) .gl-modal__close:hover { background: var(--ds-bg-surface); }
  :root:not([data-theme="light"]) .gl-press-card:hover,
  :root:not([data-theme="light"]) .gl-proof__item:hover { background: var(--ds-bg-muted); }
  :root:not([data-theme="light"]) .gl-about-story__proof .gl-proof__item:hover { background: transparent; }

  /* Lang + theme toggle in OS-dark · same as explicit data-theme="dark" */
  :root:not([data-theme="light"]) .gl-lang-toggle { background: rgba(255, 255, 255, 0.06); }
  :root:not([data-theme="light"]) .gl-lang-btn.is-active {
    background: var(--gray-0);
    color: var(--gray-900);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
  }
  :root:not([data-theme="light"]) .gl-theme-toggle { background: rgba(255, 255, 255, 0.06); }
  :root:not([data-theme="light"]) .gl-theme-btn.is-active {
    background: var(--gray-0);
    color: var(--gray-900);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
  }

  /* Header nav hover · darker contrast */
  :root:not([data-theme="light"]) .gl-header__nav-link:hover {
    color: var(--ds-text-primary);
    background: rgba(255, 255, 255, 0.10);
  }

  /* is-on-dark always transparent in OS dark too */
  :root:not([data-theme="light"]) .gl-header.is-on-dark {
    background: transparent;
    -webkit-backdrop-filter: none;
            backdrop-filter: none;
    border-bottom-color: transparent;
  }

  /* Section / page borders · gray-200 → --ds-border-default */
  :root:not([data-theme="light"]) .gl-page-hero { border-bottom-color: var(--ds-border-default); }
  :root:not([data-theme="light"]) .gl-region--bordered { border-bottom-color: var(--ds-border-default); }
  :root:not([data-theme="light"]) .gl-region--trust {
    border-top-color: var(--ds-border-default);
    border-bottom-color: var(--ds-border-default);
  }
  :root:not([data-theme="light"]) .gl-footer__legal { border-top-color: var(--ds-border-default); }
  :root:not([data-theme="light"]) .gl-drawer__header,
  :root:not([data-theme="light"]) .gl-drawer__footer { border-color: var(--ds-border-default); }

  /* Footer copyright */
  :root:not([data-theme="light"]) .gl-footer__copyright { color: var(--ds-text-tertiary); }
}

/* ============================================================
 * English typography · serif system
 * ------------------------------------------------------------
 * Active only when <html lang="en"> (synced from app.jsx lang state).
 * Korean (lang="ko") keeps the default Pretendard sans system.
 *
 * - Display headlines → Playfair Display (editorial display serif)
 * - Body & prose      → Source Serif 4 (humanist body serif, screen-read)
 * - UI elements       → kept on the sans stack for affordance clarity
 *   (buttons, nav, footer legal, metrics, eyebrows, small labels)
 *
 * To switch the body serif later, edit only --font-serif-body in tokens.css.
 * To switch display serif, edit --font-serif-display.
 * ============================================================ */

/* Body baseline · whole page reads in serif body font under EN. */
:root[lang="en"] body {
  font-family: var(--font-serif-body);
}

/* Display headings · the largest, most editorial moments. */
:root[lang="en"] .gl-hero-dark__title,
:root[lang="en"] .gl-page-hero__title,
:root[lang="en"] .gl-section__title,
:root[lang="en"] .gl-prose__title,
:root[lang="en"] .gl-closing__title,
:root[lang="en"] .gl-ipcard__title,
:root[lang="en"] .gl-product__name,
:root[lang="en"] .gl-product__title {
  font-family: var(--font-serif-display);
}

/* UI exceptions · keep sans for clarity on functional/dense elements.
 * NYT, Anthropic, etc. pair editorial serif body with a sans UI layer.
 * Buttons, nav, lang toggle, footer chrome, small metrics, eyebrows. */
:root[lang="en"] .gl-btn,
:root[lang="en"] .gl-header__nav-link,
:root[lang="en"] .gl-lang-toggle,
:root[lang="en"] .gl-lang-btn,
:root[lang="en"] .gl-drawer__lang-toggle,
:root[lang="en"] .gl-drawer__lang-btn,
:root[lang="en"] .gl-footer__legal,
:root[lang="en"] .gl-footer__col-title,
:root[lang="en"] .gl-footer__link,
:root[lang="en"] .gl-footer__copyright,
:root[lang="en"] .gl-footer__tagline,
:root[lang="en"] .gl-page-hero__eyebrow,
:root[lang="en"] .gl-section__eyebrow,
:root[lang="en"] .gl-proof-row__metric,
:root[lang="en"] .gl-proof-row__label,
:root[lang="en"] .gl-flow-map__group-tag,
:root[lang="en"] .gl-flow-map__node-name,
:root[lang="en"] .gl-flow-map__node-desc,
:root[lang="en"] .gl-flow-map__node-tip,
:root[lang="en"] .gl-flow-map__label,
:root[lang="en"] .gl-product__tag,
:root[lang="en"] .gl-product__status,
:root[lang="en"] .gl-product__meta-list,
:root[lang="en"] .gl-business-tabbar,
:root[lang="en"] .gl-press-card__date,
:root[lang="en"] .gl-press-card__outlet,
:root[lang="en"] .gl-press-card__arrow,
:root[lang="en"] .gl-link-preview__host,
:root[lang="en"] .gl-tweaks {
  font-family: var(--font-sans);
}
