/* ════════ 공용 UI 레이어 — 디자인 토큰의 단일 소스 ════════
 *
 * 왜 있나: 같은 값(--sh-card·--r-lg·--t)이 페이지마다 :root 로 복제돼 있어, 한 페이지를
 * 손보면 나머지가 뒤처지는 드리프트가 반복됐다. 여기 한 곳만 고치면 전 페이지가 함께 올라간다.
 *
 * 어떻게 쓰나: 페이지 <head> 에서 nav.css 다음, 페이지 <style> **앞**에 링크한다.
 *   <link rel="stylesheet" href="{{ url_for('static', filename='ui.css') }}">
 * 페이지 고유 규칙이 뒤에 오므로 레이아웃은 그대로고, 페이지가 정의하지 않은 값만 여기서 온다.
 * (그래서 페이지 :root 에서 --sh-card 같은 중복 정의를 지워야 이 값이 실제로 적용된다.)
 *
 * 스타일 기조: 미니멀리즘 + 벤또 그리드. 여기에 2026 트렌드 중 '레이어·깊이감'과
 * '마이크로 인터랙션'만 절제해서 더한다. 효과가 글자를 방해하면 넣지 않는다(가독성 우선).
 *
 * ── 토큰 이름 규칙 (2026-08-03, astryx 디자인시스템에서 이식) ──
 * 이름은 **쓰임(purpose)** 으로 짓는다, 모양이 아니라. `--color-text-secondary` 는 되고
 * `--gray-600` 은 안 된다. 값이 바뀌어도 이름이 계속 맞아야 하기 때문이다.
 * 그래서 페이지 CSS 에는 생 hex·생 px 이 없어야 한다 — 전부 아래 토큰을 참조한다.
 * (astryx 는 React 컴포넌트 라이브러리라 Jinja 템플릿엔 못 쓴다. 가져온 건 토큰 체계뿐이고
 *  값은 기존 애플 계열 정체성 — parchment #f2f2f5 · 잉크 #1d1d1f · Action Blue #0066cc — 그대로다.)
 */

:root{
  /* ════════ 색 — 목적으로 이름 짓는다 ════════ */

  /* 액션: 파랑 하나로 통일. 이 앱에서 '누를 수 있다'는 뜻은 이 색뿐이다 */
  --color-accent:#0066cc;
  --color-accent-hover:#0058b0;
  --color-accent-pressed:#0a4a95;
  --color-accent-focus:#0071e3;          /* 포커스 링만 살짝 밝게 — 배경 위에서 더 잘 보인다 */
  --color-accent-muted:rgba(0,102,204,.10);
  --color-on-accent:#fff;

  /* 표면: body → surface/card → muted 순으로 종이가 한 겹씩 쌓인다 */
  --color-background-body:#f2f2f5;
  --color-background-surface:#fff;
  --color-background-card:#fff;
  --color-background-muted:#f6f6f8;
  --color-background-pearl:#fafafc;
  --color-background-inverted:#1d1d1f;

  /* 글자: primary → secondary → tertiary 로 갈수록 옅어진다.
     tertiary(#6e6e74)가 하한선이다 — 이보다 옅으면 WCAG AA(4.5:1)를 깬다(아래 대비 메모 참고) */
  --color-text-primary:#1d1d1f;
  --color-text-primary-hover:#3a3a3e;   /* 잉크를 한 톤만 풀어 호버를 알린다(서브내비 링크) */
  --color-text-secondary:#66666b;
  --color-text-tertiary:#6e6e74;
  --color-text-disabled:#a1a1a6;
  --color-text-on-inverted:#fff;
  --color-text-on-inverted-secondary:#a1a1a6;   /* 잉크 타일 위 보조문구 */

  /* 선: border → emphasized 로 갈수록 진해진다. subtle 은 구분선용 */
  --color-border:#e8e8ed;
  --color-border-emphasized:#dcdce1;
  --color-border-subtle:#f0f0f2;

  /* 상태 */
  --color-error:#b42318;
  --color-error-muted:#fbeae7;
  /* 상태색 — 페이지마다 :root 에 흩어져 있던 값을 여기로 모았다(가장 많이 쓰인 값 채택:
     `--ok:#1d8a4f` 10곳). 정의가 없던 탓에 `.msg.ok{color:var(--ok)}` 같은 선언이 조용히
     버려져 성공 문구가 초록으로 뜨지 않았다. */
  --color-success:#1d8a4f;
  --color-success-muted:#eaf6ee;
  --color-info:#1d5fa8;
  --color-info-muted:#eaf1fb;
  --color-warning:#8a5a00;
  --color-warning-muted:#fdf3e2;

  /* 라임 포인트 — 어두운 잉크 글자만 얹어 대비를 확보한다(밝은 글자는 얹지 않는다) */
  --color-lime:#c9f24a;
  --color-text-on-lime:#1a2400;
  --color-text-on-lime-secondary:#3f5200;

  /* ── 보조 텍스트 대비 메모 ──
     #86868b 은 캔버스(#f2f2f5)에서 3.24:1, 흰배경 3.62:1 로 WCAG AA(4.5) 미달이었다
     (13.5px 보조문구·11px 라벨에서 계산 검출, 2026-07-28). 두 배경 모두 통과하는 값으로 올렸다:
     --color-text-tertiary #6e6e74 = 4.53:1 / 5.07:1. 더 옅게 내리지 말 것. */

  /* ════════ 여백 — 4px 배수 한 벌 ════════
   * 스케일 밖의 값(7px·26px·46px 처럼)을 쓰면 페이지마다 리듬이 어긋난다. 여기서 골라 쓴다. */
  --spacing-0:0;
  --spacing-0-5:2px;
  --spacing-1:4px;
  --spacing-1-5:6px;
  --spacing-2:8px;
  --spacing-3:12px;
  --spacing-4:16px;
  --spacing-5:20px;
  --spacing-6:24px;
  --spacing-7:28px;
  --spacing-8:32px;
  --spacing-9:36px;
  --spacing-10:40px;
  --spacing-11:44px;
  --spacing-12:48px;

  /* ════════ 모서리 ════════
   * 이름이 곧 쓰임이다: inner(칩·배지 안쪽) → element(버튼·입력) → container(카드) → page(큰 타일) */
  --radius-inner:10px;
  --radius-element:14px;
  --radius-container:18px;
  --radius-page:22px;
  --radius-full:999px;

  /* ════════ 깊이감: 3단 레이어 ════════
   * 얕은 한 겹보다 두 겹이 종이처럼 뜬다.
   * 단계는 "그림자를 얼마나 주고 싶은가"가 아니라 "이 면이 페이지에서 얼마나 떠 있나"로 고른다.
   * 한 면에 한 단계만. low=페이지에 놓인 카드 · med=주변 위로 뜬 것(호버·팝오버) · high=화면 전체 위(모달). */
  --shadow-low:0 1px 2px rgba(20,20,32,.05), 0 4px 14px rgba(20,20,32,.05);
  --shadow-med:0 2px 6px rgba(20,20,32,.07), 0 18px 40px rgba(20,20,32,.10);
  --shadow-high:0 8px 24px rgba(20,20,32,.12), 0 32px 64px rgba(20,20,32,.14);

  /* ════════ 타이포 ════════
   * 크기와 굵기를 쌍으로 묶어둔다 — 한쪽만 바뀌면 위계가 무너지기 때문이다.
   * caption(12px)이 한글 하한선이다. 11px 한글은 읽기 어려워 쓰지 않는다. */
  --font-family-body:-apple-system,BlinkMacSystemFont,'Pretendard','Pretendard Variable',system-ui,sans-serif;

  --text-display-size:32px;    --text-display-weight:700;    --text-display-tracking:-.03em;
  --text-heading-1-size:26px;  --text-heading-1-weight:700;  --text-heading-1-tracking:-.03em;
  --text-heading-2-size:19px;  --text-heading-2-weight:600;  --text-heading-2-tracking:-.02em;
  --text-heading-3-size:17px;  --text-heading-3-weight:600;  --text-heading-3-tracking:-.02em;
  --text-body-size:15px;       --text-body-weight:400;       --text-body-leading:1.5;
  --text-label-size:13px;      --text-label-weight:400;      --text-label-leading:1.5;
  --text-caption-size:12px;    --text-caption-weight:400;

  /* ════════ 모션 ════════
   * 감속 곡선 하나로 통일(제각각이면 앱이 산만해진다).
   * fast=마이크로 인터랙션 · medium=등장/퇴장 · slow=진입 시퀀스 */
  --ease-standard:cubic-bezier(.22,.61,.36,1);
  --duration-fast:.2s;
  --duration-medium:.32s;
  --duration-slow:.55s;

  /* ════════ 구 이름 → 새 토큰 별칭 ════════
   * 기존 18개 페이지가 이 이름들로 쓰고 있다(--sh-card 34곳·--muted-2 84곳·--t 55곳 등).
   * 값을 여기 복제하지 않고 위 토큰을 가리키게 해서 실제 소스는 한 곳만 남긴다.
   * 새로 쓰는 CSS 에는 아래 별칭 대신 위의 정식 이름을 쓴다.
   *
   * ── 왜 색 별칭까지 여기 있나 (2026-08-03) ──
   * nav.css 는 토큰을 하나도 정의하지 않고 12개(--ac·--canvas·--ink·--line·--muted-3·--pill 등)를
   * **참조만** 한다. 그래서 지금까지는 페이지마다 :root 에 그 값들을 다시 선언해야 공용 내비가
   * 제 색으로 떴다 — 이게 페이지별 :root 복제(=드리프트)의 실제 원인이었다.
   * 여기서 한 번 채워주면 페이지는 그 보일러플레이트 없이도 내비가 정상 렌더된다. */
  --ac:var(--color-accent);
  /* 별칭 4개는 템플릿 22개가 참조하는데 정의된 곳이 없었다 — `var(--ac-2)` 가 무효값이 되어
     **모든 primary 버튼이 hover 시 흰색으로 사라졌다**(사용자 지적: '전부 올리기' 버튼).
     페이지가 :root 에서 덮어쓰면 그쪽이 이긴다(인라인 style 이 나중에 온다). */
  --ac-2:var(--color-accent-hover);
  --ac-focus:var(--color-accent-focus);
  --ac-ink:var(--color-on-accent);
  --ac-soft:var(--color-accent-muted);
  --canvas:var(--color-background-body);
  /* 표면 별칭 3개도 정의된 적이 없었다(2026-08-20 실측: `/brand-kit` 에서 `--surface` 미정의 →
     `.card{background:var(--surface)}` 가 **무효 선언으로 버려져** 카드 배경이 투명이었다.
     ui.css 의 다른 규칙이 우연히 가려 줘서 눈에 안 띄었을 뿐이다). 아래 린트가 재발을 막는다. */
  --surface:var(--color-background-surface);
  --sans:var(--font-family-body);
  --ok:var(--color-success);
  --ok-soft:var(--color-success-muted);
  --hair:var(--color-border-subtle);
  --tint:var(--color-accent-muted);
  --info:var(--color-info);
  --info-soft:var(--color-info-muted);
  --warn:var(--color-warning);
  --warn-soft:var(--color-warning-muted);
  --raise:var(--color-background-muted);
  --pearl:var(--color-background-pearl);
  --ink:var(--color-text-primary);
  --ink-2:var(--color-text-primary-hover);
  --muted:var(--color-text-secondary);
  --muted-3:var(--color-text-disabled);
  --line:var(--color-border-emphasized);
  --line-2:var(--color-border);
  --danger:var(--color-error);
  --pill:var(--radius-full);
  --sh-card:var(--shadow-low);
  --sh-lift:var(--shadow-med);
  --sh-pop:var(--shadow-high);
  --muted-2:var(--color-text-tertiary);
  --r-sm:var(--radius-inner);
  --r-md:var(--radius-element);
  --r-lg:var(--radius-container);
  --r-xl:var(--radius-page);
  --r-pill:var(--radius-full);
  --ease:var(--ease-standard);
  --t:var(--duration-fast) var(--ease-standard);
  --t-slow:var(--duration-medium) var(--ease-standard);
}

/* ════════ 히어로 오로라 — 페이지 상단에 옅은 깊이 한 겹 ════════
 * .ui-hero 를 헤더 컨테이너에 붙이면 뒤로 그라디언트가 깔린다.
 * 사각형 경계가 보이면 싼 티가 나므로 마스크로 가장자리를 지워 스며들게 한다. */
.ui-hero{position:relative;isolation:isolate}
/* 크기를 호스트 상대(%)로 주면 인사말처럼 작은 블록에선 오로라도 같이 작아져 안 보인다.
   상단 기준 고정 높이로 깔아 어느 페이지든 같은 세기로 읽히게 한다. */
.ui-hero::before{
  content:"";position:absolute;top:-160px;left:-25%;right:-25%;height:560px;
  pointer-events:none;z-index:-1;
  background:
    radial-gradient(40% 52% at 24% 46%, rgba(0,102,204,.18), transparent 72%),
    radial-gradient(36% 48% at 76% 34%, rgba(201,242,74,.22), transparent 72%),
    radial-gradient(32% 44% at 54% 72%, rgba(120,90,255,.12), transparent 72%);
  filter:blur(46px);
  -webkit-mask-image:radial-gradient(68% 62% at 46% 46%, #000 28%, transparent 78%);
          mask-image:radial-gradient(68% 62% at 46% 46%, #000 28%, transparent 78%);
}

/* ════════ 마이크로 인터랙션 ════════
 * "완성도 차이는 여기서 갈린다" — 누를 수 있다는 걸 손끝으로 알려주는 최소 반응. */

/* 들어올리기 — 카드·타일처럼 클릭 가능한 표면에. 쉴 때 높이에서 딱 한 단계만 올린다(low → med).
 * 여기서 정식 이름(--shadow-*)이 아니라 별칭을 쓰는 건 의도다: 페이지가 --sh-card 를 자기 값으로
 * 덮어썼으면 :active 는 그 페이지의 '쉴 때 그림자'로 돌아가야 한다. 정식 이름을 박아두면
 * 카드가 실제로 쉬는 높이와 다른 그림자로 내려앉아 어긋난다. 지역 재정의가 사라지면 둘은 같아진다. */
.ui-lift{transition:transform var(--t), box-shadow var(--t), border-color var(--t)}
.ui-lift:hover{transform:translateY(-3px);box-shadow:var(--sh-lift)}
.ui-lift:active{transform:translateY(-1px);box-shadow:var(--sh-card)}

/* 눌림 — 버튼처럼 즉시 반응해야 하는 것에 */
.ui-press{transition:transform var(--t), box-shadow var(--t), background var(--t)}
.ui-press:hover{transform:translateY(-1px)}
.ui-press:active{transform:translateY(0)}

/* 포커스 링 — 키보드 사용자가 지금 어디인지 항상 보이게(접근성 기본)
   페이지가 --ac-focus 로 덮어쓴 경우를 존중하고, 없으면 토큰으로 떨어진다 */
.ui-lift:focus-visible,.ui-press:focus-visible{
  outline:2px solid var(--ac-focus,var(--color-accent-focus));outline-offset:2px}

/* 모션 최소화 설정을 존중 — 어지럼증·전정기관 이슈 */
@media(prefers-reduced-motion:reduce){
  .ui-lift,.ui-press{transition:none}
  .ui-lift:hover,.ui-press:hover,.ui-lift:active,.ui-press:active{transform:none}
}

/* ════════ 파일 선택 (.ui-file) ════════
 * 브라우저 기본 `<input type=file>` 은 OS 크롬("파일 선택 | 선택된 파일 없음")을 그대로 그려
 * 어떤 디자인에도 맞지 않는다. 그래서 **네이티브 입력을 화면에서 감추고 라벨을 버튼처럼** 쓴다.
 * `display:none` 이 아니라 크기 0 + opacity 0 인 이유: display:none 은 포커스를 받지 못해
 * 키보드로 파일을 고를 수 없다.
 *
 *   <label class="ui-file">
 *     <input type="file" id="x" multiple accept="...">
 *     <span class="ui-file-btn">파일 고르기</span>
 *     <span class="ui-file-name">선택된 파일 없음</span>
 *   </label>
 *
 * 라벨 텍스트 갱신은 `static/js/uifile.js` 가 위임 리스너로 알아서 한다(페이지 JS 불필요).
 */
.ui-file{display:inline-flex;align-items:center;gap:10px;cursor:pointer;max-width:100%}
.ui-file input[type=file]{position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
.ui-file-btn{display:inline-flex;align-items:center;gap:6px;white-space:nowrap;
  border:1px solid var(--line,var(--color-border-emphasized));
  background:var(--surface,var(--color-background-surface));
  color:var(--ink,var(--color-text-primary));
  padding:9px 15px;border-radius:var(--pill,var(--radius-full));
  font:inherit;font-size:13.5px;font-weight:600;transition:var(--t,150ms ease)}
.ui-file:hover .ui-file-btn{background:var(--raise,var(--color-background-muted))}
.ui-file input[type=file]:focus-visible + .ui-file-btn{
  outline:2px solid var(--ac-focus,var(--color-accent-focus));outline-offset:2px}
.ui-file-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-size:12.5px;color:var(--muted-2,var(--color-text-tertiary))}
.ui-file[data-picked="1"] .ui-file-name{color:var(--ink,var(--color-text-primary))}

/* ════════ 접이식 도움말 (.ui-help) ════════
 * 화면에 설명을 늘어놓으면 읽지 않는다. 한 줄만 남기고 "왜/한계" 는 접어 둔다. */
.ui-help{margin-top:6px}
.ui-help > summary{cursor:pointer;font-size:12px;color:var(--ac,var(--color-accent));
  list-style:none;display:inline-flex;align-items:center;gap:4px}
.ui-help > summary::-webkit-details-marker{display:none}
.ui-help > summary::before{content:"?";display:inline-grid;place-items:center;width:14px;height:14px;
  border-radius:50%;border:1px solid currentColor;font-size:10px;font-weight:700}
.ui-help > div{margin-top:6px;font-size:12px;line-height:1.7;
  color:var(--muted-2,var(--color-text-tertiary))}
