/* UST21 — 모델 선택 → 뷰어 껍데기
 *
 * 화면은 둘뿐이다. 첫 화면(.intro)에서 모델을 고르면 뷰어 껍데기(.shell)가
 * 덮고, 위 막대는 남은 채 아래 iframe 만 갈아 끼운다.
 *
 * 색·크기·모서리·그림자 토큰은 KOOS 뷰어(Visualization_AI_koos/site/style.css
 * :3–28)의 :root 를 그대로 가져왔다. 뷰어 넷은 skin/skin.css 가 같은 값으로
 * 맞추므로, 껍데기와 그 안의 뷰어가 한 화면처럼 보인다. 색을 새로 만들지
 * 말고 KOOS 쪽이 바뀌면 여기도 맞춰라.
 *
 * 예전에는 SCHISM 계열 토큰(--ink-2/-3/-4, --r-sm/md/lg, 고정폭 글꼴, 흰 강조)을
 * 썼다. 이름은 남겨 두고(선택자 다 고치기 싫어서) 값만 KOOS 로 바꿨다:
 *   --ink-2 = KOOS --dim, --ink-3 = --ink-4 = KOOS --faint (KOOS 는 세 단뿐이다)
 *   --r-lg 12 / --r-md 9 / --r-sm 8 (KOOS 는 판 12, 단추 9, 작은 단추 8)
 *   고정폭 글꼴 토큰은 없앴다. KOOS 는 숫자를 tabular-nums 로만 다룬다.
 *
 * 인라인 style 속성은 CSP 가 막는다 (_headers). 위치·지연·색 전부 여기서
 * 클래스와 :nth-child 로 준다. HTML 에 style="…" 을 쓰면 조용히 안 먹는다.
 */
:root{
  --bg:    #070b12;
  --ink:   #e8eef6;
  --dim:   #93a2b8;
  --faint: #7f8ca2;              /* #5d6b80 은 대비 3.4:1 — 작은 글씨가 AA 에 못 미쳤다 */
  --ink-2: var(--dim);
  --ink-3: var(--faint);
  --ink-4: var(--faint);

  --glass:  rgba(12,18,28,.72);
  --glass2: rgba(16,24,36,.86);
  --fill-1: rgba(255,255,255,.07);
  --fill-2: rgba(255,255,255,.12);
  --fill-3: rgba(255,255,255,.18);

  --line:   rgba(255,255,255,.10);
  --line-2: var(--line);              /* KOOS 에 굵은 선은 없다. 가는 선 하나 */

  --shadow:    0 8px 28px rgba(0,0,0,.45);
  --shadow-sm: 0 4px 14px rgba(0,0,0,.35);

  --accent:    #4da3ff;               /* KOOS 강조. 초점 테두리에 쓴다 */
  --on-accent: #08121f;               /* 강조색 위의 글자 */

  --r-sm: 8px;  --r-md: 9px;  --r-lg: 12px;  --r-pill: 999px;
  --blur: blur(14px) saturate(1.3);

  --edge: 14px;
  --bar:  56px;                       /* 위 막대 높이 */

  --ease: cubic-bezier(.32,.72,.28,1);
  --dur:  .18s;
  --dur-2: .42s;                      /* 화면 전환. 이보다 길면 답답하다 */

  /* 고르는 중인 모델의 색. app.js 가 손이 얹힌 단추를 보고 실시간으로 바꾼다.
     배경(.bg-accent)·제목 둘째 줄·판 테두리·위 막대의 켜진 탭이 이걸 따라간다.
     쉬는 값은 app.js 의 폴백·flow.js 의 BASE 와 **셋이 같아야 한다** — JS 가
     손을 뗄 때 그 값을 다시 넣으므로, 여기만 바꾸면 첫 hover 뒤에 색이 튄다.
     지금은 셋 다 KOOS 의 --accent(#4da3ff = 77,163,255)다. */
  --accent-rgb: 77,163,255;

  /* KOOS 글꼴 스택 앞에 Pretendard Variable 만 얹었다 (index.html 이 불러온다) */
  --font: "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont,
          "Apple SD Gothic Neo", "Malgun Gothic", "Noto Sans KR", system-ui, sans-serif;
}

*,*::before,*::after{ box-sizing:border-box; }
html,body{ height:100%; }

body{
  margin:0;
  font:400 13px/1.5 var(--font);       /* KOOS 본문 13px. 1.45 는 홍보 문단에 빡빡해 1.5 */
  color:var(--ink);
  background:var(--bg);
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;                  /* 어떤 폭에서도 가로 스크롤은 없다 */
}
/* 뷰어를 볼 때는 페이지가 스크롤되면 안 된다 — 스크롤은 뷰어 몫이다 */
body.is-viewer{ overflow:hidden; }

/* ── 배경 네 겹 ─────────────────────────────────────────────
   .bg(바다색 그라디언트) → .bg-accent(고른 모델 색) → canvas(입자) → .bg-veil
   순서가 곧 z 순서다. 셋 다 fixed 라 첫 화면이 스크롤돼도 같이 안 움직인다 */
.bg{
  position:fixed; inset:0; z-index:0;
  background:
    radial-gradient(120% 78% at 50% -12%, rgba(30,134,188,.22) 0%, transparent 62%),
    radial-gradient(85% 55% at 88% 108%, rgba(192,116,42,.09) 0%, transparent 58%),
    linear-gradient(180deg, #0b1220 0%, #070b12 55%, #05080d 100%);
}
.bg-flow{
  position:fixed; inset:0; z-index:1;
  width:100%; height:100%;
  pointer-events:none;
  opacity:.5;
  transition:opacity var(--dur-2) var(--ease);
}
/* 뷰어가 덮으면 배경 입자는 보이지도 않으면서 GPU 만 먹는다 */
body.is-viewer .bg-flow{ opacity:0; }

/* 고른 모델의 색으로 바다 위쪽이 물든다. 캔버스 입자 색과 짝을 이룬다.
   transition 을 길게 준 건 단추 사이를 훑을 때 색이 튀지 않게 하려는 것 */
.bg-accent{
  position:fixed; inset:0; z-index:0;
  pointer-events:none;
  opacity:0;
  background:
    radial-gradient(90% 62% at 50% -8%,
      rgba(var(--accent-rgb),.32) 0%, transparent 64%),
    radial-gradient(60% 45% at 18% 104%,
      rgba(var(--accent-rgb),.14) 0%, transparent 60%);
  transition:opacity .55s var(--ease), background .55s var(--ease);
}
:root.has-accent .bg-accent{ opacity:1; }
body.is-viewer .bg-accent{ opacity:0; }

/* 입자 위에 얹는 얇은 막. 두 가지 일을 한다.
   1. 위경도 격자 — 지도 위에 있다는 느낌. 가운데만 보이고 가장자리로 갈수록
      mask 로 지운다. 화면 전체에 깔면 모눈종이가 된다.
   2. 가장자리 어둡히기 — 글자가 놓이는 곳의 입자를 눌러 읽기 쉽게 한다 */
.bg-veil{
  position:fixed; inset:0; z-index:1;
  pointer-events:none;
  background:radial-gradient(110% 90% at 50% 45%,
             transparent 48%, rgba(5,8,13,.62) 100%);
}
.bg-veil::before{
  content:'';
  position:absolute; inset:0;
  background:
    linear-gradient(rgba(255,255,255,.05) 1px, transparent 1px) 0 0 / 100% 112px,
    linear-gradient(90deg, rgba(255,255,255,.05) 1px, transparent 1px) 0 0 / 112px 100%;
  -webkit-mask-image:radial-gradient(70% 60% at 50% 50%, #000 0%, transparent 100%);
          mask-image:radial-gradient(70% 60% at 50% 50%, #000 0%, transparent 100%);
}

/* ══ 첫 화면 ═════════════════════════════════════════════ */
.intro{
  position:fixed; inset:0; z-index:2;
  display:flex; align-items:center; justify-content:center;
  overflow-y:auto; overflow-x:hidden;
  padding:calc(var(--edge) + env(safe-area-inset-top)) var(--edge)
          calc(var(--edge) + env(safe-area-inset-bottom));
  transition:opacity var(--dur-2) var(--ease),
             transform var(--dur-2) var(--ease),
             visibility 0s linear var(--dur-2);
}
body.is-viewer .intro{
  opacity:0;
  transform:scale(.97);
  visibility:hidden;
  pointer-events:none;
}

/* 한 화면에 다 들어와야 한다. 그래서 제목과 숫자를 나란히 두고(왼쪽 글,
   오른쪽 숫자), 그 아래 단추 한 줄, 맨 아래 한 줄. 세로로 쌓기만 하면
   노트북 화면(768px)에서 단추가 접힌 채 시작한다 */
.intro-inner{
  width:100%; max-width:1120px;
  margin:auto;                        /* 넘치면 위가 잘리지 않고 스크롤된다 */
  padding:12px 0 10px;
  display:grid;
  grid-template-columns:minmax(0,1fr) auto;
  grid-template-areas:
    "top   top"
    "head  facts"
    "label label"
    "picks picks"
    "foot  foot";
  column-gap:56px;
  align-items:end;
}
.intro-top  { grid-area:top; }
.intro-head { grid-area:head; }
.facts      { grid-area:facts; }
.pick-label { grid-area:label; }
.picks      { grid-area:picks; }
.intro-foot { grid-area:foot; }

/* ── 등장 안무 ──────────────────────────────────────────────
   위에서 아래로, 왼쪽에서 오른쪽으로. 한꺼번에 뜨면 어디를 볼지 모른다.
   fill-mode 는 backwards 다 — forwards 로 두면 끝난 뒤에도 keyframe 의
   transform 이 남아서 hover 의 transform 을 덮어 버린다 */
@keyframes rise{
  from{ opacity:0; transform:translateY(18px); }
  to  { opacity:1; transform:none; }
}
@keyframes unmask{                    /* 제목 — 아래에서 밀려 올라온다 */
  from{ transform:translateY(108%); }
  to  { transform:none; }
}
@keyframes draw{                      /* 가로줄 — 왼쪽에서 그어진다 */
  from{ transform:scaleX(0); }
  to  { transform:none; }
}
@keyframes lift{                      /* 판 — 조금 작게, 조금 아래에서 */
  from{ opacity:0; transform:translateY(26px) scale(.985); }
  to  { opacity:1; transform:none; }
}
@keyframes pulse{                     /* 살아 있음 표시 점 */
  0%  { box-shadow:0 0 0 0 rgba(var(--accent-rgb),.55); }
  70% { box-shadow:0 0 0 8px rgba(var(--accent-rgb),0); }
  100%{ box-shadow:0 0 0 0 rgba(var(--accent-rgb),0); }
}

/* 전체 1.3초. 예전 1.8초는 판이 뜨기를 기다리는 게 느껴졌다.
   제목 두 줄이 올라온 직후(.4초)에 판이 따라붙는다 — 읽고 나면 손이 갈 곳이
   이미 와 있어야 한다 */
.intro-top  { animation:rise .55s var(--ease) 0s backwards; }
.kicker     { animation:rise .55s var(--ease) .05s backwards; }
.h1-line > span{ animation:unmask .7s var(--ease) backwards; }
.h1-line:nth-child(1) > span{ animation-delay:.1s; }
.h1-line:nth-child(2) > span{ animation-delay:.18s; }
.intro-lede { animation:rise .55s var(--ease) .3s backwards; }
.facts      { animation:rise .55s var(--ease) .36s backwards; }
.pick-label { animation:rise .5s var(--ease) .4s backwards; }
.pick-label::after{ animation:draw .8s var(--ease) .46s backwards; }
.proj       { animation:lift .6s var(--ease) backwards; }
.grp:nth-child(1) .proj:nth-child(1){ animation-delay:.46s; }
.grp:nth-child(1) .proj:nth-child(2){ animation-delay:.52s; }
.grp:nth-child(1) .proj:nth-child(3){ animation-delay:.58s; }
.grp:nth-child(2) .proj:nth-child(1){ animation-delay:.64s; }
.grp:nth-child(2) .proj:nth-child(2){ animation-delay:.70s; }
.grp:nth-child(2) .proj:nth-child(3){ animation-delay:.76s; }
.intro-foot { animation:rise .55s var(--ease) .78s backwards; }

/* ── 맨 윗줄 — 로고와 언어 ─────────────────────────────── */
.intro-top{
  display:flex; align-items:center; justify-content:space-between;
  margin-bottom:clamp(18px,3vh,36px);
}
.intro-logo{ height:24px; width:auto; display:block; opacity:.92; }

.intro-lang{
  display:flex; align-items:center; gap:2px;
  padding:3px;
  font-size:11px; font-weight:600; letter-spacing:.06em;
  background:var(--fill-1);
  border:1px solid var(--line);
  border-radius:var(--r-pill);
}
.intro-lang a,.intro-lang span{
  display:block;
  padding:3px 10px;
  border-radius:var(--r-pill);
  text-decoration:none;
  color:var(--ink-4);
  transition:color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.intro-lang a:hover{ color:var(--ink-2); background:var(--fill-1); }
.intro-lang .is-on{ color:var(--ink); background:var(--fill-2); }

/* ── 한글 줄바꿈 — 낱말 가운데서 끊지 않는다 ─────────────
   기본값은 글자 단위라 "검증까 / 지" 처럼 낱말이 쪼개진다. 넘칠 때만 끊는다 */
html:lang(ko) body{ word-break:keep-all; overflow-wrap:break-word; }

/* ── 제목 덩이 ──────────────────────────────────────────── */
.intro-head{ max-width:680px; min-width:0; }

.kicker{
  margin:0 0 12px;
  font-size:13px; font-weight:600; letter-spacing:0;
  color:var(--dim);
}
:lang(en) .kicker{ letter-spacing:.02em; }

.intro-head h1{
  margin:0;
  font-size:clamp(32px,3.9vw,50px);
  font-weight:800;
  letter-spacing:-.03em;            /* 한글 800 은 이보다 좁히면 붙는다 */
  line-height:1.08;
}
/* 줄마다 창을 하나씩 두고 글자가 그 창 아래에서 올라온다. 창 위아래에 여유를
   두는 건 쉼표·꼬리 글자가 잘리지 않게 하려는 것 */
.h1-line{
  display:block; overflow:hidden;
  padding:.06em 0 .12em; margin:-.06em 0 -.12em;
}
.h1-line > span{ display:block; }
/* 둘째 줄은 브랜드 파랑으로 **고정**(디자인 2차). 카드에 손을 얹어도 안 바뀐다 */
.intro-head em{
  font-style:normal;
  color:var(--accent);
}

.intro-lede{
  margin:16px 0 0;
  max-width:41em;                   /* 한 줄 40자 안팎. 두 줄에 끝난다 */
  font-size:clamp(14px,1.2vw,15.5px);
  line-height:1.7;
  color:#b4bcc8;
  text-wrap:pretty;
}

/* ── 숫자 넷 — 제목 오른쪽 2×2 ─────────────────────────────
   숫자 30px 아래에 이름 13px. 이름이 숫자 옆에 11px 로 붙어 있으면 안 읽힌다.
   단위(종·시간·곳)는 숫자에 붙여 반 크기로 — 한국어는 수에 단위가 붙어야 읽힌다 */
.facts{
  list-style:none; margin:40px 0 0; padding:4px 0 4px 28px;
  align-self:start;                 /* 제목 첫 줄 높이에 윗끝을 맞춘다 */
  border-left:1px solid var(--line);
  display:grid; grid-template-columns:repeat(2, auto);
  gap:22px 40px;
}
.facts li{ display:flex; flex-direction:column; gap:6px; min-width:0; cursor:default; }
.facts li[title]{ cursor:help; }
.facts b{
  font-size:30px; font-weight:700;
  letter-spacing:-.02em;
  line-height:1;
  color:var(--ink);
  font-variant-numeric:tabular-nums;
  white-space:nowrap;
}
.facts small{
  font-size:15px; font-weight:600; letter-spacing:0;
  margin-left:2px;
  color:var(--dim);
}
.facts span{
  font-size:13px; line-height:1.3;
  color:var(--dim);
  white-space:nowrap;
}

/* ── 묶음 머리 — 점 하나, 이름, 짧은 풀이, 오른쪽으로 긋는 선 ──
   카드 여섯을 "수치모델 셋 · 응용 서비스 셋" 두 줄로 나눈다. 런처 메뉴의
   두 묶음과 같은 이름이다. 한글에는 자간을 주지 않는다 */
.picks{
  margin-top:clamp(20px,3vh,34px);
  display:flex; flex-direction:column; gap:16px;
}
.pick-label{
  margin:0 0 9px;
  display:flex; align-items:center; gap:10px;
  font-size:14px; font-weight:700; letter-spacing:0;
  color:var(--ink);
}
.pick-label em{
  font-style:normal; font-size:12.5px; font-weight:500;
  color:var(--dim);
}
.pick-label::after{
  content:'';
  flex:1 1 auto; height:1px; margin-left:6px;
  background:linear-gradient(90deg, var(--line-2), transparent);
  transform-origin:left center;
}
.live{
  flex:0 0 auto;
  width:7px; height:7px; border-radius:50%;
  background:var(--accent);
}
/* 두 묶음 머리의 점은 똑같이 — 하나만 뛰거나 테를 두르면 그쪽이 "켜진" 것처럼 읽힌다 */

.picks-row{
  display:grid;
  grid-template-columns:repeat(3, minmax(0, 1fr));
  gap:14px;
  align-items:stretch;
}

/* ── 카드 ───────────────────────────────────────────────────
   위: 실제 뷰어 화면 한 조각(무엇이 나오는지 먼저 보인다)
   가운데: 표식 · 분류 · 이름, 설명 두 줄
   아래: 기술 꼬리표와 "결과 보기" 알약 — 카드 전체가 누르는 자리다 */
.proj{
  position:relative;
  display:flex; flex-direction:column;
  min-width:0;
  overflow:hidden;

  background:var(--glass);
  backdrop-filter:var(--blur);
  -webkit-backdrop-filter:var(--blur);
  border:1px solid var(--line);
  border-radius:var(--r-lg);
  box-shadow:var(--shadow);

  transition:transform var(--dur) var(--ease),
             border-color .3s var(--ease);
}
/* 카드가 통째로 뜬다 */
.proj:has(.pick:hover),
.proj:has(.pick:focus-visible){
  transform:translateY(-2px);
  border-color:rgba(var(--m),.6);
}
.proj:has(.pick:active){ transform:translateY(-1px); }

.pick{
  /* button 기본값 지우기 */
  appearance:none; font:inherit; color:inherit; text-align:left;
  border:0; background:transparent;
  position:relative; isolation:isolate;
  display:flex; flex-direction:column; align-items:stretch;
  width:100%; height:100%; min-width:0;
  padding:0;
  cursor:pointer;
  transition:background var(--dur) var(--ease);

  /* 카드 자기 색 — app.js MODELS·런처 메뉴와 같은 값. 표식·화살표·hover 가 따라간다 */
  --m:var(--accent-rgb);
}
.pick[data-model="koos"]     { --m:96,176,232; }
.pick[data-model="kop"]      { --m:108,214,208; }
.pick[data-model="roms"]     { --m:226,160,92; }
.pick[data-model="seaheat"]  { --m:240,128,104; }
.pick[data-model="searoute"] { --m:150,170,240; }
.pick[data-model="busantwin"]{ --m:196,150,232; }
/* 카드 테두리도 제 색을 쓰도록 바깥 틀에 같은 값을 준다 (페이지 색은 안 건드린다) */
.proj{ --m:77,163,255; }
.proj:has(> .pick[data-model="koos"])     { --m:96,176,232; }
.proj:has(> .pick[data-model="kop"])      { --m:108,214,208; }
.proj:has(> .pick[data-model="roms"])     { --m:226,160,92; }
.proj:has(> .pick[data-model="seaheat"])  { --m:240,128,104; }
.proj:has(> .pick[data-model="searoute"]) { --m:150,170,240; }
.proj:has(> .pick[data-model="busantwin"]){ --m:196,150,232; }

/* 아래에서 올라오는 제 색 빛. 쉴 때는 옅게, 얹으면 또렷이 */
.pick::after{
  content:'';
  position:absolute; inset:0; z-index:-1;
  opacity:.3;
  background:radial-gradient(120% 80% at 50% 120%,
             rgba(var(--m, 77,163,255),.22) 0%, transparent 70%);
  transition:opacity var(--dur-2) var(--ease);
}
.pick:hover, .pick:focus-visible{ background:rgba(255,255,255,.035); }
.pick:hover::after, .pick:focus-visible::after{ opacity:1; }
.pick:focus-visible{
  outline:2px solid rgba(var(--m, 77,163,255),.85);
  outline-offset:-4px;
  border-radius:var(--r-lg);
}

.pick-thumb{
  position:relative; display:block;
  height:clamp(64px, 8.6vh, 96px);
  overflow:hidden;
  background:#0b111a;
  border-bottom:1px solid var(--line);
}
.pick-thumb img{
  display:block; width:100%; height:100%;
  object-fit:cover;
  filter:saturate(.95);
  transition:filter .4s var(--ease), transform .6s var(--ease);
}
.pick-thumb::after{                 /* 아래로 카드 바탕에 스며든다 */
  content:''; position:absolute; inset:0;
  background:linear-gradient(180deg, transparent 45%, rgba(10,15,23,.45) 100%);
}
.pick:hover .pick-thumb img,
.pick:focus-visible .pick-thumb img{ filter:none; transform:scale(1.04); }

.pick-top{
  position:relative;
  display:flex; align-items:center;
  padding:13px 18px 0;
  min-width:0;
}
/* 표식은 화면 조각 아래끝에 걸친 둥근 배지(오른쪽). 분류·이름·설명·꼬리표가 모두
   같은 왼쪽 선(18px)에서 시작한다 — 표식이 글 앞에 서면 왼쪽 끝이 들쭉날쭉했다 */
.pick-mark{
  position:absolute; top:-23px; right:16px;
  width:46px; height:46px; padding:8px;
  border-radius:50%;
  background:#111925;
  border:1px solid rgba(var(--m, 77,163,255),.42);
  box-shadow:0 4px 14px rgba(0,0,0,.45);
  color:rgb(var(--m, 77,163,255));
  transition:border-color var(--dur-2) var(--ease), transform var(--dur-2) var(--ease);
}
.pick-mark svg{ display:block; width:100%; height:100%; }
.pick:hover .pick-mark{ border-color:rgba(var(--m, 77,163,255),.85); transform:scale(1.05); }

.pick-titles{ display:flex; flex-direction:column; gap:3px; min-width:0; padding-right:48px; }
.pick-cat{
  font-size:12px; font-weight:600; line-height:1.3;
  color:var(--dim);
}
.pick-name{
  font-size:clamp(19px,1.65vw,22px); font-weight:700;
  letter-spacing:-.02em;
  line-height:1.15;
  color:var(--ink);
}
.pick-desc{
  margin:8px 18px 0;
  font-size:13.5px;
  color:#b4bcc8;
  line-height:1.55;
}
.pick-foot{
  margin-top:auto;
  padding:12px 14px 14px 18px;
  display:flex; align-items:center; justify-content:space-between; gap:10px;
  min-width:0;
}
.pick-meta{
  min-width:0;
  font-size:11.5px; letter-spacing:.01em;
  color:var(--dim);
  font-variant-numeric:tabular-nums;
}
/* "결과 보기" — 누를 수 있게 생긴 알약. 화살표는 카드 색 */
.pick-go{
  flex:0 0 auto;
  display:inline-flex; align-items:center; gap:7px;
  height:32px; padding:0 12px 0 14px;
  font-size:13px; font-weight:600;
  color:#dbe4ef;
  background:rgba(255,255,255,.04);
  border:1px solid rgba(255,255,255,.16);
  border-radius:var(--r-pill);
  white-space:nowrap;
  transition:background var(--dur) var(--ease), border-color var(--dur) var(--ease),
             color var(--dur) var(--ease);
}
.pick-go i{
  font-style:normal;
  color:rgb(var(--m, 77,163,255));
  transition:transform var(--dur) var(--ease), color var(--dur) var(--ease);
}
.pick:hover .pick-go, .pick:focus-visible .pick-go{
  color:#fff;
  background:rgba(var(--m, 77,163,255),.18);
  border-color:rgba(var(--m, 77,163,255),.7);
}
.pick:hover .pick-go i{ transform:translateX(3px); color:#fff; }

/* ── 표식 — 손이 얹히면 저마다 제 방식으로 움직인다 ───────
   KOOS 는 예보 바늘이 돌고, SCHISM 은 절점이 차례로 켜지고, SWAN 은 파도가
   밀려오고, ROMS 는 연직 프로파일이 그려진다. 각 모델이 무엇인지 말로
   설명하기 전에 몸이 먼저 안다 */
@keyframes sweep{ to{ transform:rotate(360deg); } }
@keyframes march{ to{ transform:translateX(-14px); } }
@keyframes blink{
  0%,100%{ opacity:.35; } 50%{ opacity:1; }
}
@keyframes trace{
  from{ stroke-dashoffset:100; } to{ stroke-dashoffset:0; }
}
.m-hand{ transform-box:view-box; transform-origin:24px 24px; }
.pick:hover .m-hand{ animation:sweep 4s linear infinite; }

.m-node{ opacity:.55; }
.pick:hover .m-node{ animation:blink 1.6s var(--ease) infinite; }
.pick:hover .m-node:nth-of-type(2){ animation-delay:.25s; }
.pick:hover .m-node:nth-of-type(3){ animation-delay:.5s; }
.pick:hover .m-node:nth-of-type(4){ animation-delay:.75s; }
.m-far{ transition:opacity var(--dur-2) var(--ease); }
.pick:hover .m-far{ opacity:.7; }

.pick:hover .m-wave{ animation:march linear infinite; }
.pick:hover .m-wave:nth-of-type(1){ animation-duration:2.8s; }
.pick:hover .m-wave:nth-of-type(2){ animation-duration:2.3s; }
.pick:hover .m-wave:nth-of-type(3){ animation-duration:1.9s; }
.pick:hover .m-wave:nth-of-type(4){ animation-duration:2.5s; }

.m-prof{ stroke-dasharray:100; stroke-dashoffset:0; }
.pick:hover .m-prof{ animation:trace 1.2s var(--ease) both; }

/* ── 맨 아랫줄 — 자료 기준 ──────────────────────────────────
   한 줄로 쉼표를 이어 붙이면 훑어 읽을 수 없다. 이름·기준 짝을 표로 */
.intro-foot{
  margin-top:clamp(26px,4vh,40px);
  padding-top:16px;
  border-top:1px solid var(--line);
  display:grid; grid-template-columns:auto minmax(0,1fr);
  gap:4px 28px;
  font-size:12px; line-height:1.7;
  color:var(--dim);
}
.foot-h{ margin:0; font-weight:700; color:var(--dim); white-space:nowrap; }
.foot-list{
  margin:0;
  display:grid; grid-template-columns:repeat(3, minmax(0,1fr));
  gap:2px 28px;
}
.foot-list div{ display:flex; gap:8px; min-width:0; }
.foot-list dt{ flex:0 0 auto; font-weight:600; color:#b4bcc8; }
.foot-list dd{ margin:0; min-width:0; }
.intro-foot .models{
  grid-column:2; margin:6px 0 0;
  font-size:11.5px; color:var(--faint);
}
/* 맨 끝 한 줄 — 누가 만든 곳인지 */
.intro-foot .foot-end{
  grid-column:1 / -1;
  margin:14px 0 0; padding-top:12px;
  border-top:1px solid var(--line);
  display:flex; justify-content:space-between; gap:16px; flex-wrap:wrap;
  font-size:11.5px; color:var(--faint);
}
/* 넓은 화면: 이름·기준 짝을 두 묶음(수치모델 셋 | 응용 서비스 셋)으로 모은다.
   세 칸 균등 분할은 짧은 짝 사이에 빈 틈이 커서 흩어져 보였다 */
@media (min-width:901px){
  .foot-list{
    grid-template-columns:max-content max-content 44px max-content max-content;
    grid-auto-flow:row;
    justify-content:start;
    gap:2px 14px;
  }
  .foot-list div{ display:contents; }
  .foot-list div:nth-child(-n+3) dt{ grid-column:1; }
  .foot-list div:nth-child(-n+3) dd{ grid-column:2; }
  .foot-list div:nth-child(n+4) dt{ grid-column:4; }
  .foot-list div:nth-child(n+4) dd{ grid-column:5; }
  .foot-list div:nth-child(3n+1) > *{ grid-row:1; }
  .foot-list div:nth-child(3n+2) > *{ grid-row:2; }
  .foot-list div:nth-child(3n+3) > *{ grid-row:3; }
}

/* ══ 뷰어 껍데기 ═════════════════════════════════════════ */
.shell{
  position:fixed; inset:0; z-index:3;
  display:grid;
  grid-template-rows:auto 1fr;
  opacity:0;
  transform:translateY(8px);
  transition:opacity var(--dur-2) var(--ease),
             transform var(--dur-2) var(--ease);
  pointer-events:none;
}
body.is-viewer .shell{ opacity:1; transform:none; pointer-events:auto; }
.shell[hidden]{ display:none; }

/* ── 모델 전환 ──────────────────────────────────────────── */
.switch{
  display:flex; align-items:center; gap:3px;
  flex:1 1 auto; min-width:0;
  overflow-x:auto;
  scrollbar-width:none;
}
.switch::-webkit-scrollbar{ display:none; }

.switch .sep{
  flex:0 0 auto;
  width:1px; height:18px;
  margin:0 5px;
  background:var(--line-2);
}
.switch button{
  appearance:none; font:inherit; color:inherit;
  flex:0 0 auto;
  display:flex; flex-direction:column; align-items:flex-start;
  gap:0;
  padding:5px 12px;
  cursor:pointer;
  background:transparent;
  border:1px solid transparent;
  border-radius:var(--r-md);            /* KOOS 모델 탭 9px. 알약이 아니다 */
  line-height:1.25;
  transition:background var(--dur) var(--ease),
             border-color var(--dur) var(--ease);
}
.switch button b{
  font-size:12.5px; font-weight:700;
  color:var(--ink-3);
  transition:color var(--dur) var(--ease);
}
.switch button i{
  font-style:normal;
  font-size:10px;
  color:var(--ink-4);
  white-space:nowrap;
}
.switch button:hover{ background:var(--fill-1); }
.switch button:hover b{ color:var(--ink-2); }
.switch button:focus-visible{ outline:2px solid var(--accent); outline-offset:1px; }
/* 켜진 탭 = KOOS 의 모델 탭. 모델 색 알약에 어두운 글자(#08121f).
   흰 바탕에 색 글자이던 것을 뒤집었다 — 이게 뷰어 넷과 랜딩을 한 식구로
   보이게 하는 표식이다 */
.switch button.is-on{
  background:rgb(var(--accent-rgb));
  border-color:transparent;
}
.switch button.is-on b{ color:var(--on-accent); }
.switch button.is-on i{ color:var(--on-accent); opacity:.66; }
.switch button.is-on:hover{ background:rgb(var(--accent-rgb)); }
.switch button.is-on:hover b{ color:var(--on-accent); }

.pop{
  flex:0 0 auto;
  display:inline-flex; align-items:center; gap:5px;
  padding:7px 13px;
  font-size:12px; font-weight:600;
  color:var(--ink-3);
  text-decoration:none;
  background:var(--fill-1);
  border:1px solid var(--line);
  border-radius:var(--r-md);            /* KOOS .iconbtn.wide 와 같은 9px */
  white-space:nowrap;
  transition:background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.pop:hover{ background:var(--fill-2); color:var(--ink); }

/* ── 뷰어가 들어가는 자리 ───────────────────────────────── */
.stage{ position:relative; min-height:0; background:var(--bg); }
.stage iframe{
  display:block;
  width:100%; height:100%;
  border:0;
}

.loading{
  position:absolute; inset:0; z-index:2;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:6px; padding:24px;
  text-align:center;
  background:var(--bg);
}
.loading[hidden]{ display:none; }
.loading p{ margin:0; font-size:13px; color:var(--ink-3); }
.loading .loading-sub{ font-size:11.5px; color:var(--ink-4); max-width:56ch; }
.spin{
  width:26px; height:26px; margin-bottom:12px;
  border:2px solid var(--line-2);
  border-top-color:rgb(var(--accent-rgb));
  border-radius:50%;
  animation:spin .9s linear infinite;
}
@keyframes spin{ to{ transform:rotate(360deg); } }

/* ── 좁은 화면 ──────────────────────────────────────────── */

/* 태블릿·세로 노트북: 숫자는 소개글 바로 아래 한 줄, 카드는 한 줄에 하나.
   카드는 가로 한 줄(화면 조각 · 분류/이름/설명 · 화살표)로 눕힌다 */
@media (max-width:900px){
  .intro-inner{
    grid-template-columns:1fr;
    grid-template-areas:"top" "head" "facts" "picks" "foot";
    column-gap:0;
  }
  .intro-head{ max-width:none; }

  .facts{
    margin:22px 0 0; padding:16px 0 0;
    border-left:0; border-top:1px solid var(--line);
    grid-template-columns:repeat(4, auto); justify-content:start;
    gap:14px 32px;
  }
  .facts b{ font-size:24px; }
  .facts small{ font-size:13px; }
  .facts span{ font-size:12.5px; }

  .picks-row{ grid-template-columns:1fr; gap:10px; }

  .pick{
    display:grid;
    grid-template-columns:128px minmax(0,1fr) auto;
    grid-template-areas:"thumb top go" "thumb desc go";
    grid-template-rows:auto 1fr;
    column-gap:16px;
    padding:12px 14px 12px 12px;
    align-items:center;
  }
  .pick-thumb{
    grid-area:thumb; align-self:stretch;
    height:auto; min-height:88px;
    border:1px solid var(--line); border-radius:var(--r-sm);
  }
  .pick-thumb::after{ display:none; }
  .pick-top{ grid-area:top; padding:0; align-self:end; }
  .pick-mark{ display:none; }        /* 화면 조각이 표식 몫을 한다 */
  .pick-titles{ padding-right:0; }
  .pick-desc{ grid-area:desc; align-self:start; margin:4px 0 0; font-size:13px; }
  .pick-foot{ grid-area:go; margin:0; padding:0; }
  .pick-meta{ display:none; }
  .pick-go{ width:36px; height:36px; padding:0; justify-content:center; }
  .pick-go span{ display:none; }     /* 화살표만 남긴다. 알약은 그대로 둥글게 */

  .intro-foot{ grid-template-columns:1fr; }
  .foot-list{ grid-template-columns:repeat(2, minmax(0,1fr)); }
  .intro-foot .models{ grid-column:1; }
}

@media (max-width:640px){
  .bg-flow{ opacity:.36; }
  .bg-veil::before{ display:none; }   /* 좁은 화면에서 격자는 소음이다 */

  .intro-inner{ padding:8px 0 6px; }
  .intro-top{ margin-bottom:26px; }
  .intro-head h1{ font-size:clamp(28px,8.4vw,40px); }  /* 360px 에서 열두 글자 ≈ 270px, 한 줄 */
  .intro-lede{ font-size:14.5px; }

  .facts{ grid-template-columns:repeat(2, minmax(0,1fr)); gap:16px 20px; }
  .facts b{ font-size:24px; }

  .picks{ gap:18px; }
  .pick-label{ font-size:14px; }
  .pick-label em{ font-size:12px; }
  .pick-label::after{ display:none; }
  .pick{
    grid-template-columns:84px minmax(0,1fr) auto;
    column-gap:13px;
    padding:11px 12px 11px 11px;
  }
  .pick-thumb{ min-height:84px; }
  .pick-name{ font-size:18px; }
  .pick-desc{ font-size:12.5px; margin-top:3px; }

  .foot-list{ grid-template-columns:1fr; }

  /* 언어 단추 — 손가락 자리 44×40 */
  .intro-lang a,.intro-lang span{ min-width:44px; min-height:36px; padding:0 12px; display:grid; place-items:center; }
}

/* ── 움직임을 줄여 달라고 했으면 줄인다 ─────────────────── */
@media (prefers-reduced-motion:reduce){
  *{ transition:none !important; animation:none !important; }
  .bg-flow{ display:none; }
  .proj:has(.pick:hover){ transform:none; }
  .pick:hover .pick-mark{ transform:none; }
}

/* ══ 프로젝트 막대 ═══════════════════════════════════════════════
   UST21 로고 옆에 프로젝트 셋을 그냥 늘어놓는다. 누르면 바뀐다. 여닫는
   메뉴도, 부채꼴도, 설명 글자도 없앴다 — 보이는 대로 누르면 되는 게 제일
   빠르다. 로고는 첫 화면으로 돌아가는 단추다.

   단추마다 제 색을 준다(첫 화면의 판 색과 같은 값). 지금 보는 것이
   어느 프로젝트인지 글자를 읽지 않고도 알게 하려는 것이다. */
.launcher{
  position:fixed; z-index:6;
  top:calc(12px + env(safe-area-inset-top));
  left:calc(12px + env(safe-area-inset-left));
  display:flex; align-items:center; gap:4px;
  padding:5px 6px 5px 5px;
  background:var(--glass);
  backdrop-filter:var(--blur); -webkit-backdrop-filter:var(--blur);
  border:1px solid var(--line);
  border-radius:var(--r-pill);
  box-shadow:var(--shadow);
  opacity:0; pointer-events:none;
  transition:opacity var(--dur-2) var(--ease);
}
body.is-viewer .launcher{ opacity:1; pointer-events:auto; }

/* 로고 = 첫 화면으로 */
.lnch-btn{
  appearance:none; font:inherit; padding:6px 9px;
  display:grid; place-items:center; cursor:pointer;
  background:transparent; border:0; border-radius:var(--r-pill);
  transition:background var(--dur) var(--ease);
}
.lnch-btn:hover{ background:var(--fill-1); }
.lnch-btn:focus-visible{ outline:2px solid var(--accent); outline-offset:-1px; }
.lnch-btn img{ height:16px; width:auto; display:block; opacity:.9; }

/* 로고와 프로젝트 사이 가는 선 하나 */
/* 지금 보는 프로젝트 — 알약에 이름 하나만. 색은 app.js 가 --accent-rgb 로
   흘려 주므로 여기서 모델마다 또 적지 않는다(두 곳이 어긋날 자리를 안 만든다) */
.lnch-now{
  appearance:none; font:inherit; cursor:pointer;
  display:flex; align-items:center; gap:6px;
  margin-left:5px; padding:5px 9px 5px 11px;
  border:1px solid rgba(var(--accent-rgb), .40);
  border-radius:var(--r-pill);
  background:rgba(var(--accent-rgb), .16);
  color:var(--ink);
  max-width:min(46vw, 260px);
  transition:background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.lnch-now b{
  font-size:12.5px; font-weight:700; letter-spacing:-.01em;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.lnch-now .lnch-caret{
  width:12px; height:12px; flex:0 0 auto; opacity:.7;
  transition:transform var(--dur) var(--ease);
}
.lnch-now:hover{ background:rgba(var(--accent-rgb), .24); border-color:rgba(var(--accent-rgb), .58); }
.lnch-now:focus-visible{ outline:2px solid rgb(var(--accent-rgb)); outline-offset:1px; }
.launcher.is-open .lnch-now .lnch-caret{ transform:rotate(180deg); }
.launcher.is-open .lnch-now{ background:rgba(var(--accent-rgb), .26); }

/* 펼친 판 — **떠 있다.** 자리를 안 먹으므로 뷰어의 왼쪽 위 판을 안 민다 */
.lnch-menu{
  position:absolute; z-index:1;
  top:calc(100% + 7px); left:0;
  min-width:272px;
  padding:6px;
  display:flex; flex-direction:column; gap:3px;
  /* **거의 불투명하게.** 이 판은 뷰어 지도 위에 뜨는데, 고수온·부산 트윈은
     밝은 지도라 반투명이면 글씨가 묻힌다. 유리 느낌은 흐림으로 내고
     바탕은 읽히도록 채운다. backdrop-filter 를 못 쓰는 브라우저에서도
     이 값 하나로 읽히므로 따로 대비책을 두지 않는다. */
  /* **단색이다. 유리로 두지 않는다.**
     backdrop-filter 를 걸면 뒤엣것이 다시 끌려 올라온다 — 바탕을 .976 까지
     채워도 뷰어 글자가 그대로 비쳤다(실제로 찍어서 확인했다). 이 판은 밝은
     지도(고수온·부산 트윈) 위에 뜨므로 읽히는 것이 먼저다.
     알약(.launcher)은 작아서 유리로 둬도 안 읽힐 것이 없으니 그대로 둔다. */
  background:#0d131c;
  border:1px solid rgba(255,255,255,.14);
  border-radius:var(--r-md);
  box-shadow:0 14px 40px rgba(0,0,0,.62), 0 2px 8px rgba(0,0,0,.45);
  animation:lnch-drop .16s var(--ease) backwards;
}
.lnch-menu[hidden]{ display:none; }
@keyframes lnch-drop{ from{ opacity:0; transform:translateY(-6px); } to{ opacity:1; transform:none; } }
/* 첫 줄 — 전체 목록(첫 화면)으로. 로고를 눌러도 되지만 그걸 아는 사람은 적다 */
.lnch-home{
  appearance:none; font:inherit; cursor:pointer;
  display:grid; grid-template-columns:16px minmax(0,1fr);
  column-gap:10px; align-items:center;
  width:100%; min-height:44px; padding:6px 12px 6px 10px;
  text-align:left; color:var(--ink);
  background:transparent; border:0; border-radius:var(--r-sm);
  transition:background var(--dur) var(--ease);
}
.lnch-home svg{ grid-row:span 2; width:16px; height:16px; color:var(--dim); }
.lnch-home b{ font-size:13.5px; font-weight:600; line-height:1.3; }
.lnch-home i{ font-style:normal; font-size:11.5px; line-height:1.3; color:var(--dim); }
.lnch-home:hover{ background:rgba(255,255,255,.045); }
.lnch-home:focus-visible{ outline:2px solid var(--accent); outline-offset:-2px; }

.lnch-grp{
  margin:6px 0 2px; padding:8px 12px 0;
  border-top:1px solid var(--line);
  font-size:11.5px; font-weight:700; letter-spacing:0;
  color:var(--dim);
}
:lang(en) .lnch-grp{ font-size:10.5px; letter-spacing:.06em; text-transform:uppercase; }
.lnch-menu .switch{ display:flex; flex-direction:column; gap:2px; overflow:visible; }

/* 항목은 모두 같은 중립 바탕. 프로젝트 색은 왼쪽 점 하나로만 —
   색 바탕 여섯이 나란히 서면 탁한 얼룩이 된다. 켜진 것은 제 색 막대와 옅은 바탕 */
.lnch-menu .switch button{
  appearance:none; font:inherit; cursor:pointer;
  position:relative;
  display:grid; grid-template-columns:8px minmax(0,1fr);
  column-gap:12px; row-gap:1px; align-items:center;
  width:100%; min-height:48px; padding:6px 12px 6px 12px;
  white-space:nowrap; text-align:left;
  color:var(--ink);
  background:transparent;
  border:0; border-radius:var(--r-sm);
  transition:background var(--dur) var(--ease);
}
.lnch-menu .switch button::before{
  content:''; grid-row:span 2;
  width:8px; height:8px; border-radius:50%;
  background:rgb(var(--m, 77,163,255));
}
.lnch-menu .switch button b{ font-size:13.5px; font-weight:600; letter-spacing:-.01em; line-height:1.3; color:var(--ink); }
.lnch-menu .switch button i{ display:block; font-style:normal; font-size:11.5px; line-height:1.3; color:var(--dim); opacity:1; }
/* 얹힌 것은 아주 옅은 회색만 — 켜진 것(제 색 막대 + 밝힌 바탕)과 헷갈리지 않게 */
.lnch-menu .switch button:hover{ background:rgba(255,255,255,.045); }
.lnch-menu .switch button:hover b{ color:#fff; }
.lnch-menu .switch button:focus-visible{ outline:2px solid rgb(var(--m, 77,163,255)); outline-offset:-2px; }
.lnch-menu .switch button.is-on{
  /* 제 색은 .10 만, 그 밑에 중립 밝힘을 깐다 — 주황·갈색 계열이 탁해지지 않게 */
  background:linear-gradient(rgba(var(--m, 77,163,255), .10), rgba(var(--m, 77,163,255), .10)), rgba(255,255,255,.06);
  box-shadow:inset 3px 0 0 rgb(var(--m, 77,163,255));
}
.lnch-menu .switch button.is-on b{ color:#fff; font-weight:700; }
.lnch-menu .switch button.is-on i{ color:#c3cedc; }
.lnch-menu .switch button.is-on:hover{ background:linear-gradient(rgba(var(--m, 77,163,255), .13), rgba(var(--m, 77,163,255), .13)), rgba(255,255,255,.07); }

/* 프로젝트 색 — 첫 화면 카드(.pick)·app.js 의 MODELS 와 같은 값. 여섯 다 있어야 한다 */
.lnch-menu .switch button[data-model="koos"]     { --m:96,176,232; }
.lnch-menu .switch button[data-model="kop"]      { --m:108,214,208; }
.lnch-menu .switch button[data-model="roms"]     { --m:226,160,92; }
.lnch-menu .switch button[data-model="seaheat"]  { --m:240,128,104; }
.lnch-menu .switch button[data-model="searoute"] { --m:150,170,240; }
.lnch-menu .switch button[data-model="busantwin"]{ --m:196,150,232; }

.shell{ grid-template-rows:1fr; }

/* 좁아지면 알약을 조금 줄인다. 메뉴는 떠 있는 판이라 이름을 줄일 까닭이 없다 */
@media (max-width:900px){
  .launcher{ top:calc(9px + env(safe-area-inset-top)); left:calc(9px + env(safe-area-inset-left)); }
}
@media (max-width:560px){
  .lnch-btn{ padding:5px 7px; }
  .lnch-btn img{ height:14px; }
  .lnch-menu{ min-width:0; width:min(300px, calc(100vw - 24px)); }
}
