:root{
  --bg:#000;
  --acc:#ffeb6b;                       /* Figma yellow accent */
  --pane-company:#1e2036; --pane-market:#1d1d25;
  --pane-road:#1f2031;    --pane-careers:#121216;
  --panel-jp:#30313d;     --panel-sg:#2b2c3b;
  --rule:#434343;
  --fg:#fff; --dim:#c0c0c0; --mute:#888; --faint:#555;
  /* Body weight and colour (2026-08-31 Jin) — Spoqa Light rendered far too thin, so body text
     moved up to Regular(400) and description text came down from #C0C0C0 to #999999.
     Figma only carries this on the PC frame, but Mobile uses the same values (confirmed by Jin). */
  --body-w:400; --body-c:#999999;
  --line:rgba(255,255,255,.14); --line-soft:rgba(255,255,255,.07);
  --blue:#293378; --blue-lift:#3a47a0; --blue-soft:#7f8ce0;
  /* Figma PC 1920: content 1204 + 358 margin each side.
     .wrap carries 28px padding on each side, so max-width lands at 1204+56=1260. */
  --wrap:1260px;
  /* CJK leading adjustment (2026-08-31 Jin) — Japanese and Chinese have dense strokes and feel
     cramped at the same leading. Every line-height is written as calc(value + var(--lh-a)) so
     only this one token changes per language.
     Korean and English are 0, so the comp values do not move by a single pixel. */
  --lh-a:0px;
  --lang:"Spoqa Han Sans Neo";                      /* Korean, the default */
  --serif:"IBM Plex Serif",var(--lang),Georgia,"Times New Roman",serif;
  --ui:"Inter",var(--lang),system-ui,-apple-system,sans-serif;
}
html[data-lang="ja"]{--lang:"BIZ UDPGothic"}
html[data-lang="ja"],html[data-lang="zh"]{--lh-a:4px}
html[data-lang="zh"]{--lang:"alibaba-puhuiti","PingFang SC","Microsoft YaHei"}
html[data-lang="en"]{--lang:"Inter"}

@font-face{font-family:"Spoqa Han Sans Neo";font-style:normal;font-weight:300;font-display:swap;
  src:url(https://s3.ap-northeast-1.amazonaws.com/core-files.liberti.co.jp/common/fonts/SpoqaHanSansNeo-Light.woff2) format("woff2")}
@font-face{font-family:"Spoqa Han Sans Neo";font-style:normal;font-weight:400;font-display:swap;
  src:url(https://s3.ap-northeast-1.amazonaws.com/core-files.liberti.co.jp/common/fonts/SpoqaHanSansNeo-Regular.woff2) format("woff2")}
@font-face{font-family:"Spoqa Han Sans Neo";font-style:normal;font-weight:500;font-display:swap;
  src:url(https://s3.ap-northeast-1.amazonaws.com/core-files.liberti.co.jp/common/fonts/SpoqaHanSansNeo-Medium.woff2) format("woff2")}
@font-face{font-family:"Spoqa Han Sans Neo";font-style:normal;font-weight:700;font-display:swap;
  src:url(https://s3.ap-northeast-1.amazonaws.com/core-files.liberti.co.jp/common/fonts/SpoqaHanSansNeo-Bold.woff2) format("woff2")}

*{margin:0;padding:0;box-sizing:border-box;-webkit-text-size-adjust:none}
html{scroll-behavior:smooth}
body{
  background:var(--bg);color:var(--fg);
  min-width:320px;
  font-family:var(--ui);
  font-size:15px;line-height:calc(1.75em + var(--lh-a));font-weight:300;word-break:keep-all;-webkit-font-smoothing:antialiased;
  display:flow-root;   /* keep the hero margin-top from escaping the body */
}
html[data-lang="ja"] body{word-break:normal;line-break:strict}
html[data-lang="zh"] body{word-break:normal}
html[data-lang="en"] body{word-break:normal}
html[data-lang="en"] .pin-now{--pin-up:9px}
html[data-lang="ja"] .pin-now{--pin-up:11px}
ul,ol{list-style:none} a{color:inherit;text-decoration:none}
em,i,cite,address{font-style:normal}
img,svg,video{display:block;max-width:100%}
button{font:inherit;color:inherit;background:none;border:none;cursor:pointer}
.wrap{width:100%;max-width:var(--wrap);margin:0 auto;padding:0 28px;position:relative}
/* stop a long unbreakable string from blowing out an fr grid (defeats the min-width:auto default) */
.why>*,.why-cols>*,.why-col>*,.mkt>*,.values>*,.rm-i,.job-grid>*,.jd-body>*,.sec-head>*{min-width:0}

.reveal{opacity:0;transform:translateY(20px);transition:opacity .8s cubic-bezier(.2,.7,.3,1),transform .8s cubic-bezier(.2,.7,.3,1)}
.reveal.in{opacity:1;transform:none}

/* ============================================================
   Section entrance sequence (2026-09-01 Jin)
   When a section enters the viewport its parts fade in one at a time: title -> sub -> body.
   .reveal observes each element separately and fires them independently, so it cannot express
   an order — hence this separate mechanism.
   - Mark a section `data-seq` and site.js adds `.is-seq` when it enters the viewport
   - Mark individual elements `.seq` and give them a duration (--seq-dur) and start (--seq-delay)
   - They fade in while rising --seq-rise from below (Jin 2026-09-01: a fade in place looks flat)
   ============================================================ */
/* ⚠️ A component with its own transition (.job background, .filters button color, and so on)
   overwrites .seq's transition wholesale and kills the fade — same specificity, later wins.
   So the sequence transition lives in --seq-tr, and those components append var(--seq-tr) to
   the end of their own transition list. */
:root{--seq-tr:opacity var(--seq-dur,500ms) ease-out,
                transform var(--seq-dur,500ms) var(--seq-ease,cubic-bezier(.2,.7,.3,1))}
.seq{opacity:0;transform:translateY(var(--seq-rise,100px));transition:var(--seq-tr)}
/* Final opacity is --seq-op (default 1). Elements designed to be semi-transparent set it here —
   writing opacity directly on the element outranks .seq (a single class) and kills the fade. */
.is-seq .seq{opacity:var(--seq-op,1);transform:none;transition-delay:var(--seq-delay,0ms)}
/* No JS, or reduced-motion preference: just show everything */
.no-seq .seq{opacity:var(--seq-op,1);transform:none;transition:none}
@media (prefers-reduced-motion:reduce){
  .seq{opacity:var(--seq-op,1);transform:none;transition:none}
}

/* --- Company timeline -------------------------------------------------
   Change only the durations and everything downstream shifts on its own (delays are chained
   with calc). --seq-gap is extra spacing between items; at 0 the next one starts the instant
   the previous finishes. Same on desktop and mobile.                     */
#about{
  --t-title:500ms;   /* title */
  --t-sub:200ms;     /* sub text under the title */
  --t-lead:700ms;    /* lead copy (English and Korean together) */
  --t-value:500ms;   /* value 01 / 02 */
  --seq-gap:0ms;
  --pause-title:200ms; /* one beat of rest after the title group finishes (Jin 2026-09-01) */
  --seq-rise:100px;  /* rise distance */
  --d-sub:calc(var(--t-title) + var(--seq-gap));
  --d-lead:calc(var(--d-sub) + var(--t-sub) + var(--pause-title));
  --d-v1:calc(var(--d-lead) + var(--t-lead) + var(--seq-gap));
  --d-v2:calc(var(--d-v1) + var(--t-value) + var(--seq-gap));
}
#about .sec-title{--seq-dur:var(--t-title);--seq-delay:0ms}
#about .sec-sub  {--seq-dur:var(--t-sub);  --seq-delay:var(--d-sub)}
#about .mission,
#about .mission-sub{--seq-dur:var(--t-lead);--seq-delay:var(--d-lead)}
/* value 01/02 fade in place (Jin 2026-09-01) — rising with their rules attached makes the table look shaky */
#about .value{--seq-rise:0px}
#about .value:nth-child(1){--seq-dur:var(--t-value);--seq-delay:var(--d-v1)}
#about .value:nth-child(2){--seq-dur:var(--t-value);--seq-delay:var(--d-v2)}

/* --- Market timeline -------------------------------------------------
   title -> (rest) -> lead copy -> sub copy (a beat later, just --tap behind)
   -> evidence 01/02/03 fade in place, and the chart springs up from below alongside evidence 01.
   Same on desktop and mobile.                                            */
#market{
  --t-title:500ms;   /* title */
  --t-lead:500ms;    /* lead copy */
  --t-sub:500ms;     /* sub copy under the lead */
  --t-item:500ms;    /* evidence 01 / 02 / 03 */
  --t-chart:1800ms;  /* chart — longer and slower than the other items (Jin 2026-09-01) */
  --d-chart:1200ms;  /* chart start — enters one step ahead of the evidence list */
  --pause-title:200ms;
  --pause-list:200ms; /* gap from the end of the lead group to the evidence list */
  --tap:150ms;       /* the quick beat between lead and sub */
  --seq-rise:100px;
  --d-lead:calc(var(--t-title) + var(--pause-title));
  --d-sub:calc(var(--d-lead) + var(--tap));
  /* the evidence list starts one beat after the lead group finishes */
  --d-i1:calc(var(--d-sub) + var(--t-sub) + var(--pause-list));
  --d-i2:calc(var(--d-i1) + var(--t-item));
  --d-i3:calc(var(--d-i2) + var(--t-item));
  /* Once evidence 03 is up, blink the yellow label to draw the eye.
     One blink (480) + rest (120), twice = 1200ms. The ratios live in the keyframes, so changing
     the total length stretches blink and rest together in proportion. */
  --blink-total:1200ms;
  --d-blink:calc(var(--d-i3) + var(--t-item));
}
#market .sec-title{--seq-dur:var(--t-title);--seq-delay:0ms}
#market .mkt-h    {--seq-dur:var(--t-lead); --seq-delay:var(--d-lead)}
#market .mkt-lead {--seq-dur:var(--t-sub);  --seq-delay:var(--d-sub)}
/* evidence list : rising with its rules attached makes the table look shaky, so fade in place */
#market .mkt-list li{--seq-rise:0px;--seq-dur:var(--t-item)}
#market .mkt-list li:nth-child(1){--seq-delay:var(--d-i1)}
#market .mkt-list li:nth-child(2){--seq-delay:var(--d-i2)}
#market .mkt-list li:nth-child(3){--seq-delay:var(--d-i3)}
/* chart : enters before evidence 01 (1200) and rises slowly in place (1800) (Jin 2026-09-01) */
#market .mkt-viz{--seq-dur:var(--t-chart);--seq-delay:var(--d-chart);--seq-rise:0px}

/* --- Roadmap timeline -------------------------------------------------
   title -> sub -> (rest) -> stages 01-04 fading in place, 100 apart
   -> card heading and sub copy (same rhythm as the title area) -> country cards 01/02.
   Each stage owns its own top and bottom rule, so the rules fade in with the item.
   Same on desktop and mobile.                                            */
#roadmap{
  --t-title:500ms;   /* title */
  --t-sub:200ms;     /* sub text under the title */
  --t-step:400ms;    /* stages 01-04 */
  --t-head:500ms;    /* card heading */
  --t-headsub:200ms; /* card sub copy */
  --t-card:750ms;    /* country card 01 / 02 (desktop) */
  --pause-title:200ms; /* gap after the title group */
  --pause-cards:0ms;   /* gap from stages to card heading (desktop) */
  --gap-step:50ms;   /* gap between stages (desktop) */
  --gap-card:100ms;  /* gap between cards — mobile only */
  --seq-rise:100px;
  --d-sub:var(--t-title);
  --d-s1:calc(var(--d-sub) + var(--t-sub) + var(--pause-title));
  --d-s2:calc(var(--d-s1) + var(--t-step) + var(--gap-step));
  --d-s3:calc(var(--d-s2) + var(--t-step) + var(--gap-step));
  --d-s4:calc(var(--d-s3) + var(--t-step) + var(--gap-step));
  --d-head:calc(var(--d-s4) + var(--t-step) + var(--pause-cards));
  --d-headsub:calc(var(--d-head) + var(--t-head));
  --d-c1:calc(var(--d-headsub) + var(--t-headsub));
  /* desktop : card 02 overlaps in when card 01 is about halfway (Jin 2026-09-01) */
  --d-c2:calc(var(--d-c1) + var(--t-card) / 2);
}
#roadmap .sec-title{--seq-dur:var(--t-title);--seq-delay:0ms}
#roadmap .sec-sub  {--seq-dur:var(--t-sub);  --seq-delay:var(--d-sub)}
/* stages : rising with the rules attached makes the table look shaky, so fade in place */
#roadmap .rm-i{--seq-rise:0px;--seq-dur:var(--t-step)}
#roadmap .rm-i:nth-child(1){--seq-delay:var(--d-s1)}
#roadmap .rm-i:nth-child(2){--seq-delay:var(--d-s2)}
#roadmap .rm-i:nth-child(3){--seq-delay:var(--d-s3)}
#roadmap .rm-i:nth-child(4){--seq-delay:var(--d-s4)}
/* card heading and sub copy : same rhythm as the title area (rising) */
#roadmap .why-head h4{--seq-dur:var(--t-head);   --seq-delay:var(--d-head)}
#roadmap .why-head p {--seq-dur:var(--t-headsub);--seq-delay:var(--d-headsub)}
/* country cards : fade in place */
#roadmap .why-col{--seq-rise:0px;--seq-dur:var(--t-card)}
#roadmap .why-col:nth-child(1){--seq-delay:var(--d-c1)}
#roadmap .why-col:nth-child(2){--seq-delay:var(--d-c2)}

/* Mobile and tablet : everything stacks vertically, so the rhythm has to differ (Jin 2026-09-01)
   - keep 100 between stages (on desktop the four sit side by side, where 50 is right)
   - rest 400 between stage 04 and the card heading (you scroll across that gap)
   - cards come one at a time rather than overlapping (--gap-card apart) */
@media (max-width:1024px){
  #roadmap{
    --gap-step:100ms;
    --t-card:500ms;
    --d-c2:calc(var(--d-c1) + var(--t-card) + var(--gap-card));
  }

  /* The card group starts when its own position enters the viewport, not when the section does.
     The mobile roadmap runs 1894px tall, so counting from the top of the section would play the
     cards out entirely offscreen. site.js observes the data-seq on .why separately.
     The two rules below must outrank the section-level rule (.is-seq .seq) — hence the #roadmap. */
  #roadmap .why .seq{opacity:0;transform:translateY(var(--seq-rise,100px))}
  #roadmap .why.is-seq .seq{opacity:var(--seq-op,1);transform:none;
                            transition-delay:var(--seq-delay,0ms)}
  /* restart the count from 0 inside the card group */
  #roadmap .why-head h4{--seq-delay:0ms}
  #roadmap .why-head p {--seq-delay:var(--t-head)}
  #roadmap .why-col:nth-child(1){--seq-delay:calc(var(--t-head) + var(--t-headsub))}
  #roadmap .why-col:nth-child(2){--seq-delay:calc(var(--t-head) + var(--t-headsub)
                                                 + var(--t-card) + var(--gap-card))}
}

/* --- Careers timeline -------------------------------------------------
   title -> 5 filter tabs -> (rest) -> 6 job rows -> (rest) -> open application banner.
   --gap-* for tabs and rows measures from when the PREVIOUS item started, which gives the
   rat-a-tat feel. To space them from when the previous item finished, add its duration:
   calc(var(--t-tab) + 50ms). Same on desktop and mobile.                 */
#careers{
  --t-title:500ms;   /* title */
  --t-tab:700ms;     /* filter tabs — all five as one group (Jin 2026-09-01) */
  --t-item:300ms;    /* job rows */
  --gap-item:50ms;   /* between rows — the gap after the previous row has fully arrived (Jin 2026-09-01) */
  --step-item:calc(var(--t-item) + var(--gap-item));
  --t-cta:500ms;     /* open application banner */
  --pause-list:300ms;/* after the tabs are up -> the list */
  --pause-cta:300ms; /* after the list is up -> the banner */
  --seq-rise:100px;
  --d-tab:var(--t-title);
  --tab-end:calc(var(--d-tab) + var(--t-tab));
  --d-list:calc(var(--tab-end) + var(--pause-list));
  --list-end:calc(var(--d-list) + var(--step-item) * 5 + var(--t-item));
  --d-cta:calc(var(--list-end) + var(--pause-cta));
}
#careers .sec-title{--seq-dur:var(--t-title);--seq-delay:0ms}
/* filter tabs : all five as one group, rising from below */
#careers .filters{--seq-dur:var(--t-tab);--seq-delay:var(--d-tab)}
/* job rows : fade in place; each row owns its top and bottom rule, so they arrive together */
#careers .job-grid .job{--seq-rise:0px;--seq-dur:var(--t-item)}
#careers .job-grid .job:nth-child(1){--seq-delay:var(--d-list)}
#careers .job-grid .job:nth-child(2){--seq-delay:calc(var(--d-list) + var(--step-item))}
#careers .job-grid .job:nth-child(3){--seq-delay:calc(var(--d-list) + var(--step-item) * 2)}
#careers .job-grid .job:nth-child(4){--seq-delay:calc(var(--d-list) + var(--step-item) * 3)}
#careers .job-grid .job:nth-child(5){--seq-delay:calc(var(--d-list) + var(--step-item) * 4)}
#careers .job-grid .job:nth-child(6){--seq-delay:calc(var(--d-list) + var(--step-item) * 5)}
/* open application banner : rising from below */
#careers .cta{--seq-dur:var(--t-cta);--seq-delay:var(--d-cta)}

/* Yellow label emphasis ($1-8B + description) : blinks three times once the evidence list is up.
   transform is already carrying the positioning, so leave it alone and animate opacity only. */
@keyframes pin-blink{
  0%{opacity:1}  20%{opacity:0}  40%{opacity:1}   /* blink 1 */
  50%{opacity:1}                                  /* rest */
  70%{opacity:0} 90%{opacity:1}  100%{opacity:1}  /* blink 2 + rest */
}
#market.is-seq .pin-now{
  animation:pin-blink var(--blink-total) ease-in-out var(--d-blink) 1;
}
@media (prefers-reduced-motion:reduce){
  #market.is-seq .pin-now{animation:none}
}
.is-empty,.is-off{display:none !important}
/* Two line-break switches —
   .br-m : one line on desktop, broken only on mobile
   .br-p : forces the comp's break on desktop only; once cards fold to a single column it is
           dropped so the text flows naturally */
.br-m{display:none}
.br-p{display:inline}


/* ===== header ===== */
.header{position:fixed;inset:0 0 auto;z-index:120;background:#000}
/* The Figma header (102px) is not centred — logo y33 / nav y44 / language y42.
   To keep the comp coordinates exactly, use flex-start plus a per-element margin-top. */
.header .wrap{display:flex;align-items:flex-start;height:102px}
.logo{display:block;width:96px;margin-top:33px}
.gnb{display:flex;gap:70px;margin-left:81px;margin-top:44px;font-family:var(--ui)}
.gnb a{display:inline-block;font-size:15px;line-height:calc(18px + var(--lh-a));color:#e0e0e0;transition:color .25s}
/* Reserve each item's width at its bold measurement so neighbouring menu items do not shift
   when one turns bold. height:0 keeps it out of the vertical flow. */
.gnb a::after{content:attr(data-t);display:block;height:0;overflow:hidden;
  font-weight:700;visibility:hidden;pointer-events:none}
.gnb a:hover{color:#fff;font-weight:700}
/* Inside a section, only the current menu stays bold and the rest dim.
   Figma `section-header current menu` 5617:224 — active Inter Bold #e0e0e0 / inactive Regular #777 */
.gnb.marking a{color:#777}
.gnb.marking a:hover{color:#e0e0e0;font-weight:700}
.gnb.marking a.active{color:#e0e0e0;font-weight:700}
.lang{position:relative;margin-left:auto;margin-top:42px}
.lang>button{display:flex;align-items:center;gap:12px;font-size:13px;line-height:calc(16px + var(--lh-a));
  color:#fff;padding:0;transition:color .25s;font-weight:400}
.lang>button:hover{color:var(--acc)}
.lang>button::after{content:"";width:12px;height:8px;flex:0 0 auto;background:currentColor;
  /* images/icon-caret-down.svg, transplanted verbatim.
     Opened over file://, the browser treats an external SVG in a mask as a different origin and
     blocks it, so the caret disappears. */
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M10 2L6 6L2 2' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat center/12px 8px;
          mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M10 2L6 6L2 2' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat center/12px 8px}
/* Language popup : Figma `Select Open sample` 5617:263 — 108x148, items 24 + gap 6, 17 padding
   top and bottom. Opens centred horizontally on the select. */
.lang ul{position:absolute;left:50%;transform:translateX(-50%);top:calc(100% + 14px);
  width:108px;background:#222;border:1px solid #333;border-radius:6px;
  box-shadow:0 2px 6px rgba(0,0,0,.1);overflow:hidden;
  padding:17px 0;display:none;flex-direction:column;gap:6px;z-index:5}
.lang.open ul{display:flex}
.lang li a{display:block;height:24px;padding-top:3px;font-size:13px;line-height:calc(18px + var(--lh-a));font-weight:400;
  color:#aaa;text-align:center;transition:background .2s,color .2s}
.lang li a:hover{background:#000;color:#f4f4f4}
.lang li a.on{color:#f4f4f4;font-weight:500}

/* ===== hero : video =====
   Default (1024 and below) — size the video to the viewport width and sit it right under the
   header. 1025 and up is overridden to full screen (100vh) in the responsive block at the
   bottom of this file. */
.hero{position:relative;margin-top:102px;width:100%;aspect-ratio:16/9;overflow:hidden;background:#000}
.hero video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.hero .veil{position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(180deg,rgba(0,0,0,.30) 0%,rgba(0,0,0,0) 22%,rgba(0,0,0,0) 62%,rgba(0,0,0,.58) 100%)}
/* In embedded mode (control bar visible) drop the bottom gradient — there is no sub copy or
   scroll cue to protect, so it only muddies the control bar.
   site.js sets data-hero according to whether fullscreen mode is active. */
html[data-hero="inline"] .hero .veil{display:none}
/* Figma PC: sub copy bottom 1052 -> cue top 1068 (gap 16), cue bottom 1112 -> hero bottom 1182 (70).
   ⚠ Percentage padding resolves against the containing block's WIDTH, so 6.5% became 124.8px at
   1920. Pin it in px. */
/* Hidden by default — when the hero is shorter than the viewport the next section is already
   visible, so the scroll cue has nothing to do, and the sub copy collides with the centred text
   inside the video. Turned on only in fullscreen mode (responsive block at the bottom). */
.hero-bar{position:absolute;left:0;right:0;bottom:0;z-index:3;
  display:none;flex-direction:column;align-items:center;gap:16px;padding-bottom:70px}
.kicker{font-family:var(--ui);font-size:18px;line-height:calc(26px + var(--lh-a));font-weight:400;color:#ddd;opacity:.7;text-align:center;
  text-shadow:0 2px 24px rgba(0,0,0,.6)}

/* Scroll cue : images/hero-scroll-cue.svg verbatim (44x44)
   dashed ring r21.5 / opacity .3 / dash 2 2  +  solid ring r13.5  +  arrow below.
   Motion — one bounce (plus a small echo), rest about 2s, repeat. The solid ring trails the
   arrow slightly. */
.cue{display:block;width:44px;height:44px;color:#fff;
  animation:cueBounce 2.4s linear infinite}
.cue svg{width:44px;height:44px}
.cue-dash{transition:stroke-opacity .3s}
.cue:hover{animation-play-state:paused}
.cue:hover .cue-dash{stroke-opacity:.6}
/* Ring and arrow bounce together twice at the same amplitude, pause briefly, then twice more
   (Jin 2026-08-31). Of the 2.4s total: 0.82s bouncing + 1.58s still.
   ⚠ Keep the animation's timing-function linear and put the easing inside the keyframes —
     easing the whole thing squashes the two bounces at different speeds. */
@keyframes cueBounce{
  /* first */
  0%  {transform:translateY(0);   animation-timing-function:cubic-bezier(.33,0,.67,1)}
  8%  {transform:translateY(5px); animation-timing-function:cubic-bezier(.33,0,.67,1)}
  17% {transform:translateY(0);   animation-timing-function:cubic-bezier(.33,0,.67,1)}
  /* second */
  25% {transform:translateY(5px); animation-timing-function:cubic-bezier(.33,0,.67,1)}
  34% {transform:translateY(0)}
  /* brief pause */
  100%{transform:translateY(0)}
}
@media (prefers-reduced-motion:reduce){ .cue{animation:none} }

/* ===== statement : Singapore background band ===== */
.statement{height:420px;background:#0b1020 url(images/bg-singapore.png) center/cover no-repeat;
  display:flex;align-items:flex-start;overflow:hidden}
.statement .wrap{padding-top:101px}
.statement h2{font-family:var(--serif);font-weight:300;font-size:40px;line-height:calc(48px + var(--lh-a));
  text-shadow:0 1px 8px rgba(0,0,0,.3)}

/* ===== section shell ===== */
.pane{padding:250px 0 220px}
/* Figma draws every section at a fixed height. Guarantee that height with min-height, but let
   the section grow naturally when a language makes the body text longer. */
.pane-company{background:var(--pane-company);min-height:1080px}
.pane-market{background:var(--pane-market);min-height:1080px}
.pane-road{background:var(--pane-road);min-height:1477px;padding-bottom:189px}
/* ⛔ Careers alone gets no min-height (Jin 2026-09-01).
   Filtering rows out left the comp height (1321) standing and opened a large empty gap below.
   Jin's call: this page is scrolled through continuously, so the footer moving up is fine.
   -> Content decides the height; only the padding is held. The other three sections keep theirs. */
.pane-careers{background:var(--pane-careers);padding-bottom:100px}
.sec-title{font-family:var(--serif);font-weight:300;font-size:60px;line-height:calc(70px + var(--lh-a));letter-spacing:-1.2px}
.sec-sub{margin-top:16px;font-size:14px;line-height:calc(22px + var(--lh-a));color:#fff;font-weight:400}
.label{font-size:11px;letter-spacing:.24em;text-transform:uppercase;color:var(--acc);margin-bottom:26px}

/* ===== 01 company ===== */
.sec-split{display:grid;grid-template-columns:minmax(0,408fr) minmax(0,796fr);align-items:start}
.sec-body{padding-top:86px}
.mission{font-family:var(--serif);font-weight:300;font-size:30px;line-height:calc(38px + var(--lh-a))}
.mission em{color:var(--acc)}
.mission-sub{margin-top:12px;font-size:20px;line-height:calc(28px + var(--lh-a));color:var(--body-c);font-weight:var(--body-w)}
.values{margin-top:80px}
/* The top rule belongs to the first item, not the ul — it has to fade in together with that item.
   The coordinates are unchanged (the ul's border-top position = the first li's border-top). */
.value{display:flex;align-items:center;gap:20px;padding:50px 0;border-bottom:1px solid var(--rule)}
.value:first-child{border-top:1px solid var(--rule)}
.value h4{flex:0 0 260px;font-family:var(--serif);font-weight:300;font-size:30px;line-height:calc(38px + var(--lh-a))}
.value p{flex:1 1 0;min-width:0;font-size:20px;line-height:calc(28px + var(--lh-a));color:var(--body-c);font-weight:var(--body-w)}

/* ===== 02 market ===== */
/* comp: 37 below the title */
.mkt{margin-top:37px;display:grid;column-gap:69px;
  grid-template-columns:minmax(0,694fr) minmax(0,440fr);
  grid-template-areas:"head viz" "list viz";align-items:start}
.mkt-head{grid-area:head}
.mkt-list{grid-area:list;margin-top:80px}
.mkt-viz{grid-area:viz}
.mkt-h{font-size:28px;line-height:calc(38px + var(--lh-a));font-weight:500}
.mkt-h em{color:var(--acc)}
.mkt-lead{margin-top:8px;font-size:14px;line-height:calc(22px + var(--lh-a));color:var(--dim);font-weight:var(--body-w)}
/* The top rule belongs to the first item, not the ul — it has to fade in together with that item */
.mkt-list li:first-child{border-top:1px solid var(--rule)}
.mkt-list li{padding:30px 0;border-bottom:1px solid var(--rule);font-size:18px;line-height:calc(26px + var(--lh-a));color:var(--body-c);font-weight:var(--body-w)}
/* comp: white up to the emphasis, grey for the sentence after it. m2 has an intro before the bold too, so .lead paints that white */
.mkt-list b{color:#fff;font-weight:500}
.mkt-list .lead{color:#fff}

/* concentric rings : the SVG scales proportionally, the labels ride on top in real px */
/* the outer ring starts 15 above the lead copy (measured from ring 01 in the comp) */
.rings{position:relative;width:100%;max-width:440px;aspect-ratio:1;margin:-15px 0 0 auto}
.rings svg{width:100%;height:100%;overflow:visible}
/* concentric rings : values straight from images/chart-rings.svg — fill + dashed stroke */
.rings .c-ring{stroke:#4c4c4c;stroke-dasharray:2 3}
.rings .c-1{fill:#18181e} .rings .c-2{fill:#1d1d25} .rings .c-3{fill:#2e2e37}
.rings .c-now{fill:#1d1d25;stroke:#fff648;stroke-dasharray:2 3}
/* Lay the leader line (dot + rule 23x6, images/chart-leader.svg) in column 1 and put the amount
   and label to its right. left 51% puts the dot's centre at the comp's x227. The amount sits
   right at the end of the rule (248), the label 14 further along at 261. */
.pin{position:absolute;left:51%;transform:translateY(-12px);white-space:nowrap;
  display:grid;grid-template-columns:23px auto;column-gap:14px;align-items:center}
.pin i{grid-area:1/1;height:6px;
  background:url(images/chart-leader.svg) no-repeat left center/contain}
.pin b{grid-area:1/2;margin-left:-13px;font-size:18px;line-height:calc(24px + var(--lh-a));font-weight:700}
.pin em{grid-area:2/2;align-self:start;margin-top:3px;font-size:13px;line-height:calc(18px + var(--lh-a));color:#b2b2b2;font-weight:400}
.pin1{top:7.7%} .pin2{top:31.8%} .pin3{top:51.8%}
/* The yellow label varies a lot in length by language and breaks out of the ring if kept on one
   line. Cap it at 30% (=132px), narrower than the chord inside the ring (≈142px at its
   narrowest), and allow wrapping.
   The Korean label for mk4.c measures 110px, so it still fits on one line. */
/* The yellow label hangs from its top edge, so in languages where the description wraps to two
   lines (en, ja) it drifts down by the extra height and leaves the centre of the ring.
   -> Pull it up by half of the added line.
   ko and zh stay on one line, so --pin-up is 0 = the comp coordinates exactly. (Jin 2026-09-01) */
.pin-now{left:50%;top:75.9%;transform:translate(-50%,calc(var(--pin-y,-12px) - var(--pin-up,0px)));grid-template-columns:auto;
  width:30%;white-space:normal;text-align:center}
.pin-now b{grid-area:1/1;margin-left:0;color:var(--acc)}
.pin-now em{grid-area:2/1;margin-top:0;color:var(--acc);font-size:14px}

/* ===== 03 roadmap ===== */
/* Each stage owns its rules, not the container.
   On desktop the four sit side by side, so the top and bottom rules read as one continuous line;
   once the width forces a wrap they break into per-stage blocks (which is what the comp wants). */
.rm{margin-top:49px;display:grid;grid-template-columns:repeat(4,1fr)}
.rm-i{padding:0 20px 35px 10px;
  border-top:1px solid var(--rule);border-bottom:1px solid var(--rule)}
.rm-s{display:block;width:fit-content;margin:-8px 0 0 -10px;padding:0 10px;
  font-family:var(--ui);font-weight:500;font-size:11px;line-height:calc(16px + var(--lh-a));color:#000;background:#cbcbcb}
.rm-i.done .rm-s{background:#4a4a4a;color:#989898}
.rm-i.now  .rm-s{background:var(--acc);color:#000}
.rm-i h5{margin-top:25px;font-family:var(--serif);font-weight:300;font-size:24px;line-height:calc(38px + var(--lh-a))}
/* strike-through thickness scales with font size (2px at 24px) — pin it to 1px */
.rm-i.done h5{text-decoration:line-through;text-decoration-thickness:1px}
.rm-i.now  h5{color:var(--acc)}
.rm-i p{margin-top:15px;font-size:16px;line-height:calc(24px + var(--lh-a));color:var(--body-c);font-weight:var(--body-w)}
.rm-i.now p{color:#fff}

/* ===== Why Japan, and why Singapore ===== */
.why{margin-top:110px}
.why-head{text-align:center}
.why-head h4{font-family:var(--serif);font-weight:400;font-size:30px;line-height:calc(40px + var(--lh-a))}
/* pass the final .8 opacity through --seq-op — writing opacity directly overrides .seq's fade */
.why-head p{font-family:var(--serif);font-weight:300;font-size:24px;line-height:calc(40px + var(--lh-a));--seq-op:.8}
.why-head p:not(.seq){opacity:.8}
.why-cols{margin-top:50px;display:grid;grid-template-columns:1fr 1fr}
/* Comp desktop: card title left 50 · top 40 · items left 70 · bottom padding 60
   (content 409 + padding = 470).
   min-height matches the heights of the two cards, and the bottom 60 holds as content grows. */
.why-col{padding:40px 40px 60px 50px;min-height:470px}
.why-jp{background:var(--panel-jp)}
.why-sg{background:var(--panel-sg)}
.wg{font-family:var(--serif);font-weight:300;font-size:24px;line-height:calc(40px + var(--lh-a))}
.wg .dash{color:var(--mute)}
.wg em{color:var(--acc)}
.wl{margin-top:35px;display:grid;gap:30px;padding-left:20px}
.wl li{display:grid;grid-template-columns:34px minmax(0,1fr)}
.wl .jn{font-family:var(--ui);font-weight:500;font-size:18px;line-height:calc(24px + var(--lh-a))}
.wl h6{font-family:var(--ui);font-weight:500;font-size:18px;line-height:calc(24px + var(--lh-a))}
.wl p{margin-top:10px;font-size:16px;line-height:calc(22px + var(--lh-a));color:var(--body-c);font-weight:var(--body-w)}

/* ===== 04 careers ===== */
.jobs-head{display:flex;align-items:flex-start;flex-wrap:wrap}
/* comp: the tabs start 34 below the top of the title (title box 70) */
.filters{display:flex;gap:40px;margin-left:82px;padding-top:34px;flex-wrap:wrap}
/* comp: inactive Inter Regular #AAA, active Inter Medium #FFEB6B, the count (n) in Light */
.filters button{font-family:var(--ui);font-weight:400;font-size:16px;line-height:calc(24px + var(--lh-a));color:#aaa;text-align:left;
  border-bottom:2px solid transparent;transition:color .25s}
.filters button:hover{color:#fff}
.filters button.on{color:var(--acc);border-bottom-color:var(--acc);font-weight:500}
.filters .n{font-weight:300}

/* comp: 70 below the title (= below jobs-head) */
.job-grid{margin-top:70px}
/* The top rule belongs to the first row, not the container — it has to fade in with that row.
   The coordinates are unchanged (same treatment as .values / .mkt-list).
   ⛔ Do NOT use :first-child — that is DOM order, so when the filter hides the first row with
      .is-off (display:none) it still points at that hidden row. That is why the top rule vanished
      entirely on the Engineering, Product and Business tabs (Jin 2026-09-01).
      Instead every row carries a top rule, and any row that HAS a visible row before it drops it.
      -> On every tab the rule survives only on the first VISIBLE row. */
.job-grid .job{border-top:1px solid var(--rule)}
.job-grid .job:not(.is-off) ~ .job:not(.is-off){border-top:0}
.job{display:grid;grid-template-columns:150px 150px minmax(0,1fr) 120px auto;
  column-gap:50px;align-items:center;padding:40px 0;border-bottom:1px solid var(--rule);
  transition:background .3s, var(--seq-tr)}
.c-meta{display:contents}
/* Without an explicit grid-row the DOM order (cat, loc, stat, title, go) diverges from the column
   order and title/go get pushed to a second line. Pin all five cells to row 1. */
.c-cat,.c-loc,.c-title,.c-stat,.c-go{grid-row:1}
.c-cat  {grid-column:1;text-align:center;font-family:var(--serif);font-weight:300;font-size:22px;line-height:calc(34px + var(--lh-a));color:var(--dim)}
.c-loc  {grid-column:2;text-align:center;font-size:18px;line-height:calc(24px + var(--lh-a));color:var(--body-c);font-weight:var(--body-w)}
.c-title{grid-column:3;font-size:18px;line-height:calc(24px + var(--lh-a));color:var(--body-c);font-weight:var(--body-w)}
.c-stat {grid-column:4;text-align:center;font-size:18px;line-height:calc(24px + var(--lh-a));color:var(--mute);font-weight:var(--body-w)}
.c-go   {grid-column:5;display:flex;align-items:center;gap:10px;padding:0 2px;color:#444}
.c-go em{font-size:14px;line-height:calc(24px + var(--lh-a));color:inherit;font-weight:var(--body-w)}
/* Arrow : images/icon-arrow.svg (20x8) embedded as a data-URI mask so it follows currentColor.
   Referencing an external SVG as a mask is blocked as a different origin over file:// and the
   arrow disappears. Job rows, the banner button and the JD apply button all share this one asset. */
.c-go i,.cta a i,.jd-apply a i{width:20px;height:8px;flex:0 0 auto;background:currentColor;
  -webkit-mask:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='20'%20height='8'%20viewBox='0%200%2020%208'%20fill='none'%3E%3Cpath%20d='M0.5%203.18164H0V4.18164H0.5V3.68164V3.18164ZM19.8536%204.03519C20.0488%203.83993%2020.0488%203.52335%2019.8536%203.32809L16.6716%200.146107C16.4763%20-0.0491555%2016.1597%20-0.0491555%2015.9645%200.146107C15.7692%200.341369%2015.7692%200.657951%2015.9645%200.853214L18.7929%203.68164L15.9645%206.51007C15.7692%206.70533%2015.7692%207.02191%2015.9645%207.21717C16.1597%207.41244%2016.4763%207.41244%2016.6716%207.21717L19.8536%204.03519ZM0.5%203.68164V4.18164H19.5V3.68164V3.18164H0.5V3.68164Z'%20fill='%23fff'/%3E%3C/svg%3E") no-repeat center/20px 8px;
          mask:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='20'%20height='8'%20viewBox='0%200%2020%208'%20fill='none'%3E%3Cpath%20d='M0.5%203.18164H0V4.18164H0.5V3.68164V3.18164ZM19.8536%204.03519C20.0488%203.83993%2020.0488%203.52335%2019.8536%203.32809L16.6716%200.146107C16.4763%20-0.0491555%2016.1597%20-0.0491555%2015.9645%200.146107C15.7692%200.341369%2015.7692%200.657951%2015.9645%200.853214L18.7929%203.68164L15.9645%206.51007C15.7692%206.70533%2015.7692%207.02191%2015.9645%207.21717C16.1597%207.41244%2016.4763%207.41244%2016.6716%207.21717L19.8536%204.03519ZM0.5%203.68164V4.18164H19.5V3.68164V3.18164H0.5V3.68164Z'%20fill='%23fff'/%3E%3C/svg%3E") no-repeat center/20px 8px;
  transition:transform .3s}
.job--live{cursor:pointer}
.job--live .c-cat,.job--live .c-loc,.job--live .c-title{color:#fff}
.job--live .c-loc,.job--live .c-title{font-weight:400}
.job--live .c-stat{color:var(--acc)}
.job--live .c-go{color:var(--mute)}
.job--live:hover{background:rgba(255,255,255,.04)}
.job--live:hover .c-go{color:#fff}
.job--live:hover .c-go i{transform:translateX(4px)}
.job--soon{cursor:default}

/* Open application banner : keeps its side-by-side layout as the width shrinks (Jin 2026-09-01).
   With flex-wrap:wrap the button dropped to its own line the moment width ran short, so the
   tablet range (721-1483) looked different from desktop.
   -> nowrap keeps the button in place and lets the sentence wrap to two lines instead, and
      align-items:center parks the button at the vertical centre of the box.
   min-width:0 on .cta p : with the flex default (min-width:auto) it cannot shrink below
   min-content and can shove the button out. Below 720 this switches to flex-direction:column,
   so it does not apply there. */
.cta{margin-top:40px;background:#272733;min-height:100px;
  display:flex;align-items:center;justify-content:center;gap:60px;padding:20px 60px;flex-wrap:nowrap}
/* text-wrap:balance : stops a lone fragment being left on the last line when it wraps to two.
   At 1024 it evens out from 554.6/44.2 to 296.6/302.2.
   Desktop stays on one line, so it has no effect there. */
.cta p{min-width:0;text-wrap:balance;font-size:16px;line-height:calc(24px + var(--lh-a));color:var(--body-c);font-weight:var(--body-w)}
.cta a{display:inline-flex;align-items:center;gap:10px;border:1px solid var(--dim);padding:3px 10px;
  font-size:14px;line-height:calc(24px + var(--lh-a));font-weight:var(--body-w);color:var(--dim);white-space:nowrap;transition:.25s}
/* the banner button arrow uses the same mask (shared with the .c-go i rule above) */
.cta a:hover{background:var(--dim);color:#121216;border-color:var(--dim)}

/* Back to top : images/icon-top.svg as a mask (the border is inside the SVG too).
   Its base aligns to the bottom of the banner (-40) and it stands 100 in from the right edge of
   the content (1562) (Jin 2026-08-31, 60 -> 100).
   margin-right is "offset + button width" — 100 + 40 = 140. */
/* By default it floats at the bottom right of the viewport (100 off the floor) and settles into
   its comp position once that position reaches the same height.
   site.js drives the offset with translateY — it never leaves the flow, so section heights stay
   stable, and the value converges continuously to 0 as you scroll, so it never jolts on arrival. */
.totop{display:block;width:40px;height:40px;margin:-40px -140px 0 auto;will-change:transform;
  color:var(--faint);background:currentColor;
  -webkit-mask:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='40'%20height='40'%20viewBox='0%200%2040%2040'%20fill='none'%3E%3Crect%20x='0.5'%20y='0.5'%20width='39'%20height='39'%20stroke='%23fff'/%3E%3Cpath%20d='M26%2017L19.5%2011L13%2017'%20stroke='%23fff'%20stroke-linecap='round'%20stroke-linejoin='round'/%3E%3Cline%20x1='19.5'%20y1='11.5'%20x2='19.5'%20y2='29.5'%20stroke='%23fff'%20stroke-linecap='round'%20stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat center/40px 40px;
          mask:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='40'%20height='40'%20viewBox='0%200%2040%2040'%20fill='none'%3E%3Crect%20x='0.5'%20y='0.5'%20width='39'%20height='39'%20stroke='%23fff'/%3E%3Cpath%20d='M26%2017L19.5%2011L13%2017'%20stroke='%23fff'%20stroke-linecap='round'%20stroke-linejoin='round'/%3E%3Cline%20x1='19.5'%20y1='11.5'%20x2='19.5'%20y2='29.5'%20stroke='%23fff'%20stroke-linecap='round'%20stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat center/40px 40px;
  transition:color .25s,opacity .3s}
.totop:hover{color:#fff}
/* Hidden over the hero — it sits awkwardly on the video, and you are already at the top so the
   button has nothing to do. site.js picks the reveal point as "the moment the statement band
   meets the header".
   ⚠ The default is VISIBLE and JS turns it off — so the button survives if the JS dies.
   ⛔ Do NOT name the class `is-off` — that name belongs to the careers filter and
      `.is-off{display:none !important}` is declared above. Reusing it would set the button to
      display:none, and site.js's "skip on mobile" test would never turn it back on. */
.totop.is-tucked{opacity:0;pointer-events:none}
/* Hidden outright on narrow screens (Jin 2026-08-31).
   The button sits outside the content area (100 to the right), so if the side margin is narrower
   than 112 (=100+40-28) it overflows and produces a horizontal scrollbar.
   margin = (100vw - 1260) / 2, so reaching 112 requires 100vw >= 1484.
   ⚠️ Changing --wrap (1260) or the offset (100) means recomputing this number. */
@media (max-width:1483px){ .totop{display:none} }

/* ===== footer ===== */
/* Comp desktop footer: no top rule. Mobile alone gets one, inset from both sides (720 block
   below). The logo and copyright are not centred in the area — each has its own coordinate:
   logo top 31 / copyright top 37. */
.footer{background:var(--pane-careers)}
.footer .wrap{display:flex;gap:6px;align-items:flex-start;height:90px;flex-wrap:wrap}
.footer .flogo{width:71px;margin-top:31px}
.footer .copy{margin-top:37px;font-family:var(--ui);font-size:12px;line-height:calc(15px + var(--lh-a));
  font-weight:400;color:var(--faint)}
.footer nav{display:flex;gap:24px;margin-left:auto;font-size:12px;color:var(--faint)}
.footer nav a:hover{color:#fff}
.note{margin-top:16px;font-size:11.5px;color:rgba(255,255,255,.3)}

/* ===== JD detail page ===== */
/* Figma PC 1920: the header is fixed, so .jd starts at y0. The meta line begins at 222, the
   detail and sidebar end at 1389 and the body ends at 1509, so the bottom padding is 120. */
.jd{background:var(--pane-careers);padding:222px 0 120px}
.jd-grid{display:grid;grid-template-columns:minmax(0,714fr) minmax(0,388fr);column-gap:102px;align-items:start}
.jd-main{min-width:0}

/* Meta line : shares its text tokens with the job-list rows (.c-*). Those live in a table grid,
   so only the layout is overridden here. */
.jd-meta{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.jd-meta .c-cat,.jd-meta .c-loc,.jd-meta .c-stat{
  grid-row:auto;grid-column:auto;font-family:inherit;font-weight:400;
  font-size:12px;line-height:calc(20px + var(--lh-a));text-align:left;color:var(--dim)}
.jd-meta .c-stat{color:var(--acc)}
.jd-meta .c-loc::before,.jd-meta .c-stat::before{content:"";display:inline-block;
  width:1px;height:11px;background:#333;margin-right:12px;vertical-align:-1px}

.jd-title{margin-top:20px;font-family:var(--serif);font-weight:300;
  font-size:40px;line-height:calc(50px + var(--lh-a));letter-spacing:-.8px}
.jd-lead{margin-top:30px;font-size:18px;line-height:calc(24px + var(--lh-a));color:var(--dim);font-weight:400}

/* Detail body : company intro bottom -> white rule 80, rule -> first badge 30 (Figma padding 31 - border 1) */
.jd-blocks{margin-top:80px;padding-top:30px;border-top:1px solid #fff;display:grid;gap:40px}
/* The paragraph divider is the same #222 as the underline on the sidebar rows (both #222222 in
   Figma). --rule (#434343) is used only for the sidebar's left rule on desktop. */
.jd-block+.jd-block{padding-top:39px;border-top:1px solid #222}
.jd-chip{width:fit-content;padding:3px 14px;background:#3b3b3b;font-size:14px;line-height:calc(20px + var(--lh-a));color:#fff;font-weight:400}
/* Bullets : in Figma the bullet sits +9 and the text +24 from the left of the text box (at 16px).
   With list-style:disc the browser decides where the marker goes and the coordinates cannot be
   matched, so they are drawn by hand. */
.jd-block ul{margin-top:20px;list-style:none;padding-left:20px}
.jd-block li{position:relative;padding-left:24px;
  font-size:16px;line-height:calc(32px + var(--lh-a));color:var(--dim);font-weight:400}
.jd-block li::before{content:"";position:absolute;left:7px;top:14px;
  width:4px;height:4px;border-radius:50%;background:currentColor}

/* The left divider has to run down to whichever of the two columns is TALLER, not just to the
   sidebar's own content (Jin 2026-09-01).
   .jd-grid is align-items:start, so the sidebar stood only as tall as itself and the rule cut off
   halfway whenever the detail body was longer.
   -> This item alone uses align-self:stretch to fill the row height (.jd-body stays start).
   Inside it is align-content:start, so the terms content stays pinned to the top as it stretches. */
.jd-side{margin-top:40px;padding-left:30px;border-left:1px solid var(--rule);
  display:grid;gap:0;align-content:start;min-width:0;align-self:stretch}
.jd-sh{font-size:20px;line-height:calc(28px + var(--lh-a));letter-spacing:-.4px;color:#fff;font-weight:400}
.jd-rows{margin-top:30px;padding-left:20px}
.jd-row{display:flex;gap:20px;align-items:flex-start;padding:20px 0;
  border-bottom:1px solid #222;font-size:15px;line-height:calc(22px + var(--lh-a));letter-spacing:-.3px}
.jd-row dt{flex:0 0 80px;color:#999;font-weight:400}
.jd-row dd{flex:1 1 0;min-width:0;color:var(--dim);font-weight:400}
.jd-row dd a:hover{color:#fff;text-decoration:underline}
.jd-row .tbd{display:block}

/* In English the label spellings (Compensation, Working hours, Company name, ...) run past 80px
   and wrap to two lines, so each row's value starts at a different height and the column looks
   ragged.
   Size the label column automatically to the LONGEST label — every row shares that one column —
   and forbid wrapping. No number is hardcoded, so it follows any copy change. Browsers without
   subgrid fall back via the @supports block below. */
html[data-lang="en"] .jd-rows{display:grid;grid-template-columns:max-content minmax(0,1fr);column-gap:20px}
html[data-lang="en"] .jd-row{display:grid;grid-column:1/-1;grid-template-columns:subgrid;
  gap:0;align-items:start}
html[data-lang="en"] .jd-row dt{flex:none;white-space:nowrap}
html[data-lang="en"] .jd-row dd{flex:none}
@supports not (grid-template-columns:subgrid){
  html[data-lang="en"] .jd-rows{display:block}
  html[data-lang="en"] .jd-row{display:flex}
  html[data-lang="en"] .jd-row dt{flex:0 0 112px}
  html[data-lang="en"] .jd-row dd{flex:1 1 0;min-width:0}
}
.jd-apply{padding:50px 0 0 20px}
/* rule, arrow and text all #fff (Jin 2026-08-31 comp revision). The arrow is currentColor, so it follows. */
.jd-apply a{display:flex;align-items:center;justify-content:center;gap:10px;padding:10px;
  border:1px solid #fff;font-size:16px;line-height:calc(24px + var(--lh-a));font-weight:400;color:#fff;transition:.25s}
.jd-apply a:hover{background:#fff;color:var(--pane-careers)}

/* ============================================================
   Responsive
   ============================================================ */
/* Align the bottom of the chart to the bottom of the evidence list — the evidence sentences run
   one or two lines depending on language, so anchoring from the top (comp -15) leaves the bottom
   edge inconsistent across languages.
   The reference line is the FLOOR OF THE YELLOW RING (ring 04) — in the comp it lands exactly on
   the bottom of the evidence list (767).
   The .rings box (440) bottoms out 15.5 below the yellow ring (cy345 + r79.5 = 424.5), so it is
   dropped by that amount. translateY percentages resolve against the element's own size, so the
   ratio holds even as the rings shrink on a narrow screen.
   The rings are pulled out with absolute so they do not count toward row height (otherwise the
   evidence list gets pushed), then the viz cell is stretched across both rows and bottom-aligned.
   Applies only at 1025 and up, where the layout is side by side.
   Note: for Korean this computes to the same position as the old comp value (-15), so nothing moves. */
@media (min-width:1025px){
  .mkt-viz{align-self:stretch;position:relative}
  .rings{position:absolute;right:0;bottom:0;margin:0;
    transform:translateY(calc(100% * 15.5 / 440))}
}

@media (min-width:721px){
  /* on desktop the market headline is one line (only the mobile frame breaks it in two) */
  .mkt-h br{display:none}
  /* Japanese does not fit on one line on desktop and drops a single character to the next line ->
     break at the comma so it reads as two lines. This is the opposite of the other languages. */
  html[data-lang="ja"] .mkt-h br{display:inline}
}

/* Hero "fullscreen (height-driven)" mode — enabled only when BOTH width and aspect ratio qualify.
   Splitting on width alone classified iPad Pro landscape (1366x1024, ratio 1.33) as desktop and
   cropped 25% off the sides. The video is 16:9, so the lower the ratio the worse the crop:
   1.6 loses 10%, 1.5 loses 16%, 1.33 loses 25%.
   Setting the floor at 3/2 (=1.5) lets every laptop and desktop through (1.54-1.78), while tablet
   landscape (1.33) and tall windows fall to the width-driven 16:9 mode below.
   Only in this mode does the header sit over the video, so the header background rule lives inside
   the same condition. */
@media (min-width:1025px) and (min-aspect-ratio:3/2){
  .hero{margin-top:0;height:100vh;aspect-ratio:auto}
  /* the sub copy and scroll cue show only in this mode, where the hero fills the screen */
  .hero-bar{display:flex}
  /* Lay 70% black behind the header over the hero only, so the text does not get lost on the video.
     From the Company section on, site.js adds .solid and it returns to opaque black.
     Note: on 2026-09-01 this was changed to "stay translucent all the way down" and then REVERTED
        — Jin confirmed the body text showing through the header made it hard to read. Translucency
        only makes sense over the video. */
  .header{background:rgba(0,0,0,.7);transition:background .3s}
  .header.solid{background:#000}
}

@media (max-width:1024px){
  /* Bottom padding unified to 120, matching mobile (Jin, 2026-09-01). There is no comp for this
     range, so it steps down: desktop 220 -> tablet 120 -> mobile 120. */
  .pane{padding:150px 0 120px}
  .pane-company,.pane-market,.pane-road,.pane-careers{min-height:0}
  .pane-road,.pane-careers{padding-bottom:120px}
  .sec-title{font-size:clamp(36px,5vw,60px);line-height:calc(1.16em + var(--lh-a))}
  .sec-split{grid-template-columns:1fr;gap:40px}
  .sec-body{padding-top:0}
  .mkt{grid-template-columns:1fr;grid-template-areas:"head" "viz" "list";row-gap:44px}
  .mkt-list{margin-top:0}
  .rings{margin:0 auto}
  /* folded to two columns, each of the four blocks carries its own top and bottom rule */
  .rm{grid-template-columns:repeat(2,1fr);row-gap:44px}
  .rm-i{padding-bottom:44px}
  /* Once the cards stack vertically: 10 between them, full bleed to the right edge, and the same
     background colour on both. All three used to be scoped to 720 and below, so they were missing
     across the 721-1024 range. */
  .br-p{display:none}
  .why-cols{grid-template-columns:1fr;gap:10px;margin-right:-28px}
  .why-col{min-height:0;background:var(--panel-sg)}
  .job{grid-template-columns:120px 110px minmax(0,1fr) 100px auto;column-gap:24px}
  .c-cat{font-size:19px}
  .c-loc,.c-title,.c-stat{font-size:16px}
  .jd{padding:180px 0 100px}
  .jd-grid{grid-template-columns:1fr;row-gap:60px}
  .jd-title{font-size:clamp(28px,3.6vw,40px);line-height:calc(1.26em + var(--lh-a))}
  /* comp mobile : the sidebar top rule is white 1px, with 60 below it */
  .jd-side{margin-top:0;padding-left:0;border-left:none;
    border-top:1px solid #fff;padding-top:60px}
}

@media (max-width:720px){
  .wrap{padding:0 20px}
  .br-m{display:inline}

  /* header */
  .header .wrap{height:70px}
  .logo{width:89px;margin-top:25px}
  .gnb{display:none}
  .lang{margin-top:34px}
  /* On mobile it is RIGHT-aligned rather than centred on the select (Jin 2026-09-01).
     .lang is the last element in the header .wrap (margin-left:auto) so it sits flush right, and
     .wrap's padding in this range is 20, which makes right:0 exactly 20 from the screen edge. */
  .lang ul{left:auto;right:0;transform:none}
  .lang>button{font-size:13px}

  /* hero : the mobile frame has no copy or scroll cue (hiding is the default now, so only the height is set here) */
  .hero{margin-top:70px}

  /* statement */
  .statement{height:200px}
  .statement .wrap{padding-top:36px}
  .statement h2{font-size:24px;line-height:calc(30px + var(--lh-a))}

  /* section shell : titles in the 20px gutter, body indented 40px */
  /* In the Figma mobile comp all four sections are a uniform 90 top / 120 bottom (measured
     2026-09-01). These have to override road 140 and careers 100 from the 1024 block above, so
     each section states it explicitly. */
  .pane{padding:90px 0 120px}
  /* ⛔ Do NOT pin the comp heights as min-height on mobile (Jin, 2026-09-01).
     The Figma mobile heights (834/1155/1894/1317) were measured at 375 wide; on anything wider
     the text wraps less and the content gets shorter. min-height then dumped all the slack at the
     bottom and every section ended up with different spacing. Content decides the height; only
     the padding follows the comp, at 90 top / 120 bottom. */
  .pane-company,.pane-market,.pane-road,.pane-careers{padding-bottom:120px}
  .sec-title{font-size:34px;line-height:calc(42px + var(--lh-a));letter-spacing:-.68px}
  .sec-sub{margin-top:6px;font-size:12px;line-height:calc(20px + var(--lh-a))}
  .sec-split{gap:0}
  .sec-body,.mkt,.rm,.why{padding-left:20px}

  /* company */
  .sec-body{padding-top:70px}
  .mission{font-size:20px;line-height:calc(28px + var(--lh-a))}
  .mission-sub{margin-top:14px;font-size:15px;line-height:calc(22px + var(--lh-a))}
  .values{margin-top:50px}
  .value{flex-direction:column;align-items:flex-start;gap:12px;padding:34px 0}
  .value h4{flex:none;font-size:20px;line-height:calc(28px + var(--lh-a))}
  .value p{font-size:15px;line-height:calc(22px + var(--lh-a))}

  /* market */
  .mkt{margin-top:44px;row-gap:34px}
  .mkt-h{font-size:18px;line-height:calc(26px + var(--lh-a))}
  /* the screen is narrow enough on mobile that forcing a break at the comma reads worse — drop it and let it wrap naturally */
  html[data-lang="ja"] .mkt-h br{display:none}
  .mkt-lead{margin-top:14px;font-size:12px;line-height:calc(20px + var(--lh-a))}
  .mkt-list li{padding:34px 0;font-size:15px;line-height:calc(22px + var(--lh-a))}
  .rings{margin:0 auto}
  .pin{left:44.3%;grid-template-columns:10px auto;column-gap:8px;transform:translateY(-10px)}
  .pin b{margin-left:-9px}
  .pin em{margin-top:-2px}
  .pin b{font-size:14px;line-height:calc(20px + var(--lh-a))}
  .pin em{font-size:12px;line-height:calc(18px + var(--lh-a))}
  /* Pin the caption width to the inner ring's diameter (≈114px).
     Without a width it shrink-to-fits down to 33px and splits into three lines. */
  /* ⚠️ .pin and .pin-now have equal specificity, so WHICHEVER COMES LATER WINS.
     `.pin{transform:translateY(-10px)}` and `.pin b{margin-left:-9px}` in this media query sit
     after the `.pin-now` rules in the desktop block above, which meant
       · translate(-50%) was lost and the label slid half its width right of the ring centre
       · only the amount (b) was pulled 9px left, throwing it out of vertical alignment with the
         description (em).
     -> Both values are re-declared here in the mobile block (Jin 2026-09-01). */
  .pin-now{left:50%;top:73.6%;--pin-y:-10px;width:112px;grid-template-columns:1fr;
    transform:translate(-50%,calc(var(--pin-y) - var(--pin-up,0px)))}
  .pin-now b{margin-left:0}
  .pin-now em{margin-top:8px}
  .pin-now b{font-size:16px;line-height:calc(22px + var(--lh-a))}
  .pin-now em{font-size:12px;white-space:normal}

  /* roadmap : vertical stack, a top rule on every item */
  /* Single column — a rule above every stage, and a bottom rule only on the last one (LAUNCH),
     for five dividers total.
     Measured from the mobile comp: subtitle bottom -> divider 01 is 68, each stage has 48 below
     it, and the last one has 40. */
  .rm{margin-top:68px;grid-template-columns:1fr;row-gap:0}
  .rm-i{padding:0 0 48px 10px;border-bottom:none}
  .rm-i:last-child{padding-bottom:40px;border-bottom:1px solid var(--rule)}
  .rm-i h5{margin-top:20px;font-size:20px;line-height:calc(28px + var(--lh-a))}
  .rm-i p{margin-top:6px;font-size:14px;line-height:calc(20px + var(--lh-a))}

  /* why : measured from the mobile comp — divider 05 -> heading 80, heading -> sub copy 14, sub copy -> cards 30 */
  .why{margin-top:80px}
  .why-head{text-align:left}
  .why-head h4{font-size:24px;line-height:calc(28px + var(--lh-a))}
  .why-head p{margin-top:14px;font-size:18px;line-height:calc(24px + var(--lh-a))}
  /* the mobile gutter is 20, so the right-hand full bleed is -20 too */
  .why-cols{margin-top:30px;margin-right:-20px}
  /* comp mobile: title left 30 · top 30 · right 40 · bottom 50 · items left 40 */
  .why-col{padding:30px 40px 50px 30px}
  .wg{font-size:18px;line-height:calc(24px + var(--lh-a))}
  .wl{margin-top:20px;gap:20px;padding-left:10px}
  .wl li{grid-template-columns:26px minmax(0,1fr)}
  .wl .jn,.wl h6{font-size:15px;line-height:calc(22px + var(--lh-a))}
  .wl p{margin-top:3px;font-size:14px;line-height:calc(20px + var(--lh-a))}

  /* careers : tabs stack vertically on the right, rows go two-tier */
  .jobs-head{flex-wrap:nowrap;justify-content:space-between;gap:20px}
  /* Comp: the tab group (w101) is flush to the content's right edge at 355, and each tab is
     left-aligned inside it. Buttons centre their text by default, so left alone every label
     bunches to its own centre. */
  .filters{margin-left:auto;padding-top:21px;flex-direction:column;
    align-items:flex-start;gap:15px;flex-wrap:nowrap}
  .filters button{font-size:14px;line-height:calc(20px + var(--lh-a));white-space:nowrap}
  /* the tab group (191) is taller than the title (42) and sets the jobs-head height — 89 below it */
  .job-grid{margin-top:89px}
  .cta{margin-top:46px}
  .job{grid-template-columns:minmax(0,1fr) auto;column-gap:12px;row-gap:5px;padding:34px 0}
  .c-meta{display:flex;align-items:center;gap:12px;flex-wrap:wrap;grid-row:1;grid-column:1/-1}
  .c-cat,.c-loc,.c-stat{font-family:inherit;font-size:12px;line-height:calc(20px + var(--lh-a));text-align:left}
  .c-loc::before,.c-stat::before{content:"";display:inline-block;width:1px;height:11px;
    background:var(--faint);margin-right:12px;vertical-align:-1px}
  .c-title{grid-row:2;grid-column:1;font-size:15px;line-height:calc(22px + var(--lh-a))}
  .c-go{grid-row:2;grid-column:2;align-self:center}
  .c-go em{display:none}

  .cta{background:none;min-height:0;padding:0;
    flex-direction:column;align-items:flex-start;gap:16px}
  .cta p{font-size:14px;line-height:calc(20px + var(--lh-a))}
  .cta a{font-size:12px;line-height:calc(20px + var(--lh-a))}
  /* the back-to-top button is hidden entirely below 1484 (see the "narrow screens" comment) */

  /* footer : comp mobile — top rule inset 20 on each side, logo top 33 / copyright top 37 */
  .footer .wrap{gap:5px}
  /* The rule is inset 20 on each side (comp x20-355). Putting the border on .wrap would cover the padding too and run the full screen width. */
  .footer .wrap::before{content:"";position:absolute;left:20px;right:20px;top:0;
    height:1px;background:#303030}
  .footer .flogo{width:64px;margin-top:33px}
  .footer .copy{margin-top:37px;font-size:11px;line-height:calc(13px + var(--lh-a))}
  .footer nav{gap:16px}

  /* JD detail : measured from Figma mobile job detail 5611:2410 (2026-08-31)
     ⚠ The weight differs from desktop — desktop is Regular(400), mobile is Light(300).
       The comps diverge by breakpoint, so follow them as drawn (Jin 2026-08-31).
     Most spacing and sizing matches desktop, so only the differences are overridden.
     (badge 14/20 · padding 3/14, info rows 20/0 · gap 20 · 15/22, and the 80 label width are all
     the same as desktop.) */
  .jd{padding:130px 0 120px}
  .jd-meta .c-cat,.jd-meta .c-loc,.jd-meta .c-stat{font-weight:300}
  .jd-title{margin-top:20px;font-size:34px;line-height:calc(42px + var(--lh-a));letter-spacing:0}
  .jd-lead{margin-top:30px;font-size:14px;line-height:calc(20px + var(--lh-a));font-weight:300}
  /* Company intro bottom -> white rule 62, rule -> first badge 60 (the mobile frame uses Auto
     Layout, so in Figma too the stroke 1 and padding 60 push together = the same arithmetic
     as CSS) */
  .jd-blocks{margin-top:62px;padding-top:60px;gap:40px}
  .jd-block+.jd-block{padding-top:39px}
  /* bullets : desktop (+9/+24) scaled proportionally for 15px (+8/+22) */
  .jd-block ul{margin-top:20px;padding-left:9px}
  .jd-block li{padding-left:22px;font-size:15px;line-height:calc(32px + var(--lh-a));font-weight:300}
  .jd-block li::before{left:6px}
  .jd-sh{font-weight:300}
  .jd-row dt,.jd-row dd{font-weight:300}
  .jd-apply{padding:20px 0 0}
}


/* ============================================================
   Application modal + copy toast
   Figma modal 5640:223 (460×278) · toast 5640:263 (300×60)
   - Vertical arithmetic : 60 (top) + 24 (blurb) + 15 + 24 (mail row) + 50 + 46 (button)
     + 30 (bottom) = 249
     (2026-09-01 comp revision — the blurb shrank from two lines to one, taking the modal
     from 278 to 249)
   - The toast overlaps the dead centre of the modal (Jin 2026-09-01). While it is up, the modal
     content drops to 50%.
   - pointer-events:none — the toast covers the mail row, so clicks pass through.
   ============================================================ */
.modal{position:fixed;inset:0;z-index:200;display:flex;align-items:center;justify-content:center}
.modal[hidden]{display:none}
.modal-dim{position:absolute;inset:0;background:rgba(0,0,0,.5)}
/* min-width : .modal is position:fixed, so it does not inherit body{min-width:320px}.
   Left alone it keeps narrowing forever as the window drops below 320 (Jin 2026-09-01).
   It stops at 320 (the site's minimum width) minus 20x2 side margin = 280. */
.modal-box{position:relative;width:460px;min-width:280px;background:#333;border-radius:10px;
  box-shadow:0 4px 10px rgba(0,0,0,.5);text-align:center}
.modal-in{padding:60px 30px 30px;transition:opacity .2s}
.modal.is-copied .modal-in{opacity:.5}

/* Blurb : the comp text is a single auto-width (hug) line (294x24), so no width is pinned.
   ⛔ Do NOT set word-break here — body already handles it per language
      (ko keep-all / ja normal+strict / zh and en normal). Applying keep-all to the modal alone
      turned Japanese into one solid run that hit 406px and broke past the 400 content width
      (found while applying translations, Jin 2026-09-01).
   text-wrap:balance : stops a lone fragment on the last line in the languages that wrap to two
      (ja, en). ja 377.6/28.8 -> 208.3/198.2 · en 391.8/51.1 -> 214.8/228.1. Browsers without it
      fall back to normal wrapping.
   ⚠️ Kept as data-i18n-html so a <br> can be used where a specific break is needed. */
.modal-desc{margin:0 auto;font-family:var(--lang);font-weight:400;
  font-size:18px;line-height:calc(24px + var(--lh-a));color:#fff;text-wrap:balance}

/* Mail row : text (172) + gap 11 + icon (18) = 201.
   In a 24px row the icon is not at the vertical centre (+3) but at +4 as drawn in the comp
   -> flex-start + margin-top. */
.modal-mail{margin-top:15px}
.mail-copy{display:inline-flex;align-items:flex-start;gap:11px;
  margin:0;padding:0;border:0;background:none;-webkit-appearance:none;appearance:none;cursor:pointer}
.mail-copy span{font-family:var(--ui);font-weight:400;font-size:20px;line-height:24px;color:var(--acc);
  /* Figma 5640:225 : UNDERLINE / SOLID / offset·thickness AUTO / skip-ink on (Jin 2026-09-01) */
  text-decoration:underline;text-decoration-thickness:auto;text-underline-offset:auto}
.mail-copy img{display:block;width:18px;height:18px;margin-top:4px}

.modal-ok{display:block;width:100%;height:46px;margin-top:50px;
  border:1px solid #c0c0c0;border-radius:0;background:none;-webkit-appearance:none;appearance:none;cursor:pointer;
  font-family:var(--lang);font-weight:400;font-size:16px;line-height:calc(24px + var(--lh-a));color:#fff;
  transition:background .25s,color .25s}
.modal-ok:hover{background:#fff;color:#333}

.modal-toast{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  width:300px;margin:0;padding:18px 0;border-radius:10px;
  background:rgba(0,0,0,.8);box-shadow:0 2px 10px rgba(0,0,0,.5);
  font-family:var(--lang);font-weight:400;font-size:16px;line-height:calc(24px + var(--lh-a));color:#fff;
  opacity:0;pointer-events:none;transition:opacity .2s}
.modal.is-copied .modal-toast{opacity:1}

@media (prefers-reduced-motion:reduce){
  .modal-in,.modal-toast{transition:none}
}

/* 480 and below : full width apart from a 20 margin on each side (Jin 2026-09-01) */
@media (max-width:480px){
  .modal{padding:0 20px}
  .modal-box{width:100%}
  .modal-toast{max-width:100%}
  /* The forced break (<br>) in the i18n copy is only for the range where the modal holds 460.
     At 481 and up the content width is 400 and the Japanese first line (275.2) fits, but from
     here down the width shrinks, that first line wraps again and it becomes three lines
     (at 375 the content is 275).
     -> Drop the forced break and let text-wrap:balance handle it. */
  .modal-desc br{display:none}
  /* Mobile typography (Jin 2026-09-01) — blurb 18/24 -> 15/22, mail 20/24 -> 16/24,
     toast 16/24 -> 14/20. Only the confirm button stays at 16.
     The toast keeps its 18 vertical padding, so its height goes 60 -> 56. */
  .modal-desc{font-size:15px;line-height:calc(22px + var(--lh-a))}
  .mail-copy span{font-size:16px;line-height:24px}
  .modal-toast{font-size:14px;line-height:calc(20px + var(--lh-a))}
}


/* On the job detail page the header matches the page background (--pane-careers #121216), on both
   desktop and mobile (Jin 2026-09-01).
   ⚠️ It has the same specificity as `.header.solid` (0,2,0), so it MUST come after that rule to win.
   Hence it lives at the very end of the file — it overrides both the hero mode's
   `.header{rgba(0,0,0,.7)}` and `.header.solid{#000}`. */
.page-jd .header{background:var(--pane-careers)}
.page-jd .header.solid{background:var(--pane-careers)}
