:root{
  --bg:#f6f7f9; --surface:#ffffff; --line:#e9ebef; --line-2:#dfe2e8;
  --text:#1a1d23; --muted:#6b7280; --muted-2:#9aa1ac;
  --primary:#ea580c; --primary-dark:#c2410c; --primary-soft:#fff0e6;
  --success:#16a34a; --success-soft:#e7f6ec;
  --danger:#e23b3b; --danger-soft:#fdecec;
  --warning:#d97706; --warning-soft:#fff4e5;
  --hover:#f3f4f7; --hover-2:#f7f8fa; --th-bg:#f7f8fa; --input-bg:#ffffff;
  --radius:0; --radius-sm:0;
  --shadow:0 1px 2px rgba(16,24,40,.04), 0 6px 24px rgba(16,24,40,.05);
  --bronze:#a6713c; --silver:#8a93a0; --gold:#e0a008; --platinum:#20a392;
  --diamond:#27b8d4; --ruby:#e44b78; --master:#b3382f;
  --line-strong:#111;
  --sidebar-w:264px; --sidebar-mini:68px;
  /* 모든 폼 컨트롤이 같은 높이를 쓴다 — 입력칸·버튼·셀렉트가 한 줄에 서면
     브라우저 기본 위젯끼리 높이가 어긋나 보이던 문제를 여기서 못 박는다. */
  --ctl-h:42px; --ctl-h-sm:32px; --ctl-h-lg:48px;
}
:root[data-theme="dark"]{
  --bg:#0f1218; --surface:#171b22; --line:#262c37; --line-2:#333a47;
  --text:#e6e8ec; --muted:#9aa3b0; --muted-2:#707886;
  --primary:#fb923c; --primary-dark:#f97316; --primary-soft:#2c1a10;
  --success:#2bb763; --success-soft:#15281c;
  --danger:#f06a6a; --danger-soft:#2c1a1a;
  --warning:#e0a64a; --warning-soft:#2c2316;
  --hover:#1f2530; --hover-2:#1c222c; --th-bg:#1c222c; --input-bg:#10141a;
  --shadow:0 1px 2px rgba(0,0,0,.3), 0 6px 24px rgba(0,0,0,.35);
  --line-strong:#e6e8ec;
}
*{box-sizing:border-box}
/* hidden 속성은 UA 스타일시트의 display:none 으로만 동작해서, 클래스에
   display:flex/grid 를 주면 조용히 무시된다(요소가 계속 보인다). 여기서 못 박는다. */
[hidden]{display:none !important}
html,body{margin:0;padding:0}
body{
  /* 'Pretendard Variable' 이 CDN 에서 오는 가변 폰트(base.html), 'Pretendard' 는
     기기에 깔려 있을 때 쓰는 통짜 폰트 — 둘 다 없으면 시스템 폰트로 내려간다. */
  font-family:'Pretendard Variable','Pretendard',-apple-system,BlinkMacSystemFont,
              'Apple SD Gothic Neo','Segoe UI',Roboto,sans-serif;
  background:var(--bg); color:var(--text); font-size:14.5px; line-height:1.55;
  -webkit-font-smoothing:antialiased;
}
a{color:inherit;text-decoration:none}
button{font-family:inherit;cursor:pointer}
input,textarea,select{font-family:inherit}

/* ---------------- layout ---------------- */
.layout{display:flex;min-height:100vh}
.sidebar{
  position:fixed;top:0;left:0;width:var(--sidebar-w);height:100vh;
  background:var(--surface);border-right:1px solid var(--line);
  display:flex;flex-direction:column;padding:18px 14px;z-index:50;
}
.content{margin-left:var(--sidebar-w);flex:1;min-width:0}
.container{max-width:980px;margin:0 auto;padding:34px 30px 80px}

.sidebar-head{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:0 6px 16px}
.sidebar-head .brand{flex:1;min-width:0}
.collapse-btn,.floating-toggle{display:inline-flex;align-items:center;justify-content:center;
  width:34px;height:34px;border:1px solid var(--line);background:var(--surface);border-radius:0;
  color:var(--muted);cursor:pointer;flex:none;transition:.12s}
.collapse-btn:hover,.floating-toggle:hover{background:var(--hover);color:var(--text)}
.collapse-btn svg,.floating-toggle svg{width:18px;height:18px}
.floating-toggle{position:fixed;top:14px;left:14px;z-index:60;display:none;box-shadow:var(--shadow)}

/* collapsed == mini icon rail (desktop). Only the symbols, the logo, the
   toggle and the avatar/login buttons survive; every label is hidden. */
html.sidebar-collapsed .sidebar{width:var(--sidebar-mini);padding:18px 10px;align-items:center}
html.sidebar-collapsed .content{margin-left:var(--sidebar-mini)}
html.sidebar-collapsed .sidebar-head{flex-direction:column;gap:10px;padding:0 0 14px;width:100%}
html.sidebar-collapsed .brand{padding:0}
html.sidebar-collapsed .brand>div:not(.logo){display:none}
html.sidebar-collapsed .nav{width:100%}
html.sidebar-collapsed .nav-label{display:none}
/* no labels on the rail means no way to re-open a group — force them all open
   (needs to outweigh .nav-group.closed .nav-items) */
html.sidebar-collapsed .nav-group.closed .nav-items{grid-template-rows:1fr}
html.sidebar-collapsed .nav-group+.nav-group{margin-top:8px;padding-top:8px;border-top:1px solid var(--line)}
html.sidebar-collapsed .nav a{justify-content:center;padding:11px 0;gap:0}
html.sidebar-collapsed .nav a span{display:none}
html.sidebar-collapsed .usercard{border:none;padding:0;justify-content:center}
html.sidebar-collapsed .usercard:hover{background:transparent;opacity:.85}
html.sidebar-collapsed .usercard .meta{display:none}
/* the rail centers its children, so these two have to claim the full width
   themselves — otherwise .block's width:100% resolves against a shrink-to-fit
   parent and the buttons collapse into slivers */
html.sidebar-collapsed .auth-cta{width:100%}
html.sidebar-collapsed .auth-cta .btn{padding:10px 0;justify-content:center}
html.sidebar-collapsed .auth-cta .btn svg{display:block}
html.sidebar-collapsed .auth-cta .btn span{display:none}

.brand{display:flex;align-items:center;gap:10px;padding:6px}
.brand .logo{
  width:34px;height:34px;border-radius:0;overflow:hidden;
  display:grid;place-items:center;color:#fff;font-weight:800;font-size:18px;flex:none;
}
.brand .logo img{width:100%;height:100%;object-fit:contain;display:block}
.brand b{font-size:18px;letter-spacing:-.3px}
.brand span{display:block;font-size:11px;color:var(--muted-2);margin-top:-2px}

/* the nav is the only scrolling part of the sidebar: the brand stays on top,
   the profile / 로그인·회원가입 block stays pinned to the bottom, and a long
   menu scrolls between them instead of pushing the footer off-screen.
   min-height:0 is what actually lets a flex child shrink enough to scroll. */
.nav{display:flex;flex-direction:column;gap:2px;margin-top:4px;
  flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;
  scrollbar-width:thin;scrollbar-color:var(--line-2) transparent}
.nav::-webkit-scrollbar{width:8px}
.nav::-webkit-scrollbar-thumb{background:var(--line-2);border:2px solid var(--surface)}
.nav::-webkit-scrollbar-track{background:transparent}
.nav-group{display:flex;flex-direction:column;gap:2px}
.nav-group+.nav-group{margin-top:14px}
/* group header: grey label on the left, chevron on the same line at the right */
.nav-label{display:flex;align-items:center;justify-content:space-between;width:100%;
  padding:2px 12px 5px;background:none;border:none;cursor:pointer;text-align:left;
  font-size:11px;font-weight:700;letter-spacing:.06em;font-family:inherit;
  color:var(--muted-2);text-transform:uppercase}
.nav-label:hover{color:var(--text)}
.nav-label .chev{width:13px;height:13px;flex:none;opacity:.75;
  transform:rotate(90deg);transition:transform .2s ease}
.nav-group.closed .nav-label .chev{transform:rotate(0deg)}
/* 1fr → 0fr collapses the rows to nothing, which animates (unlike height:auto) */
.nav-items{display:grid;grid-template-rows:1fr;transition:grid-template-rows .22s ease}
.nav-items>div{min-height:0;overflow:hidden;display:flex;flex-direction:column;gap:2px}
.nav-group.closed .nav-items{grid-template-rows:0fr}
@media (prefers-reduced-motion:reduce){.nav-items,.nav-label .chev{transition:none}}
.nav a{
  display:flex;align-items:center;gap:11px;padding:10px 12px;border-radius:0;
  color:var(--muted);font-weight:500;transition:.12s;
}
.nav a svg{width:19px;height:19px;flex:none}
/* the discord row carries a long label — let it wrap instead of overflowing.
   the mark stays on currentColor like every other icon in the rail. */
.nav a.discord span{font-size:13.5px;line-height:1.3}
.nav a:hover{background:#f3f4f7;color:var(--text)}
.nav a.active{background:var(--primary-soft);color:var(--primary-dark);font-weight:600}
.nav .sep{height:1px;background:var(--line);margin:10px 8px}

/* .nav takes the free space now — no spacer div in the sidebar any more */
.sidebar-head{flex:none}
.sidebar-foot{flex:none;display:flex;flex-direction:column;gap:8px;
  padding-top:12px;margin-top:8px;border-top:1px solid var(--line)}
.usercard{
  display:flex;align-items:center;gap:11px;padding:10px;border-radius:0;
  border:1px solid var(--line);transition:.12s;
}
.usercard:hover{background:#f7f8fa}
.usercard .meta{min-width:0}
.usercard .nick{font-weight:600;font-size:13.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.usercard .mail{font-size:11.5px;color:var(--muted-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.auth-cta{display:flex;flex-direction:column;gap:8px}
.auth-cta .btn svg{display:none}   /* icon only shows in the mini rail */

.avatar{border-radius:50%;background:var(--primary-soft);color:var(--primary-dark);
  display:grid;place-items:center;font-weight:700;flex:none;overflow:hidden;object-fit:cover}
.avatar img{width:100%;height:100%;object-fit:cover}
.avatar.s{width:38px;height:38px;font-size:15px}
.avatar.m{width:54px;height:54px;font-size:20px}
.avatar.l{width:104px;height:104px;font-size:38px;border:4px solid #fff;box-shadow:var(--shadow)}

/* ---------------- page header ---------------- */
.page-head{display:flex;align-items:flex-end;justify-content:space-between;margin-bottom:22px;gap:16px}
.page-head h1{font-size:25px;margin:0;letter-spacing:-.5px}
.page-head p{margin:4px 0 0;color:var(--muted)}

/* ---------------- buttons ---------------- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:7px;
  height:var(--ctl-h);padding:0 16px;border-radius:0;
  border:1px solid var(--line-2);background:#fff;color:var(--text);font-weight:600;font-size:14px;
  transition:.12s;white-space:nowrap;
  /* 같은 .btn 이라도 <button> 은 사파리가 네이티브 컨트롤로 그려서 지정한
     height 위에 제 나름의 메트릭을 얹는다. <a class="btn"> 옆에 세우면 그
     버튼만 몇 px 더 커 보이던 이유. appearance 를 꺼서 둘을 같은 박스로 만든다. */
  -webkit-appearance:none;appearance:none;
  margin:0;line-height:1;text-align:center;
}
.btn:hover{border-color:#cfd3db;background:#fafbfc}
.btn.primary{background:var(--primary);border-color:var(--primary);color:#fff}
.btn.primary:hover{background:var(--primary-dark);border-color:var(--primary-dark)}
.btn.success{background:var(--success);border-color:var(--success);color:#fff}
.btn.danger{background:#fff;border-color:var(--danger);color:var(--danger)}
.btn.danger:hover{background:var(--danger-soft)}
.btn.ghost{border-color:transparent;background:transparent}
.btn.sm{height:var(--ctl-h-sm);padding:0 11px;font-size:13px}
.btn.lg{height:var(--ctl-h-lg);padding:0 22px;font-size:15px}
.btn.block{width:100%;justify-content:center}
.btn svg{width:17px;height:17px}

/* ---------------- cards ---------------- */
.card{background:var(--surface);border:1px solid var(--line);border-radius:0;
  box-shadow:var(--shadow)}
.card.p{padding:22px}
.grid{display:grid;gap:16px}
.grid.c2{grid-template-columns:repeat(2,1fr)}
.grid.c3{grid-template-columns:repeat(3,1fr)}
.grid.c4{grid-template-columns:repeat(4,1fr)}

.stat{background:var(--surface);border:1px solid var(--line);border-radius:0;
  padding:18px 20px;box-shadow:var(--shadow)}
.stat .k{font-size:12.5px;color:var(--muted);font-weight:600}
.stat .v{font-size:30px;font-weight:800;letter-spacing:-1px;margin-top:6px}

/* ---------------- forms ---------------- */
.field{margin-bottom:16px}
.field label{display:block;font-weight:600;font-size:13.5px;margin-bottom:6px}
.field .hint{font-weight:400;color:var(--muted-2);font-size:12px;margin-left:6px}
.input,textarea.input,select.input{
  width:100%;height:var(--ctl-h);padding:0 13px;border:1px solid var(--line-2);border-radius:0;
  background:#fff;color:var(--text);font-size:14px;line-height:calc(var(--ctl-h) - 2px);
  transition:.12s;
}
textarea.input,select[multiple].input{height:auto;padding:11px 13px;line-height:1.55}
input[type=file].input{padding:9px 13px;line-height:normal}
.input:focus,textarea.input:focus,select.input:focus{
  outline:none;border-color:var(--primary);box-shadow:0 0 0 3px var(--primary-soft)}
textarea.input{resize:vertical;min-height:90px}
textarea.code{font-family:'JetBrains Mono','SF Mono',ui-monospace,Menlo,monospace;
  font-size:13px;line-height:1.5;min-height:160px;white-space:pre;overflow:auto}
.row{display:flex;gap:14px}
.row>*{flex:1}

/* ---------------- flash ---------------- */
.flashes{position:fixed;top:18px;right:18px;z-index:200;display:flex;flex-direction:column;gap:10px;max-width:380px}
.flash{display:flex;align-items:center;gap:12px;padding:12px 12px 12px 16px;border-radius:0;
  box-shadow:var(--shadow);font-weight:500;background:#fff;border:1px solid var(--line);
  animation:slidein .25s ease}
.flash .msg{flex:1;min-width:0}
.flash .close{flex:none;width:26px;height:26px;border:none;background:transparent;color:var(--muted-2);
  border-radius:0;font-size:15px;line-height:1;cursor:pointer;display:grid;place-items:center;transition:.12s}
.flash .close:hover{background:#f1f3f6;color:var(--text)}
@keyframes slidein{from{opacity:0;transform:translateX(20px)}to{opacity:1;transform:none}}

/* ---------------- problem list ---------------- */
.plist{display:flex;flex-direction:column;gap:0;background:var(--surface);
  border:1px solid var(--line);border-radius:0;overflow:hidden;box-shadow:var(--shadow)}
.prow{display:flex;align-items:center;gap:14px;padding:15px 20px;border-bottom:1px solid var(--line);transition:.1s}
.prow:last-child{border-bottom:none}
.prow:hover{background:#f8f9fb}
.prow .t{flex:1;min-width:0}
.prow .t b{font-size:15.5px;font-weight:600}
.prow .t .sub{font-size:12.5px;color:var(--muted-2);margin-top:2px}
/* 전체 사용자 목록 — same row shell, avatar + coi-n instead of a tier dot */
.userrow{gap:12px}
.userrow .unum{width:26px;flex:none;text-align:center;font-weight:800;
  font-size:13px;color:var(--muted-2)}
.userrow .avatar{flex:none}
.userrow .coin-chip{padding:5px 11px;font-size:12.5px;flex:none}
.userrow .coin-chip .ic{width:18px;height:18px;font-size:10.5px}
/* tier dot — always carries the problem's tier color. hollow ring = 미해결,
   filled = 해결. */
.prow .solvedot{--dot:var(--line-2);width:10px;height:10px;border-radius:50%;flex:none;
  background:transparent;box-shadow:inset 0 0 0 2.5px var(--dot)}
.prow .solvedot.on{background:var(--dot)}
.prow .solvedot.s-브론즈{--dot:var(--bronze)}
.prow .solvedot.s-실버{--dot:var(--silver)}
.prow .solvedot.s-골드{--dot:var(--gold)}
.prow .solvedot.s-플래티넘{--dot:var(--platinum)}
.prow .solvedot.s-다이아{--dot:var(--diamond)}
.prow .solvedot.s-다이아몬드{--dot:var(--diamond)}
.prow .solvedot.s-루비{--dot:var(--ruby)}
.prow .solvedot.s-마스터{--dot:var(--master)}

.tier{display:inline-flex;align-items:center;gap:6px;padding:3px 10px;border-radius:0;
  font-size:12px;font-weight:700;border:1px solid var(--line)}
.tier .dot{width:8px;height:8px;border-radius:50%}
.tier.브론즈 .dot{background:var(--bronze)} .tier.브론즈{color:var(--bronze)}
.tier.실버 .dot{background:var(--silver)} .tier.실버{color:var(--silver)}
.tier.골드 .dot{background:var(--gold)} .tier.골드{color:#b07c00}
.tier.플래티넘 .dot{background:var(--platinum)} .tier.플래티넘{color:var(--platinum)}
.tier.다이아 .dot{background:var(--diamond)} .tier.다이아{color:#127f93}
.tier.다이아몬드 .dot{background:var(--diamond)} .tier.다이아몬드{color:#127f93}
.tier.루비 .dot{background:var(--ruby)} .tier.루비{color:var(--ruby)}
.tier.마스터 .dot{background:var(--master)} .tier.마스터{color:var(--master)}
.tier.none{color:var(--muted-2)} .tier.none .dot{background:var(--line-2)}

/* ---------------- 대회 (contests) ---------------- */
.contest-card{display:flex;flex-direction:column;gap:8px;transition:.12s}
.contest-card:hover{border-color:var(--primary);transform:translateY(-1px)}
.contest-card .row-top{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.contest-card .row-top .spacer{flex:1}
.contest-card .ctitle{font-size:17px}
.contest-card .cmeta{display:flex;gap:14px;flex-wrap:wrap;margin-top:2px;
  font-size:12.5px;color:var(--muted-2)}
.contest-card .live-dot{width:6px;height:6px;margin-right:5px}

.join-code{display:flex;align-items:center;gap:18px;flex-wrap:wrap;margin-bottom:24px;
  padding:14px 18px;background:var(--surface);border:1px solid var(--primary);
  box-shadow:var(--shadow)}
.join-code .k{font-size:11.5px;font-weight:700;color:var(--muted-2)}
.join-code .v{font-size:24px;font-weight:800;letter-spacing:.22em;color:var(--primary-dark)}

.cletter{display:grid;place-items:center;width:26px;height:26px;flex:none;
  border:1px solid var(--line-2);font-size:12.5px;font-weight:800;color:var(--muted)}

.vis-pick{display:grid;grid-template-columns:repeat(2,1fr);gap:10px}
.vis-opt{display:flex;align-items:flex-start;gap:9px;padding:13px 14px;cursor:pointer;
  border:1px solid var(--line-2);background:var(--surface);transition:.12s}
.vis-opt:hover{border-color:var(--primary)}
.vis-opt:has(input:checked){border-color:var(--primary);background:var(--primary-soft)}
.vis-opt input{margin:3px 0 0;accent-color:var(--primary);flex:none}
.vis-opt b{display:block;font-size:14px}
.vis-opt em{display:block;font-style:normal;font-size:12px;color:var(--muted-2);margin-top:3px}
.vis-opt .lock{display:inline-block;margin-top:6px;font-size:11px;font-weight:700;
  color:var(--danger);background:var(--danger-soft);padding:2px 7px}
.vis-opt.locked{opacity:.65;cursor:not-allowed}
.vis-opt.locked:hover{border-color:var(--line-2)}

/* 채점 방법 picker (문제 만들기) — same card shape as the contest one.
   상자 안에는 이름만 둔다. 고르는 자리에서 긴 설명을 읽히지 않는다. */
.mode-pick{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
.mode-pick.two{grid-template-columns:repeat(2,1fr)}
.mode-opt{display:flex;align-items:center;gap:9px;padding:13px 14px;cursor:pointer;
  border:1px solid var(--line-2);background:var(--surface);transition:.12s}
.mode-opt:hover{border-color:var(--primary)}
.mode-opt:has(input:checked){border-color:var(--primary);background:var(--primary-soft)}
.mode-opt input{margin:0;accent-color:var(--primary);flex:none}
.mode-opt b{display:block;font-size:14px}

/* 채점 방법과 따로 켜고 끄는 스위치들 (스페셜 저지 · 전부 맞아야 100점) */
.sj-toggle{display:flex;align-items:center;gap:9px;margin:10px 0 0;padding:13px 14px;
  cursor:pointer;border:1px solid var(--line-2);background:var(--surface);transition:.12s}
.sj-toggle:hover{border-color:var(--primary)}
.sj-toggle:has(input:checked){border-color:var(--primary);background:var(--primary-soft)}
.sj-toggle input{margin:0;accent-color:var(--primary);flex:none}
.sj-toggle b{display:block;font-size:14px}
.sj-only{margin-top:16px}
/* 채점 방법을 하나도 안 켠 폼 */
.mode-warn{margin:10px 0 0;color:var(--danger);font-weight:700}

/* 채점 케이스 */
.sec-head{display:flex;justify-content:space-between;align-items:center;
  gap:12px;flex-wrap:wrap;margin-bottom:6px}
.tc-row{border:1px solid var(--line);margin-bottom:12px;background:var(--surface)}
.tc-head{display:flex;align-items:center;gap:12px;padding:10px 14px;background:var(--hover)}
.tc-row:has(.tc-body:not([hidden])) .tc-head{border-bottom:1px solid var(--line)}
.tc-head b{font-size:13.5px;flex:none}
/* 접힌 줄에 보이는 요약 — 크기와 첫 줄. 본문은 열어야 나온다. */
.tc-sum{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  color:var(--muted-2);font-weight:600}
/* 파일로 올린 칸: 브라우저는 내용을 읽지 않고 이름과 크기만 보여준다 */
.tc-filed{padding:10px 12px;background:var(--hover-2);border-bottom:1px solid var(--line);
  font-size:12.5px}
.tc-filed b{word-break:break-all}
.tc-filed .btn{margin-left:8px}
.tc-pts{display:flex;align-items:center;gap:7px;font-size:12px;color:var(--muted-2);font-weight:600}
.tc-pts .input{width:74px;height:var(--ctl-h-sm);padding:0 8px;line-height:calc(var(--ctl-h-sm) - 2px)}
.tc-total{margin-top:4px;font-weight:700}
.tc-total.ok{color:var(--success)}
.tc-total.bad{color:var(--danger)}
.tc-alts{border-top:1px solid var(--line);padding:10px 14px;background:var(--hover-2)}
.tc-alt-head{display:flex;align-items:center;justify-content:space-between;gap:10px}
.tc-alt{margin-top:8px;border:1px solid var(--line)}
.tc-alt .h{display:flex;align-items:center;justify-content:space-between;
  padding:6px 10px;font-size:12px;font-weight:700;color:var(--muted-2);
  background:var(--hover);border-bottom:1px solid var(--line)}
/* 출력을 정답 코드가 만들어 줄 때, 출력 칸 자리에 놓이는 안내 */
.tc-auto{padding:14px;background:var(--hover-2);font-size:12.5px;font-weight:600;
  color:var(--muted-2);min-height:90px;display:flex;flex-direction:column;
  justify-content:center;gap:3px}
.tc-auto .muted{font-weight:500}
.tcfile{font-size:11.5px;font-weight:700;color:var(--primary);cursor:pointer}
.tcfile:hover{text-decoration:underline}
.ioex .h{display:flex;align-items:center;justify-content:space-between;gap:8px}

/* 서브태스크 부분 점수 */
.st-partial{display:flex;align-items:flex-start;gap:8px;margin:0 0 12px;
  padding:10px 12px;background:var(--hover-2);border:1px solid var(--line);
  font-size:12.5px;color:var(--muted-2);cursor:pointer}
.st-partial input{margin:1px 0 0;accent-color:var(--primary);flex:none}
.st-partial b{color:var(--text)}

/* 코드 칸 머리 (언어 · 파일 올리기 · 상태) */
.code-head{display:flex;align-items:flex-end;gap:12px;flex-wrap:wrap;margin-bottom:8px}
.code-head > label:first-child{font-size:12.5px;font-weight:700;color:var(--muted-2)}
.codefile{display:inline-flex;align-items:center;margin:0;cursor:pointer}
.codefile input[type=file]{position:absolute;width:1px;height:1px;opacity:0;
  pointer-events:none;clip:rect(0 0 0 0);overflow:hidden}
.codefile .btn{pointer-events:none}
/* 초록은 정답(AC) 자리다. 여기서 '잘 됐다'는 색이 아니라 굵기로만 말한다. */
.codefile-note{max-width:340px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.codefile-note.ok{color:var(--text);font-weight:600}
.codefile-note.bad{color:var(--danger);font-weight:600}

/* 만점 합계 */
.pt-sum{font-size:14px;color:var(--text)}
.pt-sum.warn{color:var(--warning)}
.pt-sum.bad{color:var(--danger)}

@media(max-width:860px){.mode-pick,.mode-pick.two{grid-template-columns:1fr}}

/* 출제 자격 진행 바 (대회 만들기 상단) */
.rights-strip{display:flex;align-items:center;gap:20px;flex-wrap:wrap;margin-bottom:20px;
  padding:14px 18px;background:var(--surface);border:1px solid var(--line);box-shadow:var(--shadow)}
.rights-now .k{font-size:11.5px;color:var(--muted-2);font-weight:600}
.rights-now .v{font-size:26px;font-weight:800;line-height:1;color:var(--primary-dark)}
.rights-steps{display:flex;gap:8px;flex-wrap:wrap}
.rights-steps .step{font-size:12px;font-weight:700;padding:5px 10px;
  border:1px solid var(--line-2);color:var(--muted-2)}
.rights-steps .step.on{border-color:var(--success);color:var(--success);background:var(--success-soft)}

/* scoreboard */
.board{width:100%;border-collapse:collapse;font-size:13.5px;min-width:520px}
.board th,.board td{padding:10px 12px;border-bottom:1px solid var(--line);text-align:left}
.board th{background:var(--th-bg);color:var(--muted);font-weight:600;font-size:12px}
.board .r{text-align:right}
.board tr:last-child td{border-bottom:none}
.board .rank{font-weight:800;color:var(--muted-2)}
.board .rank.r1{color:var(--primary)} .board .rank.r2{color:var(--silver)} .board .rank.r3{color:var(--bronze)}
.board .who{display:flex;align-items:center;gap:9px;font-weight:600}
.board .who .avatar.s{width:26px;height:26px;font-size:12px}
.board tr.me{background:var(--primary-soft)}
.board .cell{font-variant-numeric:tabular-nums;color:var(--muted-2)}
.board .cell.full{color:var(--success);font-weight:800}
.board .cell.part{color:var(--warning);font-weight:700}
.board .cell .min{display:block;font-size:10.5px;font-weight:500;color:var(--muted-2)}

/* profile: 출제 실적 */
.maker-strip{display:flex;align-items:center;gap:18px;flex-wrap:wrap;margin-top:24px;
  padding:16px 20px;background:var(--surface);border:1px solid var(--line);box-shadow:var(--shadow)}
.maker-badge{display:flex;align-items:center;gap:11px;padding-right:18px;border-right:1px solid var(--line)}
.maker-badge svg{width:30px;height:30px;color:var(--muted-2)}
.maker-badge.lit svg{color:var(--success)}
.maker-badge .k{font-size:11.5px;color:var(--muted-2);font-weight:600}
.maker-badge .v{font-size:26px;font-weight:800;line-height:1.1;letter-spacing:-.5px}
.maker-badge .v em{font-style:normal;font-size:12.5px;font-weight:600;color:var(--muted-2);margin-left:4px}
.maker-badge.lit .v{color:var(--success)}
.maker-stats{display:flex;gap:22px}
.maker-stats .s{text-align:center}
.maker-stats .s .v{font-size:18px;font-weight:800;line-height:1.2}
.maker-stats .s .k{font-size:11.5px;color:var(--muted-2)}
/* 대회 개설 자격 칩(.maker-rights)은 프로필에서 뺐다. 자격 안내는 대회 만들기
   화면(.rights-strip)에만 남는다 — 자격을 확인할 자리는 거기 하나면 된다. */

/* ---------------- 문제 분류 (tier cards + algorithm tags) ---------------- */
.cat-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:12px}
.cat-card{display:flex;flex-direction:column;gap:2px;padding:16px 18px;background:var(--surface);
  border:1px solid var(--line);box-shadow:var(--shadow);transition:.12s}
.cat-card:hover{border-color:var(--primary);transform:translateY(-1px)}
.cat-card .dot{width:11px;height:11px;border-radius:50%;background:var(--line-2);margin-bottom:6px}
.cat-card b{font-size:15px}
.cat-card .n{font-size:12.5px;color:var(--muted-2)}
.cat-card.t-브론즈 .dot{background:var(--bronze)}
.cat-card.t-실버 .dot{background:var(--silver)}
.cat-card.t-골드 .dot{background:var(--gold)}
.cat-card.t-플래티넘 .dot{background:var(--platinum)}
.cat-card.t-다이아몬드 .dot{background:var(--diamond)}
.cat-card.t-루비 .dot{background:var(--ruby)}

.tag-block{margin-bottom:16px}
.tag-block-head{font-size:12.5px;font-weight:700;color:var(--muted);margin-bottom:8px}
.tag-cloud{display:flex;flex-wrap:wrap;gap:8px}
.tag-chip{display:inline-flex;align-items:center;gap:7px;padding:7px 12px;font-size:13px;
  font-weight:600;background:var(--surface);border:1px solid var(--line-2);transition:.12s}
.tag-chip:hover{border-color:var(--primary);color:var(--primary-dark);background:var(--primary-soft)}
.tag-chip .n{font-size:11.5px;font-weight:700;color:var(--muted-2)}
.tag-chip.zero{opacity:.5}   /* NB: not .empty — that is the empty-state block */
.tag-chip.sm{padding:4px 10px;font-size:12px}
.tag-pick{display:inline-flex;align-items:center;gap:7px;padding:7px 12px;font-size:13px;
  font-weight:600;background:var(--surface);border:1px solid var(--line-2);cursor:pointer;transition:.12s}
.tag-pick:hover{border-color:var(--primary)}
.tag-pick input{margin:0;accent-color:var(--primary)}
.tag-pick:has(input:checked){border-color:var(--primary);background:var(--primary-soft);
  color:var(--primary-dark)}

.badge{display:inline-flex;align-items:center;gap:5px;font-size:11.5px;font-weight:700;
  padding:3px 9px;border-radius:0;background:#f1f3f6;color:var(--muted)}
.badge.green{background:var(--success-soft);color:var(--success)}
.badge.blue{background:var(--primary-soft);color:var(--primary-dark)}
.badge.red{background:var(--danger-soft);color:var(--danger)}
.badge.amber{background:var(--warning-soft);color:var(--warning)}

/* ---------------- problem detail ---------------- */
.prob-head{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:8px}
.prob-head h1{font-size:27px;margin:0;letter-spacing:-.6px}
.limits{display:flex;gap:10px;margin:16px 0 26px;flex-wrap:wrap}
.limit{background:var(--surface);border:1px solid var(--line);border-radius:0;padding:10px 16px;box-shadow:var(--shadow)}
.limit .k{font-size:11.5px;color:var(--muted-2);font-weight:600}
.limit .v{font-size:16px;font-weight:700;margin-top:1px}

/* problem info table (시간/메모리/맞힌·제출 사람/정답비율) */
.info-table{width:100%;border-collapse:collapse;margin:16px 0 28px;background:var(--surface);
  border:1px solid var(--line);border-radius:0;overflow:hidden;box-shadow:var(--shadow)}
.info-table th{background:#f7f8fa;color:var(--muted);font-weight:600;font-size:12.5px;
  padding:10px 14px;text-align:center;border-bottom:1px solid var(--line)}
.info-table td{padding:13px 14px;text-align:center;font-weight:700;font-size:15px}
.info-table th:not(:last-child),.info-table td:not(:last-child){border-right:1px solid var(--line)}

.section{margin-bottom:30px}
.section h3{font-size:18px;margin:0 0 12px;padding-bottom:9px;border-bottom:1px solid var(--line)}
.section .body{white-space:pre-wrap;word-break:break-word;font-size:16px;line-height:1.7}

/* judge time/memory usage */
.usage{display:flex;gap:18px;margin-top:12px;font-size:13.5px;color:var(--muted)}
.usage b{color:var(--text);font-weight:700}
.ioex{display:grid;grid-template-columns:1fr 1fr;gap:0;border:1px solid var(--line);border-radius:0;overflow:hidden;margin-bottom:12px}
.ioex .h{background:#f7f8fa;padding:7px 12px;font-size:12px;font-weight:700;color:var(--muted);border-bottom:1px solid var(--line)}
.ioex pre{margin:0;padding:12px;font-family:ui-monospace,Menlo,monospace;font-size:13px;white-space:pre-wrap;word-break:break-word}
.ioex .col:first-child{border-right:1px solid var(--line)}
.derived{margin-top:24px;padding:12px 16px;background:#f7f8fa;border-radius:0;color:var(--muted);font-size:13px}

/* ---------------- modal ---------------- */
.modal-bg{position:fixed;inset:0;background:rgba(16,24,40,.42);display:none;
  align-items:center;justify-content:center;z-index:150;padding:20px;
  /* 굴림이 끝까지 갔을 때 뒤 페이지로 넘어가지 않게 여기서 끊는다 */
  overscroll-behavior:contain}
.modal-bg.open{display:flex}
/* 모달이 열려 있는 동안 뒤 페이지는 굳힌다. 사라진 스크롤바 폭은 --sbw 로
   되메워, 열고 닫을 때 본문이 옆으로 튀지 않는다. */
body.modal-open{overflow:hidden;padding-right:var(--sbw,0px)}
.modal{background:#fff;border-radius:0;width:100%;max-width:560px;max-height:90vh;overflow:auto;
  overscroll-behavior:contain;
  box-shadow:0 24px 60px rgba(16,24,40,.25);animation:pop .2s ease}
@keyframes pop{from{opacity:0;transform:scale(.96)}to{opacity:1;transform:none}}
.modal .mhead{display:flex;align-items:center;justify-content:space-between;padding:18px 22px;border-bottom:1px solid var(--line)}
.modal .mhead h3{margin:0;font-size:18px}
.modal .mbody{padding:22px}
.modal .mfoot{padding:16px 22px;border-top:1px solid var(--line);display:flex;justify-content:flex-end;gap:10px}
/* 언어가 여덟 개까지 늘 수 있어 한 줄에 다 세우지 않고 접는다 */
.lang-pick{display:flex;gap:10px;margin-bottom:10px;flex-wrap:wrap}
.lang-note{margin-bottom:12px}
.lang-pick label{flex:1 1 96px;border:1px solid var(--line-2);border-radius:0;padding:12px;
  text-align:center;font-weight:700;cursor:pointer;transition:.12s}
.lang-pick input{display:none}
.lang-pick input:checked+span{color:var(--primary-dark)}
.lang-pick label:has(input:checked){border-color:var(--primary);background:var(--primary-soft)}

/* progress */
.judge-box{margin-top:18px;display:none}
.judge-box.show{display:block}
.progress{height:12px;background:#eef0f3;border-radius:0;overflow:hidden}
.progress .bar{height:100%;width:0;background:linear-gradient(90deg,#ea580c,#fb923c);
  border-radius:0;transition:width .3s ease}
.progress .bar.ac{background:linear-gradient(90deg,#16a34a,#4ade80)}
.progress .bar.wa{background:linear-gradient(90deg,#e23b3b,#f87171)}
.verdict{margin-top:12px;font-size:20px;font-weight:800;letter-spacing:-.4px}
.verdict.ac{color:var(--success)} .verdict.wa{color:var(--danger)} .verdict.judging{color:var(--primary)}
.subresult{margin-top:12px;display:flex;flex-direction:column;gap:8px}
.subitem{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;
  border:1px solid var(--line);border-radius:0;font-size:13.5px}
.subitem.pass{background:var(--success-soft);border-color:#bfe6cb}
.subitem.fail{background:var(--danger-soft);border-color:#f3c9c9}

/* submissions table */
.subs{width:100%;border-collapse:collapse;font-size:13.5px}
.subs th,.subs td{text-align:left;padding:10px 12px;border-bottom:1px solid var(--line)}
.subs th{color:var(--muted);font-weight:600;font-size:12.5px}

/* ---------------- profile ---------------- */
.banner{height:200px;border-radius:0;overflow:hidden;background:linear-gradient(120deg,#ea580c,#8e6bff);position:relative}
.banner img{width:100%;height:100%;object-fit:cover}
.profile-top{display:flex;flex-direction:column;align-items:flex-start;gap:0;margin-top:-52px;padding:0 4px;position:relative}
.profile-top .info{width:100%;padding-top:14px}
.profile-top .info .namerow{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.profile-top .info h2{margin:0;font-size:24px;letter-spacing:-.5px}
.profile-top .info .bio{color:var(--muted);margin:10px 0 0;white-space:pre-wrap}
.profile-top .info .link{display:inline-flex;align-items:center;gap:6px;color:var(--primary);font-weight:600;margin-top:10px;font-size:13.5px}

/* 탭 — 밑줄은 anchor 의 border 로 긋는다. :after 를 절대 배치로 얹으면 기준선이
   둘(컨테이너 테두리 / 가짜 요소)이라 반드시 어긋난다. 두께는 정수 픽셀만
   쓴다: 2.5px 는 어느 화면에서도 딱 떨어지지 않아 번진 것처럼 보인다. */
.tabs{display:flex;gap:26px;margin:26px 0 22px;border-bottom:1px solid var(--line)}
.tabs a{padding:0 1px 11px;margin-bottom:-1px;    /* 2px 밑줄이 1px 선을 덮게 */
  font-size:15px;font-weight:600;color:var(--muted-2);
  border-bottom:2px solid transparent;transition:color .12s,border-color .12s}
.tabs a:hover{color:var(--text)}
.tabs a.active{color:var(--text);font-weight:700;border-bottom-color:var(--primary)}

/* portfolio — one item per row */
.pf-list{display:flex;flex-direction:column;gap:12px}
.pf-add{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;
  padding:14px;border:1px dashed var(--line-2);border-radius:0;background:#fff;
  color:var(--muted);font-weight:600;font-size:14px;cursor:pointer;transition:.12s}
.pf-add:hover{border-color:var(--primary);color:var(--primary);background:var(--primary-soft)}
.pf-add .plus{font-size:18px;line-height:1;font-weight:700}
.pf-card{display:flex;gap:16px;align-items:stretch;padding:14px 16px;
  background:var(--surface);border:1px solid var(--line);border-radius:0;box-shadow:var(--shadow)}
.pf-imgs{display:flex;gap:2px;width:230px;height:120px;flex:none;background:#f1f3f6;border-radius:0;overflow:hidden}
.pf-imgs img{flex:1;object-fit:cover;min-width:0;height:100%}
.pf-card .pf-body{flex:1;min-width:0;display:flex;flex-direction:column;justify-content:center;padding:2px 0}
.pf-card .pf-body b{font-size:16px}
.pf-card .pf-body p{margin:6px 0 0;color:var(--muted);font-size:13.5px;white-space:pre-wrap}

.feed{display:flex;flex-direction:column;gap:0;background:var(--surface);border:1px solid var(--line);
  border-radius:0;overflow:hidden;box-shadow:var(--shadow)}
.feed .item{display:flex;gap:13px;padding:14px 18px;border-bottom:1px solid var(--line)}
.feed .item:last-child{border-bottom:none}
.feed .ic{width:34px;height:34px;border-radius:0;display:grid;place-items:center;flex:none;font-size:16px}
.feed .ic svg{width:17px;height:17px}
.feed .ic.create{background:var(--primary-soft);color:var(--primary-dark)}
.feed .ic.solve{background:var(--success-soft);color:var(--success)}
.feed .ic.tier{background:var(--warning-soft);color:var(--warning)}

/* operator/master role tag (replaces crown emoji) */
.role-tag{display:inline-block;vertical-align:middle;font-size:11px;font-weight:700;line-height:1;
  padding:3px 7px;border-radius:0;background:var(--primary-soft);color:var(--primary-dark);
  margin-left:4px}
.feed .item .when{color:var(--muted-2);font-size:12px;margin-top:2px}

/* ---------------- AC 레이팅 막대 (프로필 머리) ---------------- */
/* --tone 하나만 티어별로 갈아끼우고 나머지는 거기서 만든다 */
.acbar{--tone:var(--muted-2);margin:18px 0 0;padding:14px 0 0}
.acbar.g-브론즈{--tone:var(--bronze)} .acbar.g-실버{--tone:var(--silver)}
.acbar.g-골드{--tone:var(--gold)} .acbar.g-플래티넘{--tone:var(--platinum)}
.acbar.g-다이아몬드{--tone:var(--diamond)} .acbar.g-루비{--tone:var(--ruby)}
.acbar.g-마스터{--tone:var(--master)}
.acbar-head{display:flex;align-items:baseline;justify-content:space-between;
  gap:14px;flex-wrap:wrap;margin-bottom:8px}
.acbar-tier b{font-size:17px;font-weight:800;color:var(--tone);letter-spacing:-.3px}
.acbar-tier .score{font-size:17px;font-weight:700;margin-left:6px}
.acbar-tier .rank{font-size:12px;color:var(--muted-2);margin-left:10px;font-weight:600}
.acbar-next{font-size:12.5px;color:var(--muted-2);font-weight:600}
.acbar-track{height:14px;background:var(--hover);border:1px solid var(--line)}
.acbar-fill{height:100%;min-width:2px;
  background:linear-gradient(90deg,
    color-mix(in srgb, var(--tone) 72%, #000 12%), var(--tone));
  transition:width .4s}
.acbar-note{margin:8px 0 0;font-size:12px;color:var(--muted-2)}

/* ---------------- 프로필 탭 안의 구획 제목 ---------------- */
.sec-title{display:flex;align-items:baseline;gap:8px;font-size:15px;margin:0 0 10px}
.sec-title .more{margin-left:auto;font-size:12.5px;font-weight:700;color:var(--primary)}

/* ---------------- 히스토리 꺾은선 ---------------- */
.chart-card{margin-bottom:18px}
.chart-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px;
  flex-wrap:wrap;margin-bottom:14px}
.chart-head h3{margin:0;font-size:15px}
.chart-now b{font-size:20px;font-weight:800;letter-spacing:-.5px}
.chart-now .unit{font-size:12px;color:var(--muted-2);margin-left:3px}
.chart-now .muted{margin-left:8px}
.chart-wrap{display:flex;gap:10px;height:170px}
.chart-y{display:flex;flex-direction:column;justify-content:space-between;
  font-size:11px;color:var(--muted-2);font-weight:600;text-align:right;min-width:38px}
.chart{flex:1;height:100%;overflow:visible}
.chart .grid{stroke:var(--line);stroke-width:1;stroke-dasharray:3 4}
.chart .line{fill:none;stroke:var(--primary);stroke-width:2;
  stroke-linejoin:round;stroke-linecap:round}
.chart .area{fill:var(--primary);opacity:.10;stroke:none}
.chart-x{display:flex;justify-content:space-between;margin:6px 0 0 48px;
  font-size:11px;color:var(--muted-2);font-weight:600}

/* 기록 표. 정렬은 자리로 정한다 — `.num` 은 숫자 입력 위젯이 쓰는 이름이라
   (display:flex) 표 칸에 붙이면 칸이 세로로 무너진다. */
.hist-scroll{max-height:340px;overflow:auto;border:1px solid var(--line)}
.hist-table{width:100%;border-collapse:collapse;font-size:13.5px}
.hist-table th,.hist-table td{padding:9px 14px;text-align:left;white-space:nowrap}
.hist-table th{position:sticky;top:0;z-index:1;background:var(--hover);
  color:var(--muted);font-weight:600;font-size:12px;
  border-bottom:1px solid var(--line)}
.hist-table th:not(:first-child),.hist-table td:not(:first-child){text-align:right}
.hist-table tbody tr:not(:last-child) td{border-bottom:1px solid var(--line)}
.hist-table tbody tr:hover td{background:var(--hover-2)}
.hist-table td{font-variant-numeric:tabular-nums}
.hist-table .date{color:var(--muted-2);font-weight:600}
.hist-table .up{color:var(--primary);font-weight:700}
.hist-table .flat{color:var(--line-2)}
.hist-table .unit{font-size:11.5px;color:var(--muted-2);margin-left:1px}
.hist-table .of{font-size:11.5px;color:var(--muted-2);margin-left:4px}

/* ---------------- 난이도 · 알고리즘 분포 ---------------- */
.dist-row{align-items:start}
.dist-head{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;margin-bottom:14px}
.dist-head .cap{font-size:11.5px;font-weight:700;color:var(--muted-2)}
.dist-head b{font-size:19px;font-weight:800;letter-spacing:-.5px}
.dist-body{display:flex;align-items:center;gap:18px;flex-wrap:wrap}
.donut,.radar{width:190px;flex:none;overflow:visible}
.donut circle{fill:none;stroke-width:6}
.donut .ring-bg{stroke:var(--hover)}
.donut .seg{transition:opacity .12s}
.donut:hover .seg{opacity:.35!important}
.donut .seg:hover{opacity:1!important}
.radar .ring{fill:none;stroke:var(--line);stroke-width:.6;stroke-dasharray:2 2}
.radar .spoke{stroke:var(--line);stroke-width:.6}
.radar .area{fill:var(--primary);fill-opacity:.16;stroke:var(--primary);stroke-width:1.4}
.radar .pt{fill:var(--primary)}
.radar .lbl{font-size:5px;font-weight:700;fill:var(--muted-2)}
.dist-table{flex:1;min-width:190px;border-collapse:collapse;font-size:13px}
.dist-table th{font-size:11.5px;color:var(--muted-2);text-align:left;padding:0 0 6px;font-weight:600}
.dist-table th:not(:first-child),.dist-table td:not(:first-child){text-align:right}
.dist-table td{padding:6px 0;border-top:1px solid var(--line);
  font-variant-numeric:tabular-nums}
.dist-table td.muted{color:var(--muted-2)}
@media(max-width:720px){.dist-body{justify-content:center}.donut,.radar{width:100%;max-width:240px}}

.solved-summary{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:18px}
/* 푼 문제 칩은 그 문제의 티어 색을 입는다. 초록은 이 사이트에서 '맞았습니다'
   한 가지 뜻으로만 쓰는 색이라, 푼 문제 목록 전체를 초록으로 칠하면 티어가
   무엇이든 다 같은 문제로 보인다. 티어별로 --tone 하나만 갈아끼우고, 배경·
   테두리·글자는 그 색에서 자동으로 만든다. */
.solved-chip{display:inline-flex;align-items:center;gap:7px;padding:7px 13px;border-radius:0;
  --tone:var(--muted-2);
  background:var(--hover);                 /* color-mix 를 모르는 브라우저용 */
  background:color-mix(in srgb, var(--tone) 13%, transparent);
  border:1px solid var(--line);
  border:1px solid color-mix(in srgb, var(--tone) 38%, transparent);
  font-weight:600;font-size:13px;color:var(--ink,var(--tone))}
.solved-chip .dot{width:8px;height:8px;border-radius:50%;background:var(--tone);flex:none}
/* 티어 이름은 tier_group() 이 내주는 6가지뿐이다 (models.TIER_GROUPS) */
.solved-chip.s-브론즈{--tone:var(--bronze)}
.solved-chip.s-실버{--tone:var(--silver)}
.solved-chip.s-골드{--tone:var(--gold);--ink:#b07c00}
.solved-chip.s-플래티넘{--tone:var(--platinum)}
.solved-chip.s-다이아몬드{--tone:var(--diamond);--ink:#127f93}
.solved-chip.s-루비{--tone:var(--ruby)}

.empty{text-align:center;color:var(--muted-2);padding:48px 20px}
.empty .big{font-size:38px;margin-bottom:8px}

/* theme segmented control */
.theme-switch{display:inline-flex;border:1px solid var(--line-2);border-radius:0;overflow:hidden;flex:none}
.theme-switch button{border:none;background:var(--surface);color:var(--muted);padding:9px 18px;
  font-weight:600;font-size:13.5px;cursor:pointer;transition:.12s}
.theme-switch button+button{border-left:1px solid var(--line-2)}
.theme-switch button:hover{background:var(--hover)}
.theme-switch button.active{background:var(--primary);color:#fff}
:root[data-theme="dark"] .theme-switch button.active{color:#2b1206}

/* toggle switch */
.switch{position:relative;display:inline-block;width:48px;height:28px;flex:none}
.switch input{opacity:0;width:0;height:0}
.switch .slider{position:absolute;inset:0;background:#cfd3db;border-radius:0;transition:.2s;cursor:pointer}
.switch .slider:before{content:"";position:absolute;width:22px;height:22px;left:3px;top:3px;
  background:#fff;border-radius:0;transition:.2s;box-shadow:0 1px 3px rgba(0,0,0,.2)}
.switch input:checked+.slider{background:var(--primary)}
.switch input:checked+.slider:before{transform:translateX(20px)}

.settings-tabs{display:flex;gap:8px;margin-bottom:24px}
.settings-tabs a{padding:9px 16px;border-radius:0;font-weight:600;color:var(--muted);background:#fff;border:1px solid var(--line)}
.settings-tabs a.active{background:var(--primary-soft);color:var(--primary-dark);border-color:var(--primary-soft)}

/* auth */
.auth-wrap{min-height:100vh;display:grid;place-items:center;padding:24px;
  background:radial-gradient(1200px 600px at 50% -10%,#ffeee2,transparent),var(--bg)}
.auth-card{width:100%;max-width:420px;background:#fff;border:1px solid var(--line);border-radius:0;
  padding:34px 32px;box-shadow:var(--shadow)}
.auth-card .brand{justify-content:center;padding:0 0 22px}
.auth-card h1{font-size:22px;margin:0 0 4px;text-align:center}
.auth-card .sub{text-align:center;color:var(--muted);margin:0 0 24px}
.auth-card .alt{text-align:center;margin-top:18px;color:var(--muted);font-size:13.5px}
.auth-card .alt a{color:var(--primary);font-weight:600}
.auth-back{position:fixed;top:20px;left:20px;display:inline-flex;align-items:center;gap:6px;
  padding:9px 15px;border-radius:0;background:#fff;border:1px solid var(--line);
  font-weight:600;color:var(--text);box-shadow:var(--shadow);z-index:10;transition:.12s}
.auth-back:hover{background:#fafbfc;border-color:#cfd3db}

/* ---------------- 실시간 현황 / coi-n ---------------- */
.live-dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--success);
  margin-right:7px;box-shadow:0 0 0 0 rgba(234,88,12,.5);animation:pulse 1.6s infinite}
@keyframes pulse{0%{box-shadow:0 0 0 0 rgba(234,88,12,.5)}70%{box-shadow:0 0 0 8px rgba(234,88,12,0)}100%{box-shadow:0 0 0 0 rgba(234,88,12,0)}}

.coin{display:inline-flex;align-items:center;gap:6px;font-weight:800;color:#c2410c}
.coin .ic{display:grid;place-items:center;width:20px;height:20px;border-radius:50%;
  background:linear-gradient(135deg,#fdba74,#ea580c);color:#4a1a03;font-size:12px;font-weight:900;flex:none}
.coin-chip{display:inline-flex;align-items:center;gap:8px;padding:8px 14px;border-radius:0;
  background:linear-gradient(135deg,#fff7ed,#ffedd5);border:1px solid #fdba74;font-weight:800;color:#c2410c}
.coin-chip .ic{width:22px;height:22px;border-radius:50%;display:grid;place-items:center;
  background:linear-gradient(135deg,#fdba74,#ea580c);color:#4a1a03;font-size:12px;font-weight:900}

.rank-row{display:flex;align-items:center;gap:13px;padding:13px 18px;border-bottom:1px solid var(--line)}
.rank-row:last-child{border-bottom:none}
.rank-row .num{width:30px;text-align:center;font-weight:800;font-size:16px;color:var(--muted-2);flex:none}
.rank-row.top1 .num{color:#ea580c} .rank-row.top2 .num{color:#8a93a0} .rank-row.top3 .num{color:#a6713c}
.rank-row .who{flex:1;min-width:0;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rank-row .who .sub{font-size:12px;color:var(--muted-2);font-weight:400}
.rank-row .pts{font-weight:800;color:#b07c00}

.live-sub{display:flex;align-items:center;gap:11px;padding:11px 18px;border-bottom:1px solid var(--line);font-size:13.5px}
.live-sub:last-child{border-bottom:none}
.live-sub .t{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.live-sub .when{color:var(--muted-2);font-size:12px;font-variant-numeric:tabular-nums}

/* ---------------- streak / contribution heatmap ---------------- */
/* 격자 패널 히어로 — 굵기·간격 모두 균일한 단일 격자 */
.hero{position:relative;overflow:hidden;margin-bottom:22px;
  background:#0e1117;border:1px solid #1d2230;color:#fff}
.hero-grid{position:absolute;inset:0;pointer-events:none;
  background-image:
    linear-gradient(to right,rgba(255,255,255,.14) 1px,transparent 1px),
    linear-gradient(to bottom,rgba(255,255,255,.14) 1px,transparent 1px);
  background-size:64px 64px}
.hero-in{position:relative;padding:52px 40px 46px}
.hero-tag{display:inline-block;padding:6px 12px;margin-bottom:22px;
  border:1px solid var(--primary);color:var(--primary);
  font-size:11.5px;font-weight:800;letter-spacing:.18em}
.hero h1{margin:0;font-size:46px;font-weight:800;line-height:1.06;letter-spacing:-1.6px}
.hero p{margin:18px 0 0;color:#98a1b0;font-size:15px}
/* opaque so the hero grid never shows through the buttons — only the frame
   lines around/between them */
.hero .cta{position:relative;display:grid;grid-auto-flow:column;grid-auto-columns:1fr;
  border-top:1px solid #1d2230;background:#0e1117}
.hero .cta .btn{justify-content:center;padding:19px 16px;font-size:14px;font-weight:700;
  border:none;border-left:1px solid #1d2230;background:transparent;color:#fff}
.hero .cta .btn:first-child{border-left:none}
.hero .cta .btn:hover{background:rgba(255,255,255,.05);color:var(--primary)}

.streak-card{background:var(--surface);border:1px solid var(--line);border-radius:0;
  box-shadow:var(--shadow);padding:20px 22px;margin-bottom:26px}
.streak-head{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-bottom:16px;flex-wrap:wrap}
.streak-head h3{margin:0;font-size:16px;display:flex;align-items:center;gap:8px}
.streak-stats{display:flex;gap:22px}
.streak-stats .s{text-align:right}
.streak-stats .s .v{font-size:22px;font-weight:800;letter-spacing:-.5px;line-height:1}
.streak-stats .s .v .fire{color:#ea580c}
.streak-stats .s .k{font-size:11.5px;color:var(--muted-2);margin-top:3px}

.heatmap{overflow-x:auto;padding-bottom:4px}
/* 달 이름은 달이 바뀌는 칸에만 붙고, 다음 칸들 위로 흘러넘치게 둔다 */
.hm-months{display:flex;gap:3px;margin-bottom:4px;font-size:10.5px;font-weight:700;
  color:var(--muted-2);line-height:1}
.hm-months span{width:13px;flex:none;white-space:nowrap}
.hm-grid{display:flex;gap:3px}
.hm-grid .week{display:flex;flex-direction:column;gap:3px}
/* 색은 격자와 범례가 같은 규칙을 쓴다 — 예전에는 범례가 .heatmap 바깥이라
   색 규칙이 하나도 걸리지 않아 빈 칸만 다섯 개 떠 있었다. */
.heatmap .cell,
.heatmap-legend .cell{width:13px;height:13px;border-radius:0;background:#ebedf0}
.heatmap .cell.l1,
.heatmap-legend .cell.l1{background:#fee4cc}
.heatmap .cell.l2,
.heatmap-legend .cell.l2{background:#fdba74}
.heatmap .cell.l3,
.heatmap-legend .cell.l3{background:#f97316}
.heatmap .cell.l4,
.heatmap-legend .cell.l4{background:#c2410c}
.heatmap .cell.future{background:transparent}
.heatmap .cell[data-tip]{cursor:pointer}
.heatmap-legend{display:flex;align-items:center;gap:6px;justify-content:flex-end;margin-top:10px;
  font-size:11.5px;color:var(--muted-2)}
.heatmap-legend .cell{width:12px;height:12px}
.heatmap-legend .hm-hint{margin-right:auto}

/* 칸 위에 바로 뜨는 날짜 말풍선. 브라우저 기본 title 은 1초쯤 기다려야
   나와서, 13px짜리 칸을 훑는 동안에는 사실상 안 뜬 것과 같다. */
.hm-tip{position:fixed;z-index:120;padding:6px 10px;pointer-events:none;
  background:var(--text);color:var(--surface);font-size:11.5px;font-weight:700;
  white-space:nowrap;box-shadow:var(--shadow);opacity:0;transition:opacity .08s}
.hm-tip.on{opacity:1}

.divline{display:flex;align-items:center;gap:12px}
.muted{color:var(--muted)}
.tiny{font-size:12px}
.mono{font-family:ui-monospace,Menlo,monospace}

/* ---------------- problem statement PDF ---------------- */
.pdf-ic{
  flex:none;display:grid;place-items:center;width:44px;height:44px;border-radius:0;
  background:var(--danger-soft);color:var(--danger);font-size:11px;font-weight:800;letter-spacing:.02em}
.pdf-meta{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}
.pdf-meta b{font-size:14.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

.pdf-dl{
  display:flex;align-items:center;gap:14px;margin:0 0 26px;padding:14px 16px;
  background:var(--surface);border:1px solid var(--line);border-radius:0;
  box-shadow:var(--shadow);transition:.12s}
.pdf-dl:hover{border-color:var(--line-2);transform:translateY(-1px)}
.pdf-dl .btn{flex:none;pointer-events:none}
.pdf-dl .btn svg{width:15px;height:15px}

.pdf-current{
  display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:16px;
  padding:12px 14px;border:1px solid var(--line);border-radius:0;background:var(--hover-2)}
.pdf-current.striking{opacity:.5}
.pdf-current.striking .pdf-meta b{text-decoration:line-through}
.pdf-remove{display:flex;align-items:center;gap:6px;font-size:13px;color:var(--danger);
  cursor:pointer;font-weight:600;flex:none}
.pdf-remove input{cursor:pointer}

.pdf-pick{margin-top:8px;min-height:16px;word-break:break-all}
.pdf-pick.ok{color:var(--success);font-size:12px;font-weight:600}
.pdf-pick.bad{color:var(--danger);font-size:12px;font-weight:600}

/* site credit, sits just under the page's ad slot (see ads.ad_slot) */
.made-by{
  text-align:center;font-size:11.5px;color:var(--muted-2);
  padding:10px 6px 0;user-select:none}
.made-by a{color:var(--muted);font-weight:700;border-bottom:1px solid transparent;transition:.12s}
.made-by a:hover{color:var(--primary-dark);border-bottom-color:currentColor}

/* ---------------- ad slots (Kakao AdFit) ---------------- */
/* .ad-frame is a fixed-height window that the (possibly down-scaled) .ad-box
   sits inside, so a 728x90 banner can never push the page sideways on a
   narrow screen. Both heights are set by the loader in base.html. */
.ad-slot{display:block;margin:28px 0;max-width:100%}
.ad-slot.empty{display:none}
/* the slot carrying the credit stays even when the banner never fills — only
   the empty frame is dropped, so the credit does not vanish with it */
.ad-slot.empty.with-credit{display:block}
.ad-slot.empty.with-credit .ad-frame{display:none}
.ad-frame{
  width:100%;max-width:100%;overflow:hidden;display:flex;justify-content:center;
  align-items:flex-start;min-height:0}
.ad-box{flex:none;transform-origin:top center;line-height:0}
.ad-box ins{margin:0}
.ad-box iframe{border:0;display:block}
/* the ad sits inside a modal-free flow — never let it cover site chrome */
.modal .ad-slot{display:none}

@media(max-width:860px){
  .grid.c4,.grid.c3,.grid.c2{grid-template-columns:1fr}
  .hero-in{padding:34px 22px 30px}
  .hero h1{font-size:32px;letter-spacing:-1px}
  .hero-grid{background-size:44px 44px}
  .hero .cta .btn{padding:15px 10px;font-size:13px}
  .pdf-dl{flex-wrap:wrap}
  .pdf-dl .pdf-meta{flex-basis:calc(100% - 58px)}
  .ad-slot{margin:22px 0}
  .pf-card{flex-direction:column}
  .pf-imgs{width:100%;height:160px}
  /* no mini rail on a phone — the sidebar slides fully off-canvas instead,
     and the floating button brings it back as an overlay */
  .sidebar{width:var(--sidebar-w);transition:transform .2s;box-shadow:var(--shadow)}
  html.sidebar-collapsed .sidebar{width:var(--sidebar-w);padding:18px 14px;
    align-items:stretch;transform:translateX(-100%)}
  .content,html.sidebar-collapsed .content{margin-left:0}
  html.sidebar-collapsed .floating-toggle{display:inline-flex}
}

/* ============================ DARK THEME OVERRIDES ============================ */
:root[data-theme="dark"] .btn{background:var(--surface);color:var(--text);border-color:var(--line-2)}
:root[data-theme="dark"] .btn:hover{background:var(--hover);border-color:var(--line-2)}
:root[data-theme="dark"] .btn.primary{color:#2b1206}
:root[data-theme="dark"] .btn.danger{background:var(--surface)}
:root[data-theme="dark"] .input,
:root[data-theme="dark"] textarea.input,
:root[data-theme="dark"] select.input{background:var(--input-bg);color:var(--text);border-color:var(--line-2)}
:root[data-theme="dark"] .nav a:hover{background:var(--hover)}
:root[data-theme="dark"] .usercard:hover{background:var(--hover)}
:root[data-theme="dark"] .prow:hover{background:var(--hover)}
:root[data-theme="dark"] .ioex .h,
:root[data-theme="dark"] .info-table th,
:root[data-theme="dark"] .subs th{background:var(--th-bg)}
:root[data-theme="dark"] .modal{background:var(--surface)}
:root[data-theme="dark"] .flash{background:var(--surface)}
:root[data-theme="dark"] .flash .close:hover{background:var(--hover)}
:root[data-theme="dark"] .pf-add{background:var(--surface)}
:root[data-theme="dark"] .pf-imgs{background:var(--hover)}
:root[data-theme="dark"] .settings-tabs a{background:var(--surface)}
:root[data-theme="dark"] .badge{background:var(--hover);color:var(--muted)}
:root[data-theme="dark"] .derived{background:var(--hover-2)}
:root[data-theme="dark"] .progress{background:var(--hover)}
/* 어두운 테마에서는 '제출 없음' 칸만 어둡게 깐다. 예전에는 .cell 전체를
   덮어써서(명시도가 .cell.l1 보다 높다) 어두운 테마의 격자가 통째로 회색이었다. */
/* 어두운 배경에서는 골드·다이아의 어둡게 눌러 둔 글자색이 안 읽힌다.
   그 두 티어만 원래 색으로 되돌린다 (--ink 를 버린다). */
:root[data-theme="dark"] .solved-chip{color:var(--tone)}

:root[data-theme="dark"] .heatmap .cell.l0,
:root[data-theme="dark"] .heatmap-legend .cell.l0{background:#222933}
:root[data-theme="dark"] .heatmap .cell.future{background:transparent}
/* 탭은 이제 --line / --primary 만 쓰므로 어두운 테마에서 손댈 것이 없다 */
:root[data-theme="dark"] .switch .slider{background:var(--line-2)}
:root[data-theme="dark"] body{background:var(--bg)}
:root[data-theme="dark"] .auth-wrap{background:var(--bg)}
:root[data-theme="dark"] .auth-card,
:root[data-theme="dark"] .auth-back{background:var(--surface);border-color:var(--line)}
:root[data-theme="dark"] .btn.primary{background:var(--primary);border-color:var(--primary);color:#2b1206}
:root[data-theme="dark"] .btn.primary:hover{background:var(--primary-dark);border-color:var(--primary-dark);color:#2b1206}
:root[data-theme="dark"] .btn.success{background:var(--success);border-color:var(--success);color:#2b1206}
:root[data-theme="dark"] .btn.ghost{background:transparent;border-color:transparent}
:root[data-theme="dark"] .badge.green{background:var(--success-soft);color:var(--success)}
:root[data-theme="dark"] .badge.blue{background:var(--primary-soft);color:var(--primary)}
:root[data-theme="dark"] .badge.red{background:var(--danger-soft);color:var(--danger)}
:root[data-theme="dark"] .role-tag{background:var(--primary-soft);color:var(--primary)}
:root[data-theme="dark"] .coin-chip{background:#2a1710;border-color:#5a2c12;color:#fb923c}

/* ---------------- 문제 본문 렌더링 (마크다운 / LaTeX) ---------------- */
/* 렌더 전에는 pre-wrap 으로 원문 줄바꿈을 살리고, 렌더가 끝나면(=data-rt-done)
   마크다운·LaTeX 이 스스로 문단을 만들므로 pre-wrap 을 푼다. */
.section .body.rt[data-rt-done]{white-space:normal}
.rt > :first-child{margin-top:0}
.rt > :last-child{margin-bottom:0}
.rt p{margin:0 0 12px}
.rt ul,.rt ol{margin:0 0 12px;padding-left:22px}
.rt li{margin:3px 0}
.rt h1,.rt h2,.rt h3,.rt h4{margin:20px 0 8px;line-height:1.35}
.rt h1{font-size:20px}.rt h2{font-size:18px}.rt h3{font-size:16px}.rt h4{font-size:15px}
.rt code{background:var(--hover);border:1px solid var(--line-2);padding:1px 5px;
  font-family:ui-monospace,Menlo,monospace;font-size:.9em}
.rt pre{background:var(--hover);border:1px solid var(--line-2);padding:12px;overflow-x:auto;
  margin:0 0 12px}
.rt pre code{background:none;border:none;padding:0;font-size:13px}
.rt blockquote{margin:0 0 12px;padding:2px 0 2px 14px;border-left:3px solid var(--line-2);
  color:var(--muted)}
.rt table{border-collapse:collapse;margin:0 0 12px;font-size:13.5px;display:block;
  overflow-x:auto;max-width:100%}
.rt th,.rt td{border:1px solid var(--line-2);padding:6px 10px;text-align:left}
.rt th{background:var(--th-bg)}
.rt hr{border:none;border-top:1px solid var(--line-2);margin:16px 0}
.rt a{color:var(--primary);text-decoration:underline}
.rt-error{background:var(--danger-soft);color:var(--danger);border:1px solid var(--danger);
  padding:10px 12px;font-size:13px;font-family:ui-monospace,Menlo,monospace;
  white-space:pre-wrap;word-break:break-word}

/* 문제 본문은 pre-wrap 이지만 조판된 수식 안까지 그러면 글리프가 벌어진다 */
.katex{white-space:normal}
.katex-display{margin:.7em 0;overflow-x:auto;overflow-y:hidden;padding:2px 0}

/* LaTeX.js 본문 래퍼 — 자세한 규칙은 static/vendor/latexjs/latexjs.css */
.latexdoc{white-space:normal;font-size:15px}
.latexdoc .body{white-space:normal}
.section .body.latexdoc{white-space:normal}

/* ---------------- 작성 형식 고르기 ---------------- */
.fmt-row{display:flex;gap:10px;align-items:center;flex-wrap:wrap;justify-content:space-between}
.fmt-pick{display:flex;gap:0;border:1px solid var(--line-2);background:var(--surface)}
/* .field label 이 display:block · margin-bottom 을 걸어두므로(우선순위가 더 높다)
   .fmt-pick 을 앞에 붙여 옵션 라벨에는 닿지 않게 한다. */
.fmt-pick .fmt-opt{display:flex;align-items:center;margin:0;padding:9px 16px;cursor:pointer;
  font-size:13.5px;font-weight:600;color:var(--muted);border-right:1px solid var(--line-2)}
.fmt-opt:last-child{border-right:none}
.fmt-opt input{position:absolute;opacity:0;pointer-events:none}
.fmt-opt:hover{color:var(--text)}
.fmt-opt.on{background:var(--primary-soft);color:var(--primary)}
.fmt-actions{display:flex;gap:8px}
.fmt-note{margin-top:8px;min-height:16px}

/* ---------------- 분류 고르기 ---------------- */
.tag-picked{display:flex;gap:10px;align-items:flex-start;flex-wrap:wrap;
  border:1px solid var(--line-2);background:var(--hover-2);padding:12px 14px}
.tag-chosen{display:flex;gap:6px;flex-wrap:wrap;flex:1;min-width:0}
.tag-picked .btn{flex:none;margin-left:auto}
.modal-wide{max-width:760px}
.tag-scroll{max-height:52vh;overflow-y:auto;margin-top:14px;padding-right:4px}
.tag-scroll .tag-block{margin-bottom:14px}
.tag-scroll .tag-block:last-of-type{margin-bottom:0}
.modal .preview-body .section{margin:0 0 22px}
.modal .preview-body .section:last-child{margin-bottom:0}
.modal .preview-body h3{margin:0 0 6px;font-size:13px;color:var(--muted);font-weight:600}
.modal .preview-body .body{white-space:pre-wrap;word-break:break-word;font-size:15px;line-height:1.7}

/* 문법 도움말 표 */
.mathguide{width:100%;border-collapse:collapse;font-size:13.5px}
.mathguide th{background:var(--th-bg);color:var(--muted);font-weight:600;font-size:12px;
  text-align:left;padding:8px 10px;border-bottom:1px solid var(--line-2)}
.mathguide td{padding:9px 10px;border-bottom:1px solid var(--line);vertical-align:middle}
.mathguide tr:last-child td{border-bottom:none}
.mathguide td:first-child{width:46%}
.mathguide code{background:var(--surface);border:1px solid var(--line-2);padding:2px 6px;
  font-family:ui-monospace,Menlo,monospace;font-size:12.5px;word-break:break-all}
.mathnote{margin-top:16px;padding:14px;background:var(--hover-2);border:1px solid var(--line)}
.mathnote b{font-size:13px}
.mathnote ul{margin:8px 0 0;padding-left:18px;color:var(--muted);font-size:13px;line-height:1.75}
.mathnote code{background:var(--surface);border:1px solid var(--line-2);padding:1px 5px;
  font-family:ui-monospace,Menlo,monospace;font-size:12px}

/* ---------------- 권한 관리 패널 ---------------- */
.perm-card{margin-bottom:18px}
.perm-title{margin:0 0 6px;font-size:16px}
.perm-desc{margin:0 0 16px;line-height:1.7}
.perm-check{display:flex;align-items:center;gap:8px;padding-bottom:11px}
.perm-check label{margin:0;cursor:pointer}
.perm-hint{margin-top:6px;color:var(--muted);min-height:16px}
.perm-hint.on{color:var(--success)}

/* 권한 하나 = 칸 하나. 무엇을 켜는 건지 설명이 항상 함께 보이도록. */
.perm-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:10px}
.perm-item{display:flex;gap:10px;align-items:flex-start;padding:12px 14px;
  border:1px solid var(--line-2);background:var(--surface);cursor:pointer}
.perm-item:hover{border-color:var(--line-strong)}
.perm-item input{margin-top:3px;flex:none}
.perm-item span{display:flex;flex-direction:column;gap:3px}
.perm-item b{font-size:13.5px}
.perm-item .tiny{line-height:1.5}
.perm-item:has(input:checked){border-color:var(--primary);background:var(--primary-soft)}

.perm-table td{vertical-align:top}
.perm-table .badge{margin:0 4px 4px 0}
.perm-table .role-tag{margin-left:4px}

:root[data-theme="dark"] .fmt-pick,
:root[data-theme="dark"] .tag-picked{background:var(--hover-2);border-color:var(--line-2)}
:root[data-theme="dark"] .rt pre,
:root[data-theme="dark"] .rt code{background:var(--hover);border-color:var(--line-2)}

/* ---------------- 폼 컨트롤 (브라우저 기본 위젯 대체) ----------------
   static/js/ui.js 가 <select> · <input type=number> · <input type=file> 를
   아래 마크업으로 감싼다. 원본 컨트롤은 DOM 에 남아 값을 들고 있고, 화면에서만
   숨긴다 — 자바스크립트가 죽으면 원래 위젯이 그대로 보인다. */

/* 커스텀 셀렉트 */
.sel{position:relative;width:100%}
.sel.sel-auto{width:auto;max-width:100%;display:inline-block;vertical-align:middle}
.sel-native{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none;
  clip:rect(0 0 0 0);overflow:hidden}
.sel-btn{display:inline-flex;align-items:center;justify-content:space-between;gap:10px;
  width:100%;height:var(--ctl-h);padding:0 12px 0 13px;
  border:1px solid var(--line-2);background:var(--input-bg,#fff);color:var(--text);
  font-size:14px;font-weight:500;text-align:left;transition:.12s}
.sel-btn:hover{border-color:var(--line-strong)}
/* 눌렀을 때 번지는 그림자는 쓰지 않는다. 테두리 색만 바뀌고, 키보드로 옮겨온
   초점일 때만(:focus-visible) 얇은 실선을 그린다. */
.sel-btn:focus{outline:none}
.sel.open .sel-btn{border-color:var(--primary)}
.sel-btn:focus-visible{outline:2px solid var(--primary);outline-offset:-2px}
.sel-btn:disabled{color:var(--muted-2);background:var(--hover-2);cursor:not-allowed}
.sel-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sel-chev{width:16px;height:16px;flex:none;color:var(--muted);transition:transform .15s}
/* 화살표는 목록이 놓인 쪽을 가리킨다 — 접혀 있으면 위(접힌 상태), 아래로 펼치면
   아래, 화면 끝이라 위로 펼치면 위. 기본 아이콘은 위쪽 꺾쇠다. */
.sel.open .sel-chev{transform:rotate(180deg)}
.sel.open.up .sel-chev{transform:rotate(0deg)}

/* display:flex 로 두면 항목들이 flex 아이템이 되어 max-height 에 맞춰 납작하게
   눌린다(flex-shrink 기본 1). 목록은 그냥 블록으로 쌓고 넘치면 스크롤한다. */
.sel-pop{position:absolute;z-index:120;left:0;top:calc(100% + 4px);width:100%;
  max-height:280px;overflow-y:auto;overscroll-behavior:contain;
  background:var(--surface);border:1px solid var(--line-2);
  box-shadow:var(--shadow);padding:4px;display:block}
.sel.up .sel-pop{top:auto;bottom:calc(100% + 4px)}
.sel.right .sel-pop{left:auto;right:0}
.sel-opt{display:flex;align-items:center;flex:none;width:100%;min-height:var(--ctl-h-sm);
  text-align:left;padding:9px 12px;border:none;background:transparent;color:var(--text);
  font-size:14px;line-height:1.4;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  transition:.1s}
.sel-opt:hover,.sel-opt.active{background:var(--hover)}
/* 지금 값은 배경 + 주황 굵은 글씨로만 표시한다. 체크 표시까지 붙이면 지저분하고,
   화면에 안 보이는 사용자에게는 aria-selected 가 같은 일을 한다. */
.sel-opt.on{color:var(--primary);font-weight:700}
.sel-opt:disabled{color:var(--muted-2);cursor:not-allowed}

/* 숫자 입력: 브라우저 기본 화살표를 없애고 −/＋ 버튼을 붙인다 */
.num{position:relative;display:flex;width:100%}
.num .input{padding-right:28px}
.num input[type=number]{-moz-appearance:textfield;appearance:textfield}
.num input[type=number]::-webkit-outer-spin-button,
.num input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.num-steps{position:absolute;top:1px;right:1px;bottom:1px;width:22px;
  display:flex;flex-direction:column;border-left:1px solid var(--line-2)}
.num-btn{flex:1;border:none;background:transparent;color:var(--muted-2);
  display:grid;place-items:center;padding:0;transition:.12s}
.num-btn+.num-btn{border-top:1px solid var(--line-2)}
.num-btn svg{width:11px;height:11px}
.num-btn:hover{background:var(--hover);color:var(--text)}
.num .input:focus~.num-steps{border-color:var(--primary)}

/* 파일 선택: OS 마다 다르게 생긴 기본 버튼 대신 우리 버튼 */
.filepick{display:flex;align-items:center;gap:12px;min-height:var(--ctl-h)}
.filepick-native{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none;
  clip:rect(0 0 0 0);overflow:hidden}
.filepick-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.filepick-name.on{color:var(--text);font-weight:600}

:root[data-theme="dark"] .sel-btn{background:var(--input-bg);border-color:var(--line-2)}
:root[data-theme="dark"] .sel-pop{background:var(--surface);border-color:var(--line-2)}
:root[data-theme="dark"] .sel-opt:hover,
:root[data-theme="dark"] .sel-opt.active{background:var(--hover)}
:root[data-theme="dark"] .num-btn:hover{background:var(--hover)}
