/* 공통 견본. **전에는 base.html 안 <style> 이었다** — 2026-09-18 에 파일로 뺀다.
   46KB 라 화면마다 통째로 실려 나갔다 (/main 76KB 중 46KB 가 이것). 바깥(Funnel)에서
   들어오면 받는 양도 그리는 시간도 다 비용이라 한 번 받아 캐시하게 했다.
   **theme.css 가 이것을 이긴다** — base.html 이 이것 다음에 theme.css 를 건다.
   검사는 여전히 base.html 과 함께 읽는다 (tests/helpers.py 의 source). */
    /* 사양서 선 두께. **표 칸 선과 여백 테두리가 같은 값을 쓴다** —
       한쪽만 고치면 종이에서 테두리만 굵거나 가늘어 보인다.
       전에는 칸이 1px(0.26mm) · 테두리가 0.3mm 로 미세하게 달랐다.
       tests/check_sheet.py 가 두 자리 모두 이 이름을 쓰는지 확인한다. */
    :root { --sheet-line: 0.3mm; --sheet-margin: 6mm; }

    /* 31개 컬럼을 읽을 수 있는 최소한의 스타일만 둔다. */
    body { font-family: "Malgun Gothic", sans-serif; font-size: 14px; margin: 20px; }
    h1 { font-size: 18px; }
    /* 제목 옆에 단추를 붙이는 줄. 단추는 제목 글씨를 물려받지 않게 되돌린다 —
       안 되돌리면 18px 굵은 글씨가 되어 제목의 일부처럼 보인다. */
    .page-head { display: flex; align-items: center; gap: 10px; }
    .page-head button { font-family: inherit; font-size: 13px; font-weight: 400;
                        padding: 3px 10px; cursor: pointer; }
    table { border-collapse: collapse; }
    th, td { border: 1px solid #ccc; padding: 4px 8px; text-align: left; white-space: nowrap; }
    th { background: #eee; }
    .scroll { overflow-x: auto; cursor: grab; }
    .scroll.dragging { cursor: grabbing; user-select: none; }
    .flash { color: #c00; }
    .muted { color: #666; font-size: 13px; }
    .toolbar { display: flex; align-items: center; gap: 8px; margin-bottom: 14px; }

    /* 원판 배치 화면(실험대). 이름을 won- 으로 못 박아 다른 화면에 안 닿는다. */
    /* 모델을 세로로 한 줄씩. 오른쪽 끝에 판넬당 개수 칸이 붙는다 */
    /* 이 판에 든 모델. **판 블록 안 오른쪽 절반**을 쓴다 (.won-rules 가 나눈다) */
    .won-keys { display: flex; flex-direction: column; gap: 2px;
                margin: 0; min-width: 0; }
    .won-key { display: flex; align-items: center; gap: 6px; font-size: 13px;
               padding: 2px 4px; border-bottom: 1px solid #eee; }
    /* 자식(>)이 아니라 자손으로 찾는다 — 이름은 label 안에 한 겹 더 들어 있다.
       (label 안에 label 을 두면 안쪽을 눌러도 바깥 체크박스가 켜진다) */
    /* 이름만 줄어든다. 크기·수량은 배치를 정하는 값이라 늘 다 보여야 한다 —
       한 칸에 이어 붙이면 이름이 길 때 뒤가 통째로 잘린다. */
    .won-key .name { flex: 1 1 0; min-width: 0; overflow: hidden;
                     text-overflow: ellipsis; white-space: nowrap; }
    .won-key .won-spec { flex: none; color: #555; font-size: 12px;
                         white-space: nowrap; }

    /* '빼면 원판 몇 장 주나'. **경고가 아니다** — 다른 값과 같은 세기로 둔다.
       0장(공짜)은 흐리게, 값이 있으면 조금 진하게. 색은 안 쓴다. */
    .won-cost { flex: none; margin-left: 6px; font-size: 12px; color: #999;
                white-space: nowrap; font-variant-numeric: tabular-nums; }
    .won-cost.pay { color: #555; font-weight: 600; }
    .won-key.off .name, .won-key.off .won-chip { opacity: 0.4; }
    /* 이 모델이 몇 번 판에 들어가 있나. 눌러서 옮긴다.
       **한 모델은 한 판에만** 있다 — 원판에는 같은 판넬을 찍어 내므로
       한 모델이 두 판에 걸치면 그만큼 더 만들어진다. */
    .won-at { flex: none; width: 88px; font-family: inherit; font-size: 12px;
              padding: 2px 4px; }
    /* 묶음 하나 = 한 작지 = 배치도 한 장. 판마다 제목·그림·후보를 한 벌씩 둔다 */
    .won-group { margin: 18px 0; border-top: 2px solid #ddd; padding-top: 10px; }
    /* 판 블록 위쪽 칸. **왼쪽은 판 전체에 거는 조건(분리선·크기 상한),
       오른쪽 절반은 이 판에 든 모델**이다. 모델을 판 밖에 한 벌로 두면 어느
       줄이 어느 판 것인지 번호를 짚어 가며 읽어야 한다. */
    .won-group .won-rules { display: grid; grid-template-columns: 1fr 1fr;
                            gap: 10px 16px; margin: 0 0 8px; padding: 8px;
                            background: #fafafa; border: 1px solid #eee;
                            border-radius: 4px; align-items: start; }
    /* 분리선이 위, 판넬 크기 상한이 그 아래 */
    .won-rules-left { display: flex; flex-direction: column; gap: 4px;
                      min-width: 0; }
    .won-group .won-rules h4 { margin: 6px 0 0; font-size: 12px; color: #666; }
    .won-group .won-rules h4:first-child { margin-top: 0; }
    .won-group .won-rules .won-cap { margin: 0; }
    .won-group .won-rules .won-zones { margin: 4px 0 0; }
    /* 제목 줄 오른쪽 끝에 지우기 단추를 둔다. 나머지는 왼쪽에 그대로 흐른다. */
    .won-group-title { margin: 0 0 8px; font-size: 15px;
                       display: flex; align-items: center; gap: 0; }
    /* 판을 지우는 단추. **오른쪽 끝**이다 — 되돌리기 어려운 것은 눈길이 마지막에
       닿는 자리에 둔다. 빨간 바탕에 검은 글씨: 바탕으로 위험을 알리되,
       흰 글씨는 흑백으로 복사하면 사라져 읽을 수 없다. */
    .won-del-btn { margin-left: auto; padding: 2px 10px; cursor: pointer;
                   background: #e34; color: #000; font-weight: 700;
                   font-family: inherit; font-size: 13px;
                   border: 1px solid #b12; border-radius: 3px; }
    .won-del-btn:hover { background: #f45; }
    /* 판 칸 오른쪽 아래 구석의 '작지번호 입력' 단추 (2026-09-14).
       파란 바탕에 **검은** 글씨 — 삭제 단추와 같은 까닭(흰 글씨는 흑백 복사에서 사라진다).
       그래서 바탕을 밝은 파랑으로 둔다. 진한 파랑에 검은 글씨는 안 읽힌다. */
    .won-group-foot { display: flex; justify-content: flex-end; margin-top: 8px; gap: 6px; }
    /* 작지번호를 받는 칸. 단추 자리에서 그대로 펼쳐진다 (브라우저 입력 창을 안 쓴다) */
    .won-work-form { display: flex; gap: 6px; align-items: center; }
    .won-work-input { width: 130px; padding: 2px 6px; font-family: inherit; font-size: 13px;
                      border: 1px solid #6aa6ff; border-radius: 5px; }
    .won-work-btn { padding: 2px 10px; cursor: pointer;
                    background: #6aa6ff; color: #000; font-weight: 700;
                    font-family: inherit; font-size: 13px;
                    border: 1px solid #2563eb; border-radius: 3px; }
    .won-work-btn:hover { background: #8bb9ff; }
    .won-group-title .won-no { display: inline-block; min-width: 34px;
                               padding: 1px 6px; margin-right: 4px;
                               background: #333; color: #fff; border-radius: 3px;
                               font-size: 13px; text-align: center; }
    .won-group-title .muted { font-weight: 400; font-size: 13px; }
    /* 다른 판에서 모델을 끌어오는 단추. 번호 **왼쪽**에 둔다 —
       '이 판으로 가져온다' 는 뜻이라 번호에 붙어 있어야 어느 판인지 안 흐려진다 */
    .won-pull-btn { width: 22px; height: 22px; margin-right: 6px; padding: 0;
                    font-size: 15px; line-height: 1; cursor: pointer;
                    vertical-align: middle; }
    /* 지운 판에 있던 모델이 머무는 자리. **연한 노랑** — 여기 뭔가 있으면
       아직 안 끝났다는 뜻이라, 판 블록(흰 바탕)과 눈에 띄게 갈라 둔다. */
    .won-waiting { margin: 14px 0; padding: 10px 12px; background: #fff8d0;
                   border: 1px solid #e0d080; border-radius: 4px; }
    .won-waiting h4 { margin: 0 0 6px; font-size: 13px; }
    .won-waiting .won-key { border-bottom-color: #e8dca0; }
    .won-waiting .won-none { margin: 4px 0 0; font-size: 12px; color: #a60; }

    /* 가져오기 창. 닫혀 있으면 자리를 안 차지한다(hidden) */
    .won-pull { margin: 0 0 8px; padding: 8px; background: #fffdf0;
                border: 1px solid #e8dfae; border-radius: 4px; font-size: 13px; }
    .won-pull > p { margin: 0 0 6px; }
    .won-pull-group { margin: 0 0 8px; }
    .won-pull-group > .won-no { display: inline-block; margin-bottom: 3px; }
    /* 고를 수 있는 줄. 층수·두께가 다르면 흐리게 두고 못 누르게 한다 —
       누를 수 있게 두면 만들 수 없는 배치가 조용히 나온다 */
    .won-pull-key { display: flex; align-items: center; gap: 6px;
                    padding: 2px 4px; cursor: pointer; border-radius: 3px; }
    .won-pull-key:hover { background: #f4eeca; }
    .won-pull-key.on { background: #e8f0fe; }
    .won-pull-key.no { opacity: 0.45; cursor: not-allowed; }
    .won-pull-key.no:hover { background: none; }
    /* 층수가 다른 모델. **막지는 않는다** — 한 작지에 층수가 둘 이상 있을 수
       있고 웬만하면 같은 층끼리 붙인다 (2026-09-01 확인). 금지가 아니라 선호라
       고를 수 있게 두고 눈에만 띄게 한다. 까닭은 templates/spec/wonpan.html 에. */
    .won-pull-key .name { flex: 1 1 0; min-width: 0; overflow: hidden;
                          text-overflow: ellipsis; white-space: nowrap; }
    .won-pull-key .won-spec { flex: none; color: #555; font-size: 12px;
                              white-space: nowrap; }
    /* 판 블록 안에서만 쓴다. 왼쪽 칸 세로 쌓기는 위 .won-rules-left 가 한다 —
       여기 남아 있던 `flex`·`border-left` 는 옛 가로 배치용이라 걷어냈다. */
    .won-rules { font-size: 13px; min-width: 0; }
    .won-rules h4 { font-weight: 600; }
    /* 붙일 짝을 고르는 칸. 켜면 '가르지 않는다' 는 뜻이라 붉은색이 아니다 */
    /* 분리선은 두 축(PSR · 표면처리)으로 고른다. 축 이름표. */
    .won-axis { margin: 8px 0 2px; font-size: 11px; font-weight: 700;
                color: #666; letter-spacing: 0.3px; }
    .won-axis:first-child { margin-top: 0; }
    .won-cut { display: flex; align-items: center; gap: 5px; padding: 2px 0;
               white-space: nowrap; cursor: pointer; }
    .won-cut input { margin: 0; }
    .won-cut input:disabled + span { color: #bbb; }
    /* 이 판에서 그 값을 가진 모델이 모두 꺼져 있다. **지우지 않고 못 누르게**
       둔다 — 지우면 켜 둔 선택이 같이 사라져 모델을 다시 켜도 안 돌아온다. */
    .won-cut.gone { opacity: 0.5; cursor: not-allowed; }
    .won-cut.all { margin-top: 6px; padding-top: 6px;
                   border-top: 1px solid #eee; color: #c00; }
    /* 지금 어떻게 나뉘었는지. 짝을 보고 머릿속으로 접게 하지 않는다 */
    .won-zones { margin: 8px 0 0; padding: 5px 7px; background: #f4f4f4;
                 border-left: 3px solid #c00; font-size: 12px; }
    .won-cap { display: flex; align-items: center; gap: 5px; margin: 0; }
    .won-cap input { width: 74px; padding: 2px 4px; font-family: inherit;
                     font-size: 12px; text-align: right; }
    .won-cap span { color: #888; font-size: 12px; }
    .won-key input[type="number"] { width: 56px; padding: 2px 4px; font-family: inherit;
                                    font-size: 12px; text-align: right; }
    .won-key .unit { color: #888; font-size: 12px; width: 40px; }
    .won-chip { display: inline-block; width: 18px; height: 18px; line-height: 18px;
                text-align: center; font-size: 11px; font-weight: 700;
                border: 1px solid #888; border-radius: 3px; }
    .won-work { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; align-items: start; }
    .won-work h3 { margin: 0 0 6px; font-size: 14px; }
    .won-stage { border: 1px solid #bbb; background: #fafafa; height: 620px;
                 display: flex; align-items: center; justify-content: center; }
    .won-svg { width: 100%; height: 100%; }
    .won-facts { margin: 8px 0 0; font-size: 13px; }
    .won-facts div { display: flex; gap: 10px; padding: 2px 0; }
    .won-facts dt { width: 110px; color: #666; }
    .won-facts dd { margin: 0; }
    .won-list > div { border: 1px solid #bbb; background: #fafafa; height: 620px;
                      overflow-y: auto; display: grid;
                      grid-template-columns: repeat(2, 1fr); gap: 8px; padding: 8px; }
    .won-card { border: 1px solid #ccc; background: #fff; padding: 6px; cursor: pointer;
                font-size: 12px; text-align: center; }
    .won-card.on { border-color: #06c; box-shadow: 0 0 0 2px #cfe4ff inset; }
    .won-card svg { width: 100%; height: 110px; display: block; }
    .won-card i { color: #06c; font-style: normal; }

    /* 붙여넣기 격자 */
    .grid-controls { display: flex; align-items: center; gap: 10px; }
    .grid-controls input[type="number"] { width: 70px; }
    .grid-table { border-collapse: collapse; }
    .grid-table th { background: #eee; font-size: 12px; font-weight: 600; padding: 3px 6px; white-space: nowrap; }
    /* 줄 번호 칸 — 번호와 쓰레기통을 나란히 둔다 */
    .grid-table tbody th { padding: 0 4px; }
    .grid-table tbody th span { vertical-align: middle; }
    /* 평소에는 흐리게 있다가 마우스를 올리면 검게 된다.
       아예 안 보이게 두면 있는 줄을 모르고, 늘 진하면 번호보다 눈에 띈다. */
    .row-bin {
      border: 0; background: none; padding: 0 0 0 4px; cursor: pointer;
      color: #bbb; vertical-align: middle; line-height: 0;
    }
    .row-bin:hover, .row-bin:focus-visible { color: #000; }
    .grid-table td { border: 1px solid #ccc; padding: 0; }
    .grid-table input { border: 0; padding: 3px 5px; width: 110px; font-family: inherit; font-size: 12px; }
    .grid-table input:focus { outline: 2px solid #37f; outline-offset: -2px; }
    /* 잘린 값 말풍선. 화면에 붙여(fixed) 두어야 표를 옆으로 끄는 상자에 안 잘린다 */
    .grid-tip { position: fixed; z-index: 30; max-width: 60vw; padding: 4px 8px;
                background: #24292f; color: #fff; font-size: 12px; line-height: 1.4;
                border-radius: 4px; box-shadow: 0 2px 6px rgba(0,0,0,.25);
                white-space: pre-wrap; word-break: break-all; pointer-events: none; }
    /* 끌어서 고른 칸. 모델 표와 같은 색이라 두 화면에서 같아 보인다. */
    .grid-table td.pick { background: #e8f0fe; }
    .grid-table td.pick input { background: transparent; }
    .grid-table.picking { -webkit-user-select: none; user-select: none; }
    /* 엑셀에서 병합돼 있던 칸. 값은 한 칸만 들고 있다.
       바탕색·테두리·굵은 글씨로 따로 표시하지 않는다 — 여러 줄에 걸쳐 있다는 것
       자체가 이미 눈에 보이고, 색까지 얹으면 표가 어수선해진다.

       손대는 것은 두 가지뿐이다.
         가운데 정렬 — 여러 줄의 한가운데 놓인다
         높이 100%  — 빈자리 어디를 눌러도 그 칸이 잡힌다
       글자는 input 이 알아서 세로 가운데에 둔다. */
    .grid-table td.merged {
      vertical-align: middle;   /* height:100% 가 안 먹는 브라우저에서의 대비 */
    }
    .grid-table td.merged input {
      /* 이게 없으면 100% 에 안쪽 여백(3px 5px)이 **더해져** 칸 밖으로 삐져나가고,
         입력칸의 흰 바탕이 td 의 테두리를 덮어 선이 지워진 것처럼 보인다. */
      box-sizing: border-box;
      width: 100%; height: 100%;
      text-align: center;
    }

    /* 사양서 폼 */
    .report { border: 1px solid #ccc; padding: 14px; margin-bottom: 20px; }
    .report h2 { font-size: 15px; margin: 0 0 12px; }
    .report h3 { font-size: 13px; margin: 16px 0 6px; }
    /* 되돌리기 · 다시 실행. 패널 맨 위에 둘을 나란히 둔다 */
    .figure-history { display: flex; gap: 4px; }
    .figure-history button { flex: 1; }
    .figure-history button:disabled { color: #aaa; background: #fafafa; cursor: default; }
    /* 상단 항목. 칸 수를 5로 고정해 두면 줄마다 이름이 세로로 맞아 읽기 좋다.
       줄 나눔은 spec/report.py 가 정하고, 여기서는 그 항목을 첫 칸으로 보낸다.
       항목이 모자라는 줄은 뒤가 빈 채로 둔다 — 늘려서 채우면 그 칸만 길어진다. */
    .field-grid {
      display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 8px;
    }
    .field-grid > .rowstart { grid-column-start: 1; }
    /* 화면이 좁으면 다섯 칸이 눌린다. 그때는 들어가는 대로 흘린다. */
    @media (max-width: 1100px) {
      .field-grid { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
      .field-grid > .rowstart { grid-column-start: auto; }
    }
    .field-grid label, .field-grid .field { display: flex; flex-direction: column; gap: 2px; }
    .field-grid > label > span, .field-grid > .field > span { font-size: 12px; color: #666; }
    .field-grid input, .field-grid select { padding: 4px 6px; border: 1px solid #ccc; font-family: inherit; font-size: 13px; }
    /* 고르는 칸은 적는 칸과 구별되게 살짝 다른 바탕을 준다 */
    .field-grid select { background: #fafafa; height: 27px; }
    /* 가로 x 세로 입력 */
    .pair { display: flex; align-items: center; gap: 5px; }
    .pair input { width: 100%; min-width: 0; text-align: right; }
    .pair em { font-style: normal; color: #888; }
    .model-table input, .process-table input { border: 0; padding: 2px; width: 100%; min-width: 70px; font-family: inherit; font-size: 12px; }
    .model-table input:focus, .process-table input:focus { outline: 1px solid #37f; }
    .process-table th { font-weight: 600; }

    /* ── 모델 표를 엑셀처럼 (templates/spec/_model_table.html) ── */
    /* 칸 폭을 <colgroup> 이 정한 대로 못 박는다.
       기본값(auto)에서는 브라우저가 칸 안의 글자를 보고 폭을 정하는데,
       칸을 합치면 그 줄의 칸 수가 줄어 폭을 다시 재고 표 전체가 줄어든다.
       fixed 로 두면 합치든 풀든 세로선이 제자리에 있는다.
       min-width 는 가장 좁은 칸(5%)이 60px 는 되도록 잡은 값이다. */
    .model-table { table-layout: fixed; width: 100%; min-width: 1200px; }
    /* 위의 공통 규칙이 준 min-width: 70px 를 푼다. 폭은 이제 colgroup 이 정한다 */
    .model-table input { min-width: 0; }
    /* 줄 높이를 이름 하나로 둔다. 여러 줄을 덮는 병합 칸의 높이를
       자바스크립트가 이 값에 곱해 쓴다 (_model_table.html).
       안 그러면 덮인 줄이 통째로 사라져 표가 세로로 줄어든다. */
    .model-table { --row: 26px; }
    .model-table td { height: var(--row); }
    /* 칸은 textarea 다. 칸 안에서 엔터로 줄을 바꿀 수 있어야 하기 때문이다.
       생김새는 옆의 다른 입력칸과 같게 두고, 줄 수만 글자에 맞춰 늘어난다.
         resize   손잡이를 없앤다. 높이는 적은 줄 수가 정한다
         overflow 스크롤막대를 없앤다. 안에 숨는 글자가 있으면 안 된다
         display  줄 안 요소로 두면 글자 밑선 때문에 칸 아래에 틈이 생긴다 */
    .model-table textarea {
      display: block;
      box-sizing: border-box;
      width: 100%; border: 0; padding: 2px;
      font-family: inherit; font-size: 12px; line-height: 1.3;
      resize: none; overflow: hidden;
      background: transparent;
    }
    .model-table textarea:focus { outline: 1px solid #37f; }
    .model-tools {
      display: flex; align-items: center; gap: 8px;
      margin: 0 0 6px; font-size: 13px;
    }
    .model-tools .bar { width: 1px; height: 18px; background: #ddd; }
    .model-tools label { display: flex; align-items: center; gap: 4px; }
    /* 글자 색. 이름을 고르는 목록이 아니라 **칠한 네모**를 누른다.
       바탕색은 화면 스크립트가 data-color 로 칠한다 (_model_table.html).
       여기서 색을 적으면 spec/modeltable.py 의 목록과 두 벌이 된다. */
    .swatches { display: flex; align-items: center; gap: 4px; }
    .swatches .swatch {
      width: 18px; height: 18px; padding: 0;
      border: 1px solid #b9c0cc; border-radius: 4px;
      cursor: pointer;
    }
    .swatches .swatch:hover { border-color: #667085; }
    .swatches .swatch:focus-visible { outline: 2px solid #37f; outline-offset: 1px; }
    /* 고른 글자가 없으면 누를 수 없다. 배치도에서는 글자를 집어야 대상이 정해진다 */
    .swatches .swatch:disabled { opacity: 0.35; cursor: default; }
    /* 글자 크기 칸. 목록에서 고를 수도, 없는 값을 적을 수도 있다 */
    .model-tools input[type="number"] {
      width: 62px; padding: 2px 4px; font-family: inherit; font-size: 13px;
    }
    .model-tools button:disabled { color: #aaa; background: #fafafa; cursor: default; }
    /* 고른 범위. 끌어서 고르는 중에는 글자가 함께 선택되지 않게 막는다 */
    .model-table td.pick { background: #e8f0fe; }
    .model-table.picking { -webkit-user-select: none; user-select: none; }
    /* 병합된 칸. 붙여넣기 격자와 같이 꾸미지 않는다 — 여러 줄에 걸친 것만으로 보인다.
       가로도 세로도 가운데다. 사양서의 합친 칸과 같아야 종이와 화면이 같아 보인다.

       세로 가운데는 칸(td)이 맡는다. textarea 는 제 안의 글자를 세로로 가운데에
       두지 못하므로, 높이를 100% 로 채우면 글자가 위에 붙어 버린다.
       그래서 높이를 적힌 줄 수만큼만 두고 남는 자리는 칸이 위아래로 나눠 갖는다.
       빈자리를 눌렀을 때 글자칸이 잡히는 일은 _model_table.html 이 맡는다. */
    .model-table td.merged { vertical-align: middle; }
    .model-table td.merged textarea { text-align: center; }

    /* ── 사양서 형식 ─────────────────────────────────────────
       A4(210x297mm) 한 장이되, 사본처럼 위쪽 절반만 쓴다.
       아래 절반은 판넬 배치도를 손으로 그리는 자리라 비워 둔다. */
    /* **화면과 종이가 같은 크기다** (2026-08-26). 전에는 화면이 210x297 이고
       종이만 여백만큼 작았다 — 미리 보고 인쇄하면 다른 것이 나왔다.
       여기서 A4 에서 인쇄 여백을 빼 두면 화면이 곧 인쇄물이 된다. */
    .sheet-page {
      width: calc(210mm - var(--sheet-margin) * 2);
      height: calc(297mm - var(--sheet-margin) * 2);
      box-sizing: border-box;
      /* **바깥 테두리를 여기서 긋지 않는다** (2026-08-26).
         전에는 border 로, 다음에는 안쪽으로 그은 outline 으로 둘러 봤다. 둘 다
         표의 바깥선과 **같은 자리에 두 줄**이 되어, 표가 닿는 데는 진하고
         표가 없는 아래쪽은 한 줄이라 얇았다 — 위아래 굵기가 달라 보였다.
         이제 **닿는 자리마다 한 쪽만 긋는다**: 표가 있는 데는 표의 바깥선이,
         아래 배치도 자리는 .sheet-figure 의 테두리가 그린다. 겹칠 일이 없다. */
      display: flex; flex-direction: column;
      /* 종이 여백만큼 띄운다. 아래는 장 사이를 벌리려고 16px 을 더 준다. */
      margin: var(--sheet-margin) auto calc(var(--sheet-margin) + 16px);
      background: #fff;
      /* **여백은 흰 자리다.** 그 바깥 1px 만 종이 가장자리 표시(화면 전용).
         box-shadow 는 overflow: hidden 에 안 잘려 여백 밖까지 그릴 수 있고,
         outline 은 위에서 테두리로 쓰고 있어 한 요소에 둘을 못 둔다. */
      box-shadow: 0 0 0 var(--sheet-margin) #fff,
                  0 0 0 calc(var(--sheet-margin) + 1px) #bbb;
      overflow: hidden;
    }
    .sheet-body {
      /* **표가 쓰는 만큼만 가져간다.** 절반(50%)으로 못 박아 두면 표 아래에
         빈 띠가 남는데, 그 띠에는 표의 바깥선이 없어 옆줄이 끊긴다.
         남는 자리는 아래 배치도가 가져가고, 옆줄도 거기서 이어 그린다. */
      flex: 0 0 auto;
      height: auto;
      /* **안쪽 여백이 없다** — 표가 테두리 자리에 그대로 닿는다 (2026-08-26).
         위에 2mm 를 두었더니 표 위쪽과 테두리 위쪽 사이가 벌어져 보였다. */
      padding: 0;
      /* **절반을 나누는 선은 없다** (2026-08-26). 위 표의 맨 아래 선이
         이미 자리를 갈라 주어, 한 줄이 더 있으면 겹쳐 보였다. */
      box-sizing: border-box;
      overflow: visible;
    }
    /* 아래 절반 — 배치도 자리. 폼의 그림판과 같은 비율(210 x 148.5)이라
       폼에서 그린 그대로 크기만 바뀌어 들어온다. */
    .sheet-figure {
      /* 표가 쓰고 남는 자리 전부. 표가 커지면 여기가 눌린다 —
         그림이라 눌려도 뜻이 남고, 종이는 한 장으로 지켜진다. */
      flex: 1 1 auto; height: auto; min-height: 0;
      /* **바깥 테두리 아랫부분.** 표가 안 닿는 자리라 여기서 긋는다.
         위쪽은 안 긋는다 — 표의 맨 아래 선이 이미 그 자리다 (겹치면 진해진다).
         굵기는 표 칸 선과 같은 값이라 이어 놓으면 한 줄로 보인다. */
      border: var(--sheet-line) solid #000;
      border-top: 0;
      box-sizing: border-box;
      overflow: hidden;
    }
    .sheet-figure svg { width: 100%; height: 100%; display: block; }

    /* 모델이 많아 표가 절반을 넘을 때. 절반으로 자르는 대신 표가 아래로 이어진다.
       가운데 경계선도 지운다 — 표가 그 선을 넘어가면 선이 뜻을 잃는다.

       **종이 한 장은 지킨다.** 높이를 297mm 로 못 박는다.
       min-height 로 두면 표가 커진 만큼 종이가 늘어나고,
       배치도(SVG)는 쪼갤 수 없어 **통째로 2장째로 넘어간다.** 실제로 그랬다.
       배치도는 남는 자리만큼만 쓰고 눌린다 — 그림이라 눌려도 뜻이 남는다. */
    .sheet-page.grow {
      /* 297mm 라고 적지 않는다 — 장은 인쇄 여백만큼 작다(.sheet-page). */
      height: calc(297mm - var(--sheet-margin) * 2); overflow: hidden;
      display: flex; flex-direction: column;
    }
    .sheet-page.grow .sheet-body {
      flex: 0 0 auto;               /* 표가 필요한 만큼 먼저 가져간다 */
      /* 148.5mm 라고 적지 않는다 — 인쇄할 때 장이 여백만큼 작아진다. */
      height: auto; min-height: 50%;
      overflow: visible;
    }
    .sheet-page.grow .sheet-figure {
      flex: 1 1 auto;               /* 남는 자리 전부. 최소 높이를 두지 않는다 */
      height: auto; min-height: 0;
    }

    /* ── 배치도 그림판 (폼 화면) ───────────────────────────── */
    /* 그림 왼쪽, 부가 기능 오른쪽 */
    .figure-work { display: flex; align-items: flex-start; gap: 14px; }
    .figure-panel {
      flex: 0 0 180px;
      display: flex;
      flex-direction: column;
      gap: 8px;
      font-size: 13px;
    }
    .figure-panel button { padding: 6px 8px; font-family: inherit; font-size: 13px; }
    /* 화면을 벗어나는 단추. 위의 것들과 떼어 놓는다 */
    .figure-panel .apart { margin-top: 10px; }
    /* 직접 배치 창에서 넘겨받은 그림. 확인용이라 사양서에는 안 나간다 */
    .figure-saved { margin-top: 8px; }
    .figure-saved p {
      margin: 0 0 3px; font-size: 12px; color: #666;
      font-variant-numeric: tabular-nums;
    }
    .figure-saved svg {
      width: 100%; aspect-ratio: 210 / 148.5;
      border: 1px solid #ccc; background: #fff; display: block;
      cursor: zoom-in;
    }
    /* 크게 보기. hidden 을 display:flex 가 이기므로 따로 눌러 준다 */
    .figure-big {
      position: fixed; inset: 0; z-index: 10;
      background: rgba(0, 0, 0, 0.55);
      display: flex; align-items: center; justify-content: center;
      cursor: zoom-out;
    }
    .figure-big[hidden] { display: none; }
    .figure-big-sheet { background: #fff; padding: 12px; border-radius: 4px; }
    /* 가로와 세로 양쪽에 맞춘다. 폭만 맞추면 세로로 길어져 아래가 잘린다.
       1.414 = 210 / 148.5 (A4 절반 비율) */
    .figure-big svg {
      width: min(92vw - 24px, 1380px, (90vh - 24px) * 1.414);
      aspect-ratio: 210 / 148.5;
      display: block;
    }
    .figure-size { display: flex; flex-direction: column; gap: 3px; margin-top: 4px; }
    .figure-size em { font-style: normal; font-size: 12px; }
    /* 칸에 맞추느라 정한 값보다 작게 그렸을 때. 숫자와 그림이 다른 이유를 알린다 */
    .figure-size em.cut { color: #c00; }
    .figure-size input { width: 64px; padding: 3px 5px; border: 1px solid #ccc; font-family: inherit; }
    .figure-size .repeat-row { display: flex; align-items: center; gap: 3px; font-size: 12px; }
    .figure-size .repeat-row input { width: 44px; }
    /* 분리선 추가 입력칸. 구역 이름이 길어 칸을 패널 폭에 맞춘다 */
    .split-form { padding: 6px; border: 1px solid #ddd; background: #fafafa; }
    .split-form input { width: 100%; box-sizing: border-box; }
    .split-form button { margin-top: 2px; }

    /* 쿠폰 넣기 (2026-09-18). 분리선 넣기와 같은 틀에 '가로 x 세로' · '개수' 두 줄이다. */
    .coupon-form { padding: 6px; border: 1px solid #ddd; background: #fffdf0; }
    .coupon-line { display: flex; align-items: center; gap: 3px; margin-top: 2px; }
    .coupon-line input { width: 100%; min-width: 0; box-sizing: border-box; }
    .coupon-line em { font-style: normal; color: #777; }
    .coupon-line button { white-space: nowrap; }

    .figure-stage {
      position: relative;
      flex: 1 1 auto;
      min-width: 0;
      max-width: 1176px;
      aspect-ratio: 210 / 148.5;    /* A4 아래 절반과 같은 비율 */
      border: 1px solid #ccc;
      background: #fff;
      touch-action: none;           /* 드래그 중 화면이 따라 움직이지 않게 */
      /* 도형을 끌 때 브라우저가 글자를 함께 선택해 버린다.
         그 선택이 남아 있으면 다음 조작까지 가로챈다. 글자 선택 자체를 막는다.
         (글자 수정은 더블클릭으로 하므로 선택할 일이 없다) */
      -webkit-user-select: none;
      user-select: none;
    }
    .figure-stage svg { width: 100%; height: 100%; display: block; }
    .figure-stage .shape, .figure-stage .arrow-hit, .figure-stage .text-group { cursor: move; }
    .figure-stage .split-hit { cursor: ns-resize; }   /* 분리선은 위아래로만 움직인다 */
    .figure-stage .handle { fill: #37f; stroke: #fff; stroke-width: 0.3; }
    .figure-stage .label, .figure-stage .body-text { cursor: text; }
    #figure-input {
      position: absolute;
      /* 그림판은 글자 선택을 막지만, 고치는 입력칸에서는 되어야 한다 */
      -webkit-user-select: text;
      user-select: text;
      border: 1px solid #37f;
      padding: 2px 4px;
      font-family: inherit;
      font-size: 12px;
      line-height: 1.2;
      resize: none;
      z-index: 2;
    }

    /* ── 직접 배치 (새 창) ─────────────────────────────────── */
    .place-work { display: flex; align-items: flex-start; gap: 14px; }
    .place-stage {
      position: relative;
      flex: 1 1 auto;
      min-width: 0;
      max-width: 1100px;
      aspect-ratio: 210 / 148.5;    /* 사양서 아래 절반과 같은 비율 */
      border: 1px solid #ccc;
      background: #fff;
      touch-action: none;           /* 끄는 동안 화면이 따라 움직이지 않게 */
      -webkit-user-select: none;
      user-select: none;
    }
    .place-stage svg { width: 100%; height: 100%; display: block; }
    .place-stage .block { cursor: move; }
    /* 빈 곳은 끌어서 화면을 옮긴다 (휠은 확대 · 축소) */
    .place-stage svg { cursor: grab; touch-action: none; }
    .place-stage svg.panning { cursor: grabbing; }
    .place-fit { margin: 4px 0 8px; }
    /* min-width 를 0 으로 눌러야 한다. 그냥 두면 긴 모델명이 이 칸을 넓혀
       왼쪽 그림판을 밀어낸다 (flex 항목의 기본 min-width 가 내용 크기다) */
    .place-panel { flex: 0 0 260px; min-width: 0; font-size: 13px; }
    .place-scale { margin: 0 0 10px; color: #666; font-variant-numeric: tabular-nums; }
    .place-legend table { border-collapse: collapse; }
    .place-legend td {
      border: 0; padding: 2px 7px 2px 0;
      white-space: nowrap; font-size: 12px;
    }
    .place-legend .letter { font-weight: 700; }
    .place-legend .chip {
      display: inline-block; width: 12px; height: 12px;
      border: 1px solid #999; vertical-align: -2px;
    }
    .place-legend .num { text-align: right; font-variant-numeric: tabular-nums; color: #666; }
    .place-legend .none { color: #c00; }
    /* 배치에서 빼고 넣는 체크. 끈 줄은 흐리게 두어 목록에는 남아 있게 한다 */
    .place-legend .use { margin: 0; vertical-align: -1px; cursor: pointer; }
    .place-legend .use:disabled { cursor: default; }
    .place-legend tr.dim td { color: #bbb; }
    .place-legend tr.dim .chip { opacity: 0.3; }
    .place-legend tr.dim .num { color: #ccc; }
    .place-tools {
      display: flex; flex-direction: column; gap: 6px; align-items: flex-start;
      margin-top: 14px; border-top: 1px solid #ddd; padding-top: 10px;
    }
    .place-tools button { padding: 5px 8px; font-family: inherit; font-size: 13px; }
    .place-tools button:disabled { color: #aaa; background: #fafafa; cursor: default; }
    .place-array { display: flex; flex-direction: column; gap: 3px; font-size: 12px; }
    .place-array .row { display: flex; align-items: center; gap: 3px; }
    .place-array input {
      width: 46px; padding: 3px 5px; border: 1px solid #ccc; font-family: inherit;
    }
    .place-calc {
      margin-top: 14px; border-top: 1px solid #ddd; padding-top: 10px; font-size: 13px;
    }
    .place-calc p { margin: 0 0 4px; }
    .place-calc .sum { font-weight: 700; font-size: 15px; font-variant-numeric: tabular-nums; }
    .place-calc .warn { color: #c00; }
    .place-send {
      margin-top: 14px; padding: 6px 10px; font-family: inherit; font-size: 13px;
    }
    /* 끄는 도중 잠깐 계산이 안 될 때 마지막 값을 흐리게 둔다 */
    .place-calc .stale { opacity: 0.45; }

    /* 추천 배치 (새 창) — 판넬 후보를 나란히 놓고 견준다 */
    .pick-list {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
      gap: 14px;
      margin-top: 14px;
    }
    .pick-card {
      border: 1px solid #ddd; border-radius: 4px; padding: 10px;
      display: flex; flex-direction: column; min-width: 0;
    }
    /* 어느 글자가 어느 모델인가. 카드가 아니라 화면 위에 한 번만 둔다 */
    .pick-key {
      list-style: none; margin: 10px 0 0; padding: 0;
      display: flex; flex-wrap: wrap; gap: 4px 16px; font-size: 13px;
    }
    .pick-key li { display: flex; align-items: center; gap: 5px; min-width: 0; }
    .pick-key .chip {
      flex: 0 0 auto; width: 10px; height: 10px; border: 1px solid #999; border-radius: 2px;
    }
    .pick-key b { font-weight: 700; }
    .pick-key span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .pick-key em { font-style: normal; color: #888; font-variant-numeric: tabular-nums; }
    /* 판넬당 개수를 못 박는 칸. 비우면 알아서 고른다 */
    .pick-key .want {
      width: 52px; padding: 1px 4px; font-family: inherit; font-size: 12px;
    }
    .pick-again {
      margin-top: 10px; padding: 5px 10px; font-family: inherit; font-size: 13px;
    }
    .pick-again[hidden] { display: none; }

    /* MASS-LAM 발주서 (새 창). 실물 양식과 같은 모양으로 두고 모든 칸을 고칠 수 있게 한다 */
    .lam-bar { display: flex; align-items: center; gap: 8px; margin-bottom: 14px; }
    .lam-page {
      width: 190mm; padding: 4mm 0 0; background: #fff;
      font-size: 11pt; color: #000;
    }
    /* 제목만 굵게. 고정폭 글꼴은 글자가 흩날려 보여 본문 글꼴을 그대로 쓴다. */
    .lam-title {
      text-align: center; font-size: 20pt; font-weight: 700;
      letter-spacing: 1px; margin-bottom: 6mm;
    }
    .lam-top {
      display: flex; justify-content: space-between;
      margin: 0 0 3mm; font-size: 10pt;
    }
    .lam-top-one { display: flex; align-items: baseline; gap: 6px; }
    /* 실물에는 여기 네모가 없다. 빈 자리에 적는 꼴이라 테두리를 없앤다.
       다만 화면에서는 적는 자리인 줄 알아야 해서 연한 밑줄만 둔다 (종이에는 안 나간다). */
    .lam-top-one input {
      width: 34mm; border: 0; border-bottom: 1px dotted #bbb; padding: 0 2px;
      font: inherit; color: inherit; background: transparent;
    }
    .lam-top-one input:focus { outline: 0; border-bottom-color: #37f; }

    .lam-table { width: 100%; border-collapse: collapse; table-layout: fixed; }
    .lam-table th, .lam-table td { border: 1px solid #000; padding: 2mm 2.5mm; }
    .lam-table th {
      width: 26mm; text-align: center; font-weight: 700; background: #fff;
    }
    .lam-table td { width: 40%; }
    /* 칸 안을 가로로 늘어놓는다. 입력칸에 width:100% 를 주면
       옆의 이름표(내층·외층·PNL)를 칸 밖으로 밀어낸다. */
    .lam-cell { display: flex; align-items: baseline; justify-content: center; gap: 2mm; }
    .lam-table input {
      flex: 1 1 auto; min-width: 0;      /* min-width 를 안 풀면 flex 가 안 줄어든다 */
      border: 0; padding: 0; font: inherit; color: inherit;
      background: transparent; text-align: center;
    }
    .lam-table input.grow2 { flex: 2 1 auto; }
    .lam-table input:focus { outline: 1px dotted #37f; }
    .lam-sub { flex: 0 0 auto; font-size: 9pt; color: #333; }
    .lam-mark { flex: 0 0 auto; font-size: 10pt; }
    .lam-mark.red { color: #c00; font-weight: 700; }

    .lam-note-head {
      border: 1px solid #000; border-top: 0; padding: 2mm;
      text-align: center; font-weight: 700; letter-spacing: 2px;
    }
    .lam-note-body {
      width: 100%; box-sizing: border-box; border: 1px solid #000; border-top: 0;
      padding: 2mm; font: inherit; resize: vertical; min-height: 34mm;
    }
    .lam-note-body:focus { outline: 1px dotted #37f; }
    .lam-foot { margin-top: 3mm; }
    .lam-foot input {
      border: 0; padding: 0; font: inherit; font-weight: 700;
      background: transparent; width: 60mm;
    }
    /* 판넬 비율이 제각각이라 높이를 고정해 두어야 카드가 들쭉날쭉하지 않다 */
    .pick-figure { height: 150px; background: #fafafa; border-radius: 3px; padding: 6px; }
    .pick-figure svg { width: 100%; height: 100%; display: block; }
    .pick-card dl { margin: 10px 0 0; font-size: 13px; }
    .pick-card dl div { display: flex; justify-content: space-between; gap: 8px; }
    .pick-card dt { margin: 0; color: #666; }
    .pick-card dd { margin: 0; font-variant-numeric: tabular-nums; }
    .pick-array {
      list-style: none; margin: 8px 0 0; padding: 0;
      font-size: 12px; color: #444;
    }
    .pick-array li {
      display: flex; align-items: center; gap: 4px;
      white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    }
    .pick-array .chip {
      flex: 0 0 auto; width: 9px; height: 9px; border: 1px solid #999; border-radius: 2px;
    }
    .pick-send {
      margin-top: 10px; padding: 6px 10px; font-family: inherit; font-size: 13px;
    }

    .sheet-table {
      width: 100%;
      table-layout: fixed;
      border-collapse: collapse;
      margin: 0;
      font-size: 8pt;      /* 7pt 는 종이에서 읽기 힘들었다 */
      line-height: 1.15;
    }
    /* 표를 이어 붙인다. -1px 로 맞닿은 테두리를 겹쳐 한 줄로 만든다.
       사이 공백을 없애야 공정 표까지 A4 절반 안에 들어간다. */
    .sheet-table + .sheet-table { margin-top: -1px; }
    .sheet-table td {
      /* 이게 없으면 height 가 '글자 자리'만 뜻하고 여백·테두리가 그 위에 더 붙는다.
         한 줄에 1mm 남짓이지만 줄이 스물몇 개라 공정 표가 종이 밖으로 밀려났다.
         border-box 로 두어야 아래 height 값이 곧 실제 줄 높이가 된다. */
      box-sizing: border-box;
      border: var(--sheet-line) solid #000;   /* 여백 테두리와 같은 두께 */
      background: #fff;             /* 빈 칸은 흰색 */
      /* 글자는 **모두 굵게**. 사양서는 8pt · 모델 표는 7.5pt 로 작은데,
         복사해 돌려 보는 종이라 가는 획은 복사하면 흐려진다.
         굵기로 갈라 보이던 것(.bold)은 이제 안 갈리지만, 그 자리는 원래
         색(.red)과 바탕색(.lb · .hl)이 갈라 주고 있었다. */
      font-weight: 700;
      /* 세로 0.25mm 였다. 선이 0.26 -> 0.3mm 로 굵어지면서 위아래로 0.08mm 를
         더 먹는데, 모델·공정 줄(4.1mm)에는 남는 자리가 0.03mm 뿐이라 7.5pt
         글자가 넘쳤다. 0.05mm 를 여기서 돌려준다 — 눈에는 안 보이는 차이다. */
      padding: 0.2mm 0.8mm;
      height: 5.0mm;
      text-align: center;           /* 라벨·값 모두 가운데 (세로는 표 기본값이 이미 가운데) */
      white-space: nowrap;
      /* **글자 크기는 그대로 두고, 칸을 넘으면 자른다** (2026-09-18 사용자).
         *"글씨가 넘어가더라도 크기에는 변함이 없었으면"* → 줄이기를 걷어냈고,
         *"칸을 넘어가면 잘라야지. 수량을 어떻게 보라고"* → 넘친 글자가 옆 칸 값을 덮지 않게 자른다.
         점(…)은 안 붙인다 — 한 글자라도 더 보이는 편이 낫고, 원본 사양서(엑셀)도 그냥 잘린다. */
      overflow: hidden;
      text-overflow: clip;
    }
    /* 훑어보는 칸 (2026-09-18) — 눌러서 휠로 뒷부분을 보는 중.
       화면에서만 쓰는 표시다. 지우는 규칙은 이 파일 아래 인쇄 자리에 있다. */
    .sheet-table td.sheet-peek {
      outline: 1px solid #2563eb; outline-offset: -1px; cursor: ew-resize;
    }
    .sheet-table .bold { font-weight: 700; }
    /* 사람이 폼에서 채워 넣은 값. 종이에서 눈에 띄어야 한다 (spec/report.py 의 RED_LABELS)
       굵기도 함께 준다. 판넬 SIZE·내층연결처럼 .bold 가 없는 칸만 가늘어 보였다. */
    .sheet-table td.red { color: #f00; font-weight: 700; }
    .sheet-table .big { font-size: 13pt; }
    .sheet-table .tall td { height: 7mm; }   /* 제목 줄. 11pt 글자가 들어가는 최소선 */
    /* LAYER 줄 · 판넬수-도금방식 줄. 값이 많이 들어가는 두 줄이라 가장 높다 */
    .sheet-table .mid td { height: 9mm; }
    .sheet-table .qr { width: 12mm; }
    /* 600 이었다. 칸(td)보다 **먼저 잡히는 규칙**이라(클래스가 요소를 이긴다)
       그대로 두면 라벨 칸만 나머지보다 가늘어진다. 700 으로 맞춘다. */
    .sheet-table .lb { background: #f2f2f2; font-weight: 700; }
    /* 노랑은 **엑셀 기본 노랑(FFFF00)과 같은 값**이다. 전에는 연노랑(#ffff9e)
       이었는데, 종이 쪽만 연하게 두면 같은 사양서가 인쇄본과 엑셀에서 다른
       색으로 나온다. spec/excel.py 의 YELLOW 와 짝이다 — 한쪽만 바꾸지 않는다. */
    .sheet-table .hl { background: #ffff00; font-weight: 700; }
    /* 아래 두 표는 글자가 작은데 머리글과 같은 5mm 를 쓰고 있었다.
       글자에 맞춰 줄이면 스무 줄에서 여러 mm 가 남아, 위쪽 줄을 높일 자리가 생긴다.

       4.1mm 는 거의 바닥이다. 7.5pt · 줄간격 1.15 = 3.04mm 에 안쪽 여백 0.5mm 와
       테두리가 더해져 4.07mm 가 최소다. 글자를 키우면 이 값이 먼저 넘친다 —
       그때는 tests/check_sheet.py 의 높이 검사가 먼저 잡아 준다.

       줄 높이는 --row 라는 이름으로 둔다. 여러 줄을 덮는 병합 칸의 높이를
       자바스크립트가 이 값에 곱해 쓴다 (_model_table.html 의 fillSheet).
       숫자를 두 곳에 두지 않으려는 것이다 — 검사도 이 이름을 읽는다. */
    .sheet-table.model, .sheet-table.process { --row: 4.1mm; }
    .sheet-table.model td, .sheet-table.process td { font-size: 7.5pt; height: var(--row); }
    /* 폼에서 엔터로 줄을 바꾼 것이 종이에도 그대로 나가야 한다.
       pre 는 적어 준 줄바꿈만 지키고 저 혼자 줄을 접지는 않는다
       (nowrap 처럼). wrap 계열로 두면 긴 모델명이 멋대로 접혀 줄 높이가 달라진다. */
    .sheet-table.model td { white-space: pre; }
    .sheet-table.process td:first-child { width: 9%; }
    /* 공정 표만 왼쪽 맞춤. 나머지 표는 가운데 맞춤 그대로다. */
    .sheet-table.process td { text-align: left; }

    /* ── 전체 확인 (새 창) ───────────────────────────────────
       이름을 chk- 로 못 박아 다른 화면에 안 닿는다. */
    /* 제목 줄 — 왼쪽에 무엇을 보는 자리인지, 오른쪽에 전체 줄 수. */
    .chk-top { display: flex; align-items: flex-start; justify-content: space-between;
               gap: 16px; margin-bottom: 14px; }
    .chk-top h1 { margin: 0 0 4px; }
    .chk-top .muted { margin: 0; font-size: 13px; }
    .chk-top code { background: #eef1f5; border-radius: 4px;
                    padding: 1px 5px; font-size: 12px; }
    .chk-top kbd { background: #fff; border: 1px solid #d0d5dd;
                   border-bottom-width: 2px; border-radius: 4px;
                   padding: 0 4px; font-size: 11px; font-family: inherit; }
    /* 전체 줄 수. 5만 줄짜리 표를 보고 있다는 것이 한눈에 보여야 한다. */
    .chk-count { flex: none; text-align: right; line-height: 1.1; }
    .chk-count strong { display: block; font-size: 22px; font-weight: 700;
                        letter-spacing: -0.02em; }
    .chk-count span { font-size: 12px; color: #667085; }

    /* 쪽 넘기기 줄. 한 쪽 300줄이라 164쪽쯤 된다 — 번호를 직접 칠 수 있게 둔다. */
    .chk-bar { display: flex; align-items: center; justify-content: space-between;
               gap: 12px; margin: 0 0 12px; flex-wrap: wrap; }
    .chk-pager { display: flex; align-items: center; gap: 4px;
                 background: #fff; border: 1px solid #e4e7ec; border-radius: 8px;
                 padding: 4px; box-shadow: 0 1px 2px rgba(16,24,40,.04); }
    .chk-pager button {
      min-width: 30px; height: 28px; padding: 0 8px;
      border: 0; border-radius: 6px; background: transparent;
      color: #344054; font-size: 14px; line-height: 1; cursor: pointer;
    }
    .chk-pager button:hover:not(:disabled) { background: #f2f4f7; color: #1d4ed8; }
    .chk-pager button:disabled { color: #cfd4dc; cursor: default; }
    .chk-at { display: flex; align-items: center; gap: 5px; padding: 0 4px; }
    .chk-at input { width: 4em; height: 26px; padding: 0 6px; text-align: right;
                    border: 1px solid #d0d5dd; border-radius: 6px;
                    font-size: 13px; font-family: inherit; }
    .chk-at input:focus { outline: none; border-color: #2563eb;
                          box-shadow: 0 0 0 3px rgba(37,99,235,.14); }
    .chk-at em { font-style: normal; color: #667085; font-size: 13px; }
    /* 고른 칸 수를 알리는 자리. 골랐을 때만 도드라진다. */
    .chk-note { font-size: 12px; color: #667085; }
    .chk-note.on { color: #1d4ed8; font-weight: 600; }

    /* ── 표 ──────────────────────────────────────────────────
       칸이 36개라 가로로 넓다. `.chk-scroll` 안에서만 흐르게 잡는다. */
    /* `.scroll` 은 잡아끌어 옮기는 표를 위해 `cursor: grab` 인데, 여기는
       칸을 고르는 자리라 그 손 모양이 거짓말이 된다 (data-nopan 이라 끌리지도
       않는다). 두 클래스로 적어 뒤에 오는 theme.css 의 `.scroll` 을 이긴다. */
    .scroll.chk-scroll {
      max-height: 74vh; overflow: auto; cursor: default;
      border: 1px solid #e4e7ec; border-radius: 10px;
      background: #fff; box-shadow: 0 1px 2px rgba(16,24,40,.04);
    }
    .chk-table td { cursor: cell; }
    .chk-table { border-collapse: separate; border-spacing: 0;
                 white-space: nowrap; user-select: none; }
    .chk-table th, .chk-table td {
      border-right: 1px solid #eef0f3; border-bottom: 1px solid #eef0f3;
      padding: 5px 9px; font-size: 12px; max-width: 24em;
      overflow: hidden; text-overflow: ellipsis;
    }
    .chk-table tbody tr:hover td { background: #fafbfc; }
    /* **머리줄과 줄 번호는 붙어 있어야 한다.** 36칸을 오른쪽으로 밀면
       무슨 칸을 보고 있는지, 몇 번째 줄인지가 사라진다. */
    .chk-table thead th {
      position: sticky; top: 0; z-index: 2;
      background: #f8f9fb; color: #475467; font-weight: 600;
      font-family: var(--ui, inherit); cursor: pointer;
      border-bottom: 1px solid #d0d5dd; white-space: nowrap;
    }
    .chk-table thead th:hover { background: #eef1f5; color: #1d4ed8; }
    .chk-table tbody th {
      position: sticky; left: 0; z-index: 1;
      background: #fbfcfd; color: #98a2b3; font-weight: 400;
      text-align: right; cursor: pointer;
      border-right: 1px solid #e4e7ec; font-variant-numeric: tabular-nums;
    }
    .chk-table tbody th:hover { background: #eef1f5; color: #1d4ed8; }
    .chk-table thead th.chk-corner { left: 0; z-index: 3; min-width: 3.5em; }
    /* 고른 칸. 옅게 깔고 글자는 그대로 둔다 — 진하게 칠하면 36칸이
       한꺼번에 물들 때 값을 못 읽는다. */
    .chk-table td.on, .chk-table tbody tr:hover td.on {
      background: rgba(37, 99, 235, 0.13); }
    .chk-table th.on { background: #dde5f6; color: #1d4ed8; }

    /* ── 작지 확인 — 당일/전체 · 고치기 · 저장 (2026-09-17) ───── */
    .chk-head-line { display: flex; align-items: center; gap: 12px; margin-bottom: 4px; }
    .chk-head-line h1 { margin: 0; }
    .chk-mode { display: inline-flex; background: #f2f4f7; border-radius: 8px; padding: 3px; gap: 2px; }
    .chk-mode button { border: 0; background: transparent; border-radius: 6px;
                       padding: 4px 14px; font-size: 13px; color: #475467; cursor: pointer;
                       font-family: inherit; }
    .chk-mode button.on { background: #fff; color: #1d4ed8; font-weight: 600;
                          box-shadow: 0 1px 2px rgba(16,24,40,.08); }
    .chk-save-box { display: inline-flex; align-items: center; gap: 10px; }
    .chk-dirty-note { font-size: 12px; color: #b54708; font-weight: 600; }
    .chk-save { height: 30px; padding: 0 18px; border: 0; border-radius: 6px;
                background: #2563eb; color: #fff; font-size: 13px; font-weight: 600;
                cursor: pointer; font-family: inherit; }
    .chk-save:disabled { background: #d0d5dd; cursor: default; }
    /* 고친 칸 — 저장 전까지 옅은 노랑 */
    .chk-table td.chk-dirty { background: #fff4d6; }
    .chk-table td.chk-dirty.on { background: #f5dfa0; }
    /* 빈 줄(새로 적는 자리). 번호만 옅게 */
    .chk-table tr.chk-new th { color: #c4cad4; }
    /* 표 위에 얹는 입력칸. 고르기만 했을 때는 안 보이고, 치기 시작하면 보인다 */
    .scroll.chk-scroll { position: relative; }
    .chk-editor { position: absolute; left: 0; top: 0; width: 0; height: 0; z-index: 4;
                  box-sizing: border-box; margin: 0; padding: 3px 8px; font-size: 12px;
                  font-family: inherit; border: 2px solid #2563eb; background: #fff;
                  outline: none; opacity: 0; pointer-events: none; }
    .chk-editor.editing { opacity: 1; pointer-events: auto; }
    /* 쪽 넘기기 — 표 아래 가운데 */
    .chk-foot { display: flex; justify-content: center; margin: 12px 0 4px; }

    /* ── 칸 경계를 끌어 넓히기 (2026-09-18 사용자 — "실제 엑셀처럼 마우스로 잡아서") ──
       머리줄 오른쪽 끝 · 줄 번호 아래 끝에 잡는 자리를 얹는다. 6px 이라 눈에는 안 보이고
       손에는 잡힌다. `position: sticky` 인 머리칸 안에 두므로 자리는 그 칸을 따라 움직인다. */
    .chk-table th { position: sticky; }
    .chk-grip-col, .chk-grip-row { position: absolute; z-index: 4; }
    /* 칸은 `overflow: hidden` 이라 밖으로 내밀면 잘린다. 안쪽 끝에 붙인다. */
    .chk-grip-col { top: 0; right: 0; width: 6px; height: 100%; cursor: col-resize; }
    .chk-grip-row { left: 0; bottom: 0; height: 6px; width: 100%; cursor: row-resize; }
    .chk-grip-col:hover, .chk-grip-row:hover { background: rgba(37, 99, 235, 0.35); }
    /* 끄는 동안 표 전체에 같은 커서를 씌운다 — 칸을 벗어나도 손 모양이 안 바뀐다. */
    .chk-scroll.sizing-col, .chk-scroll.sizing-col * { cursor: col-resize !important; }
    .chk-scroll.sizing-row, .chk-scroll.sizing-row * { cursor: row-resize !important; }
    /* `.chk-pager { display: flex }` 가 hidden 을 덮는다 — 당일 화면에 쪽 넘기기가 떴다 */
    .chk-pager[hidden] { display: none; }

    /* ── 인쇄 ────────────────────────────────────────────────
       종이에는 사양서만 나간다. 도구 모음·설명·폼은 빼고,
       화면에서만 쓰는 종이 경계 그림자도 지운다.
       절반을 나누는 선은 양식의 일부라 그대로 인쇄된다. */
    @media print {
      /* 종이 가장자리 여백. 전에는 0 이라 사양서가 A4 끝까지 꽉 찼다.
         **여기를 늘리면 위 절반이 그만큼 좁아진다.** 표는 137.0mm 를 쓰고
         위 절반이 (297 - 여백x2) / 2 이므로

             여백 + 안쪽여백x2  <=  11.5mm

         를 지켜야 공정 표가 안 잘린다. 6 + 2x2 = 10 으로 두어 지금까지의
         여유 1.5mm 를 그대로 남겼다. 이 셈은 tests/check_sheet.py 가
         CSS 에서 두 값을 읽어 다시 해 본다 — 숫자를 늘리면 거기서 걸린다.

         엑셀도 같은 6mm 다 (spec/xlsx.py 의 PAGE_MARGIN_MM). 두 값이 갈리면
         같은 사양서가 인쇄본과 엑셀에서 다른 크기로 나온다. */
      @page { size: A4; margin: 6mm; }

      body { margin: 0; background: #fff; }

      .toolbar, h1, h3, .muted, .flash { display: none !important; }
      .figure-big { display: none !important; }   /* 열려 있어도 종이에는 안 나온다 */
      .lam-bar { display: none !important; }      /* 발주서의 단추 줄 */

      /* 발주서. 칸이 입력칸인 티가 안 나게 하고 A4 여백만 준다. */
      .lam-page { width: auto; margin: 12mm 14mm; }
      .lam-table input:focus,
      .lam-note-body:focus,
      .lam-top-one input:focus { outline: 0; }
      /* 화면에서만 두는 밑줄. 종이에는 실물처럼 빈 자리로 나간다. */
      .lam-top-one input { border-bottom: 0; }
      .lam-note-body { resize: none; }

      /* **크기·테두리·안쪽 여백은 화면과 같다** — 위 .sheet-page 규칙 그대로다.
         여기서는 화면에서만 쓰던 것(종이 가장자리 표시·장 사이 간격)만 걷어낸다.
         outline 은 바깥 테두리라 **그대로 둔다.** */
      .sheet-page {
        margin: 0;                     /* @page 여백이 그 몫을 한다 */
        box-shadow: none;              /* 흰 여백 고리 + 종이 가장자리 (화면용) */
        page-break-after: always;
      }
      /* 마지막 장 뒤에는 넘기지 않는다. 그냥 두면 빈 종이가 한 장 더 나온다. */
      .sheet-page:last-child { page-break-after: auto; }
      /* 브라우저는 인쇄할 때 배경색을 빼버린다.
         라벨 칸의 노랑·회색이 사본과 같이 나오도록 강제한다.
         절반을 나누는 선도 색이 빠지지 않게 함께 지정한다. */
      .sheet-body,
      .sheet-table td {
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
      }
      /* 훑어보던 표시는 화면 것이다 (2026-09-18). 자리는 인쇄 직전에 처음으로 돌아간다. */
      .sheet-table td.sheet-peek { outline: 0; }
    }
