@layer tokens, base, components, utilities;

@import url("https://cdn.jsdelivr.net/gh/orioncactus/pretendard@1.3.9/dist/web/static/pretendard.min.css");

/* =========================================================================
   엘리스트랙 레이서 생활기록부 — 스타일시트

   구조: @layer tokens → base → components → utilities
        레이어 순서가 우선순위를 고정하므로, 나중에 쓴 규칙이 실수로
        토큰이나 base를 덮어쓰는 사고가 구조적으로 발생하지 않는다.

   색: elice_brand color.pdf (Brand Div. Design Team, EliceGroup, 2023.10)
       Elice Violet #6700e6 / 공식 10단계 램프 / Color Scheme 6:3:1
       (base 60 : sub 30 : point 10 — 진보라는 액션·수치에만)

   차트 팔레트는 dataviz 검증기 통과값. 임의로 바꾸지 말 것:
       카테고리컬 CVD ΔE 9.1(light) / 8.4(dark), 일반시야 22.9 / 19.8

   구획 찾기(검색용):
     [T] 토큰      [B] 베이스     [C-NAV] 상단바·네비  [C-BAR] 기수바
     [C-BTN] 버튼  [C-FORM] 폼    [C-CARD] 카드        [C-TBL] 표
     [C-TAG] 상태  [C-KPI] KPI    [C-LC] 라이프사이클  [C-CHART] 차트
     [C-CAL] 달력  [C-ATT] 출석   [C-SURVEY] 설문      [C-PEER] 동료평가
     [C-SCHED] 시간표  [C-GANTT] 간트  [C-TL] 타임라인 [C-LOGIN] 로그인
     [U] 유틸리티  [P] 인쇄
   ========================================================================= */


/* ═══════════════════════════════════════════════════════════ [T] 토큰 ══ */
@layer tokens {
  :root {
    color-scheme: light;

    /* ── 엘리스 공식 램프 (원시값 — 역할 토큰을 통해서만 쓴다) ───────── */
    --v-900:#230054; --v-800:#4700a8; --v-700:#6700e6; --v-600:#7126f4;
    --v-500:#804cff; --v-400:#8f6cff; --v-300:#aa8dff; --v-200:#c6b3ff;
    --v-100:#dfd6ff; --v-050:#f2effb;

    /* 중립 램프 — 6:3:1의 base 60을 담당. 보라 기운을 살짝 섞어 브랜드와 붙는다 */
    --n-950:#12101a; --n-900:#1c1430; --n-800:#332c4a; --n-700:#4c4566;
    --n-600:#6b6483; --n-500:#8b86a0; --n-400:#aeaabe; --n-300:#cfccdb;
    --n-200:#e9e6f2; --n-100:#f2f0f7; --n-050:#f6f5fa; --n-000:#ffffff;

    /* ── 역할 토큰 (화면은 이것만 참조) ──────────────────────────────── */
    --bg:          var(--n-050);
    --surface:     var(--n-000);
    --surface-2:   var(--n-100);
    --surface-3:   var(--n-200);
    --ink:         var(--n-900);   /* 17.6:1 */
    --ink-2:       var(--n-700);   /*  8.9:1 */
    --muted:       var(--n-600);   /*  5.1:1 — 기존 #8b86a0는 3.2:1로 본문 대비 미달이었다 */
    --line:        var(--n-200);
    --line-strong: var(--n-300);

    --brand:        var(--v-700);
    --brand-strong: var(--v-800);
    --brand-soft:   var(--v-050);
    --brand-soft-2: var(--v-100);
    --on-brand:     #ffffff;

    /* 상태 — 텍스트/테두리용(대비 확보)과 차트 마크용을 분리 */
    --ok:#0b7a42;      --ok-soft:#e7f7ee;   --ok-line:#b7e6cb;
    --warn:#a04a08;    --warn-soft:#fdf3e3; --warn-line:#f3d9a8;
    --danger:#c02626;  --danger-soft:#fdecec; --danger-line:#f4c2c2;
    --info:#1e5fa8;    --info-soft:#e8f1fb; --info-line:#b9d5f0;

    /* ── 차트 팔레트 (dataviz 검증 통과 — 변경 시 재검증 필수) ───────── */
    /* 카테고리컬: 정체성 구분. 고정 순서, 절대 순환/생성 금지 */
    --cat-1: var(--v-700);   /* 엘리스 바이올렛 */
    --cat-2: #eb6834;        /* orange */
    --cat-3: #1baf7a;        /* aqua   — 흰 배경 2.82:1 → 직접 라벨 의무 */
    --cat-4: #eda100;        /* yellow — 흰 배경 2.17:1 → 직접 라벨 의무 */
    --cat-neutral: var(--n-400);   /* 온라인·기타 등 비강조 */

    /* 순차(ordinal 4단): 크기 비교 — 히트맵. 한 색상, 밝은→진한 */
    --seq-1: var(--v-300); --seq-2: var(--v-500);
    --seq-3: var(--v-700); --seq-4: var(--v-800);

    /* 발산(Likert 5점): 중립을 가운데. 극이 서로 반대로 읽혀야 한다 */
    --div-pos-2: var(--v-800); --div-pos-1: var(--v-500);
    --div-mid:   var(--n-300);
    --div-neg-1: #f0a882;      --div-neg-2: #d4551f;

    /* 차트 크롬 */
    --grid-line: var(--n-200);
    --axis-line: var(--n-300);
    --chart-surface: var(--surface);

    /* ── 타입 스케일 (한글 기준 — 크기마다 줄간격·자간을 따로 준다) ──── */
    --fs-display:28px; --lh-display:1.15; --ls-display:-0.02em;
    --fs-h1:22px;      --lh-h1:1.3;       --ls-h1:-0.01em;
    --fs-h2:15px;      --lh-h2:1.4;       --ls-h2:-0.005em;
    --fs-body:14px;    --lh-body:1.65;    --ls-body:0;
    --fs-sm:13px;      --lh-sm:1.55;      --ls-sm:0;
    --fs-xs:11px;      --lh-xs:1.4;       --ls-xs:0.01em;

    --font-sans:"Pretendard","Pretendard Variable",-apple-system,
                BlinkMacSystemFont,"Apple SD Gothic Neo","Segoe UI",sans-serif;

    /* ── 간격 스케일 (4px 기반) ─────────────────────────────────────── */
    --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px;
    --sp-5:24px; --sp-6:32px; --sp-7:48px;

    /* 콘텐츠 블록 간 수직 리듬 — "어디까지가 한 덩어리인지" 눈에 잡히게 */
    --gap-page-title: var(--sp-5);   /* 페이지 제목 ↔ 첫 카드   24 */
    --gap-card:       var(--sp-4);   /* 카드 ↔ 카드             16 */
    --gap-card-head:  var(--sp-3);   /* 카드 제목 ↔ 내용        12 */
    --gap-section:    var(--sp-5);   /* 카드 안 섹션 ↔ 섹션     24 */
    --gap-text:       var(--sp-2);   /* 문단·리스트 항목 사이    8 */

    /* ── 모서리 ─────────────────────────────────────────────────────── */
    --r-sm:6px;   /* 태그·칩·입력 */
    --r-md:10px;  /* 버튼·탭 */
    --r-lg:14px;  /* 카드 */
    --r-pill:999px;

    --shadow-pop: 0 8px 24px rgba(28,20,48,.10);
    --focus: 2px solid var(--brand);
  }

  /* ── 다크 모드 ──────────────────────────────────────────────────────
     브랜드 문서가 Background(light)/Background(dark) 두 벌을 규정한다.
     자동 반전이 아니라 다크 표면에 맞춰 따로 계단한 값이다.
     차트 카테고리컬은 다크 밴드(OKLCH L 0.48–0.67)에 맞춰 재계단했다. */
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
      color-scheme: dark;
      --bg:#17131f; --surface:#201a2b; --surface-2:#292235; --surface-3:#342c42;
      --ink:#f4f2f8; --ink-2:#cfccdb; --muted:#a09ab5;
      --line:#342c42; --line-strong:#463d57;

      --brand:var(--v-300); --brand-strong:var(--v-200);
      --brand-soft:#2a2140; --brand-soft-2:#372a52; --on-brand:#17131f;

      --ok:#3ec46f;     --ok-soft:#12331f;     --ok-line:#1f5c36;
      --warn:#f0a63a;   --warn-soft:#3a2a10;   --warn-line:#6b4a15;
      --danger:#f87171; --danger-soft:#3a1a1a; --danger-line:#6b2b2b;
      --info:#7db6ef;   --info-soft:#152840;   --info-line:#27476e;

      --cat-1:var(--v-400); --cat-2:#d95926; --cat-3:#199e70; --cat-4:#c98500;
      --cat-neutral:var(--n-600);
      --seq-1:var(--v-100); --seq-2:var(--v-200);
      --seq-3:var(--v-400); --seq-4:var(--v-600);
      --div-pos-2:var(--v-200); --div-pos-1:var(--v-400);
      --div-mid:#4c4566;
      --div-neg-1:#c98a6a; --div-neg-2:#e07640;

      --grid-line:#342c42; --axis-line:#463d57;
      --shadow-pop:0 8px 24px rgba(0,0,0,.45);
    }
    .brand-logo{filter:brightness(0) invert(1)}
  }
  /* 명시 토글이 OS 설정을 이긴다 (양방향) */
  :root[data-theme="dark"] {
    color-scheme: dark;
    --bg:#17131f; --surface:#201a2b; --surface-2:#292235; --surface-3:#342c42;
    --ink:#f4f2f8; --ink-2:#cfccdb; --muted:#a09ab5;
    --line:#342c42; --line-strong:#463d57;
    --brand:var(--v-300); --brand-strong:var(--v-200);
    --brand-soft:#2a2140; --brand-soft-2:#372a52; --on-brand:#17131f;
    --ok:#3ec46f;     --ok-soft:#12331f;     --ok-line:#1f5c36;
    --warn:#f0a63a;   --warn-soft:#3a2a10;   --warn-line:#6b4a15;
    --danger:#f87171; --danger-soft:#3a1a1a; --danger-line:#6b2b2b;
    --info:#7db6ef;   --info-soft:#152840;   --info-line:#27476e;
    --cat-1:var(--v-400); --cat-2:#d95926; --cat-3:#199e70; --cat-4:#c98500;
    --cat-neutral:var(--n-600);
    --seq-1:var(--v-100); --seq-2:var(--v-200);
    --seq-3:var(--v-400); --seq-4:var(--v-600);
    --div-pos-2:var(--v-200); --div-pos-1:var(--v-400);
    --div-mid:#4c4566;
    --div-neg-1:#c98a6a; --div-neg-2:#e07640;
    --grid-line:#342c42; --axis-line:#463d57;
    --shadow-pop:0 8px 24px rgba(0,0,0,.45);
  }
  :root[data-theme="dark"] .brand-logo{filter:brightness(0) invert(1)}
}


/* ══════════════════════════════════════════════════════════ [B] 베이스 ══ */
@layer base {
  *,*::before,*::after{box-sizing:border-box}

  body{
    margin:0; background:var(--bg); color:var(--ink);
    font-family:var(--font-sans);
    font-size:var(--fs-body); line-height:var(--lh-body);
    -webkit-font-smoothing:antialiased;
  }

  h1{font-size:var(--fs-h1);line-height:var(--lh-h1);letter-spacing:var(--ls-h1);
     font-weight:700;margin:0 0 var(--gap-page-title)}
  h2{font-size:var(--fs-h2);line-height:var(--lh-h2);letter-spacing:var(--ls-h2);
     font-weight:700;margin:0 0 var(--gap-card-head)}
  h3{font-size:var(--fs-body);line-height:var(--lh-body);font-weight:700;
     margin:0 0 var(--sp-2)}
  p{margin:0 0 var(--gap-text)}
  p:last-child{margin-bottom:0}

  a{color:var(--brand);text-decoration:none}
  a:hover{text-decoration:underline}

  /* 포커스 링 — 전 인터랙티브 요소 공통. 키보드 사용자가 위치를 잃지 않게 */
  :focus-visible{outline:var(--focus);outline-offset:2px;border-radius:var(--r-sm)}

  /* 폼 컨트롤 공통 */
  select,input,textarea{
    font:inherit;color:var(--ink);background:var(--surface);
    border:1px solid var(--line-strong);border-radius:var(--r-sm);
    padding:7px 10px;
  }
  select:hover,input:hover,textarea:hover{border-color:var(--brand-soft-2)}
  input:disabled,select:disabled,textarea:disabled{
    background:var(--surface-2);color:var(--muted);cursor:not-allowed}
  textarea{resize:vertical;min-height:64px}
  input[type=checkbox],input[type=radio]{accent-color:var(--brand);width:auto}
  /* 값을 입력한 뒤에만 오류를 보여준다 (타이핑 중 빨개지지 않게) */
  input:user-invalid,select:user-invalid{border-color:var(--danger)}

  code{background:var(--brand-soft);color:var(--brand-strong);
       padding:1px 6px;border-radius:var(--r-sm);font-size:var(--fs-sm)}

  table{width:100%;border-collapse:collapse}
  ul,ol{margin:0 0 var(--gap-text);padding-left:18px}
  li{margin:0 0 var(--sp-1)}

  img{max-width:100%}
  [hidden]{display:none !important}
}


/* ═════════════════════════════════════════════════════ [C-NAV] 상단바 ══ */
@layer components {
  .topbar{
    display:flex;align-items:center;flex-wrap:wrap;gap:var(--sp-2) var(--sp-3);
    background:var(--surface);border-bottom:1px solid var(--line);
    padding:var(--sp-3) var(--sp-5);
  }
  .brand{
    display:flex;align-items:center;gap:var(--sp-2);
    font-weight:700;font-size:16px;line-height:1.3;
    color:var(--ink);margin-right:var(--sp-4);
  }
  .brand:hover{text-decoration:none;opacity:.75}
  .brand-logo{height:22px;width:auto;flex:0 0 auto}
  .badge{
    font-size:var(--fs-xs);line-height:var(--lh-xs);letter-spacing:var(--ls-xs);
    background:var(--brand-soft);color:var(--brand-strong);
    padding:2px 8px;border-radius:var(--r-pill);font-weight:700;
  }
  /* 토글 스위치 — 상태는 data-on 속성으로, 클릭은 폼 POST로 (무JS) */
  .switch{
    position:relative;width:36px;height:21px;flex:0 0 auto;
    border-radius:var(--r-pill);border:1px solid var(--line-strong);
    background:var(--surface-2);padding:0;cursor:pointer;vertical-align:middle;
    transition:background .12s,border-color .12s}
  .switch::after{
    content:"";position:absolute;top:2px;left:2px;width:15px;height:15px;
    border-radius:var(--r-pill);background:var(--ink-2);
    transition:left .12s,background .12s}
  .switch:hover{opacity:.85}
  .switch[data-on="1"]{background:var(--brand);border-color:var(--brand)}
  .switch[data-on="1"]::after{left:calc(100% - 17px);background:#fff}

  .nav{display:flex;flex-wrap:wrap;gap:0 var(--sp-4);align-items:center}
  .nav a,.nav-main{
    color:var(--muted);font-weight:600;font-size:var(--fs-sm);
    line-height:var(--lh-sm);padding:var(--sp-2) 0;
    border-bottom:2px solid transparent;
  }
  .nav a:hover,.nav-main:hover{color:var(--ink);text-decoration:none}
  .nav a.on,.nav-main.on{color:var(--brand);border-bottom-color:var(--brand)}

  .nav-dropdown{position:relative}
  .nav-main{display:inline-block;cursor:pointer}
  .nav-sub{
    display:none;position:absolute;top:100%;left:0;z-index:30;
    min-width:190px;padding:var(--sp-1) 0;
    background:var(--surface);border:1px solid var(--line);
    border-radius:var(--r-md);box-shadow:var(--shadow-pop);
  }
  /* hover + focus-within — 마우스와 키보드 양쪽에서 열린다 (JS 불필요) */
  .nav-dropdown:hover .nav-sub,
  .nav-dropdown:focus-within .nav-sub{display:block}
  .nav-sub a{
    display:block;padding:var(--sp-2) var(--sp-3);
    border-bottom:none;white-space:nowrap;
  }
  .nav-sub a:hover{background:var(--brand-soft);color:var(--brand)}
  .nav-sub a.on{background:var(--brand-soft);color:var(--brand)}

  /* 우측 계정 영역 — 기존에는 우측 슬롯 자체가 없었다 */
  .topbar-right{margin-left:auto;display:flex;align-items:center;gap:var(--sp-3)}
  .user-chip{
    display:inline-flex;align-items:center;gap:var(--sp-2);
    font-size:var(--fs-sm);color:var(--muted);
  }
  .user-chip b{color:var(--ink);font-weight:600}


  /* ═══════════════════════════════════════════════ [C-BAR] 기수 바 ══ */
  .cohortbar{
    background:var(--surface);border-bottom:1px solid var(--line);
    padding:var(--sp-3) var(--sp-5);
  }
  .cohortbar form{display:flex;gap:var(--sp-3);align-items:center;flex-wrap:wrap}
  .cohortbar label{color:var(--muted);font-weight:600;font-size:var(--fs-sm)}
  .period-badge{
    font-size:var(--fs-sm);color:var(--brand-strong);background:var(--brand-soft);
    border:1px solid var(--brand-soft-2);border-radius:var(--r-sm);
    padding:4px 10px;font-weight:600;white-space:nowrap;
  }

  .container{max-width:1360px;margin:0 auto;padding:var(--sp-5)}


  /* ══════════════════════════════════════════════════ [C-BTN] 버튼 ══
     4단계: 주 액션(채움) / 보조(외곽선) / 위험 / 텍스트. 크기 md·sm 2종. */
  button,.btn{
    display:inline-flex;align-items:center;justify-content:center;gap:var(--sp-1);
    font:inherit;font-weight:600;line-height:1.2;cursor:pointer;
    padding:8px 14px;border-radius:var(--r-md);
    border:1px solid var(--brand);background:var(--brand);color:var(--on-brand);
    transition:background .12s,border-color .12s,color .12s;
  }
  button:hover,.btn:hover{
    background:var(--brand-strong);border-color:var(--brand-strong);
    color:var(--on-brand);text-decoration:none}

  .btn-ghost{
    background:var(--surface);border-color:var(--line-strong);color:var(--brand);
  }
  .btn-ghost:hover{
    background:var(--brand-soft);border-color:var(--brand-soft-2);color:var(--brand-strong)}

  .btn-danger{
    background:var(--surface);border-color:var(--danger-line);color:var(--danger);
  }
  .btn-danger:hover{background:var(--danger-soft);border-color:var(--danger);color:var(--danger)}

  .btn-link{
    background:none;border:none;padding:2px 4px;border-radius:var(--r-sm);
    color:var(--brand);font-weight:600;
  }
  .btn-link:hover{background:var(--brand-soft);color:var(--brand-strong)}
  .btn-link.danger{color:var(--danger)}
  .btn-link.danger:hover{background:var(--danger-soft);color:var(--danger)}
  .btn-link.muted{color:var(--muted)}
  .btn-link.muted:hover{background:var(--surface-2);color:var(--ink)}

  .sm{padding:4px 10px;font-size:var(--fs-sm);line-height:var(--lh-sm)}
  .btn-link.sm{padding:2px 6px}

  .tabs{display:flex;gap:var(--sp-2);flex-wrap:wrap;margin-bottom:var(--gap-card)}
  .tab{
    display:inline-flex;align-items:center;gap:var(--sp-1);
    padding:7px 14px;border:1px solid var(--line-strong);border-radius:var(--r-md);
    color:var(--muted);font-weight:600;font-size:var(--fs-sm);background:var(--surface);
  }
  .tab:hover{color:var(--ink);border-color:var(--brand-soft-2);text-decoration:none}
  .tab.on{background:var(--brand);color:var(--on-brand);border-color:var(--brand)}
  .tab .sub{color:inherit;opacity:.75;font-weight:500}


  /* ═══════════════════════════════════════════════════ [C-FORM] 폼 ══
     .frow(가로) / .stack(세로) — 최상위 규칙. 예전에는 `.editform .frow`로만
     존재해 `.editform` 래퍼 없는 폼이 전부 레이아웃을 못 받았다. */
  .frow{
    display:flex;gap:var(--sp-3);flex-wrap:wrap;align-items:flex-end;
    margin-bottom:var(--sp-3);
  }
  .frow:last-child{margin-bottom:0}
  .frow.center{align-items:center}

  .stack{display:flex;flex-direction:column;gap:var(--sp-3);align-items:stretch}

  .frow > label,.stack > label{
    display:flex;flex-direction:column;gap:var(--sp-1);
    font-size:var(--fs-sm);line-height:var(--lh-sm);
    color:var(--muted);font-weight:600;flex:1;min-width:150px;
  }
  .frow > label input,.frow > label select,.frow > label textarea,
  .stack > label input,.stack > label select,.stack > label textarea{
    color:var(--ink);font-weight:400;width:100%}
  .frow > button,.frow > .btn,.frow > input[type=file],.frow > select,.frow > input{
    flex:0 0 auto}
  .stack > button,.stack > .btn{align-self:flex-start}

  label.full{flex-basis:100%;min-width:0}
  label.chk,.chk{
    display:flex;flex-direction:row;align-items:center;gap:var(--sp-2);
    flex:0 0 auto;color:var(--ink);font-weight:500;font-size:var(--fs-sm)}
  .chk input{width:auto;flex:0 0 auto}

  .search{min-width:190px}
  .search.block{width:100%;margin-bottom:var(--sp-3)}

  .req{color:var(--danger);margin-left:1px}
  .hint{
    color:var(--muted);font-weight:400;
    font-size:var(--fs-sm);line-height:var(--lh-sm);
    margin-top:var(--sp-2);max-width:70ch;
  }

  input[type=file]{
    padding:6px 8px;background:var(--surface-2);border-style:dashed;
    font-size:var(--fs-sm);max-width:100%}


  /* ════════════════════════════════════════════════════ [C-CARD] 카드 ══ */
  .card{
    background:var(--surface);border:1px solid var(--line);
    border-radius:var(--r-lg);padding:var(--sp-5);margin-bottom:var(--gap-card);
  }
  .card > :last-child{margin-bottom:0}
  .card.narrow{max-width:620px}
  .card + .card{margin-top:0}
  .card section + section{margin-top:var(--gap-section)}

  .grid2{display:grid;grid-template-columns:1fr 1fr;gap:var(--gap-card)}
  .grid2 > .card{margin-bottom:0}

  .page-head{
    display:flex;align-items:flex-start;justify-content:space-between;
    gap:var(--sp-3);flex-wrap:wrap;margin-bottom:var(--gap-page-title);
  }
  .page-head h1{margin:0}
  .page-head .muted{font-weight:400}
  .toolbar-right{
    margin-left:auto;display:flex;gap:var(--sp-2);align-items:center;flex-wrap:wrap}
  .sub-h{
    font-size:var(--fs-sm);color:var(--muted);font-weight:700;
    margin:var(--gap-section) 0 var(--sp-2)}

  .empty{
    background:var(--surface);border:1px dashed var(--line-strong);
    border-radius:var(--r-lg);padding:var(--sp-7);
    text-align:center;color:var(--muted);
  }
  .flash{
    background:var(--ok-soft);border:1px solid var(--ok-line);color:var(--ok);
    border-radius:var(--r-md);padding:var(--sp-3) var(--sp-4);
    margin-bottom:var(--gap-card);font-size:var(--fs-sm);font-weight:600;
  }
  .warn-card{background:var(--warn-soft);border-color:var(--warn-line)}


  /* ═════════════════════════════════════════════════════ [C-TBL] 표 ══ */
  .table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}

  .mini th,.mini td{
    padding:var(--sp-2) var(--sp-2);border-bottom:1px solid var(--line);
    text-align:left;vertical-align:middle;
  }
  .mini th{
    font-size:var(--fs-xs);line-height:var(--lh-xs);letter-spacing:var(--ls-xs);
    color:var(--muted);font-weight:700;white-space:nowrap}
  .mini tr:last-child td{border-bottom:0}
  .mini .row-actions{justify-content:flex-end}

  .list{
    background:var(--surface);border:1px solid var(--line);
    border-radius:var(--r-lg);overflow:hidden;
  }
  .list th{
    background:var(--surface-2);color:var(--muted);
    font-size:var(--fs-xs);line-height:var(--lh-xs);letter-spacing:var(--ls-xs);
    font-weight:700;text-align:left;
    padding:var(--sp-3) var(--sp-4);border-bottom:1px solid var(--line);
    position:sticky;top:0;z-index:2;
  }
  .list td{padding:11px var(--sp-4);border-bottom:1px solid var(--line)}
  .list tbody tr:last-child td{border-bottom:0}

  /* 행 강조: 예전엔 진한 연보라(#dfd6ff)를 배경 전체에 깔아 6:3:1을 깼다.
     중립 배경 + 좌측 인디케이터로 바꿔 포인트 컬러를 아낀다. */
  .list tbody tr:hover td{background:var(--surface-2)}
  .list tbody tr:hover td:first-child{box-shadow:inset 3px 0 0 var(--brand)}
  .list tbody tr:has(a:focus-visible) td{background:var(--surface-2)}

  .list th.sortable a,.sortable{color:var(--muted);display:inline-flex;
    align-items:center;gap:2px}
  .list th.sortable a:hover{color:var(--brand);text-decoration:none}
  .list th.sorted a{color:var(--brand)}
  .list th .arr{font-size:var(--fs-xs)}

  .list tr.risk-row td{background:var(--danger-soft)}
  .list tr.risk-row td:first-child{box-shadow:inset 3px 0 0 var(--danger)}
  .list tr.risk-row:hover td{background:var(--danger-soft);filter:brightness(.98)}
  .list tr.dropout-row td{background:var(--surface-3);color:var(--muted)}
  .list tr.dropout-row td .sub{color:var(--muted)}
  .list tr.metric-alert td{font-weight:600}

  .name{font-weight:600}
  .name a{color:var(--ink)}
  .name a:hover{color:var(--brand);text-decoration:none}
  .sub{
    display:block;font-weight:400;color:var(--muted);
    font-size:var(--fs-xs);line-height:var(--lh-xs)}

  .num,.cell-num{font-variant-numeric:tabular-nums}
  .num{text-align:right}
  .cell-num{text-align:left;width:88px}
  .list th.cell-num{color:var(--muted)}
  .cell-bad{color:var(--danger);font-weight:700}
  .att-no{width:38px;text-align:center;color:var(--muted);font-size:var(--fs-sm)}

  .row-actions{display:flex;gap:var(--sp-2);align-items:center;white-space:nowrap}
  .row-actions form{display:inline}
  .exprow{
    display:flex;justify-content:space-between;align-items:center;gap:var(--sp-3);
    padding:var(--sp-2) 0;border-bottom:1px solid var(--line);font-size:var(--fs-sm)}
  .exprow:last-child{border-bottom:0}


  .kv th{
    text-align:left;color:var(--muted);font-weight:600;
    padding:var(--sp-2) var(--sp-3) var(--sp-2) 0;width:96px;vertical-align:top;
    font-size:var(--fs-sm)}
  .kv td{padding:var(--sp-2) 0;vertical-align:top}


  /* ══════════════════════════════════════════════ [C-TAG] 상태 태그 ══
     CSS 선택자를 한국어 상태명에서 분리했다. 예전에는
     .tag[data-st="출석"] 처럼 도메인 문자열에 물려 있어, 표시 문구를 바꾸면
     스타일시트까지 같이 고쳐야 했다. 이제 의미 톤 5종에만 건다. */
  .tag{
    display:inline-block;font-size:var(--fs-sm);line-height:var(--lh-sm);
    padding:2px 9px;border-radius:var(--r-sm);white-space:nowrap;
    background:var(--surface-3);color:var(--ink-2);font-weight:600;
  }
  .tag[data-tone="good"]{background:var(--ok-soft);color:var(--ok)}
  .tag[data-tone="warn"]{background:var(--warn-soft);color:var(--warn)}
  .tag[data-tone="bad"]{background:var(--danger-soft);color:var(--danger)}
  .tag[data-tone="info"]{background:var(--info-soft);color:var(--info)}
  .tag[data-tone="active"]{background:var(--brand-soft);color:var(--brand-strong)}

  .risk{
    background:var(--danger-soft);color:var(--danger);
    font-size:var(--fs-sm);font-weight:700;padding:2px 9px;border-radius:var(--r-sm)}
  .risk-why{font-size:var(--fs-sm);line-height:var(--lh-sm);color:var(--warn)}
  .risk-banner{
    background:var(--danger-soft);border:1px solid var(--danger-line);color:var(--danger);
    border-radius:var(--r-md);padding:var(--sp-3) var(--sp-4);
    margin-bottom:var(--gap-card);font-size:var(--fs-sm);font-weight:600;
  }


  /* ══════════════════════════════════════════════════ [C-KPI] KPI ══ */
  .kpis{
    display:grid;grid-template-columns:repeat(auto-fit,minmax(168px,1fr));
    gap:var(--sp-3);margin-bottom:var(--gap-card);
  }
  .kpi{
    background:var(--surface);border:1px solid var(--line);
    border-radius:var(--r-lg);padding:var(--sp-4);
  }
  .kpi.danger{background:var(--danger-soft);border-color:var(--danger-line)}
  .kpi-label{
    color:var(--muted);font-size:var(--fs-sm);line-height:var(--lh-sm);font-weight:600}
  .kpi-value{
    font-size:var(--fs-display);line-height:var(--lh-display);
    letter-spacing:var(--ls-display);font-weight:700;margin-top:var(--sp-1);
    /* 큰 숫자에는 tabular-nums를 쓰지 않는다 — 디스플레이 크기에서 헐거워 보인다 */
  }
  .kpi-value .unit{
    font-size:var(--fs-sm);color:var(--muted);font-weight:500;margin-left:2px;
    letter-spacing:0}
  .kpi.danger .kpi-value{color:var(--danger)}
  .kpi-link{
    font-size:var(--fs-sm);display:inline-block;margin-top:var(--sp-2);font-weight:600}
  .kpi-delta{
    display:inline-flex;align-items:center;gap:2px;
    font-size:var(--fs-xs);font-weight:700;padding:1px 6px;
    border-radius:var(--r-sm);margin-left:var(--sp-2);letter-spacing:0}
  .kpi-delta.up{color:var(--ok);background:var(--ok-soft)}
  .kpi-delta.down{color:var(--danger);background:var(--danger-soft)}
  .kpi-delta.flat{color:var(--muted);background:var(--surface-2)}

  /* 미터 — 값 대비 한계. 트랙은 같은 램프의 옅은 단계 */
  .bar{
    height:6px;background:var(--surface-3);border-radius:var(--r-pill);
    overflow:hidden;margin-top:var(--sp-2);position:relative}
  .bar > span{display:block;height:100%;background:var(--brand);border-radius:var(--r-pill)}
  .bar > .thr{
    position:absolute;top:-2px;bottom:-2px;width:2px;background:var(--axis-line);
    border-radius:0}


  /* ═══════════════════════════════════ [C-LC] 라이프사이클(순서 단계) ══
     모집→교육→취업은 순서가 있는 단계이므로 카테고리컬이 아니라 순차 램프. */
  .lc-band{display:flex;gap:var(--sp-2);margin:0 0 var(--gap-card);flex-wrap:wrap}
  .lc-step{
    flex:1;min-width:140px;display:flex;flex-direction:column;gap:2px;
    padding:var(--sp-3) var(--sp-3);border:1px solid var(--line);
    border-radius:var(--r-md);color:var(--ink);background:var(--surface);
  }
  .lc-step.done{background:var(--surface-2)}
  .lc-step.cur{box-shadow:inset 0 0 0 2px var(--brand);background:var(--brand-soft)}
  .lc-step.todo{opacity:.5}
  .lc-p{font-size:var(--fs-sm);font-weight:700;color:var(--muted)}
  .lc-step.cur .lc-p{color:var(--brand-strong)}
  .lc-now{
    font-size:var(--fs-xs);background:var(--brand);color:var(--on-brand);
    border-radius:var(--r-sm);padding:0 5px;margin-left:2px;font-weight:700}
  .lc-cur{font-size:var(--fs-body);font-weight:700}

  .lc-badge{
    display:inline-block;font-size:var(--fs-xs);line-height:var(--lh-xs);
    font-weight:700;padding:2px 9px;border-radius:var(--r-pill);
    background:var(--surface-3);color:var(--ink-2)}
  .lc-badge[data-step="1"]{background:var(--seq-1);color:var(--n-900)}
  .lc-badge[data-step="2"]{background:var(--seq-2);color:#fff}
  .lc-badge[data-step="3"]{background:var(--seq-3);color:#fff}

  /* 단계 분포 스택바 — 세그먼트 사이 2px 표면 간격 (테두리 대신) */
  .lc-bar{
    display:flex;gap:2px;height:28px;border-radius:var(--r-sm);
    background:var(--surface-3);margin:var(--sp-1) 0 var(--sp-3);
    overflow:hidden}
  .lc-seg{
    display:flex;align-items:center;justify-content:center;
    font-size:var(--fs-xs);font-weight:700;min-width:2px;color:#fff;
    overflow:hidden;white-space:nowrap}
  .lc-seg[data-step="1"]{background:var(--seq-1);color:var(--n-900)}
  .lc-seg[data-step="2"]{background:var(--seq-2)}
  .lc-seg[data-step="3"]{background:var(--seq-3)}
  .lc-legend{display:flex;gap:var(--sp-2);flex-wrap:wrap;font-size:var(--fs-sm)}


  /* ══════════════════════════════════════════════════ [C-CHART] 차트 ══ */
  /* 상태 분포 — 가로 막대 (크기 비교, 단일 색) */
  .dist{list-style:none;margin:0;padding:0}
  .dist li{
    display:grid;grid-template-columns:110px 1fr 56px;align-items:center;
    gap:var(--sp-3);margin-bottom:var(--sp-2)}
  .dist li:last-child{margin-bottom:0}
  .dist-label{font-size:var(--fs-sm);color:var(--ink-2)}
  .dist-bar{height:10px;background:var(--surface-3);border-radius:var(--r-pill);overflow:hidden}
  .dist-bar > span{display:block;height:100%;background:var(--brand);border-radius:var(--r-pill)}
  .dist-n{text-align:right;color:var(--muted);font-variant-numeric:tabular-nums;
    font-size:var(--fs-sm)}

  /* 스파크 컬럼 차트 (진도율·테스트) */
  .flow-scroll{overflow-x:auto;padding-bottom:var(--sp-2)}
  .spark-h3{
    font-size:var(--fs-sm);color:var(--muted);font-weight:600;
    margin:0 0 var(--sp-2)}
  .spark{
    display:flex;gap:var(--sp-2);align-items:flex-end;
    padding:var(--sp-1) 0;margin-bottom:var(--sp-4);overflow-x:auto;
    position:relative}
  .spark-col{
    flex:1;min-width:46px;text-align:center;
    display:flex;flex-direction:column;justify-content:flex-end}
  .spark-bar{
    height:72px;display:flex;align-items:flex-end;
    background:var(--surface-2);border-radius:var(--r-sm);
    overflow:hidden;position:relative}
  .spark-bar > span{
    display:block;width:100%;background:var(--brand);
    border-radius:var(--r-sm) var(--r-sm) 0 0}
  .spark-bar > span.low{background:var(--danger)}
  .spark-bar.test > span{background:var(--cat-3)}
  .spark-bar.test > span.low{background:var(--danger)}
  /* 미응시 — 0점과 구분되도록 빗금. 값이 없다는 뜻이지 0이 아니다 */
  .spark-bar > span.miss{
    height:100% !important;background:repeating-linear-gradient(45deg,
      var(--surface-3) 0 4px,transparent 4px 8px);border-radius:0}
  /* 임계선 — 왜 빨간지 색 말고도 보이게. 막대 상자 안에 두어야
     라벨 높이와 무관하게 정확한 위치에 그려진다(픽셀 계산 금지). */
  .spark-thr{
    position:absolute;left:0;right:0;height:0;
    border-top:1px dashed var(--axis-line);
    z-index:2;pointer-events:none}
  .spark-lab{
    font-size:var(--fs-xs);line-height:var(--lh-xs);color:var(--muted);
    margin-top:3px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .spark-val{font-size:var(--fs-xs);font-weight:700;line-height:var(--lh-xs)}
  .spark-val.low{color:var(--danger)}

  /* 차트 공통 — 범례·축·표 뷰 */
  .chart-legend{
    display:flex;gap:var(--sp-3);flex-wrap:wrap;align-items:center;
    font-size:var(--fs-xs);line-height:var(--lh-xs);color:var(--muted);
    margin-bottom:var(--sp-2)}
  .chart-legend .k{display:inline-flex;align-items:center;gap:var(--sp-1)}
  /* 범례 스와치 — 색은 토큰 이름으로 지정한다(마크업에 색을 쓰지 않는다) */
  .swatch{
    width:18px;height:10px;border-radius:3px;display:inline-block;flex:0 0 auto;
    background:var(--cat-neutral)}
  .swatch[data-swatch="seq-1"],.heat-scale i[data-swatch="seq-1"]{background:var(--seq-1)}
  .swatch[data-swatch="seq-2"],.heat-scale i[data-swatch="seq-2"]{background:var(--seq-2)}
  .swatch[data-swatch="seq-3"],.heat-scale i[data-swatch="seq-3"]{background:var(--seq-3)}
  .swatch[data-swatch="seq-4"],.heat-scale i[data-swatch="seq-4"]{background:var(--seq-4)}
  .swatch[data-swatch="div-neg-2"]{background:var(--div-neg-2)}
  .swatch[data-swatch="div-neg-1"]{background:var(--div-neg-1)}
  .swatch[data-swatch="div-mid"]{background:var(--div-mid)}
  .swatch[data-swatch="div-pos-1"]{background:var(--div-pos-1)}
  .swatch[data-swatch="div-pos-2"]{background:var(--div-pos-2)}
  .chart-note{
    font-size:var(--fs-xs);color:var(--muted);margin-top:var(--sp-2)}

  /* 가로 막대 목록 (강사 시수 등) */
  .hbars{list-style:none;margin:0 0 var(--sp-4);padding:0}
  .hbars li{
    display:grid;grid-template-columns:120px 1fr 64px;align-items:center;
    gap:var(--sp-3);margin-bottom:var(--sp-2)}
  .hbars .hb-label{
    font-size:var(--fs-sm);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .hbars .hb-track{height:12px;background:var(--surface-2);border-radius:var(--r-pill)}
  .hbars .hb-fill{
    display:block;height:100%;background:var(--brand);border-radius:var(--r-pill)}
  .hbars .hb-val{
    text-align:right;font-variant-numeric:tabular-nums;font-size:var(--fs-sm);
    font-weight:600}


  /* ══════════════════════════════════ [C-SURVEY] 만족도(Likert) ══
     5점 척도는 순서형 비율 → 중립 기준 발산형 누적 막대.
     예전에는 .q-bar(원래 flex 행 컨테이너)를 세로 막대로 오용해 너비 0이었다. */
  .blk-summary{
    display:flex;flex-wrap:wrap;gap:var(--sp-3);margin-bottom:var(--gap-card)}
  .blk-card{
    border:1px solid var(--line);border-radius:var(--r-md);
    padding:var(--sp-3) var(--sp-4);min-width:104px;text-align:center;
    background:var(--surface)}
  .blk-card.low{background:var(--danger-soft);border-color:var(--danger-line)}
  .blk-name{font-size:var(--fs-sm);color:var(--muted);font-weight:600}
  .blk-avg{
    font-size:var(--fs-h1);line-height:var(--lh-h1);font-weight:800;color:var(--brand)}
  .blk-card.low .blk-avg{color:var(--danger)}
  .blk-avg small{font-size:var(--fs-xs);color:var(--muted);font-weight:600}

  .q-row{padding:var(--sp-3) 0;border-bottom:1px solid var(--line)}
  .q-row:last-child{border-bottom:0}
  .q-text{font-size:var(--fs-sm);line-height:var(--lh-sm);margin-bottom:var(--sp-2)}

  /* 발산형 막대: 중립(보통)의 절반을 기준선에 맞춰 좌우로 뻗는다 */
  .lik{
    display:grid;grid-template-columns:1fr 60px;align-items:center;gap:var(--sp-3)}
  .lik-track{
    position:relative;height:20px;background:var(--surface-2);
    border-radius:var(--r-sm);overflow:hidden}
  /* 막대는 트랙 폭의 절반만 차지한다. 중립(보통)의 한가운데를 기준선에 맞추려면
     막대를 좌우로 최대 ±50%까지 밀어야 하는데, 폭이 100%면 밀 때 잘린다. */
  .lik-row{position:absolute;top:0;bottom:0;width:50%;display:flex}
  .lik-seg{height:100%;min-width:0}
  .lik-seg + .lik-seg{box-shadow:-2px 0 0 var(--surface)}   /* 2px 표면 간격 */
  .lik-seg[data-v="1"]{background:var(--div-neg-2)}
  .lik-seg[data-v="2"]{background:var(--div-neg-1)}
  .lik-seg[data-v="3"]{background:var(--div-mid)}
  .lik-seg[data-v="4"]{background:var(--div-pos-1)}
  .lik-seg[data-v="5"]{background:var(--div-pos-2)}
  /* 기준선 — 트랙 정가운데. '보통'의 한가운데가 여기 맞춰진다 */
  .lik-zero{
    position:absolute;left:50%;top:-3px;bottom:-3px;width:1px;
    background:var(--ink-2);opacity:.55;z-index:2;pointer-events:none}
  .lik-avg{
    text-align:right;font-variant-numeric:tabular-nums;font-weight:700;
    font-size:var(--fs-sm)}
  .lik-avg.low{color:var(--danger)}
  .q-dist{
    display:flex;gap:var(--sp-2);flex-wrap:wrap;
    font-size:var(--fs-xs);color:var(--muted);margin-top:var(--sp-1)}
  .q-dist span{background:var(--surface-2);padding:1px 6px;border-radius:var(--r-sm)}


  /* ═════════════════════════════════════════ [C-PEER] 동료평가 히트맵 ══ */
  .peer{border-collapse:separate;border-spacing:2px;min-width:max-content}
  .peer th,.peer td{
    padding:var(--sp-2) var(--sp-3);text-align:center;font-size:var(--fs-sm);
    border-radius:var(--r-sm)}
  .peer thead th{
    background:var(--surface-2);font-size:var(--fs-xs);color:var(--muted);
    font-weight:700}
  .peer th.corner{background:var(--surface);text-align:left;color:var(--muted)}
  .peer th.er{
    background:var(--surface-2);text-align:left;white-space:nowrap;font-weight:600}
  .peer-cell{font-variant-numeric:tabular-nums;font-weight:600;color:var(--ink)}
  .peer-cell.self{background:var(--surface-2);color:var(--muted)}
  /* 순차 히트맵 — 한 색상, 옅은→진한. 무지개 금지 */
  .peer-cell[data-heat="1"]{background:var(--surface-2);color:var(--ink)}
  .peer-cell[data-heat="2"]{background:var(--seq-1);color:var(--n-900)}
  .peer-cell[data-heat="3"]{background:var(--seq-2);color:#fff}
  .peer-cell[data-heat="4"]{background:var(--seq-3);color:#fff}
  .peer-cell[data-heat="5"]{background:var(--seq-4);color:#fff}
  /* 진하기는 '점수 크기'를 나타낸다. 그런데 눈으로 찾아야 하는 건 낮은 점수라,
     농도만으로는 문제가 눈에 덜 띈다 → 기준 미달 셀에 테두리를 덧댄다. */
  .peer-cell[data-low="1"]{outline:2px solid var(--danger);outline-offset:-2px}
  .peer .recv-row td{background:var(--surface-2);font-weight:700}
  .heat-scale{display:inline-flex;align-items:center;gap:2px;margin-left:var(--sp-2)}
  .heat-scale i{width:16px;height:10px;border-radius:2px;display:inline-block}


  /* ═══════════════════════════════════════════════════ [C-CAL] 달력 ══ */
  .cal-wrap{
    display:grid;grid-template-columns:minmax(320px,420px) 1fr;
    gap:var(--gap-card);align-items:start}
  .cal-card{padding:var(--sp-4)}
  .cal{width:100%;border-collapse:collapse;table-layout:fixed}
  .cal th{
    font-size:var(--fs-xs);color:var(--muted);padding:var(--sp-1) 0;
    text-align:center;font-weight:600}
  .cal th.sun{color:var(--danger)}
  .cal th.sat{color:var(--info)}
  .cal-cell{height:48px;text-align:center;vertical-align:top;padding:2px}
  .cal-day{
    display:flex;flex-direction:column;align-items:center;
    justify-content:flex-start;height:100%;border-radius:var(--r-sm);
    color:var(--ink);padding-top:var(--sp-1);position:relative}
  .cal-day:hover{background:var(--brand-soft);text-decoration:none}
  /* 수업일: 예전엔 전부 같은 연보라 면이었다 → 출석률 농도로 구분 */
  .cal-day.class-day{background:var(--surface-2)}
  .cal-day.class-day[data-att="1"]{background:var(--seq-1);color:var(--n-900)}
  .cal-day.class-day[data-att="2"]{background:var(--seq-2);color:#fff}
  .cal-day.class-day[data-att="3"]{background:var(--seq-3);color:#fff}
  .cal-day.class-day[data-att="4"]{background:var(--seq-4);color:#fff}
  .cal-day.class-day[data-att] .cal-num{color:inherit}
  .cal-cell.today-sel .cal-day{outline:2px solid var(--brand);outline-offset:-2px}
  .cal-num{font-size:var(--fs-sm);font-weight:600}
  .cal-num.hol{color:var(--danger)}
  .cal-num.satday{color:var(--info)}
  .cal-day.dim-oop{opacity:.3}
  .cal-day.noclass{opacity:.35;cursor:default}
  .cal-day.noclass:hover{background:transparent}
  .cal-badge{
    margin-top:2px;font-size:var(--fs-xs);background:var(--brand);
    color:var(--on-brand);border-radius:var(--r-sm);padding:0 5px;font-weight:700}
  .cal-day[data-att] .cal-badge{background:rgba(255,255,255,.25);color:#fff}
  .cal-dot{margin-top:var(--sp-1);width:5px;height:5px;border-radius:50%;
    background:var(--brand)}
  .cal-nav{
    display:flex;align-items:center;gap:var(--sp-3);margin-bottom:var(--sp-3)}
  .cal-nav .nav-off{opacity:.3;cursor:default;pointer-events:none}


  /* ══════════════════════════════════════════════════ [C-ATT] 출석 ══ */

  .att-list th{
    text-align:left;font-size:var(--fs-xs);color:var(--muted);
    padding:var(--sp-2);border-bottom:1px solid var(--line);font-weight:700}
  .att-list td{padding:var(--sp-2);border-bottom:1px solid var(--line);
    vertical-align:middle}
  .att-list tr:last-child td{border-bottom:0}
  .att-list td.name{white-space:nowrap;padding-right:var(--sp-4)}
  .att-list .num{white-space:nowrap;width:110px}


  .att-chips{display:flex;gap:var(--sp-2);flex-wrap:wrap;margin:2px 0 var(--sp-3)}
  .att-chip,.att-chips .chip{
    font-size:var(--fs-sm);font-weight:600;padding:3px 10px;
    border-radius:var(--r-pill);background:var(--surface-3);color:var(--ink-2)}
  .att-chip[data-tone="good"],.chip[data-tone="good"]{background:var(--ok-soft);color:var(--ok)}
  .att-chip[data-tone="warn"],.chip[data-tone="warn"]{background:var(--warn-soft);color:var(--warn)}
  .att-chip[data-tone="bad"],.chip[data-tone="bad"]{background:var(--danger-soft);color:var(--danger)}
  .att-chip[data-tone="info"],.chip[data-tone="info"]{background:var(--info-soft);color:var(--info)}

  .att-legend{
    display:flex;gap:var(--sp-2);flex-wrap:wrap;margin-top:var(--sp-2);
    font-size:var(--fs-xs);color:var(--muted);align-items:center}
  .att-legend .lg{padding:2px 8px;border-radius:var(--r-sm)}

  .entry-card{min-height:220px}
  .entry-empty{
    display:flex;align-items:center;justify-content:center;
    height:180px;text-align:center}


  /* ══════════════════════════════════════════════ [C-SCHED] 시간표 ══ */
  .sched{display:flex;flex-direction:column;gap:var(--sp-3)}
  .sched-day{
    display:grid;grid-template-columns:120px 1fr;gap:var(--sp-3);
    border-top:1px solid var(--line);padding-top:var(--sp-3)}
  .sched-date{font-weight:700;font-size:var(--fs-sm);color:var(--brand-strong)}
  .sched-items{display:flex;flex-direction:column;gap:var(--sp-1)}
  /* 6:3:1 — 전 항목을 연보라로 채우지 않고 중립 배경 + 좌측 색선만 */
  .sched-item{
    display:flex;align-items:center;gap:var(--sp-3);
    background:var(--surface-2);border-radius:var(--r-sm);
    border-left:3px solid var(--line-strong);
    padding:var(--sp-2) var(--sp-3);font-size:var(--fs-sm)}
  .sched-item.rest{color:var(--muted)}
  .sched-item.mode-on{border-left-color:var(--cat-neutral)}
  .sched-item.mode-off{border-left-color:var(--brand)}
  .mode-badge{
    font-size:var(--fs-xs);font-weight:700;padding:1px 8px;
    border-radius:var(--r-sm);flex:0 0 auto;
    background:var(--surface-3);color:var(--ink-2)}
  .mode-badge[data-mode="off"]{background:var(--brand-soft);color:var(--brand-strong)}
  .sched-time{
    font-variant-numeric:tabular-nums;font-weight:600;flex:0 0 100px}
  .sched-subj{font-weight:600;flex:1}
  .sched-meta{color:var(--muted);font-size:var(--fs-xs)}
  .sched-del{display:inline;flex:0 0 auto}


  /* ═══════════════════════════════════════════════════ [C-GANTT] 간트 ══
     예전에는 pages_more.py 안에 76줄 인라인 <style>로 자체 색 세트를 들고 있어
     이 화면만 다른 제품처럼 보였다. 토큰으로 흡수했다. */
  .gantt-card{
    background:var(--surface);border:1px solid var(--line);
    border-radius:var(--r-lg);padding:var(--sp-4);overflow-x:auto}
  .gantt-chart{min-width:760px;position:relative;padding-top:30px}
  .gantt-months{
    position:absolute;top:0;left:150px;right:0;height:24px;
    border-bottom:1px solid var(--grid-line)}
  .gm{
    position:absolute;top:4px;transform:translateX(-50%);
    font-size:var(--fs-xs);color:var(--muted);
    font-variant-numeric:tabular-nums;white-space:nowrap}
  .gantt-grid{position:absolute;top:26px;left:150px;right:0;bottom:0;z-index:1}
  .gl{position:absolute;top:0;bottom:0;width:1px;background:var(--grid-line)}
  .gantt-rows{position:relative;z-index:2}
  .ggrp{
    display:flex;align-items:center;gap:var(--sp-2);height:28px;
    font-size:var(--fs-sm);font-weight:700;margin-top:var(--sp-2)}
  .ggrp .chip{width:11px;height:11px;border-radius:3px;flex:0 0 auto}
  .grow{display:flex;align-items:center;height:44px;
    border-bottom:1px solid var(--grid-line)}
  .growlab{
    width:150px;flex:0 0 150px;padding-right:var(--sp-2);
    display:flex;flex-direction:column;justify-content:center}
  .gqi{font-size:var(--fs-sm);font-weight:600}
  .gtrack{position:relative;flex:1;height:100%}
  .gbar{
    position:absolute;border-radius:var(--r-sm);display:flex;align-items:center;
    font-size:var(--fs-xs);font-weight:700;white-space:nowrap}
  .gbar.online{top:25px;height:12px;background:var(--cat-neutral);border-radius:4px}
  .gbar.off{top:16px;height:22px;color:#fff;padding:0 var(--sp-2)}
  .gbar.off[data-track="1"]{background:var(--cat-1)}
  .gbar.off[data-track="2"]{background:var(--cat-3)}
  .gbar.off[data-track="3"]{background:var(--cat-4);color:var(--n-900)}
  /* 라벨이 막대보다 길면 밖으로 — overflow:hidden으로 잘라내지 않는다 */
  .gbar.off.lab-out{
    color:var(--ink);background:none !important;padding-left:0}
  .gbar.off.lab-out::before{
    content:"";position:absolute;left:0;top:0;bottom:0;width:100%;
    border-radius:var(--r-sm);background:inherit}
  .gbar-lab{position:relative;z-index:1}
  .gbar-lab.outside{
    position:absolute;left:calc(100% + 6px);color:var(--muted);font-weight:600}
  .gbar.draft{opacity:.55;border:2px dashed;box-sizing:border-box;
    background:transparent !important}
  .gbar.online.draft{border-color:var(--cat-neutral)}
  .gbar.off.draft[data-track="1"]{border-color:var(--cat-1);color:var(--cat-1)}
  .gbar.off.draft[data-track="2"]{border-color:var(--cat-3);color:var(--cat-3)}
  .gbar.off.draft[data-track="3"]{border-color:var(--cat-4);color:var(--cat-4)}
  .gbadge{
    font-size:var(--fs-xs);font-weight:800;padding:1px 6px;
    border-radius:3px;margin-left:5px;white-space:nowrap}
  .gbadge.confirmed{background:var(--ok-soft);color:var(--ok)}
  .gbadge.draft{background:var(--warn-soft);color:var(--warn)}
  .gbadge.mixed{background:var(--danger-soft);color:var(--danger)}
  .gbadge.none{background:var(--surface-3);color:var(--muted)}
  .gsw{width:20px;height:11px;border-radius:3px;display:inline-block;flex:0 0 auto}
  .gsw.online{background:var(--cat-neutral)}
  .gsw[data-track="1"]{background:var(--cat-1)}
  .gsw[data-track="2"]{background:var(--cat-3)}
  .gsw[data-track="3"]{background:var(--cat-4)}
  .gsw.draft{
    background:repeating-linear-gradient(45deg,var(--cat-neutral) 0 3px,transparent 3px 6px)}


  /* ═════════════════════════════════════════ [C-TL] 타임라인·상세 ══ */
  .journey{
    display:flex;list-style:none;padding:0;margin:0 0 var(--gap-card);gap:0}
  .journey li{
    flex:1;text-align:center;position:relative;padding-top:var(--sp-5);margin:0}
  .journey li::before{
    content:"";position:absolute;top:6px;left:50%;width:100%;height:2px;
    background:var(--line)}
  .journey li:last-child::before{display:none}
  .j-dot{
    position:absolute;top:0;left:50%;transform:translateX(-50%);
    width:12px;height:12px;border-radius:50%;background:var(--brand)}
  .j-label{font-weight:600;font-size:var(--fs-sm)}
  .j-val{color:var(--muted);font-size:var(--fs-sm)}


  .timeline{list-style:none;padding:0;margin:var(--sp-3) 0 0}
  .timeline li{
    display:flex;gap:var(--sp-3);padding:var(--sp-3) 0;
    border-top:1px solid var(--line);margin:0}
  .timeline li:first-child{border-top:0;padding-top:0}
  .tl-cat{
    flex:0 0 auto;height:fit-content;font-size:var(--fs-xs);font-weight:700;
    padding:2px 8px;border-radius:var(--r-sm);
    background:var(--surface-3);color:var(--ink-2)}
  .tl-cat[data-cat="상담"]{background:var(--brand-soft);color:var(--brand-strong)}
  .tl-cat[data-cat="출석"]{background:var(--danger-soft);color:var(--danger)}
  .tl-cat[data-cat="학습"]{background:var(--info-soft);color:var(--info)}
  .tl-cat[data-cat="프로젝트"]{background:var(--ok-soft);color:var(--ok)}
  .tl-meta{font-size:var(--fs-xs);color:var(--muted)}
  .tl-content{font-size:var(--fs-sm);line-height:var(--lh-sm);flex:1}
  .tl-content p{margin:2px 0}
  .tl-content ul{margin:var(--sp-1) 0;padding-left:18px}

  .status-log{list-style:none;padding:0;margin:var(--sp-2) 0 0}
  .status-log li{
    display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-2) 0;
    border-top:1px solid var(--line);font-size:var(--fs-sm);flex-wrap:wrap;margin:0}
  .sl-time{
    font-variant-numeric:tabular-nums;color:var(--muted);
    font-size:var(--fs-xs);flex:0 0 130px}
  .sl-change b{color:var(--brand-strong)}

  .flagrow{
    display:flex;justify-content:space-between;align-items:center;gap:var(--sp-3);
    padding:var(--sp-2) 0;border-bottom:1px solid var(--line);font-size:var(--fs-sm)}
  .flagrow:last-child{border-bottom:0}
  .flagrow.off .fl-reason{color:var(--muted)}
  .fl-badge{
    font-size:var(--fs-xs);background:var(--surface-3);color:var(--muted);
    padding:1px 7px;border-radius:var(--r-sm);margin-left:var(--sp-1)}
  .fl-actions{display:flex;gap:var(--sp-2);flex:0 0 auto}
  .flagrow form{display:inline}


  /* 성적표 */


  /* ═══════════════════════════════════════ [C-SEGTOGGLE] 세그먼트 토글 ══
     탭(.tab)과 달리 알약형 트랙 안에 버튼이 들어간다 — 여러 화면이 아니라
     '같은 화면의 상태(뷰)'를 전환할 때. 예: 출석부 HRD ⇄ 자리이탈. */
  .seg-toggle{
    display:inline-flex;background:var(--brand-soft);border-radius:var(--r-md);
    padding:3px;gap:2px;
  }
  .seg-btn{
    padding:6px 14px;border-radius:calc(var(--r-md) - 3px);
    font-weight:600;font-size:var(--fs-sm);color:var(--muted);
  }
  .seg-btn:hover{color:var(--ink);text-decoration:none}
  .seg-btn.on{background:var(--surface);color:var(--brand);box-shadow:var(--shadow-pop)}


  /* ══════════════════════════════════════════════════ [C-NOTICE] 안내 ══
     판정 기준/규칙을 설명하는 배너. 기본은 안내(파랑), .warn 수식자는
     수동 보정·주의 신호(호박)에만 쓴다 — 색 의미를 .warn-card와 맞춘다. */
  .notice{
    display:flex;gap:var(--sp-3);align-items:flex-start;
    background:var(--info-soft);border:1px solid var(--info-line);color:var(--ink-2);
    border-radius:var(--r-md);padding:var(--sp-3) var(--sp-4);
    margin-bottom:var(--gap-card);font-size:var(--fs-sm);line-height:var(--lh-sm);
  }
  .notice-icon{flex:0 0 auto;font-size:var(--fs-h2);line-height:1}
  .notice b{color:var(--info)}
  .notice.warn{background:var(--warn-soft);border-color:var(--warn-line)}
  .notice.warn b{color:var(--warn)}

  .adjusted-tag{
    display:inline-block;font-size:var(--fs-xs);font-weight:700;
    padding:2px 8px;border-radius:var(--r-sm);
    background:var(--warn-soft);color:var(--warn);
  }


  /* ══════════════════════════════════════════════════ [C-MODAL] 모달 ══
     JS가 없으므로 :target으로만 열고 닫는다. 여는 링크: href="#modal-id".
     닫는 링크/배경: href="#_" — 본문 상단의 빈 앵커(#_)로 해시를 비운다. */
  .modal-anchor{display:none}
  .modal-overlay{
    display:none;position:fixed;inset:0;z-index:50;
    align-items:center;justify-content:center;padding:var(--sp-4);
    background:rgba(28,20,48,.55);backdrop-filter:blur(2px);
  }
  .modal-overlay:target{display:flex}
  .modal{
    background:var(--surface);border-radius:var(--r-lg);
    width:min(640px,94vw);max-height:88vh;overflow-y:auto;
    box-shadow:0 24px 60px rgba(28,20,48,.35);
    padding:var(--sp-5);animation:modal-pop .16s ease;
  }
  .modal.wide{width:min(960px,96vw)}
  @keyframes modal-pop{
    from{opacity:0;transform:translateY(6px) scale(.98)}
    to{opacity:1;transform:none}
  }
  .modal-head{
    display:flex;align-items:flex-start;justify-content:space-between;
    gap:var(--sp-3);margin-bottom:var(--gap-card-head);
  }
  .modal-head h2{margin:0}
  .modal-close{
    flex:0 0 auto;color:var(--muted);font-weight:700;font-size:var(--fs-h2);
    line-height:1;padding:2px 8px;border-radius:var(--r-sm);
  }
  .modal-close:hover{background:var(--surface-2);color:var(--ink);text-decoration:none}
  .modal-section + .modal-section{
    margin-top:var(--gap-section);padding-top:var(--gap-section);border-top:1px solid var(--line)}
  .modal-section h3{margin:0 0 var(--sp-2)}


  /* ══════════════════════════════════════════════════ [C-MATRIX] 매트릭스 ══
     레이서 × 주차 출결 집계. 0인 상태는 생략하고 있는 것만 필로 보여준다. */
  .matrix-scroll{
    overflow:auto;max-height:72vh;border-radius:var(--r-lg);
    border:1px solid var(--line);background:var(--surface);
  }
  .matrix-tbl{border-collapse:separate;border-spacing:0;min-width:max-content}
  .matrix-tbl th,.matrix-tbl td{
    padding:var(--sp-2) var(--sp-2);border-bottom:1px solid var(--line);
    text-align:center;vertical-align:middle;
  }
  .matrix-tbl thead th{
    position:sticky;top:0;z-index:2;background:var(--surface-2);
    font-size:var(--fs-xs);color:var(--muted);font-weight:700;white-space:nowrap;
  }
  .matrix-tbl .matrix-name{
    position:sticky;left:0;z-index:1;background:var(--surface);
    text-align:left;font-weight:600;white-space:nowrap;box-shadow:2px 0 0 var(--line);
  }
  .matrix-tbl thead th.matrix-corner{position:sticky;left:0;top:0;z-index:3;background:var(--surface-2)}
  .matrix-cell{display:flex;flex-direction:column;gap:2px;align-items:center;min-width:64px}
  .matrix-pill{
    font-size:var(--fs-xs);font-weight:700;padding:1px 6px;border-radius:var(--r-sm);
    background:var(--surface-3);color:var(--ink-2);white-space:nowrap;
  }
  .matrix-pill[data-tone="good"]{background:var(--ok-soft);color:var(--ok)}
  .matrix-pill[data-tone="warn"]{background:var(--warn-soft);color:var(--warn)}
  .matrix-pill[data-tone="bad"]{background:var(--danger-soft);color:var(--danger)}
  .matrix-pill[data-tone="info"]{background:var(--info-soft);color:var(--info)}
  .matrix-empty{color:var(--muted);font-size:var(--fs-xs)}


  /* ══════════════════════════════════════════════ [C-LOGIN] 로그인 ══ */
  .login-wrap{
    min-height:100vh;display:flex;align-items:center;justify-content:center;
    padding:var(--sp-5);background:var(--bg)}
  .login-card{
    width:100%;max-width:400px;background:var(--surface);
    border:1px solid var(--line);border-radius:var(--r-lg);
    padding:var(--sp-6);box-shadow:var(--shadow-pop)}
  .login-brand{
    display:flex;flex-direction:column;align-items:center;gap:var(--sp-2);
    font-size:var(--fs-h2);font-weight:700;text-align:center;
    margin-bottom:var(--sp-1)}
  .login-brand .brand-logo{height:28px}
  .login-sub{color:var(--muted);font-size:var(--fs-sm);
    text-align:center;margin-bottom:var(--sp-5)}
  .login-card button{width:100%;margin-top:var(--sp-2);padding:10px 14px}
  .login-err{
    background:var(--danger-soft);border:1px solid var(--danger-line);
    color:var(--danger);border-radius:var(--r-md);
    padding:var(--sp-2) var(--sp-3);font-size:var(--fs-sm);font-weight:600;
    margin-bottom:var(--sp-4)}
}


/* ══════════════════════════════════════════════════ [U] 유틸리티 ══ */
@layer utilities {
  .muted{
    color:var(--muted);font-weight:400;
    font-size:var(--fs-sm);line-height:var(--lh-sm)}
  .muted-sm{
    color:var(--muted);font-size:var(--fs-sm);line-height:var(--lh-sm);
    list-style:none;padding:0;margin:var(--sp-2) 0 0}
  .muted-sm li{padding:2px 0;margin:0}
  .ok{color:var(--ok)}
  .warn{color:var(--warn)}
  .bad{color:var(--danger)}
  .nowrap{white-space:nowrap}
  .center{text-align:center}
  .prose{max-width:70ch}

  .mt-1{margin-top:var(--sp-1)} .mt-2{margin-top:var(--sp-2)}
  .mt-3{margin-top:var(--sp-3)} .mt-4{margin-top:var(--sp-4)}
  .mt-5{margin-top:var(--sp-5)}
  .mb-0{margin-bottom:0} .mb-3{margin-bottom:var(--sp-3)}
  .mb-4{margin-bottom:var(--sp-4)}
  .w-full{width:100%} .flex-1{flex:1} .input-w90{width:96px} .input-w120{width:120px}
  .form-inline{display:inline}
  .scroll-x{overflow-x:auto}
}


/* ══════════════════════════════════════════════════════ 반응형 ══ */
@media (max-width:980px){
  .cal-wrap{grid-template-columns:1fr}
}
@media (max-width:820px){
  .grid2{grid-template-columns:1fr}
  .container{padding:var(--sp-4)}
  .topbar,.cohortbar{padding:var(--sp-3) var(--sp-4)}
  .nav{gap:0 var(--sp-3)}
  .sched-day{grid-template-columns:1fr}
  .dist li{grid-template-columns:90px 1fr 48px}
  .hbars li{grid-template-columns:96px 1fr 56px}
}


/* ════════════════════════════════════════════════════════ [P] 인쇄 ══
   성적표에 인쇄 버튼이 있는데 @media print 규칙이 하나도 없어
   상단바·기수바까지 종이에 찍혔다. */
@media print{
  .topbar,.cohortbar,.toolbar-right,.tabs,.flash,.page-head .btn-ghost,
  .nav,.btn,button{display:none !important}
  .container{max-width:none;padding:0}
  body{background:#fff;color:#000;font-size:11px}
  .card{
    border:1px solid #ccc;border-radius:0;box-shadow:none;
    break-inside:avoid;page-break-inside:avoid;padding:10px;margin-bottom:10px}
  .grid2{grid-template-columns:1fr 1fr;gap:10px}
  h1{font-size:16px;margin-bottom:8px}
  h2{font-size:12px}
  a{color:#000;text-decoration:none}
  a[href]::after{content:none}
  .list,.mini{font-size:10px}
  thead{display:table-header-group}
  tr{break-inside:avoid}
}
