/* 「어떻게 만들까요?」 — 도구 막대 · 올라오는 창 · 사진마다 설정
 *
 * 🔴 owner 지시(2026-08-02)
 *   ① 「이런 식으로 개별로 클릭클릭해서」 — mixtiles 의 Frame/Size/Border 도구 막대
 *   ② 「개별로 적용해야 되고」 — 사진마다 따로 정할 수 있어야 한다
 *   ③ 「사진 사이즈도 판단해서 쉽게 선택할 수 있게」 — 화소로 어디까지 선명한지 알려준다
 *   ④ 「용지 선택도 가이드」 — 표면·등급을 나눠 보여주고 설명을 붙인다
 */

/* ── 사진 칸 ─────────────────────────────────────────────
   🔴 owner 지시(2026-08-02): 「1번 이미지는 삭제하고 사진을 클릭하면
     디테일하게 조절할 수 있게 팝업으로 하면 좀 더 심플하고 이어지는 느낌」
     아래 붙어 있던 「4x6 · 무광  바꾸기」 줄을 없앴다. 이제 **사진 자체가 단추**다.
   🔴 owner 지시: 「많이 흐려요 그 옆으로 지금 셋팅된 걸 심플하게 확인」
     사진 위에 반투명 딱지로 얹는다 — ✕ 단추와 같은 방식이라 눈에 익다. */
.pface{display:block;width:100%;padding:0;border:0;background:none;
  cursor:pointer;position:relative;font:inherit;color:inherit;text-align:left}

/* 🔴 owner 지적(2026-08-02): 「이렇게 선택하면 여기도 반영이 되어야지」
   칸에도 매트를 **실제로** 그린다. 딱지 글자만으로는 고른 게 안 보였다.
   🔴 inset 을 %로 준다 — 좌우는 칸 너비, 위아래는 칸 높이로 풀린다.
     칸 크기가 제각각인 줄맞춤 격자에서도 비율이 정확히 맞는다.
   🔴 서버 합성(render.py)과 **같은 규칙**으로 계산한 값이 들어온다. */
.pmat{position:relative;display:block;width:100%;aspect-ratio:var(--ar,1);
  background:var(--c-surface-alt);overflow:hidden}
/* 🔴 owner 지적(2026-08-02): 「사진이 왜 확대가 되어 있지?」 — 내가 낸 버그였다.
     실측: 매트 상자는 345×230 인데 **사진이 800×533 원본 크기 그대로** 그려지고,
     overflow:hidden 이 나머지를 잘라내 확대된 것처럼 보였다.
   🔴 원인: `position:absolute` 인 **그림(replaced element)** 에 `width:auto` 를 주면
     CSS 규칙상 inset 을 넣어도 늘어나지 않고 **원래 크기**를 쓴다 (CSS 2.1 §10.3.7).
     테두리 없는 사진(inset:0)까지 전부 이 규칙에 걸렸다.
   🔴 그래서 크기를 **직접 계산해서** 준다. --mx/--my 는 %라
     가로는 상자 너비, 세로는 상자 높이 기준으로 정확히 풀린다. */
.pmat .im{position:absolute;top:var(--my,0);left:var(--mx,0);
  width:calc(100% - 2 * var(--mx, 0%));
  height:calc(100% - 2 * var(--my, 0%));
  aspect-ratio:auto;object-fit:cover;
  transition:top var(--m-base) var(--m-ease), left var(--m-base) var(--m-ease),
             width var(--m-base) var(--m-ease), height var(--m-base) var(--m-ease)}
/* 🔴 초점 테두리가 사진에 잘리지 않게 안쪽으로 그린다 */
.pface:focus-visible{outline:3px solid var(--c-focus);outline-offset:-3px}

.ph .tags{position:absolute;left:var(--s2);bottom:var(--s2);
  display:flex;flex-direction:column;align-items:flex-start;gap:4px;
  max-width:calc(100% - var(--s3) * 2)}
/* 🔴 딱지 하나로 통일한다. 흐림 알림과 설정이 모양이 다르면 어수선하다.
     반투명 먹색 + 흰 글자 — 어떤 사진 위에서도 읽힌다. */
.ph .tag{display:inline-block;max-width:100%;
  padding:3px var(--s2);border-radius:var(--r-sm);
  background:rgba(var(--brand-ink-rgb),.62);color:var(--brand-white);
  font-size:var(--t-cap);font-weight:700;line-height:1.35;
  /* 🔴🔴 2026-08-14 실측 — 세로 사진 칸에서 딱지가 「■ …」 「4×…」 로 **읽을 수가 없었다.**
     `white-space:nowrap` + ellipsis 라 칸이 좁으면 글이 통째로 잘려 나갔다.
     제일 중요한 「사진이 선명하지 않아요」가 안 읽히면 딱지를 다는 뜻이 없다.
     → 자르지 말고 **두 줄까지 접는다.** 낱말 가운데서 쪼개지지 않게 keep-all 을 같이 준다. */
  white-space:normal;word-break:keep-all;overflow-wrap:anywhere;
  /* 🔴🔴 2026-08-20 감사에서 잡힘 — 오늘 딱지에 ■·▲ 기호를 붙이고 글자를 13→14px 로
     키우면서, 두 줄만 보여 주던 이 상자에 **세 줄**이 들어가게 됐다.
     실측(320~430px 폰, 좁은 칸): 상자 80×46 / 글 80×65 → 19px 이 잘려
     손님이 보는 글이 「■ 선명하지」였다. 「않아요」가 통째로 사라졌다.
     🔴 기호를 도로 빼지 않는다 — 두 화면 말을 같게 맞춘 것이 목적이었다.
        보여 주는 줄을 셋으로 늘린다. 넓은 칸에서는 어차피 두 줄로 끝난다. */
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden;
  -webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}
/* 🔴 기호는 어두운 바탕 위라 **밝은 쪽**을 쓴다 (upload.css 와 같은 값) */
.tag--warn .dot{color:#FFC98A}
.tag--bad  .dot{color:#FF9E9A}
.tag .dot{font-style:normal}
/* 지금 설정은 한 단계 조용하게 — 흐림 알림이 먼저 보여야 한다 */
.tag--set{background:rgba(var(--brand-ink-rgb),.48);font-weight:600}

/* ── 올라오는 창 ─────────────────────────────────────────
   🔴 화면을 옮기지 않는다. 보던 사진이 뒤에 그대로 있어야 비교가 된다. */
dialog.sheet{border:0;padding:0;margin:auto auto 0;width:100%;max-width:560px;
  background:var(--c-surface);color:var(--c-text);
  border-radius:var(--r-xl) var(--r-xl) 0 0;
  max-height:var(--sheet-h);overflow:hidden}
@media (min-width:600px){
  dialog.sheet{margin:auto;border-radius:var(--r-xl)}
}
dialog.sheet::backdrop{background:rgba(var(--brand-ink-rgb),.45)}
.sheet .in{display:flex;flex-direction:column;max-height:var(--sheet-h)}
/* 🔴🔴 아래 여섯 곳은 **여백만** 줄인 것이다 (2026-08-28).
   창에서 「그림도 목록도 아닌 것」이 443px 이나 돼서 미리보기가 95×142 까지 쪼그라들었다.
   글자 크기·문구는 한 글자도 안 건드리고 여백에서 93px 을 되찾아 사진에 준다.
   🔴 차례칸(.stepdot)이 --tap(48px) **정확히** 바닥에 닿는다 — 여기서 더 줄이면 안 된다.
   실측 근거는 design/tokens.css 의 --sheet-fixed 주석에 있다. */
.sheet .shead{display:flex;align-items:flex-start;gap:var(--s3);
  padding:var(--s3) var(--s5) var(--s2)}
.sheet .shead .grow{flex:1;min-width:0}
.sheet h2{font-size:var(--t-prod);margin:0}
.sheet .shead .sub{margin:2px 0 0}
.sheet .sx{flex:0 0 auto;min-width:var(--tap);min-height:var(--tap);
  border:0;background:none;color:var(--c-text);font-size:20px;cursor:pointer;
  border-radius:var(--r-pill)}
.sheet .sx:hover{background:var(--c-surface-alt)}
/* 🔴🔴 목록이 쓰는 칸. 창에서 **줄어들 수 있는 칸은 여기 하나뿐**이다 — 스크롤 상자라
   flex 의 자동 최소크기가 0이 되기 때문이다. 그래서 넘치는 양을 혼자 다 뒤집어쓴다.
   위 미리보기가 커지면 이 칸이 0이 됐다 — 2026-08-27 사고의 구조적 원인.
   이제 미리보기 쪽에 천장(--pv-max)을 둬서 이 칸이 마르지 않게 한다.
   🔴 overscroll-behavior — 끝에서 더 밀어도 뒷장이 따라 움직이지 않게 (집안 관례,
      menu.css:8 과 같은 규칙). 시트에만 빠져 있었다. */
.sheet .sbody{padding:0 var(--s5) var(--s5);overflow:auto;
  overscroll-behavior:contain;-webkit-overflow-scrolling:touch}
/* 🔴 아래 여백은 **홈 인디케이터·제스처 막대를 피한다.** 시트가 화면 바닥에 붙어
   있어서(margin:auto auto 0) 이게 없으면 단추 아랫부분이 그 띠에 걸려 누르기 나쁘다.
   🔴 `max(...)` 라 그런 띠가 없는 기기·PC 에서는 원래 여백 그대로다 (집안 관례,
      shop.css 의 `.sticky` 와 같은 꼴). 600px 이상은 창이 가운데 떠서 필요 없다. */
.sheet .sfoot{display:flex;gap:var(--s3);padding:var(--s3) var(--s5) var(--s4);
  padding-bottom:max(var(--s4), env(safe-area-inset-bottom));
  border-top:1px solid var(--c-border);background:var(--c-surface)}
@media (min-width:600px){
  .sheet .sfoot{padding-bottom:var(--s4)}
}
.sheet .sfoot .btn{flex:1}
/* 🔴 단추가 셋이면 한 줄에 못 넣는다 — 320px 에서 글자가 두 줄로 접힌다.
   고르는 것 하나(핑크)를 위에 통째로 두고, 나머지 둘을 아래 한 줄에 나눈다. */
.sheet .sfoot--stack{flex-direction:column;align-items:stretch;gap:var(--s2)}
.sheet .sfoot--stack > .btn{flex:0 0 auto}
/* 🔴 320px 에서 「그냥 장바구니로」가 **두 줄로 접혔다**(실측 132px).
   글자를 줄이지 않는다 — 사장님이 고르신 말이다.
   대신 자리가 모자라면 두 단추가 **알아서 위아래로** 선다.
   min-width 를 글자 길이(9.5em)로 주면 media query 없이 폭에 따라 저절로 갈린다. */
.sheet .sfoot-two{display:flex;gap:var(--s2);flex-wrap:wrap}
.sheet .sfoot-two .btn{flex:1 1 9.5em;min-width:9.5em}

.sgroup{margin-top:var(--s4)}
.sgroup > h3{font-size:var(--t-sm);color:var(--c-text-sub);font-weight:700;
  margin:0 0 var(--s2)}

/* 고르는 칸 */
.opt{display:grid;grid-template-columns:auto 1fr auto;gap:2px var(--s3);
  width:100%;text-align:left;align-items:center;
  padding:var(--s3) var(--s4);margin-bottom:var(--s2);
  min-height:var(--tap);
  border:2px solid var(--c-border);border-radius:var(--r-lg);
  background:var(--c-surface);color:var(--c-text);font:inherit;cursor:pointer;
  transition:border-color var(--m-base) var(--m-ease),
             background var(--m-base) var(--m-ease)}
.opt .oname{font-weight:700}
.opt .odesc{grid-column:2;font-size:var(--t-cap);color:var(--c-text-sub)}
/* 🔴🔴 2026-09-01 — 창 머리의 **지금 고른 장당 값**. 감사 실측으로 잡은 것:
   부제는 `.sub`(--c-text-sub · 대비 12.5:1)를 물려받는데, **고르개 칸의 값은
   --c-text(대비 18.51:1)** 이라 「지금 내가 고른 값」이 「그 칸을 고르면 되는 값」보다
   **옅게** 보였다. 중요도가 거꾸로 선다.
   🔴 굵기로는 못 가른다 — 같은 줄의 판정글(`.fitv`)도 이미 700 이라,
      부제 폭의 **66%가 굵은 글**이었다. 굵게가 많으면 굵게는 강조가 아니다.
      그래서 굵기는 그대로 두고 **색만** 칸의 값과 같은 급으로 올린다.
   🔴 `.shead .sub b` 로 걸지 않는다 — 흐림·중복 경고 창들도 `.sub` 안에서 `<b>` 를 쓴다.
      그 창들 글까지 같이 진해지면 안 시킨 변화다. 이 값에만 이름을 준다. */
.shead .sub b.pricenow{color:var(--c-text)}
/* 🔴 2026-09-03 — 종이를 아직 안 고른 손님에게는 「장당 300원부터」로 적힌다.
   「부터」까지 값과 같은 무게로 서면 숫자가 확정값처럼 읽힌다. 「인화 안내」
   화면(products/print.js:39)이 이미 쓰는 꼴과 맞춘다 — 숫자는 진하게, 꼬리는 흐리게. */
.shead .sub b.pricenow small{font-size:var(--t-cap);font-weight:400;color:var(--c-text-sub)}

.opt .oright{grid-column:3;grid-row:1 / span 2;text-align:right;
  font-size:var(--t-cap);font-weight:700;white-space:nowrap}
/* 앞의 작은 그림 (크기 비율) — **액자에 든 사진** 모양.
   🔴 2026-09-15 owner 지적: 「동그라미 부분이 체크 박스 같아 액자처럼 안 보인다」.
      전에는 모래색 채움 + 1px 연한 선 + 둥근 모서리 = 빈 체크 박스와 똑같았다.
      액자로 읽히게 하는 것은 **세 겹 구조**다: 테(액자) → 흰 띠(매트) → 안쪽 사진.
      거기에 얕은 그림자를 줘서 종이 위에 놓인 물건처럼 보이게 한다. 모서리는 각지게(액자는 둥글지 않다).
   🔴 크기는 --mini 하나로 정한다. 비율(--w · --h)은 options.js 미니네모() 가 넣는다.
      사진창(.photo-size-grid)은 36px, 359px 이하 폰은 30px — 아래 그 자리 규칙에서 --mini 만 바꾼다.
   🔴 안쪽 사진은 실제 사진이 아니라 **누구나 사진으로 읽는 그림**(하늘·언덕·해)이다.
      실제 사진을 넣으면 가로 사진이 세로 칸에 잘려 「내 사진이 잘리나」로 읽힌다 — 이 그림의 일은 비율뿐이다. */
.opt .omini{grid-column:1;grid-row:1 / span 2;
  display:grid;place-items:center;width:44px;height:44px}
/* 🔴 테는 **흰색**이다 (owner 선택 2026-09-15: 처음 잉크색으로 드렸더니 「화이트로 변환해볼래?」).
      흰 테는 흰 카드 위에서 사라진다 — 그래서 바깥에 1px 연한 윤곽선(box-shadow 첫 값)과
      얕은 그림자를 같이 준다. 테와 매트가 다 희므로 둘은 한 덩어리의 흰 띠로 읽히고,
      그 안의 사진이 액자에 든 것처럼 보인다 (mixtiles 흰 액자와 같은 인상). */
.opt .omini i{--mini:32px;display:block;box-sizing:border-box;
  width:calc(var(--mini) * var(--w,1));height:calc(var(--mini) * var(--h,1));
  border:2px solid #FFFFFF;padding:2px;background:#FFFFFF;border-radius:1px;
  box-shadow:0 0 0 1px rgba(var(--brand-ink-rgb),.22),0 1px 3px rgba(var(--brand-ink-rgb),.28)}
.opt .omini i::after{content:"";display:block;width:100%;height:100%;
  background:radial-gradient(circle at 68% 30%,#FFE39A 0 15%,transparent 16%),
             linear-gradient(180deg,#BFD8EE 0 52%,#9CBF94 52% 74%,#D9C6A0 74%)}
.opt:hover{border-color:var(--c-text-sub)}
/* 🔴 품절 칸 — 2026-09-10 감사로 잡은 것.
   `options.js` 의 `색칸()` 이 품절 액자에 `disabled` + 「품절」 글자를 붙이는데,
   `.opt[disabled]` 규칙이 **한 줄도 없었다.** `.opt` 가 색·바탕·cursor 를 직접
   지정해서 브라우저 기본 흐림을 덮어 버린다 — 즉 **못 누르는 칸이 누를 수 있는
   칸과 똑같이 보였다.** 손님은 눌러 보고 아무 일도 안 일어나는 이유를 모른다.
   형제인 테두리 색 칩은 `.msw[disabled]`(243줄)로 이미 흐리게 하고 있었다.
   액자 칩만 빠져 있었다. **같은 값**을 쓴다 — 두 곳이 달라 보이면 그것도 사고다. */
.opt[disabled]{opacity:.35;cursor:not-allowed}
.opt[disabled]:hover{border-color:var(--c-border)}
/* 🔴 고른 것을 색만으로 안 알린다 — 테두리·바탕·✓ 가 함께 바뀐다 (WCAG 1.4.1) */
.opt[aria-pressed="true"]{border-color:var(--c-btn-point-bg);
  background:var(--c-surface-point)}
/* 🔴 핑크 글자(--c-text-brand)는 18.66px 이상에서만 쓴다 — 작은 글씨에서는 5.53:1 로
   가게 기준(본문 7:1)에 못 미친다. ✓ 는 글자가 아니라 **기호**라 키워도 어색하지 않다.
   사장님 선택(2026-08-03): 「글자는 먹색 · ✓ 만 핑크」 */
/* 🔴 owner 지시(2026-09-19)로 크기 칸의 이름 아래에 **액자 한 줄**이 붙었다.
   그 줄이 블록이라, 이름칸 끝에 붙던 ✓ 가 **액자 줄 아래로 밀려 제 줄을 차지했다**(실측).
   그래서 크기 칸만 이름을 `.oname-t` 로 한 번 더 감싸고 ✓ 를 거기에 건다 —
   ✓ 는 다시 크기 이름 바로 옆에 선다.
   🔴 `:has()` 는 쓰지 않는다(집안 규칙 · 바닥선 사파리 15.4). 대신 그 칸에만
      `.oname--split` 표를 달아 바깥 ✓ 를 끈다. */
/* 🔴 세기를 원래 규칙(0,3,0)보다 **높인다** — `.oname.oname--split` 로 클래스를 하나 더 쓴다.
   같은 세기로 두었더니 뒤에 오는 원래 규칙이 이겨 **✓ 가 두 번 찍혔다**(갈무리로 잡음). */
.opt[aria-pressed="true"] .oname.oname--split::after{content:none}
.opt[aria-pressed="true"] .oname-t::after{content:" ✓";color:var(--c-text-brand);
  font-size:var(--t-btn);line-height:1;vertical-align:-.06em}
.opt[aria-pressed="true"] .oname::after{content:" ✓";color:var(--c-text-brand);
  font-size:var(--t-btn);line-height:1;vertical-align:-.06em}

/* 사진 화소로 판단한 결과 — 색 + 기호 + 글자 셋 다
   🔴 owner 지시(2026-09-19): 「흐린 것들만 표시해줘야 될 것 같은데?」
      → `.fitv--good`(「✓ 선명해요」·「✓ 전부 선명」) 규칙을 지웠다. 만드는 곳이
      없어졌으니 두면 죽은 코드다. 되살릴 일이 생기면 이 커밋 앞 판에 그대로 있다. */
.fitv{font-weight:700}
.fitv--warn{color:var(--c-text-warning)}
.fitv--bad{color:var(--c-text-error)}

/* 🔴 아래 고정 바가 마지막 줄 사진을 가리지 않게 아래를 비워 둔다.
   🔴 옛 규칙은 `body:has(.tools:not([hidden]))` 였다. 두 가지가 틀렸다 —
      ① 떠 있는 도구 막대는 없앴다(2026-08-10). ② `:has()` 는 이 집 바닥선(사파리 15.4)
         밖이라 옛 아이폰에서는 이 여백이 **아예 안 걸렸다** — 그 화면에서는 마지막 사진이
         고정 바에 가려져 있었다. 조건을 떼고 그냥 건다. 이 파일은 /options/ 만 읽는다. */
/* 🔴 2026-09-17 — 바가 **떠 있는 둥근 카드**가 되면서 바닥에서 10px(PC 20px) 떠올랐다.
   그만큼 본문을 더 밀지 않으면 마지막 줄 사진이 그 10px 만큼 더 가려진다.
   🔴 안전영역도 여기서 더한다 — 전에는 바 **안쪽 여백**이 먹고 있었는데
      이제 바 **바깥 띄움**으로 옮겼기 때문이다(shop.css 참고). */
body{padding-bottom:max(144px,calc(var(--options-bar-height,0px) + 34px + env(safe-area-inset-bottom,0px)))}
@media (min-width:768px){
  body{padding-bottom:max(154px,calc(var(--options-bar-height,0px) + 44px + env(safe-area-inset-bottom,0px)))}
}

/* ── 무료배송 진행 막대 (owner 그림 · mixtiles) ─────────────
   🔴 「얼마 더 담으면 무료인지」를 숫자와 막대로 함께 보여준다.
     숫자만 있으면 감이 안 오고, 막대만 있으면 얼마인지 모른다.
   🔴 색만으로 안 알린다 — 다 채우면 글자도 「배송비 무료예요」로 바뀐다. */
.ship{background:var(--c-surface-point);border-radius:var(--r-xl);
  padding:var(--s4) var(--s4) var(--s4);margin:var(--s4) 0}
.ship-t{margin:0 0 var(--s3);font-weight:700;font-size:var(--t-sm)}
.ship-row{display:flex;align-items:center;gap:var(--s3)}
.ship-bar{flex:1;height:6px;border-radius:999px;background:var(--c-border-strong);
  overflow:hidden}
.ship-bar i{display:block;height:100%;width:0;border-radius:999px;
  background:var(--c-btn-point-bg);
  transition:width var(--m-slow, .5s) var(--m-ease)}
.ship-pill{flex:0 0 auto;background:var(--c-surface);border-radius:999px;
  padding:5px var(--s3);font-size:var(--t-cap);font-weight:700;white-space:nowrap}

/* ── 테두리 고르기 (021 · owner 그림 mixtiles «Select Border») ──
   🔴 폭은 **그림으로** 보여준다. 「좁게/중간/넓게」라는 말만으로는
     사진이 얼마나 작아지는지 아무도 모른다.
   🔴 미리보기는 서버 합성(render.py)과 **같은 비율**로 그린다.
     보이는 것과 배송되는 것이 달라지면 그게 제일 나쁜 사고다. */
.mrow{display:flex;flex-wrap:wrap;gap:var(--s3);margin-top:var(--s2)}

.mopt{display:grid;justify-items:center;gap:var(--s2);
  padding:var(--s2);border:2px solid var(--c-border);border-radius:var(--r-lg);
  background:var(--c-surface);color:var(--c-text);font:inherit;cursor:pointer;
  min-height:var(--tap);
  transition:border-color var(--m-base) var(--m-ease)}
.mopt .mname{font-size:var(--t-cap);font-weight:700}
.mopt:hover{border-color:var(--c-text-sub)}
/* 🔴 색만으로 안 알린다 — 테두리와 글자 색이 함께 바뀌고 ✓ 가 붙는다 */
.mopt[aria-pressed="true"]{border-color:var(--c-btn-point-bg)}
/* 🔴 여기는 --t-cap(작은 글씨)이다. 핑크로 두면 기준 미달이라 먹색으로 둔다.
   고른 것은 테두리·바탕·✓ 셋이 이미 알려 준다 — 색 하나가 빠져도 안 헷갈린다. */
.mopt[aria-pressed="true"] .mname{color:var(--c-text)}
.mopt[aria-pressed="true"] .mname::after{color:var(--c-text-brand);
  font-size:var(--t-btn);line-height:1;vertical-align:-.06em}
.mopt[aria-pressed="true"] .mname::after{content:" ✓"}

/* 미리보기 — 바깥이 매트 색, 안쪽이 사진 */
.mpv{position:relative;display:block;border-radius:2px;overflow:hidden;
  box-shadow:0 0 0 1px rgba(var(--brand-ink-rgb),.10) inset}
.mpv i{position:absolute;display:block;border-radius:1px}

/* 색 고르기 */
.mrow--sw{gap:var(--s2)}
.msw{position:relative;width:var(--tap);height:var(--tap);border-radius:999px;
  border:2px solid var(--c-border);cursor:pointer;padding:0;
  transition:border-color var(--m-base) var(--m-ease),transform var(--m-fast) var(--m-ease)}
.msw:hover{transform:scale(1.06)}
.msw[aria-pressed="true"]{border-color:var(--c-btn-point-bg);border-width:3px}
/* 🔴 색맹인 분에게 **동그라미 색만**으로는 아무 정보가 없다.
     고른 것에 ✓ 를 얹고, 이름은 화면낭독기가 읽도록 aria-label 로 준다. */
/* 🔴 2026-09-15 — 어두운 칩(검정·진초록…) 위에서는 흰 ✓ 가 나오게, 밝기에 따라 options.js 가
     칩마다 --sw-ink / --sw-halo 를 준다. 안 주면(밝은 칩) 지금까지의 잉크색 ✓ + 흰 번짐 그대로다. */
.msw[aria-pressed="true"]::after{content:"✓";position:absolute;inset:0;
  display:grid;place-items:center;font-weight:800;font-size:18px;
  color:var(--sw-ink,var(--c-text));text-shadow:0 0 3px var(--sw-halo,#fff),0 0 3px var(--sw-halo,#fff)}
.msw[disabled]{opacity:.35;cursor:not-allowed}
.msw[disabled]:hover{transform:none}
/* 이름은 화면에 안 띄우고 읽어주기에만 남긴다 (동그라미가 44px 라 글자가 안 들어간다) */
.msw-n{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)}

/* ── 큰 미리보기 · 뒤로가기 (owner 지적 2026-08-02) ─────────
   「선택하고 하면 실제로 반영돼서 보여야 되는 거 아니야」
   「팝업창에 뒤로가기 버튼도 없고 불편하게」

   🔴 작은 칸 네 개만으로는 고른 것이 어떻게 되는지 안 보였다.
     위에 큰 것을 두고, 고르는 즉시 여기가 바뀐다. */
.bigpv{display:flex;justify-content:center;
  padding:var(--s4) 0 var(--s5);margin-bottom:var(--s2);
  border-bottom:1px solid var(--c-border)}
/* 🔴 폰에서 300px 고정이면 좁은 화면에서 넘친다. 창 너비에 맞춰 줄인다. */
.bigpv .mpv{max-width:100%;height:auto;aspect-ratio:auto}
@media (max-width:400px){ .bigpv .mpv{width:min(300px, calc(100vw - 96px)) !important} }
/* 큰 미리보기는 실물처럼 살짝 떠 보이게 */
.bigpv .mpv{box-shadow:0 2px 6px rgba(var(--brand-ink-rgb),.10), 0 12px 28px rgba(var(--brand-ink-rgb),.10)}

/* 🔴 ← 는 ✕ 와 **같은 크기·같은 자리 규칙**을 쓴다. 창마다 다르면 손이 헤맨다. */
.sheet .sback{flex:0 0 auto;min-width:var(--tap);min-height:var(--tap);
  border:0;background:none;color:var(--c-text);font-size:20px;cursor:pointer;
  border-radius:var(--r-pill);margin-left:calc(var(--s3) * -1)}
.sheet .sback:hover{background:var(--c-surface-alt)}

/* 관리자가 끈 만들기 단추는 공통 .btn의 display보다 우선해서 숨긴다. */
[data-pick][hidden]{display:none !important}
.collage-purpose-starts{margin:8px 0 12px}
.collage-purpose-starts[hidden],.collage-pick-support[hidden],[data-collage-free][hidden]{display:none!important}
.collage-purpose-details>summary{display:flex;align-items:center;gap:8px;min-height:44px;cursor:pointer;list-style:none;font-size:14px;touch-action:manipulation}
.collage-purpose-details>summary::-webkit-details-marker{display:none}
.collage-purpose-details>summary::before{content:'▸';font-size:16px}
.collage-purpose-details[open]>summary::before{content:'▾'}
.collage-purpose-details>summary small{font-size:12px;font-weight:400;color:var(--c-text-sub)}
.collage-purpose-content{padding:4px 0 12px}
.collage-purpose-cards{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px}
.collage-purpose-cards>button{display:flex;align-items:center;gap:12px;min-width:0;min-height:44px;border:1px solid var(--c-line,#ddd);border-radius:12px;padding:14px;background:var(--c-surface,#fff);color:inherit;text-align:left;font:inherit;touch-action:manipulation}
.collage-purpose-cards>button[aria-pressed=true]{border-color:var(--c-btn-point-bg);box-shadow:0 0 0 1px var(--c-btn-point-bg)}
.collage-purpose-cards>button>span:last-child{display:grid;gap:5px;min-width:0;overflow-wrap:anywhere}
.collage-purpose-cards b{font-size:14px}.collage-purpose-cards small{font-size:12px;line-height:1.5;color:var(--c-text-sub)}
.collage-purpose-cards .cs-purpose-example{width:52px}
/* Keep selection and checkout aligned, with room between the two actions. */
#bottom{padding-top:16px;padding-bottom:max(16px,env(safe-area-inset-bottom))}
#bottom>.in{max-width:760px;gap:16px}
#bottom>.in .btn{min-height:48px;border-radius:var(--r-md,12px)}
.collage-pick-support{max-width:760px;margin:0 auto 16px;padding:0 0 16px;border-bottom:1px solid var(--c-line,#ddd);display:flex;align-items:center;gap:16px;font-size:13px}
.collage-pick-support>div:first-child{flex:1;min-width:0}
.collage-pick-support p{font-size:12px;line-height:1.5;margin:4px 0 0;overflow-wrap:anywhere}
.collage-pick-actions{display:flex;gap:12px;flex-wrap:wrap;justify-content:flex-end;max-width:100%}
.collage-pick-actions .btn{min-height:48px;border-radius:var(--r-md,12px);font-size:13px;padding:10px 16px;white-space:normal;line-height:1.5}
@media(max-width:680px){.collage-purpose-cards{grid-template-columns:1fr}.collage-purpose-cards>button{padding:12px}.collage-purpose-cards .cs-purpose-example{width:42px}.collage-pick-support{align-items:stretch;flex-direction:column;gap:12px}.collage-pick-actions{width:100%}.collage-pick-actions .btn{flex:1 1 120px}}

/* ── 023 모아 찍기 (인생네컷) ────────────────────────────────
   🔴 owner 지시: 「다양한 사진을 한 장에 담을 수 있는 기능」

   고르는 중에는 화면이 **다른 상태**임이 한눈에 보여야 한다 —
   안 그러면 사진을 눌렀는데 설정 창이 안 떠서 고장난 줄 안다. */
body.picking .grid--set .ph{cursor:pointer}
body.picking .ph .pface{outline:2px dashed var(--c-border-strong);outline-offset:-2px}
.ph--picked .pface{outline:3px solid var(--c-btn-point-bg) !important;outline-offset:-3px}
/* 🔴 색만으로 안 알린다 — 고른 것에 ✓ 가 얹힌다 (WCAG 1.4.1) */
.pickmark{position:absolute;top:var(--s2);left:var(--s2);
  width:26px;height:26px;border-radius:999px;display:grid;place-items:center;
  background:rgba(var(--brand-ink-rgb),.55);color:#fff;font-weight:800;font-size:15px;
  border:2px solid #fff}
.ph--picked .pickmark{background:var(--c-btn-point-bg)}

/* 이미 묶인 사진 — 흐리게 두고 손대지 못하게 */
.ph--in{opacity:.55}
.tag--in{background:rgba(var(--brand-ink-rgb),.62)}

/* 틀 미리보기 — 서버가 준 칸 좌표 그대로 */
.clpv{position:relative;display:block;border-radius:3px;overflow:hidden;
  box-shadow:0 0 0 1px rgba(var(--brand-ink-rgb),.10) inset;flex:0 0 auto}
.clpv i{position:absolute;display:block;border-radius:1px;background:var(--c-surface-alt)}
.clopt{min-width:112px}
.clopt .csub{font-size:var(--t-cap);color:var(--c-text-sub)}

/* 완성한 분할사진 — 사이트 공통 버튼과 간격을 사용한다.
   작은 화면에서는 사진 아래에 작업 영역을 두어 이름과 버튼이 눌리지 않게 한다. */
.sets-heading{display:flex;align-items:center;justify-content:space-between;
  flex-wrap:wrap;gap:var(--s3);margin:var(--s5) 0 var(--s3)}
.seth{font-size:var(--t-lg);margin:0}
.photo-section-count{font-size:var(--t-body);font-weight:500;color:var(--c-text-sub);white-space:nowrap;margin-left:var(--s2)}
.photo-section-note{margin:var(--s1) 0 0;word-break:keep-all;overflow-wrap:anywhere}
#single-photos[hidden],#collage-sources[hidden],#photo-batch-share[hidden]{display:none!important}
#single-photos>.grid{margin-top:var(--s3)}
.collage-sources{margin:var(--s5) 0}
.collage-sources>summary{gap:var(--s2);padding-top:var(--s3);padding-bottom:var(--s3);word-break:keep-all}
.collage-sources .foldval{flex-shrink:0}
#collage-source-grid{--base:100px;margin:var(--s3) 0 0}
#collage-source-grid .ph,#collage-source-grid .pface{cursor:default}
body.picking #collage-source-grid .pface{outline:none}
@media(max-width:359px){#collage-source-grid{--base:80px}}

#collage-share-manage[hidden]{display:none!important}
.setlist{list-style:none;display:grid;gap:var(--s4);margin:0 0 var(--s5)}
.setitem{display:grid;grid-template-columns:88px minmax(0,1fr);align-items:center;
  gap:var(--s4);min-width:0;padding:var(--s4);border:1px solid var(--c-border);
  border-radius:var(--r-lg);background:var(--c-surface)}
.setinfo{min-width:0;display:grid;gap:var(--s1);grid-template-columns:minmax(0,1fr);
  word-break:keep-all;overflow-wrap:anywhere}
.setinfo>b{font-size:var(--t-lg)}
.setitem .setactions{grid-column:1/-1;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  align-items:stretch;gap:var(--tap-gap);min-width:0;width:auto}
.setitem .setactions .btn{min-width:0;min-height:var(--tap);padding:var(--s2) var(--s3);
  line-height:1.5;white-space:normal;word-break:keep-all;overflow-wrap:anywhere}
/* DB의 긴 종이 이름도 버튼 안에서 읽을 수 있도록 줄을 바꾼다. */
.setitem .setpaper .t{min-width:0;overflow-wrap:anywhere}
.setitem .set-unset{border-color:var(--c-border);color:var(--c-text-sub)}
.setitem .setactions .btn--sec:hover:not([disabled]),
.sets-heading .btn--sec:hover,.shared-maker-guide .btn--sec:hover,
.photo-share:hover:not([disabled]){border-color:var(--c-btn-point-bg);background:var(--c-surface-point);filter:none}
@media(min-width:800px){
  .setitem{grid-template-columns:88px minmax(0,1fr) minmax(300px,360px);gap:var(--s5)}
  .setitem .setactions{grid-column:auto}
}
.btn--soft2{background:var(--c-surface-alt);color:var(--c-text);
  border:0;border-radius:var(--r-pill);font-weight:700}

/* 모아 찍기 도구 칸 — 고르는 중이면 켜진 표시 */
body.picking .tool--pick{background:var(--c-surface-point)}
/* 🔴 .tv 는 --t-sm(작은 글씨)이다. 켜진 표시는 바탕색이 이미 하고 있다. */
body.picking .tool--pick .tv{color:var(--c-text)}

/* ── 25단계 — 최대 사이즈 추천 ──────────────────────────────
   🔴 owner 지시(2026-08-05): 「사진 데이터 분석 후 최대 사이즈 추천」
     화소로 「어디까지 선명한지」를 서버가 판정해 준다(fit). 그 최댓값을 먼저 말한다 —
     칸을 하나씩 눌러 보며 알아내게 하지 않는다. */
.reco{margin:0 0 var(--s2);padding:var(--s2) var(--s4);
  background:var(--c-surface-point);border-radius:var(--r-lg);
  font-size:var(--t-sm);line-height:1.5}
/* 🔴 추천이 없을 때(모든 크기에서 흐릴 때)는 **색을 바꾼다.**
   같은 모양으로 두면 「좋은 소식」처럼 읽힌다. 색만으로 알리지 않으므로 글자도 다르다. */
.reco--none{background:var(--c-surface-alt);color:var(--c-text-sub)}
.reco--none b{color:var(--c-text)}

/* 추천 칸 표시 — 🔴 별표만 두지 않는다. 「추천」 글자를 함께 적어야
   색·기호를 못 읽는 분에게도 전해진다 (WCAG 1.4.1).
   🔴 owner 지시(2026-08-05): 「추천 별은 핑크색으로 반짝반짝」
     글자는 먹색 그대로 두고 **별만** 핑크로 반짝인다.
     왜 글자까지 핑크로 안 하나: 작은 글씨의 핑크는 가게 기준(본문 7:1)에 못 미친다
     (tokens.css — 핑크 글자는 18px 굵게 이상에만). 별은 글자가 아니라 **기호**라 괜찮다.
     이 화면의 「✓」도 같은 이유로 핑크다. */
.opt .best{margin-left:var(--s2);font-size:var(--t-cap);font-weight:700;
  color:var(--c-text);white-space:nowrap}
.opt .best .st{color:var(--brand-pink);display:inline-block;
  animation:반짝 1.6s var(--m-ease) infinite}
/* 🔴 owner 지시(2026-09-19): 액자 이름을 크기 칸에 적는다.
   추천(★)이 아닌 것은 **회색 보통 글씨** — 별과 핑크는 추천 표시로 남겨 둔다. */
.opt .best--plain{font-weight:600;color:var(--c-text-sub)}
/* 🔴 owner 지시(2026-09-19): 「금액은 빼 줘」 — 값은 안 적는다(폰·PC 같음).
   `.best-won` 규칙도 같이 지웠다. 되살릴 일이 생기면 커밋 6f9b78d 에 그대로 있다. */

/* 🔴 반짝임은 **밝기와 크기만** 건드린다. 자리를 옮기지 않는다 —
   글줄 안에서 움직이면 옆 글자가 따라 흔들려 읽기 힘들다. */
@keyframes 반짝{
  0%,100%{opacity:1;   transform:scale(1)}
  45%    {opacity:.45; transform:scale(.86)}
}

/* 사진 칸 배지 — 「더 크게 가도 선명해요」.
   🔴 흐림 알림(--warn/--bad)보다 조용해야 한다. 흐림은 손해를 막는 말이고
      이것은 권하는 말이라, 둘이 같은 세기면 정작 급한 쪽이 안 읽힌다. */
.tag--reco{background:rgba(var(--brand-ink-rgb),.48);font-weight:600}
/* 🔴 owner 지시(2026-08-05): 「추천 별은 핑크색으로 반짝반짝」
   🔴 여기는 **어두운 반투명 바탕 위**다. --brand-pink(#E51566)는 그 위에서 어둡다.
      흐림 딱지가 어두운 바탕용으로 밝은 주황(#FFC98A)을 쓰는 것과 같은 이유로,
      밝은 쪽 핑크를 쓴다. 흰 글자(#FFF) 옆에서도 핑크로 읽힌다. */
.tag--reco .dot{color:#FF8FC0;display:inline-block;
  animation:반짝 1.6s var(--m-ease) infinite}


/* 🔴 「동작 줄이기」를 켜신 분에게는 반짝임을 끈다.
   어지럼증·편두통이 있는 분에게 깜빡이는 것은 아픔이다 (WCAG 2.3.3).
   색은 그대로 남으므로 「추천」이라는 뜻은 안 사라진다. */
@media (prefers-reduced-motion:reduce){
  .opt .best .st, .tag--reco .dot{animation:none}
}


/* ── 한 창에 다 펼친 사진 설정 (owner 지시 2026-08-10) ────────────
   「사진 한번 클릭해서 쉽게 할수있게 편하게 옵션이랑 할수있게하면좋잖아」

   크기·종이·테두리가 한 창에 세로로 이어진다. 그래서 **어디서 어디까지가 한 묶음인지**
   가 안 보이면 긴 목록 하나로 읽힌다. 머리글로 끊어 준다.
   🔴 창 안에서 굴러가므로 머리글을 위에 붙여 둔다 — 아래쪽 종이 칸을 보는 중에도
      지금 무엇을 고르는 중인지 늘 보인다. */
.ogrp{position:sticky;top:0;z-index:1;margin:var(--s2) 0 var(--s1);
  padding:var(--s1) 0;background:var(--c-surface);
  font-size:var(--t-sm);font-weight:800;letter-spacing:.02em;color:var(--c-text)}
/* 🔴 첫 머리글은 위 여백을 뗀다 — 창 부제와 붙어 보이면 두 줄이 한 덩어리로 읽힌다 */
.sbody > .ogrp:first-child{margin-top:0}


/* ── 나올 모습 · 살릴 자리 끌기 (owner 지적 2026-08-10) ─────────
   「사진 사이즈별로 잘리는지, 이 사이즈를 선택했을 때 안 잘리는지 확인이 되어야」 */
.cropbox{display:flex;flex-direction:column;align-items:center;gap:var(--s1);
  margin-bottom:var(--s2)}
/* 🔴 그림 자체가 조작 대상이다. 손가락으로 끌 때 브라우저가 화면을 굴리면 안 되므로
   touch-action 으로 그 몸짓을 우리 것으로 가져온다. 이게 없으면 폰에서 사진 대신
   화면이 굴러간다 — 끌기가 아예 안 되는 것처럼 느껴진다. */
/* 🔴🔴 크기는 **여기서 정한다.** 화면(JS)은 비율만 알려 준다(`--ar` = 가로/세로).
   너비를 셋 중 가장 작은 값으로 잡고, 높이는 aspect-ratio 가 따라온다:
   · `--pv-w`                      넉넉할 때의 최대 너비
   · `100%`                        시트가 좁을 때
   · `--pv-max * --ar`             ← **높이가 --pv-max 를 넘지 않게 하는 너비**
   세 번째가 이번 고침의 핵심이다. 세로 사진일수록 --ar 이 작아 너비가 더 줄고,
   그만큼 높이가 눌려 **아래 목록 자리가 남는다.**
   🔴 여기에 px 높이를 다시 박으면 2026-08-27 사고가 그대로 돌아온다. */
/* 🔴🔴 **크기는 이 상자가 정한다.** 안쪽(.cropv·.fmpv)은 전부 100% 다.
   그래야 ① 액자 테를 백분율로 줄 수 있고(백분율 여백은 담는 상자 폭 기준),
   ② 액자를 두를 때 「자식이 부모를, 부모가 자식을」 보는 순환이 안 생긴다.
   순환이 생기면 폭이 **0 으로 무너져 사진이 통째로 사라진다** (2026-08-28 실측). */
.pvbox{display:block;width:min(var(--pv-w), 100%);margin-inline:auto}
.pvbox > *{width:100%}

.cropv{position:relative;overflow:hidden;border-radius:var(--r-md);
  width:100%;height:auto;
  touch-action:none;cursor:grab;user-select:none;-webkit-user-select:none;
  box-shadow:0 2px 8px rgba(var(--brand-ink-rgb),.10)}
/* 🔴🔴 **`@supports` 로 감싼다** (2026-08-28 감사에서 잡힘).
   `--pv-max` 안에 `dvh` 가 들어 있는데 그걸 모르는 브라우저(삼성인터넷 20 = 크로미움 106
   등, 국내에 아직 많다)에서는 `calc()` 가 무효가 된다. 그러면 var() 치환 실패라
   **`width` 속성이 통째로 `unset`** 되고, `.cropv` 는 자식이 `position:absolute` 하나뿐이라
   내용 폭이 0 → **사진이 통째로 사라진다.** (개발 중에 실제로 그 상태를 만들었다)
   🔴 앞줄에 폴백을 미리 써 두는 방식은 **안 통한다** — var() 무효는 캐스케이드를 타지 않고
      곧바로 unset 이 된다. 반드시 @supports 로 갈라야 한다.
      집안 관례와 같은 꼴이다 (home.css 의 `@supports (height:100dvh)`). */
@supports (height:1dvh){
  .pvbox{width:min(var(--pv-w), 100%, calc(var(--pv-max) * var(--ar, 1)))}
}
.cropv--drag{cursor:grabbing}
.cropv i{position:absolute;display:block;background-repeat:no-repeat}
/* 🔴 끄는 중에는 그림에 자국을 남기지 않는다 — 미리보기는 **나올 모습 그대로**여야 한다.
   테두리·격자를 얹으면 손님이 그것도 인쇄되는 줄 안다. 커서 모양으로만 알린다. */
.cropmsg{text-align:center}
.cropok{color:var(--c-text-success)}
.cropcut{color:var(--c-text-warning)}
/* 🔴 채우는 방식 고르개. 미리보기 바로 아래 — 누르면 위 그림이 그대로 바뀐다. */
.fitrow{display:flex;gap:var(--s2);justify-content:center;margin-top:var(--s1)}
/* 🔴 전체 넣기일 때는 끌 것이 없다. 손 모양을 바꿔 「여기선 못 끈다」를 알린다 —
   끌리는 줄 알고 잡아당기다 안 되면 고장으로 읽힌다. */
/* 🔴🔴 「전체 넣기」는 **끌 것이 없다.** 그런데도 touch-action:none 이 남아 있어,
   사진 위에 손가락을 대면 목록이 굴러가지 않았다 — 시트에서 사진이 가장 넓은 자리라
   손님 대부분이 거기를 짚는다. 끌 게 없을 때는 굴리기에 양보한다 (2026-08-27). */
.cropv--fit{cursor:default;touch-action:auto}

/* 🔴 이미 담긴 사진 알림 (owner 지적 2026-08-14: 「팝업으로 알려주고 **중복된 사진이 뭔지도**
   알려줘야 되는 거 아니야?」). 숫자만 「5장」이라고 하면 어느 것인지 알 수가 없다. */
/* 🔴 스크롤은 `.sbody` 하나만 갖는다. 여기서도 max-height 를 주면 **창 안에 스크롤이 두 겹**이 되어
   손가락이 어느 쪽을 미는지 알 수 없게 된다 (2026-08-14 뼈대 고칠 때 같이 잡음). */
.dup-list{list-style:none;margin:0;padding:0}
.dup-row{display:flex;align-items:center;gap:var(--s3);padding:var(--s2) 0;
  border-bottom:1px solid var(--c-border)}
.dup-row:last-child{border-bottom:0}
.dup-thumb{width:56px;height:56px;flex:none;object-fit:cover;border-radius:var(--r-md);
  background:var(--c-surface-alt)}
.dup-info{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1 1 auto}
/* 🔴 흐린 사진 줄은 **누를 수 있다** (owner 지시 2026-08-24) — 누르면 그 사진의 크기 고르개가 열린다.
   🔴 `.dup-row` 의 모양(테·여백)은 그대로 두고, 그 안에서 단추만 줄 전체를 차지하게 한다.
      안맞음창의 안 눌리는 줄과 **같은 모양**으로 보여야 한다 — 다른 것은 손가락이 닿는지뿐이다.
   🔴 누르는 자리는 56px(썸네일 높이)이라 최소 터치 크기(48px)를 넉넉히 넘는다. */
.dup-tap{display:flex;align-items:center;gap:var(--s3);width:100%;
  padding:0;border:0;background:none;font:inherit;color:inherit;text-align:left;cursor:pointer}
.dup-tap:focus-visible{outline:3px solid var(--c-focus);outline-offset:-3px}
.dup-go{flex:0 0 auto;font-size:20px;line-height:1;color:var(--c-text-sub)}
/* 🔴 owner 지시 2026-08-14 — 사진마다 「그냥 두기」. **목록에서만** 뺀다 (장바구니는 안 건드린다).
   손가락 규칙(44px)을 지키되, 글이 있는 칸을 밀어내지 않게 flex:none 으로 고정한다. */
.dup-x{flex:0 0 auto;min-width:var(--tap);min-height:var(--tap);
  display:flex;align-items:center;justify-content:center;
  border:1px solid var(--c-border);border-radius:var(--r-md);
  background:transparent;color:var(--c-text-sub);font-size:var(--t-sm);cursor:pointer}
.dup-x:hover{background:var(--c-surface-alt);color:var(--c-text)}

/* 🔴🔴 2026-08-14 owner 지시 — 「액자 이미지 넣는 부분도 있어야 소비자에게
   **이 액자다**라는 게 보여서 선택할 수 있게」. 색 이름만으로는 알 수가 없다.
   사진이 있으면 사진을, 없으면 색 동그라미를 왼쪽에 둔다. */
.opt--frame{align-items:center}
.opt--frame .fswatch{flex:0 0 auto;width:44px;height:44px;border-radius:var(--r-md);
  overflow:hidden;background:var(--c-surface-alt);
  display:flex;align-items:center;justify-content:center;
  /* 🔴 흰 액자가 흰 바탕에 묻힌다 — 아주 옅은 테두리로 경계를 만든다 */
  box-shadow:inset 0 0 0 1px rgba(var(--brand-ink-rgb),.12)}
.opt--frame .fswatch img{width:100%;height:100%;object-fit:cover;display:block}
.opt--frame .fswatch i{width:100%;height:100%;display:block}

/* ── 고르는 차례 (owner 지시 2026-08-14: 「순서대로 소비자가 할 수 있도록」) ──────
   🔴 그전에는 크기·종이·테두리·액자를 한 창에 다 펼쳤다. 실측 스크롤 3,042px —
     폰 한 화면(625px)으로 다섯 화면이었다. 무엇부터 해야 하는지 알 수 없었다.
   🔴 지금 어디인지 · 몇 개 남았는지 · 되돌아갈 수 있는지를 이 막대 하나가 다 말한다. */
.steps{display:flex;list-style:none;margin:0;padding:0 var(--s5) var(--s1);gap:var(--s2)}
.steps > li{flex:1 1 0;min-width:0}
.stepdot{display:flex;flex-direction:column;align-items:center;gap:0;
  width:100%;min-height:var(--tap);padding:0 2px;
  border:0;background:none;font:inherit;color:var(--c-text-sub);cursor:pointer;
  border-top:3px solid var(--c-border);border-radius:0}
.stepdot b{display:flex;align-items:center;justify-content:center;
  width:22px;height:22px;border-radius:999px;
  background:var(--c-surface-alt);color:var(--c-text-sub);font-size:var(--t-cap)}
.stepdot span{font-size:var(--t-cap);white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis;max-width:100%}
/* 🔴 지금 단계는 **색·굵기·선 셋 다**로 알린다 (색만으로 안 알린다 — WCAG 1.4.1) */
.stepdot.on{color:var(--c-text);font-weight:700;border-top-color:var(--c-btn-point-bg)}
.stepdot.on b{background:var(--c-btn-point-bg);color:var(--brand-white)}
.stepdot.done{color:var(--c-text)}
.stepdot.done b{background:var(--c-surface-point);color:var(--c-text-brand)}
.stepdot:hover{color:var(--c-text)}

/* 🔴 미리보기는 **붙여 둔다.** 아래에서 무엇을 골라도 바뀌는 것이 눈에 보여야 한다.
   (owner 지시: 「그걸 실시간으로 사진으로 반영이 되도록」) */
/* 🔴🔴 **천장을 둔다** (2026-08-27). 붙박이(sticky)라 굴려도 안 사라지는데 크기까지
   화면과 무관하게 정해져 있어서, 세로 사진이면 이 덩어리가 창을 통째로 먹고
   **크기 목록이 한 줄도 안 보였다.** 이제 --pv-max 를 넘지 않고, 넘칠 만하면
   아래 `.cropv` 가 비율을 지킨 채 알아서 작아진다.
   🔴 붙박이는 그대로 둔다 — owner 지시(「고르면 사진에 바로 반영되게」)를 지킨다. */
/* 🔴🔴 **화면이 짧으면 붙박이를 포기한다** (2026-08-27).
   창의 고정 부분(머리 86 + 차례 69 + 아래단추 81 + 목록머리글 40 + 추천안내 66 ≈ 342)
   만으로도 짧은 화면에서는 자리가 거의 안 남는다. 그때는 미리보기를 아무리 줄여도
   목록 두 줄이 안 나온다 — 실측으로 확인했다.
   그런 화면에서는 굴리면 미리보기가 **위로 지나가고** 목록이 온전히 드러난다.
   손님은 위로 되굴리면 다시 볼 수 있다. 「아무것도 못 고르는 것」보다 낫다.
   🔴 기종이 아니라 **높이**로 가른다. 경계는 아래 미디어 쿼리의 30rem(480px)이다 —
      폰 가로(높이 390~430)는 걸리고 노트북(높이 640대)은 안 걸린다.
      이 값을 건드리면 ops/check-sheet-space.js 가 곧바로 알려 준다. */
.pvhold{position:sticky;top:0;z-index:2;background:var(--c-surface);
  padding-bottom:var(--s1);margin-bottom:var(--s1);
  box-shadow:0 6px 10px -8px rgba(var(--brand-ink-rgb),.25)}

/* 🔴🔴 **반드시 위 `.pvhold` 선언보다 뒤에 있어야 한다** (2026-08-28 감사에서 잡힘).
   미디어 쿼리는 우선순위를 **안 올린다.** 처음에 이 블록을 위에 뒀더니 아래 `sticky` 가
   이겨서 **한 번도 적용되지 않았다** — 죽은 규칙인 채로 검사만 초록불이었다.
   짧은 화면에서는 창의 고정 부분(머리·차례·아래단추·목록머리글)만으로 자리가 거의 없어,
   미리보기를 아무리 줄여도 고를 것이 안 보인다. 그때는 붙박이를 포기하고 굴리면
   위로 지나가게 한다. 손님은 되굴려 다시 볼 수 있다 — 「아무것도 못 고르는 것」보다 낫다.
   🔴 폰 가로 모드가 이 구간에 들어온다(높이 390~430). 노트북(높이 640대)까지 걸리지
      않도록 **폭 조건을 함께** 둔다 — 창이 가운데 뜨는 600px 이상은 자리가 넉넉하다. */
/* 🔴 조건이 **하나**다 — 아주 짧은 화면(폰 가로, 높이 390~430)만.
   처음엔 `and (max-width:599px)` 를 붙였는데 **폰 가로는 폭이 844·932 라 안 걸려서**
   정작 고쳐야 할 화면이 빠졌다. 지금은 높이 하나로만 가른다.
   노트북(높이 640대)은 안 걸린다 — 거기는 자리가 넉넉하다. */
/* 🔴 세로 폰 조건을 **뺐다** (2026-08-28). 여백을 줄이고 창을 키워 자리가 생겨서,
   세로에서는 붙박이를 되살려도 목록이 보인다 — owner 지시(「고르면 사진에 바로
   반영되게」)를 지키는 쪽이 낫다. **가로(30rem)는 반드시 남긴다** — 거기서
   붙박이를 되살리면 작은 목록을 미리보기가 통째로 덮어 더 나빠진다(실측). */
@media (max-height:30rem){
  .pvhold{position:static}
  /* 🔴 추천 안내(약 66px)도 접는다. 짧은 화면에서는 **고를 것 자체가 안 보이는** 쪽이
     훨씬 나쁘다. 추천 배지는 목록 각 줄에 그대로 남는다. */
  .sheet .reco{display:none}
}

.stepnext{display:flex;justify-content:flex-end;margin-top:var(--s4)}


/* ── 차례 막대 움직임 (owner 지시 2026-08-14) ──────────────────────────
   「위 이미지 부분에 css 모션을 넣으면 좋을 것 같은데 **지금 디자인은 교체하지 말고**」
   → 쉬고 있을 때의 모습은 **한 픽셀도 안 바꾼다.** 바뀌는 순간에만 움직인다.

   🔴 이 집 규칙을 그대로 따른다 (motion.css):
     · 움직이는 것은 **transform 과 opacity 뿐** — 폰에서 버벅이지 않게
     · 전부 `.js-motion` 아래에만 둔다 — JS 가 실패해도 화면은 멀쩡히 보인다
     · 「동작 줄이기」를 켠 분에게는 안 움직인다
   🔴 `.steps--move` 는 **차례가 바뀐 때만** 붙는다. 창은 무엇을 누르든 다시 그려지므로,
      이 표시가 없으면 색 하나 고를 때마다 위 막대가 튄다. */

/* 🔴🔴 2026-08-14 사장님 지시 — 「한 번만 딱 하고 끝나네. 차라리 핑크색 줄이
   **로딩처럼 앞으로 가는 게 반복적으로** 들어가면 어때?」
   → 지금 차례의 분홍 밑줄 위를 **밝은 띠가 계속 앞으로 흐른다.**
     한 번 하고 마는 것이 아니라 그 차례에 머무는 동안 계속 돈다 — 「여기가 지금」이 늘 보인다.
   🔴 밑줄 자체(border-top)는 그대로다. 그 위를 지나가는 띠만 더한다 — 모양은 안 바뀐다.
   🔴 `--move` 로 묶지 않는다. 그 표시는 「방금 바뀌었다」는 뜻이고, 이 흐름은 **늘** 돌아야 한다.
   🔴 transform 만 움직인다 (이 집 규칙). 띠 자체는 그림자·색이 고정이라 다시 안 그린다. */
/* 🔴🔴 실측으로 잡은 것 — 처음엔 이 띠를 **단추 자신의 ::after** 로 두고 `top:-3px` 에
   얹었다. 그런데 `overflow:hidden` 은 **테두리 밖을 잘라낸다** — 띠가 통째로 사라져
   화면에 아무것도 안 보였다 (값은 움직이는데 눈에는 없었다).
   → 띠를 **한 칸 바깥(li)** 으로 옮긴다. li 의 위끝이 곧 단추의 밑줄 자리라
     `top:0` 이 정확히 그 줄 위에 얹힌다. */
.js-motion .steps > li.now{position:relative;overflow:hidden}
.js-motion .steps > li.now::after{
  content:'';position:absolute;left:0;top:0;height:3px;width:45%;
  background:linear-gradient(90deg,
    rgba(255,255,255,0), rgba(255,255,255,.92), rgba(255,255,255,0));
  animation:stepsweep 1.5s linear infinite;pointer-events:none}
@keyframes stepsweep{from{transform:translateX(-120%)}to{transform:translateX(340%)}}

/* 지금 차례의 번호가 톡 하고 자리를 잡는다 (차례가 바뀐 그때 한 번) */
.js-motion .steps--move .stepdot.on b{
  animation:stepbadge 420ms var(--m-ease) both}
@keyframes stepbadge{
  0%{transform:scale(.55);opacity:.25}
  55%{transform:scale(1.18);opacity:1}
  78%{transform:scale(.96)}
  100%{transform:scale(1);opacity:1}}

/* 방금 끝난 차례에만 ✓ 가 뜬다 (뒤로 갈 때는 조용히) */
.js-motion .steps--move .stepdot.just b{
  animation:stepcheck 520ms var(--m-ease) both}
@keyframes stepcheck{
  0%{transform:scale(.6) rotate(-12deg);opacity:0}
  60%{transform:scale(1.12) rotate(0);opacity:1}
  100%{transform:scale(1) rotate(0);opacity:1}}

/* 지금 차례의 이름이 아주 살짝 올라온다 — 눈이 그리로 간다 */
.js-motion .steps--move .stepdot.on span{
  animation:stepname 420ms var(--m-ease) both}
@keyframes stepname{from{transform:translateY(3px);opacity:.5}to{transform:none;opacity:1}}

/* 🔴 동작 줄이기 — 마지막 방어선 (motion.css 와 같은 방침) */
@media (prefers-reduced-motion:reduce){
  .js-motion .steps > li.now::after,
  .js-motion .steps--move .stepdot.on b,
  .js-motion .steps--move .stepdot.just b,
  .js-motion .steps--move .stepdot.on span{animation:none !important}
  /* 흐르는 띠는 아예 안 보이게 — 멈춘 띠가 밑줄 위에 남아 있으면 얼룩처럼 보인다 */
  .js-motion .steps > li.now::after{display:none}
}

/* 🔴 owner 지시 2026-08-14 — 「클릭하면 다음으로 넘어갈 수 있도록 뭔가 도움을 주면
   좋을 것 같은데 편하고 심플하게」. 머리글 **한 줄 안에** 조용히 붙인다.
   줄을 더 늘리지 않고, 머리글이 붙어 있어(sticky) 굴려도 늘 보인다. */
.ogrp-hint{font-weight:400;font-size:var(--t-cap);color:var(--c-text-sub);
  white-space:nowrap}
/* 아주 좁은 폰에서는 머리글이 두 줄이 되느니 안내를 접는다 — 이름이 먼저다 */
@media (max-width:340px){ .ogrp-hint{display:none} }

/* 🔴🔴 owner 지시 2026-08-14 — 「액자 선택하면 이미지에도 액자 포함돼서 합성되게」.
   고른 액자 색으로 **테를 둘러** 보여 준다. 고르고도 그림이 그대로면
   「골라진 게 맞나?」 하게 된다 (액자는 인화값의 30배다).
   🔴 나무 액자는 안쪽이 살짝 파여 있다 — 안쪽 그림자로 두께를 느끼게 한다.
     사진을 덧씌우지 않고 그림자만으로 하는 이유: 어떤 색에도 맞고, 파일을 안 받는다. */
/* 🔴 액자 결 무늬(.fmgrain)는 **shop.css 로 옮겼다** (2026-08-14) —
   장바구니 썸네일도 같은 결을 써야 한다. 두 곳에 적어 두면 언젠가 한쪽만 고쳐진다. */
/* 🔴 폭은 .pvbox 가 진다. 여기는 테만 두른다 — `--fmpad` 는 JS 가 「짧은 변의 5%」를
   폭% 로 환산해 넣어 준다(사진 칸 .phfm · 장바구니 .spv 와 같은 자). */
.fmpv{display:block;line-height:0;border-radius:0;padding:var(--fmpad, 5%);
  box-shadow:0 2px 10px rgba(var(--brand-ink-rgb),.18),
             inset 1px 1px 0 rgba(255,255,255,.16),
             inset -1px -1px 0 rgba(0,0,0,.12),
             inset 0 0 0 1px rgba(0,0,0,.05)}
/* 유리와 액자가 만나는 안쪽 선 — 흰 액자에서 진해 보여 절반으로 (owner 지적 2026-08-14) */
.fmpv > .cropv{box-shadow:inset 0 0 0 1px rgba(0,0,0,.13)}
/* ── 액자 틀(누끼)에 끼운 사진 (사장님 확정 2026-09-30 · options.js `누끼자리()`) ──────────
   상자 비율 = 누끼 그림 비율(JS 가 aspect-ratio 로 준다). 겹침: 사진(.fmcut-photo) → 틀 그림 → 흐림 알약.
   🔴 `isolation` 으로 z-index 를 이 안에 가둔다 — 시트의 다른 겹(끌기 안내·바닥 단추)과 안 섞인다.
   🔴 사진 상자는 JS 가 %로 자리를 준다(창을 덮게 · 창 가운데). `.cropv` 는 그 안을 꽉 채운다 —
      인라인 aspect-ratio 는 폭·높이를 둘 다 주면 무시된다. 둥근 모서리·그림자는 뺀다(창 모서리로 바탕이 비친다).
   🔴 틀 그림에는 필름 필터를 안 건다(필터는 `.cropv > i` 에만). 그림자는 옛 CSS 테(.fmpv)와 같은 세기. */
.fmcut{position:relative;display:block;width:100%;line-height:0;isolation:isolate}
.fmcut-photo{position:absolute;z-index:0}
.fmcut-photo > .cropv{position:absolute;top:0;left:0;width:100%;height:100%;border-radius:0;box-shadow:none}
.fmcut-img{position:absolute;top:0;left:0;display:block;width:100%;height:100%;z-index:1;
  pointer-events:none;user-select:none;-webkit-user-select:none;-webkit-user-drag:none;
  filter:drop-shadow(0 2px 6px rgba(var(--brand-ink-rgb),.18))}
.fmcut-open{position:absolute;z-index:2;pointer-events:none}

/* ── 사진 칸의 액자 (owner 지적 2026-08-14: 「액자까지 적용했는데 사진에는 적용이 안 되는데」)
   🔴 두께는 칸 너비의 5%. 안여백 %는 **네 변 모두 가로 기준**이라
      세로 사진에서도 위아래·좌우 두께가 고르게 나온다. */
/* 🔴🔴 2026-08-14 사장님 지적 — 「상단 좌측과 우측이 둥글게 되어 사진이랑 액자가 잘려 보인다」
   → 처음엔 액자를 칸의 곡선에 맞췄는데, 사장님이 **「그냥 각지게 해 줄 수 있어?」** 하셨다.
   실제 액자는 각지다. 그게 맞다.
   🔴 그러려면 **칸도 각져야** 한다 — 칸이 둥근 채로 액자만 각지면 그 곡선이 액자를
      도로 잘라낸다(overflow:hidden). 사장님 지시로 사진 칸을 **통째로** 각지게 했다
      (upload.css `.ph{border-radius:0}` — /upload/ 와 /options/ 가 함께 읽는다).
   🔴 검은 선도 낮췄다 — 흰 액자에서 그 선이 제일 먼저 눈에 걸린다고 하셨다. */
/* 🔴 2026-08-14 — 칸을 통째로 각지게 바꿔서(upload.css) 이 예외는 필요 없어졌다.
   자리만 남겨 두지 않는다 — 안 쓰는 규칙은 다음 사람을 헷갈리게 한다. */
.phfm{display:block;padding:5%;background-color:var(--fmc,#7A4A2B);
  box-shadow:inset 1px 1px 0 rgba(255,255,255,.16),
             inset -1px -1px 0 rgba(0,0,0,.12),
             inset 0 0 0 1px rgba(0,0,0,.05)}
/* 유리와 액자가 만나는 안쪽 선 — 흰 액자에서 진해 보여 절반으로 */
.phfm > .pmat{box-shadow:inset 0 0 0 1px rgba(0,0,0,.13)}

/* 🔴🔴 2026-08-14 — 320px 에서 값 칸(`+9,000원`)이 **화면 밖으로 10px** 나갔다.
   창(dialog)은 문서 흐름 밖이라 여태 검사에 안 잡혔다 (그날 검사에 눈을 달아 찾았다).
   까닭: 가운데 칸이 `1fr` 이라 **줄어들 바닥이 없었다** — 이름이 길면 그대로 밀어냈다.
   → 가운데를 `minmax(0,1fr)` 로 두어 줄어들 수 있게 하고, 좁은 폰에서는 창 안여백도 줄인다. */
.opt{grid-template-columns:auto minmax(0,1fr) auto}
.opt .oname,.opt .odesc{min-width:0;overflow-wrap:anywhere;word-break:keep-all}
@media (max-width:340px){
  .sheet .sbody{padding-left:var(--s3);padding-right:var(--s3)}
  .steps{padding-left:var(--s3);padding-right:var(--s3)}
  .sheet .shead,.sheet .sfoot{padding-left:var(--s4);padding-right:var(--s4)}
  .opt{padding-left:var(--s3);padding-right:var(--s3)}
}

/* 🔴🔴 2026-08-14 사장님 지시 — 사진마다의 설정을 **사진 밖**으로 내렸다.
   개별로 정하시면 「4×6 · 반광택 · 테두리 중간 · 액자」처럼 길어져 사진을 덮고 두 줄로 접혔다.
   여기는 칸 폭을 다 쓰므로 길어져도 잘리지 않는다.
   🔴 누르면 그 사진 설정 창이 열린다 — 사진을 누르는 것과 **같은 길**(data-one). */
.setline{display:block;width:100%;text-align:left;
  padding:var(--s2) var(--s3);border:0;background:var(--c-surface);
  color:var(--c-text);font:inherit;font-size:var(--t-cap);font-weight:600;
  line-height:1.35;cursor:pointer;
  word-break:keep-all;overflow-wrap:anywhere}
.setline:hover{background:var(--c-surface-alt)}
.setline:focus-visible{outline:3px solid var(--c-focus);outline-offset:-3px}

/* 🔴 2026-08-14 — 줄맞춤 격자는 한 줄의 칸 높이를 **제일 큰 것에 맞춘다.**
   설정 줄이 두 줄이 된 칸이 있으면 다른 칸 아래에 **회색 빈 자리**가 남아
   「덜 그려진 것」처럼 보였다 (사장님 화면으로 확인).
   → 칸 바탕을 아래 줄과 같은 흰색으로. 사진 자리의 회색은 `.im` 이 따로 갖고 있다. */
.ph{background:var(--c-surface)}

/* ══ 흐림 딱지 — 한눈에 보이게 (owner 지적 2026-08-20) ═══════════════════
   「선명하지 않아요 이 표시도 지금 보기 불편한데 쉽게 사용자가 알 수 있도록」
   🔴 실측 — 대비 자체는 통과였다(먹색 62% 위 흰 글자, 밝은 사진 5.88:1 · 어두운 사진 18.88:1).
      문제는 **눈에 안 띄는 것**이었다: 흐림·주문불가·추천 **셋이 전부 같은 먹색**이라
      급한 말이 권하는 말과 구별되지 않았다.
   🔴 그래서 **색으로 먼저 말한다.** 사이트가 이미 가진 경고색 쌍을 쓴다:
        흐릴 수 있어요   바탕 #F6EADF · 글자 #67442F → 7.26:1 (지금보다 높다)
        선명하지 않아요  바탕 #F7E5E4 · 글자 #803330 → 7.10:1
      불투명이라 **어떤 사진 위에서도 값이 고정**이다 — 반투명은 사진 색에 따라 흔들렸다.
   🔴 색만으로 알리지 않는다 — 기호(▲ ■)와 글자를 그대로 둔다 (WCAG 1.4.1).
   🔴 추천(★)은 지금처럼 **조용한 먹색**으로 둔다. 급한 것이 먼저 보여야 한다. */
/* The photo list uses the same compact status shape for every quality it flags.
   🔴 owner 지시(2026-09-19): 사진 칸 위 「선명해요」 알약을 뺐다 → `.tag--good` 은
      만드는 곳이 없어져 같이 지운다. 남은 둘(흐릴 수 있어요 · 흐려요)은 그대로다. */
.ph .tag--warn, .csec .ph .tag--warn{
  background:var(--c-surface-warning);color:var(--c-text-warning);
  font-size:var(--t-sm);padding:4px var(--s3);border-radius:var(--r-pill);
  box-shadow:0 1px 4px rgba(var(--brand-ink-rgb),.28);
  -webkit-backdrop-filter:none;backdrop-filter:none}
.ph .tag--bad, .csec .ph .tag--bad{
  background:var(--c-surface-error);color:var(--c-text-error);
  font-size:var(--t-sm);padding:4px var(--s3);border-radius:var(--r-pill);
  box-shadow:0 1px 4px rgba(var(--brand-ink-rgb),.28);
  -webkit-backdrop-filter:none;backdrop-filter:none}
/* 기호는 글자와 같은 색으로 — 밝은 바탕이라 옛 밝은 주황·분홍은 안 읽힌다 */
.ph .tag--warn .dot, .ph .tag--bad .dot,
.csec .ph .tag--warn .dot, .csec .ph .tag--bad .dot{color:inherit}

/* 🔴🔴 2026-09-01 (owner 지시) 이름 왼쪽 · 값 오른쪽(원래대로), 등급은 이름 밑
   🔴 이름과 등급 사이를 좁힌다 (owner 지시) — `.oname` 이 줄높이를 안 정해 두어
      본문값(--t-body-lh 1.7 → 16px 에서 27.2px)을 물려받고 있었다. 줄 사이가 그만큼 떴다.
      제목용 줄높이 토큰(--t-lg-lh 1.4)으로 좁힌다. **숫자를 박지 않는다.**
   🔴 값은 두 줄에 걸쳐 **세로 가운데**로 세운다 (owner 지시) — 오른쪽 끝은 그대로 두고
      위로 붙어 있던 것을 가운데로. `grid-row:1 / span 2` + `align-self:center`. */
.opt--paper4{grid-template-columns:minmax(0,1fr) auto;align-items:start;gap:0 var(--s3)}
.opt--paper4 .oname{grid-column:1;grid-row:1;line-height:var(--t-lg-lh)}
.opt--paper4 .pspec{grid-column:1;grid-row:2;font-size:var(--t-cap);
  line-height:var(--t-cap-lh);color:var(--c-text-sub);font-weight:400}
.opt--paper4 .oright{grid-column:2;grid-row:1 / span 2;text-align:right;align-self:center}

/* 🔴 「종이별 장단점 자세히 보기」 — 목록 위로 올린 자리.
   글자는 15px 인데 **누르는 상자는 44px**(min-height)이라, 감싼 <p> 에 여백을 줘도
   상자가 <p> 밖으로 튀어나와 위 머리글을 8px 파고들고 첫 칸과는 4px 밖에 안 떴다
   (집 기준 --tap-gap 12px 미달 · 감사 실측). 잘못 눌리는 자리가 된다.
   🔴 <p> 를 상자 높이(--tap)만큼 세우고 그 위아래로 여백을 준다 — 그래야 상자가 안 튀어나온다. */
.sheet .pmore{display:flex;align-items:center;min-height:var(--tap);
  margin:var(--s3) 0 var(--s3)}
.shared-maker-guide[hidden]{display:none!important}
.shared-maker-guide{display:flex;align-items:center;flex-wrap:wrap;gap:var(--s4) var(--s5);
  margin:var(--s4) 0;padding:var(--s4);border:1px solid var(--c-border);
  border-left:3px solid var(--c-btn-point-bg);border-radius:var(--r-lg);
  background:var(--c-surface);font-size:var(--t-sm);line-height:1.6}
.shared-maker-guide>div{flex:1;min-width:0}
.shared-maker-guide b{display:block;font-size:var(--t-lg);margin-bottom:var(--s1)}
.shared-maker-guide p{margin:var(--s1) 0 0;color:var(--c-text-sub);word-break:keep-all;overflow-wrap:anywhere}
.shared-maker-guide .btn{min-height:var(--tap);flex-shrink:0;font-size:var(--t-sm)}
@media(max-width:599px){
  .shared-maker-guide{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s3)}
  .shared-maker-guide .btn{width:100%;padding:var(--s2) var(--s3);white-space:normal;word-break:keep-all}
}
#collage-share-results{display:grid;gap:12px;margin:12px 0}
#collage-share-results:empty{display:none}

.include-singles-choice{margin:var(--s4) 0;padding:var(--s3) var(--s4);border:1px solid var(--c-border);border-radius:var(--r-md);background:var(--c-surface)}
.include-singles-choice[hidden]{display:none!important}
.include-singles-choice label{display:flex;align-items:center;gap:var(--s3);min-height:var(--tap);cursor:pointer}
.include-singles-choice input{width:20px;height:20px;flex:none;accent-color:var(--c-btn-point-bg)}
.include-singles-choice p{margin-top:var(--s1)}
.photo-share{width:100%;margin-top:var(--s2);min-height:var(--tap)}
.shared-maker-hint{font-size:var(--t-cap)}


/* Four-step photo editor. Every rule is limited to this editor dialog. */
dialog.sheet--photo{width:calc(100% - 32px);max-width:740px;
  height:calc(100vh - 32px);max-height:820px;margin:auto;border-radius:24px}
dialog.sheet--photo .in{height:100%;max-height:100%;min-height:0}
dialog.sheet--photo .shead{flex-shrink:0;padding:20px 24px 12px;gap:12px}
dialog.sheet--photo .shead h2{font-size:22px;line-height:1.35;letter-spacing:-.03em}
dialog.sheet--photo .shead .sub{font-size:14px;line-height:1.5;margin-top:4px}
dialog.sheet--photo .sx{width:44px;min-width:44px;min-height:44px}
dialog.sheet--photo .steps{flex-shrink:0;gap:12px;padding:0 24px 12px}
dialog.sheet--photo .stepdot{flex-direction:row;justify-content:center;gap:8px;
  min-height:44px;padding:6px 2px;border-top:0;border-bottom:2px solid var(--c-border)}
dialog.sheet--photo .stepdot.on{border-bottom-color:var(--c-btn-point-bg)}
dialog.sheet--photo .stepdot b{width:22px;height:22px;flex-shrink:0;font-size:13px}
dialog.sheet--photo .stepdot span{font-size:14px;line-height:1.3}
dialog.sheet--photo .steps>li::after{display:none}
dialog.sheet--photo .photo-options-body{display:flex;flex-direction:column;flex:1;
  min-height:0;overflow:hidden;padding:0 24px;gap:0}
/* 🔴🔴 owner 신고(2026-09-17): 「모바일·앱에서 위 사진이 **따라오면서** 아래 단추를
   누르면 보기 편했는데 왜 원복됐지?」 — 맞다. 실측(운영 393×852): 팝업 몸통을 굴리면
   미리보기 Y 가 127 → **-221** 로 올라가 사라졌다. `position:static` 이라 같이 굴러간 것이다.
   (이 줄은 오늘 밤 작업으로 생긴 게 아니라 20:09 운영본 동기화 때 들어왔다 —
    그 전부터 운영에 있던 상태다.)
 🔴 되살린다: 몸통(overflow-y:auto)에 붙여 둔다. 아래에서 무엇을 골라도 사진이 바로 보인다.
 🔴 뒤가 비치면 굴러가는 글이 사진 뒤로 지나가 지저분하다 — 흐림을 한 겹 깐다.
 🔴 **PC(600px 이상)는 해당 없다.** 거기는 미리보기가 옆 칸에 따로 서 있어 늘 보인다.
 🔴 아주 짧은 화면은 아래 `@media(max-height:30rem)` 이 붙박이를 포기한다(그 규칙 그대로). */
dialog.sheet--photo .photo-options-body>.pvhold{position:sticky;top:0;z-index:2;flex-shrink:0;
  min-width:0;margin:0;padding:12px 0 16px;box-shadow:none;background:var(--c-surface)}
@supports ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  dialog.sheet--photo .photo-options-body>.pvhold{
    backdrop-filter:blur(14px) saturate(140%);-webkit-backdrop-filter:blur(14px) saturate(140%)}
}
/* 🔴🔴 **반드시 위 선언보다 뒤에 있어야 한다** — 미디어 쿼리는 우선순위를 안 올린다.
   이 파일이 2026-08-28 에 같은 실수로 한 번 데었다(죽은 규칙인 채 검사만 초록).
   아주 짧은 화면(폰 가로)에서는 붙박이를 포기한다 — 붙여 두면 작은 목록을
   미리보기가 통째로 덮어 고를 것이 안 보인다(2026-08-27 결정). */
@media(max-height:30rem){
  dialog.sheet--photo .photo-options-body>.pvhold{position:static;backdrop-filter:none;-webkit-backdrop-filter:none}
}
dialog.sheet--photo .cropbox{display:flex;flex-direction:column;align-items:center;
  gap:10px;margin:0;min-width:0}
dialog.sheet--photo .pvbox{width:min(100%,calc(220px * var(--ar,1)));max-width:400px;
  grid-column:auto;grid-row:auto;flex-shrink:0}
dialog.sheet--photo .cropmsg{margin:0;max-width:38em;text-align:center;
  font-size:14px;line-height:1.5;word-break:keep-all;overflow-wrap:anywhere}
dialog.sheet--photo .cropmsg .linkish{min-height:44px;display:inline-flex;align-items:center}
dialog.sheet--photo .photo-preview-caption{min-width:0;text-align:center}
dialog.sheet--photo .photo-preview-caption>.sub{margin:3px 0;font-size:13px;line-height:1.5}
dialog.sheet--photo .photo-preview-caption>.linkish{display:inline-flex;align-items:center;min-height:44px;font-size:13px}
/* 🔴 owner 지시(2026-09-19): 화살표(← ↑ ↓ →)를 지웠다. `.photo-crop-controls` 규칙도
   전부 같이 지웠다 — 이 화면에만 있던 것이라 두면 죽은 코드가 된다.
   되살릴 일이 생기면 커밋 f3982d0 앞 판에 그대로 있다. */
dialog.sheet--photo .photo-paper-summary{grid-column:1 / -1;grid-row:3;min-width:0;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
  margin-top:7px;font-size:13px;line-height:1.5;font-weight:400;color:var(--c-text-sub);
  word-break:keep-all;overflow-wrap:anywhere}
dialog.sheet--photo .photo-risk-photos{display:flex;flex-wrap:wrap;gap:6px;max-height:110px;
  overflow:auto;overscroll-behavior:contain;margin:8px 0}
dialog.sheet--photo .photo-risk-photos img{display:block;width:46px;height:58px;flex:0 0 46px;
  object-fit:cover;border-radius:5px;background:var(--c-surface)}
dialog.sheet--photo .photo-step-choices{flex:1;min-height:0;min-width:0;overflow:auto;
  overscroll-behavior:contain;-webkit-overflow-scrolling:touch;overflow-anchor:none;
  padding:12px 2px 24px;scrollbar-gutter:stable}
dialog.sheet--photo .photo-step-choices>.ogrp{position:static;font-size:18px;line-height:1.4;
  margin:0 0 14px;padding:0;letter-spacing:-.02em;background:none}
dialog.sheet--photo .photo-step-choices .ogrp-hint{white-space:normal}
dialog.sheet--photo .photo-step-choices .reco{margin:0 0 12px;padding:10px 12px;
  font-size:13px;line-height:1.5;border-radius:12px;word-break:keep-all;overflow-wrap:anywhere}
dialog.sheet--photo .photo-size-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
/* 🔴 owner 지시(2026-09-19 ②): 「칸 안쪽 세로 가운데 · 약간 작게 · 크기는 무조건 통일」
   화질 글이 사진창으로 나가면서 quality 줄은 **평소에 비어 있다**(「인화지 준비 중」일 때만
   들어온다). 빈 줄은 높이 0 이라 8칸이 모두 같은 구조 = 같은 크기가 된다.
   `min-height` 104→96: 내용 실측 89px(이름 45 + 설명 18 + 사이 2 + 안여백 24) 위에
   여유 7px. 이보다 더 줄이면 칸이 내용에 딱 붙어 `align-content:center` 가 할 일이 없어진다. */
dialog.sheet--photo .photo-size-grid .opt{display:grid;grid-template-columns:36px minmax(0,1fr);
  grid-template-areas:"mini name" "mini desc" "quality quality";align-content:center;
  gap:2px 8px;margin:0;min-height:96px;padding:12px;border-radius:14px}
/* 🔴 2026-09-15 — 전에는 26px 칸에 32px 그림을 0.75 배로 **줄여**(24px) 넣어 체크 박스만 했다.
   액자 테 2px + 매트 2px 를 두르고도 안쪽 사진이 보이려면 그림 자체가 커야 한다 → 36px. */
dialog.sheet--photo .photo-size-grid .omini{grid-area:mini;width:36px;height:auto}
dialog.sheet--photo .photo-size-grid .omini i{--mini:36px}
dialog.sheet--photo .photo-size-grid .oname{grid-area:name;font-size:17px;line-height:1.35}
dialog.sheet--photo .photo-size-grid .odesc{grid-area:desc;font-size:12px;line-height:1.5}
/* 🔴 이 줄은 이제 「인화지 준비 중」**만** 쓴다 — 화질 글은 사진창 위 알약으로 갔다.
   어제 넣었던 `min-height:18px`(빈 자리 지키기)은 뺀다. 지킬 빈 자리 자체가 없어졌다:
   화질 글이 사라져 8칸이 같은 구조가 되었으므로 어긋날 짝이 없다. */
dialog.sheet--photo .photo-size-grid .oright{grid-area:quality;text-align:left;
  font-size:12px;line-height:1.5;white-space:normal;font-weight:500;margin-top:5px}
/* 🔴 owner 지시(2026-09-17): 「사진 전체 보이게 / 여백 없이 채우기」 두 카드를 없앴다.
   `.photo-fit-options` · `.photo-fit-card` 규칙도 같이 지웠다 — 이 화면에만 있던 것이라
   두면 죽은 코드가 된다. 되살릴 일이 생기면 커밋 57e0fc9 앞 판에 그대로 있다. */
dialog.sheet--photo .photo-extra{margin-top:16px;border:1px solid var(--c-border);
  border-radius:14px;background:var(--c-surface)}
dialog.sheet--photo .photo-extra>summary{display:flex;align-items:center;justify-content:space-between;
  gap:8px;min-height:52px;padding:12px 14px;list-style:none;cursor:pointer;font-size:15px;
  line-height:1.4;font-weight:700;word-break:keep-all;overflow-wrap:anywhere}
dialog.sheet--photo .photo-extra>summary>span{margin-left:auto;text-align:right;
  font-size:13px;font-weight:400;color:var(--c-text-sub)}
dialog.sheet--photo .photo-extra>summary::-webkit-details-marker{display:none}
dialog.sheet--photo .photo-extra>summary::after{content:"+";flex-shrink:0;font-size:22px;
  line-height:1;font-weight:400;color:var(--c-text-sub)}
dialog.sheet--photo .photo-extra[open]>summary::after{content:"−"}
dialog.sheet--photo .photo-extra>div{padding:0 14px 14px}
dialog.sheet--photo .photo-extra .sgroup:first-child{margin-top:0}
dialog.sheet--photo .photo-extra .opt:last-child{margin-bottom:0}
dialog.sheet--photo .photo-extra .opt{padding:12px 10px;gap:2px 8px}
dialog.sheet--photo .photo-extra .opt .oright{font-size:13px}
dialog.sheet--photo .photo-review{display:flex;flex-wrap:wrap;gap:6px 8px;
  margin:16px 0;padding:14px;border-radius:12px;background:var(--c-surface-alt);
  font-size:13px;line-height:1.6;color:var(--c-text-sub);word-break:keep-all;overflow-wrap:anywhere}
dialog.sheet--photo .photo-review>span{padding:2px 8px;border-radius:6px;background:var(--c-surface)}
dialog.sheet--photo .photo-review>b{flex-basis:100%;font-size:14px;color:var(--c-text)}
dialog.sheet--photo .photo-scope{display:flex;align-items:flex-start;gap:10px;
  min-height:48px;margin:14px 0 0;padding:10px 0;cursor:pointer;font-size:14px;line-height:1.5;
  word-break:keep-all;overflow-wrap:anywhere}
dialog.sheet--photo .photo-scope input,
dialog.sheet--photo .photo-warning input{width:20px;height:20px;flex:0 0 20px;margin:1px 0 0;
  accent-color:var(--c-btn-point-bg)}
dialog.sheet--photo .photo-scope small{display:block;margin-top:4px;font-size:12px;color:var(--c-text-sub)}
dialog.sheet--photo .photo-warning{margin:12px 0 0;padding:12px 14px;border-radius:12px;
  background:var(--c-surface-warning);color:var(--c-text-warning);font-size:13px;line-height:1.6;
  word-break:keep-all;overflow-wrap:anywhere}
dialog.sheet--photo .photo-warning p{margin:0 0 8px}
dialog.sheet--photo .photo-warning p:last-child{margin-bottom:0}
dialog.sheet--photo .photo-warning label{display:flex;align-items:flex-start;gap:10px;
  min-height:44px;padding:8px 0;cursor:pointer}
dialog.sheet--photo .pmore{margin:0 0 12px;font-size:14px}
dialog.sheet--photo .photo-editor-footer{display:flex;flex-wrap:wrap;align-items:center;
  flex-shrink:0;gap:10px;padding:12px 24px 18px;border-top:1px solid var(--c-border)}
dialog.sheet--photo .photo-price-row{flex:1 1 100%;display:flex;align-items:baseline;
  justify-content:space-between;gap:8px;font-size:14px;line-height:1.4;min-width:0}
dialog.sheet--photo .photo-price-row b{font-size:18px;line-height:1.4}
dialog.sheet--photo .photo-price-row small{font-size:12px;font-weight:400;color:var(--c-text-sub)}
dialog.sheet--photo .photo-editor-footer .btn{min-height:50px;min-width:0;padding:10px 14px;
  font-size:16px;line-height:1.35;white-space:normal;word-break:keep-all}
dialog.sheet--photo .photo-editor-footer .photo-prev{flex:0 0 88px}
dialog.sheet--photo .photo-editor-footer .photo-primary{flex:1 1 0}
dialog.sheet--photo .photo-editor-footer .btn[disabled]{opacity:.5;cursor:not-allowed}

/* ── 큰 미리보기 위의 잘림 표시 (owner 지시 2026-09-17) ─────────────────
   「사진 한 장만 넣으라고 · 큰 미리보기 하나에 분홍을 얽어라」
   🔴 분홍 한 색으로 **꽉** 덮는다. 처음엔 55% + 흰 빗금이었는데, 어두운 사진 위에서는
      분홍이 죽어 거의 안 보였다(사장님이 보내신 밤 사진에서 좌우에 가늘게만 보였다).
   🔴 색은 우리 단추 색(--c-btn-point-bg). 새 색을 만들지 않는다.
   🔴 고대비 화면에서도 보이게 Highlight 로 물러난다. */
/* 🔴🔴 **빗금을 지우지 않는다** (owner 신고 2026-09-17: 「빗금 쳐 있었는데 왜 또
   민무늬로 교체했어? 내가 주문한 사항이 아니잖아」). 맞다 — 진하게만 해 달라는 말씀이었는데
   내가 빗금까지 없앴다. 시키지 않은 것을 바꾼 것이다.
   🔴 빗금은 「여기는 잘려 나가는 자리」라는 표시다. 색만으로는 무늬가 있는 사진 위에서
      「원래 그런 색인가?」와 구별이 안 된다. */
.cropv-cut{position:absolute;background:var(--c-btn-point-bg);opacity:.86;pointer-events:none;
  background-image:repeating-linear-gradient(45deg,rgba(255,255,255,.28) 0 3px,transparent 3px 6px);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.35)}
@media(forced-colors:active){.cropv-cut{background:Highlight;opacity:1;forced-color-adjust:none}}
/* 🔴🔴 owner 지시(2026-09-17): 잘림 그림에서도 **끌어서** 자리를 옮긴다(PC 마우스·폰 터치).
   상자가 사진 비율이라 사진은 못 움직이지만, **분홍 띠(남길 자리)** 가 손가락을 따라온다.
   🔴 `touch-action:none` 이라야 폰에서 끄는 동안 화면이 같이 굴러가지 않는다.
      (그전에는 `auto` 라 손가락이 화면을 스크롤해 버려 자리를 못 잡았다.)
   🔴 화살표 넉 장은 그대로 둔다 — 키보드로 오는 손님과, 끌기를 모르는 손님의 길이다. */
/* 🔴 owner 지시(2026-09-17): 종이(테두리)와 잘림을 **한 그림에**.
   맨 아래 종이 → 사진 → 분홍 빗금 순으로 겹친다. 분홍이 덮은 자리는 잘려 나가고
   그 자리는 종이가 된다 — 그래서 이 그림 하나로 둘 다 읽힌다.
   🔴 상자 자체는 바탕을 비운다(종이를 따로 그리므로). 그림자도 종이에만 준다. */
.cropv--both{background:transparent!important;box-shadow:none;overflow:visible}
/* 🔴 흰 테두리를 고르면 종이와 화면 바탕이 둘 다 밝아 **어디까지가 종이인지** 안 보인다
   (실측 갈무리에서 그랬다). 머리카락 같은 실선 하나와 그림자로 가장자리를 알려 준다.
   🔴 실선은 **안쪽**에 넣는다(inset) — 바깥에 그리면 종이가 그만큼 커 보인다. */
.cropv-paper{position:absolute;border-radius:2px;
  box-shadow:0 3px 12px rgba(var(--brand-ink-rgb),.18),
             inset 0 0 0 1px rgba(var(--brand-ink-rgb),.10)}
.cropv--both i{position:absolute}
.cropv--cutmap{cursor:grab;touch-action:none}
.cropv--cutmap.cropv--drag{cursor:grabbing}

/* ── 「끌어서 옮길 수 있어요」 안내 (owner 지시 2026-09-17) ──────────────
   🔴 창을 열 때마다 3초(owner 지시 2026-09-17 — 2초로 줄였다가 도로 3초).
      3.0초에 스스로 스르르 사라진다 — 시계는 CSS 가 갖는다.
      JS 시계는 3.6초 뒤 **자리만** 치운다(options.js 팁시작). 두 숫자는 늘 같이 고친다.
   🔴 `pointer-events:none` — 이 안내 위를 끌어도 사진이 그대로 끌린다. 안내가 길을 막으면
      「알려 주면서 못 하게 하는」 꼴이 된다.
   🔴 폰/PC 는 **폭이 아니라 가리키개**로 가른다 — 터치 노트북도, 좁은 PC 도 맞게 나온다. */
.cropv-tip{position:absolute;inset:0;display:grid;place-items:center;pointer-events:none;z-index:2;
  animation:cropv-tip-out 400ms ease 3s forwards}
.cropv-tip-in{display:inline-flex;align-items:center;gap:var(--s2);
  /* 🔴 좁은 폰에서 사진 밖으로 튀어나가지 않게 — 안쪽에서 10px 씩 물러선다 */
  max-width:calc(100% - 20px);
  padding:var(--s2) var(--s3);border-radius:var(--r-pill);
  background:rgba(var(--brand-ink-rgb),.72);color:#fff;
  font-size:var(--t-cap);line-height:1.4;font-weight:600;text-align:left;
  box-shadow:0 4px 14px rgba(var(--brand-ink-rgb),.28);
  -webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);
  animation:cropv-tip-slide 1.6s ease-in-out infinite}
.cropv-tip-in b{font-weight:600}
/* 🔴 어느 쪽을 보여 줄지는 **options.js 가 터치 유무로** 정한다(그쪽 주석 참고).
   여기서 미디어쿼리로 가르면 검사 브라우저에서 늘 「터치」가 떠서 잡을 수가 없다. */
@keyframes cropv-tip-slide{0%,100%{transform:translateX(-9px)}50%{transform:translateX(9px)}}
@keyframes cropv-tip-out{to{opacity:0;visibility:hidden}}
/* 🔴 움직임을 줄여 달라고 하신 손님께는 **흔들지 않는다.** 글은 그대로 3초 보여 드린다 —
   안내 자체를 없애면 그분들만 끌 수 있다는 걸 모르게 된다. */
@media (prefers-reduced-motion:reduce){
  .cropv-tip-in{animation:none}
  .cropv-tip{animation:cropv-tip-out 1ms ease 3s forwards}
}

/* ── 사진 위 화질 알약 (owner 지시 2026-09-19 ②) ──────────────────────────
   「사진이 흐려요는 사진 안에 넣는 게 좋지 않아?」 · 「사진 위로 버튼 넣어서」
   · 「애니메이션 효과로 주면 좋을 것 같은데」

   🔴 모양·색은 **첫 화면 사진 칸 알약과 같은 것**(`.ph .tag--warn` / `--bad`)이다 —
      사장님이 가리키신 그 알약이다. 같은 뜻에 같은 모양을 준다.
   🔴 자리는 **위쪽**. 끌기 안내(`.cropv-tip`)는 가운데라 3초 동안 둘이 같이 떠도 안 겹친다.
   🔴 끌기 안내와 달리 **안 사라진다.** 저건 「할 수 있어요」고 이건 **경고**다.
   🔴 `pointer-events:none` — 알약 위를 끌어도 사진이 그대로 끌린다.
   🔴 줄바꿈을 막지 않는다(`white-space:normal`). 아이폰14 미리보기 폭이 133px 이라
      말줄임(…)으로 끊으면 **경고가 안 읽히는** 폭이 생긴다 — 두 줄이 되는 편이 낫다.
   🔴 색만으로 알리지 않는다 — warn·bad 는 **글자가 서로 다르다**(흐릴 수 있어요 / 흐려요). */
/* 🔴 글자·안여백은 **미리보기 폭에 맞춰** 잡았다. 처음엔 14px + 좌우 12px 이었는데
   안드로이드360 에서 미리보기가 123px 뿐이라 「흐릴 / 수 / 있어요」 **세 줄(65px)** 로
   접혀 사진의 40%를 덮었다(실측). 13px + 좌우 8px 로 줄이면 한 줄에 들어간다. */
/* 🔴🔴 가운데 맞추기를 `left:50% + translateX(-50%)` 로 하면 **안 된다.**
   자리를 띄운(absolute) 상자의 폭은 「담는 상자 폭 − left」 안에서 정해진다 —
   left:50% 를 주는 순간 쓸 수 있는 폭이 **절반**이 된다. 아이폰14 에서 미리보기 133px 의
   절반인 66px 안에 85px 짜리 글을 넣으려니 두 줄로 접혔다(실측). 글자를 줄여도 안 고쳐진다.
   → 좌우를 모두 6px 로 묶고 `margin-inline:auto` 로 가운데를 잡는다. 그러면 쓸 수 있는
     폭이 121px 로 온전히 살아난다. */
.cropv-blur{position:absolute;top:8px;left:6px;right:6px;
  width:-webkit-fit-content;width:fit-content;margin-inline:auto;z-index:2;
  max-width:calc(100% - 12px);
  padding:3px var(--s2);border-radius:var(--r-pill);
  font-size:var(--t-cap);line-height:1.35;font-weight:700;text-align:center;
  white-space:normal;word-break:keep-all;
  box-shadow:0 1px 4px rgba(var(--brand-ink-rgb),.28);
  -webkit-backdrop-filter:none;backdrop-filter:none;
  pointer-events:none}
/* 🔴 알약이 있는 동안 끌기 안내는 **알약 아래 칸**에서 가운데를 잡는다.
   안 그러면 좁은 폰(미리보기 123px)에서 여러 줄로 접힌 안내가 알약 자리까지 올라와
   둘이 포개진다(실측 — 안드로이드360·320 에서 겹침). */
.cropv--hasblur .cropv-tip{top:40px}
.cropv-blur--warn{background:var(--c-surface-warning);color:var(--c-text-warning)}
.cropv-blur--bad{background:var(--c-surface-error);color:var(--c-text-error)}
/* 🔴 나타날 때만 한 번 — 위에서 스르르 내려앉는다. 화질이 바뀔 때만 이 클래스가 붙는다
   (options.js 흐림알약 의 열쇠). 종이·테두리를 고를 때마다 다시 뛰면 눈이 어지럽다. */
.cropv-blur--in{animation:cropv-blur-in 420ms var(--m-ease) both}
@keyframes cropv-blur-in{
  from{opacity:0;transform:translateY(-10px) scale(.94)}
  to{opacity:1;transform:none}}
/* 🔴 움직임을 줄여 달라신 손님께는 **그냥 떠 있게** 한다. 경고는 없애지 않는다. */
@media (prefers-reduced-motion:reduce){
  .cropv-blur--in{animation:none}
}

/* ── (옛) 아래 작은 그림 — 지금은 안 쓴다 ────────────────────────────
   「몇 % 잘려요 하는 거, 어디가 어떻게 잘리는지 우리 핑크색으로 표시」
   🔴 위 큰 미리보기는 「나올 모습」이라 잘린 부분이 안 보인다. 여기는 **사진 전체**를
      작게 보여 주고, 잘려 나갈 자리를 핑크로 덮는다.
   🔴 작게 둔다(최대 168px). 크게 만들면 무엇이 「나올 모습」인지 헷갈린다.
   🔴 핑크는 우리 단추 색(--c-btn-point-bg)을 쓴다. 새 색을 만들지 않는다.
   🔴 반투명으로 덮는다 — 아주 가려 버리면 「무엇이」 잘리는지 못 본다.
   🔴 고대비 화면에서는 색이 안 보일 수 있어 빗금을 함께 깐다. */
dialog.sheet--photo .cropmap{margin:10px auto 0;max-width:168px;text-align:center}
dialog.sheet--photo .cropmap-img{position:relative;width:100%;border-radius:8px;overflow:hidden;
  background-size:cover;background-position:center;background-repeat:no-repeat;
  box-shadow:inset 0 0 0 1px rgba(63,48,57,.17)}
dialog.sheet--photo .cropmap-cut{position:absolute;background:var(--c-btn-point-bg);opacity:.55;
  background-image:repeating-linear-gradient(45deg,rgba(255,255,255,.28) 0 3px,transparent 3px 6px)}
dialog.sheet--photo .cropmap figcaption{margin-top:6px;font-size:12px;line-height:1.5}
@media(forced-colors:active){
  dialog.sheet--photo .cropmap-cut{background:Highlight;opacity:1;forced-color-adjust:none}
}
dialog.sheet--photo .photo-extra>summary:focus-visible{outline:3px solid var(--c-focus);outline-offset:2px}
dialog.sheet--photo .photo-step-enter{animation:photo-choice-in 180ms ease-out both}
@keyframes photo-choice-in{from{opacity:.5;transform:translateY(6px)}to{opacity:1;transform:none}}
@supports(height:1dvh){
  dialog.sheet--photo{height:calc(100dvh - 32px)}
}
@media(min-width:900px){
  dialog.sheet--photo{max-width:1040px;width:calc(100% - 64px);height:calc(100vh - 64px)}
  dialog.sheet--photo .shead{padding:24px 28px 14px}
  dialog.sheet--photo .shead h2{font-size:25px}
  dialog.sheet--photo .steps{padding:0 28px 18px}
  dialog.sheet--photo .photo-options-body{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,1fr);
    gap:28px;padding:0 28px}
  dialog.sheet--photo .photo-options-body>.pvhold{display:flex;align-items:center;justify-content:center;
    min-height:0;padding:20px;border-radius:18px;background:var(--c-surface-alt);margin-bottom:24px;
    overflow:auto;overscroll-behavior:contain}
  dialog.sheet--photo .cropbox{width:100%;gap:18px}
  dialog.sheet--photo .pvbox{width:min(100%,calc(330px * var(--ar,1)));max-width:460px}
  dialog.sheet--photo .photo-step-choices{height:100%;padding-top:0}
  dialog.sheet--photo .photo-editor-footer{padding:16px 28px 20px;gap:12px}
  dialog.sheet--photo .photo-price-row{flex:1 1 0;display:block;margin-right:16px}
  dialog.sheet--photo .photo-price-row b{display:block;font-size:20px}
  dialog.sheet--photo .photo-editor-footer .photo-primary{flex:0 1 280px}
  @supports(height:1dvh){dialog.sheet--photo{height:calc(100dvh - 64px)}}
}
/* Medium-width windows keep choices beside the preview at every height. */
@media(min-width:600px) and (max-width:899px){
  dialog.sheet--photo .photo-options-body{display:grid;
    grid-template-columns:minmax(0,2fr) minmax(0,3fr);gap:16px;padding:0 16px}
  dialog.sheet--photo .photo-options-body>.pvhold{display:flex;align-items:flex-start;justify-content:center;
    min-height:0;overflow:auto;overscroll-behavior:contain;padding:12px 8px;margin-bottom:16px;
    border-radius:14px;background:var(--c-surface-alt)}
  dialog.sheet--photo .cropbox{width:100%;gap:10px;margin-block:auto}
  dialog.sheet--photo .pvbox{width:min(100%,calc(clamp(120px,calc(100vh - 420px),220px) * var(--ar,1)))}
  dialog.sheet--photo .photo-options-body[data-stage="1"] .pvbox{
    width:min(100%,calc(clamp(100px,calc(100vh - 450px),220px) * var(--ar,1)))}
  dialog.sheet--photo .photo-step-choices{height:100%;padding-top:0}
  dialog.sheet--photo .photo-size-grid .opt{padding:10px;gap:2px 6px}
  dialog.sheet--photo .photo-size-grid .odesc{font-size:12px}
  dialog.sheet--photo .photo-preview-caption>.sub{font-size:12px}
}
@media(max-width:599px){
  dialog.sheet--photo{width:100%;max-width:none;height:100vh;max-height:100vh;margin:0;
    border-radius:0}
  dialog.sheet--photo .shead{padding:12px 16px 6px;padding-top:max(12px,env(safe-area-inset-top));gap:8px}
  dialog.sheet--photo .shead h2{font-size:20px}
  dialog.sheet--photo .shead .sub{font-size:12px}
  dialog.sheet--photo .steps{padding:0 16px 8px;gap:8px}
  dialog.sheet--photo .stepdot{flex-direction:column;gap:3px;min-height:52px;padding:4px 1px}
  dialog.sheet--photo .stepdot span{font-size:12px;line-height:1.3;white-space:normal;overflow:visible;text-overflow:clip;word-break:keep-all}
  dialog.sheet--photo .stepdot b{width:20px;height:20px;font-size:12px}
  dialog.sheet--photo .photo-options-body{padding:0 16px}
  dialog.sheet--photo .photo-options-body>.pvhold{padding:8px 0 12px;border-bottom:1px solid var(--c-border)}
  dialog.sheet--photo .cropbox{display:grid;grid-template-columns:100px minmax(0,1fr);
    align-items:center;gap:8px 14px}
  dialog.sheet--photo .pvbox{width:min(100%,calc(104px * var(--ar,1)));max-width:100%;grid-column:1;grid-row:1}
  dialog.sheet--photo .photo-preview-caption{grid-column:2;grid-row:1;text-align:left}
  dialog.sheet--photo .photo-preview-caption>.sub{font-size:12px}
  dialog.sheet--photo .cropmsg{grid-column:2;grid-row:1;font-size:12px;text-align:left;line-height:1.5}
  dialog.sheet--photo .photo-options-body[data-stage="1"] .cropbox{display:flex;gap:8px}
  dialog.sheet--photo .photo-options-body[data-stage="1"] .pvbox{width:min(100%,calc(200px * var(--ar,1)));max-width:280px}
  dialog.sheet--photo .photo-options-body[data-stage="1"] .photo-preview-caption{text-align:center}
  dialog.sheet--photo .photo-options-body[data-stage="1"] .cropmsg{font-size:13px;text-align:center}
  dialog.sheet--photo .photo-step-choices{padding:12px 2px 18px}
  dialog.sheet--photo .photo-step-choices>.ogrp{font-size:17px;margin-bottom:12px}
  dialog.sheet--photo .photo-editor-footer{padding:10px 16px 12px;
    padding-bottom:max(12px,env(safe-area-inset-bottom));gap:8px}
  dialog.sheet--photo .photo-editor-footer .photo-prev{flex-basis:70px}
  dialog.sheet--photo .photo-editor-footer .btn{min-height:48px;font-size:15px}
  dialog.sheet--photo .photo-price-row{font-size:12px}
  dialog.sheet--photo .photo-price-row b{font-size:17px}
  @supports(height:1dvh){
    dialog.sheet--photo{height:100dvh;max-height:100dvh}
    dialog.sheet--photo .photo-options-body[data-stage="1"] .pvbox{
      width:min(100%,calc(min(24dvh,200px) * var(--ar,1)))}
  }
}
@media(max-width:359px){
  dialog.sheet--photo .shead,dialog.sheet--photo .steps,
  dialog.sheet--photo .photo-options-body,dialog.sheet--photo .photo-editor-footer{
    padding-left:12px;padding-right:12px}
  dialog.sheet--photo .shead h2{font-size:18px}
  dialog.sheet--photo .photo-size-grid{gap:8px}
  dialog.sheet--photo .photo-size-grid .opt{padding:10px;grid-template-columns:32px minmax(0,1fr);gap:2px 6px}
  dialog.sheet--photo .photo-size-grid .omini{width:32px}
  dialog.sheet--photo .photo-size-grid .omini i{--mini:30px}
  dialog.sheet--photo .photo-size-grid .oname{font-size:16px}
  dialog.sheet--photo .photo-size-grid .odesc{font-size:11px}
  dialog.sheet--photo .cropbox{grid-template-columns:80px minmax(0,1fr);gap:8px 12px}
  dialog.sheet--photo .opt--paper4{padding:12px;gap:0 8px}
  dialog.sheet--photo .opt--paper4 .oname{font-size:15px}
  dialog.sheet--photo .opt--paper4 .oright{font-size:12px}
}
@media(max-width:359px) and (min-height:541px) and (max-height:700px){
  dialog.sheet--photo .photo-options-body[data-stage="1"] .cropbox{display:grid;
    grid-template-columns:80px minmax(0,1fr);align-items:center;gap:8px 12px}
  dialog.sheet--photo .photo-options-body[data-stage="1"] .pvbox{width:min(100%,calc(110px * var(--ar,1)))}
  dialog.sheet--photo .photo-options-body[data-stage="1"] .photo-preview-caption{text-align:left}
  dialog.sheet--photo .photo-options-body[data-stage="1"] .cropmsg{text-align:left;font-size:12px}
}
/* Low landscape windows use two columns and independently scroll the preview. */
@media(min-width:600px) and (max-height:540px){
  dialog.sheet--photo{width:100%;max-width:none;height:100vh;max-height:100vh;margin:0;border-radius:0}
  dialog.sheet--photo .shead{padding:8px 16px 4px}
  dialog.sheet--photo .shead h2{font-size:19px}
  dialog.sheet--photo .shead .sub{font-size:12px}
  dialog.sheet--photo .steps{padding:0 16px 6px}
  dialog.sheet--photo .stepdot{min-height:40px}
  dialog.sheet--photo .photo-options-body{display:grid;grid-template-columns:minmax(0,2fr) minmax(0,3fr);
    gap:20px;padding:0 16px}
  dialog.sheet--photo .photo-options-body>.pvhold{display:block;min-height:0;overflow:auto;
    overscroll-behavior:contain;padding:8px;margin-bottom:8px;border-radius:12px;background:var(--c-surface-alt)}
  dialog.sheet--photo .cropbox{display:flex;gap:8px}
  dialog.sheet--photo .pvbox{width:min(100%,calc(140px * var(--ar,1)));max-width:260px}
  dialog.sheet--photo .cropmsg{font-size:12px;text-align:center}
  dialog.sheet--photo .photo-step-choices{padding-top:4px}
  dialog.sheet--photo .photo-editor-footer{padding:8px 16px;gap:10px;flex-wrap:nowrap}
  dialog.sheet--photo .photo-price-row{display:block;flex:1 1 0;font-size:12px}
  dialog.sheet--photo .photo-price-row b{display:block;font-size:16px}
  dialog.sheet--photo .photo-editor-footer .btn{min-height:44px;font-size:14px}
  dialog.sheet--photo .photo-editor-footer .photo-prev{flex:0 0 72px}
  dialog.sheet--photo .photo-editor-footer .photo-primary{flex:0 1 240px}
  @supports(height:1dvh){dialog.sheet--photo{height:100dvh;max-height:100dvh}}
}
/* At high zoom, allow a single scroll surface rather than collapsing the choices. */
@media(max-width:599px) and (max-height:540px){
  dialog.sheet--photo .photo-options-body{overflow:auto;display:block}
  dialog.sheet--photo .photo-options-body>.pvhold{padding:8px 0}
  dialog.sheet--photo .photo-options-body[data-stage="1"] .cropbox{display:grid;grid-template-columns:80px minmax(0,1fr)}
  dialog.sheet--photo .photo-options-body[data-stage="1"] .pvbox{width:min(100%,calc(90px * var(--ar,1)))}
  dialog.sheet--photo .photo-options-body[data-stage="1"] .cropmsg{text-align:left;font-size:12px}
  dialog.sheet--photo .photo-step-choices{overflow:visible;height:auto;min-height:0}
}
@media(prefers-reduced-motion:reduce){
  dialog.sheet--photo .photo-step-enter{animation:none}
}

/* Frames remain visible as their own final step. */
dialog.sheet--photo .photo-frame-options{display:grid;gap:10px;margin:14px 0 18px}
dialog.sheet--photo .photo-frame-options>.opt{margin:0;min-height:78px;padding:14px 12px}
dialog.sheet--photo .photo-frame-options .fswatch{width:48px;height:48px}
dialog.sheet--photo .photo-frame-options .odesc{font-size:13px;line-height:1.5}

/* Paper comparison owns its dialog, scrolling area, and card layout. */
dialog.paper-compare{width:calc(100% - 40px);max-width:1100px;max-height:90vh;
  padding:0;margin:auto;border:1px solid var(--c-border);border-radius:24px;
  overflow:hidden;background:var(--c-surface);color:var(--c-text);
  box-shadow:0 18px 64px rgba(var(--brand-ink-rgb),.2)}
dialog.paper-compare::backdrop{background:rgba(var(--brand-ink-rgb),.42)}
dialog.paper-compare [hidden]{display:none!important}
dialog.paper-compare .paper-compare__in{display:flex;flex-direction:column;min-height:0;max-height:calc(90vh - 2px)}
dialog.paper-compare .paper-compare__head{display:grid;grid-template-columns:minmax(0,1fr) auto;
  align-items:start;flex-shrink:0;gap:6px 16px;padding:24px 28px 18px;border-bottom:1px solid var(--c-border)}
dialog.paper-compare .paper-compare__head>div{grid-column:1;min-width:0}
dialog.paper-compare .paper-compare__head h2{margin:0;font-size:25px;line-height:1.35;
  letter-spacing:-.03em;word-break:keep-all;overflow-wrap:anywhere}
dialog.paper-compare .paper-compare__head p{grid-column:1;margin:6px 0 0;font-size:14px;
  line-height:1.5;color:var(--c-text-sub);word-break:keep-all;overflow-wrap:anywhere}
dialog.paper-compare .paper-compare__head>button{grid-column:2;grid-row:1 / span 2;
  display:flex;align-items:center;justify-content:center;flex-shrink:0;
  width:44px;height:44px;min-width:44px;min-height:44px;padding:0;
  border:1px solid var(--c-border);border-radius:50%;background:var(--c-surface);
  color:var(--c-text);font-size:22px;line-height:1;cursor:pointer}
dialog.paper-compare .paper-compare__body{flex:1 1 auto;min-height:0;overflow:auto;
  overscroll-behavior:contain;-webkit-overflow-scrolling:touch;padding:22px 28px 26px}
dialog.paper-compare .paper-compare__status{margin:0 0 18px;font-size:14px;line-height:1.6;
  color:var(--c-text-sub);word-break:keep-all;overflow-wrap:anywhere}
dialog.paper-compare .paper-compare__status:empty{display:none}
dialog.paper-compare .paper-compare__grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px}
dialog.paper-compare .paper-compare__card{display:flex;flex-direction:column;min-width:0;
  padding:14px;border:1px solid var(--c-border);border-radius:16px;background:var(--c-surface)}
dialog.paper-compare .paper-compare__figure{display:flex;align-items:center;justify-content:center;
  width:100%;aspect-ratio:3 / 2;margin:0 0 16px;overflow:hidden;border-radius:10px;
  background:var(--c-surface-alt)}
dialog.paper-compare .paper-compare__figure img{display:block;width:100%;height:100%;
  aspect-ratio:3 / 2;object-fit:contain}
dialog.paper-compare .paper-compare__card h3{margin:0 0 8px;font-size:20px;
  line-height:1.35;letter-spacing:-.02em;word-break:keep-all;overflow-wrap:anywhere}
dialog.paper-compare .paper-compare__summary{margin:0 0 14px;font-size:15px;
  line-height:1.6;word-break:keep-all;overflow-wrap:anywhere}
dialog.paper-compare .paper-compare__price{margin:auto 0 14px;padding-top:8px;
  font-size:16px;line-height:1.5;font-weight:700}
dialog.paper-compare .paper-compare__price small{font-size:13px;font-weight:400;color:var(--c-text-sub)}
dialog.paper-compare [data-paper-choose]{display:flex;align-items:center;justify-content:center;
  gap:6px;width:100%;min-height:48px;padding:10px 14px;border:1px solid var(--c-btn-point-bg);
  border-radius:10px;background:var(--c-btn-point-bg);color:var(--brand-white);
  font:inherit;font-size:15px;font-weight:700;line-height:1.4;cursor:pointer;
  word-break:keep-all;overflow-wrap:anywhere}
dialog.paper-compare [data-paper-choose][aria-pressed="true"]{background:var(--c-surface-point);color:var(--c-text)}
dialog.paper-compare [data-paper-choose]:disabled{opacity:.5;cursor:not-allowed}
dialog.paper-compare .paper-compare__footer{display:flex;align-items:center;justify-content:flex-end;
  flex-shrink:0;gap:12px;padding:14px 28px 18px;border-top:1px solid var(--c-border);background:var(--c-surface)}
dialog.paper-compare .paper-compare__footer p{flex:1;margin:0;font-size:13px;line-height:1.5;
  color:var(--c-text-sub);word-break:keep-all;overflow-wrap:anywhere}
dialog.paper-compare .paper-compare__footer button{min-width:120px;min-height:48px;
  padding:10px 20px;border:1px solid var(--c-border);border-radius:10px;
  background:var(--c-surface);color:var(--c-text);font:inherit;font-size:15px;line-height:1.4;cursor:pointer}
dialog.paper-compare button:focus-visible{outline:3px solid var(--c-focus);outline-offset:2px}
@supports(height:1dvh){
  dialog.paper-compare{max-height:90dvh}
  dialog.paper-compare .paper-compare__in{max-height:calc(90dvh - 2px)}
}
@media(min-width:600px) and (max-width:899px){
  dialog.paper-compare .paper-compare__grid{grid-template-columns:repeat(2,minmax(0,1fr))}
  dialog.paper-compare .paper-compare__head{padding:20px 20px 16px}
  dialog.paper-compare .paper-compare__body{padding:18px 20px 20px}
  dialog.paper-compare .paper-compare__footer{padding:12px 20px 16px}
}
@media(max-width:599px){
  dialog.paper-compare{width:calc(100% - 24px);border-radius:20px}
  dialog.paper-compare .paper-compare__head{padding:16px;gap:6px 10px}
  dialog.paper-compare .paper-compare__head h2{font-size:20px}
  dialog.paper-compare .paper-compare__head p{font-size:13px}
  dialog.paper-compare .paper-compare__body{padding:16px}
  dialog.paper-compare .paper-compare__status{font-size:13px;margin-bottom:14px}
  dialog.paper-compare .paper-compare__grid{grid-template-columns:minmax(0,1fr);gap:14px}
  dialog.paper-compare .paper-compare__card{padding:12px}
  dialog.paper-compare .paper-compare__figure{margin-bottom:14px}
  dialog.paper-compare .paper-compare__card h3{font-size:19px}
  dialog.paper-compare .paper-compare__summary{font-size:14px}
  dialog.paper-compare .paper-compare__footer{flex-direction:column;align-items:stretch;gap:8px;padding:12px 16px;
    padding-bottom:max(12px,env(safe-area-inset-bottom))}
  dialog.paper-compare .paper-compare__footer button{width:100%}
}
@media(max-height:480px){
  dialog.paper-compare .paper-compare__head{padding-top:12px;padding-bottom:12px}
  dialog.paper-compare .paper-compare__head h2{font-size:20px}
  dialog.paper-compare .paper-compare__head p{font-size:12px}
  dialog.paper-compare .paper-compare__footer{padding-top:8px;padding-bottom:8px}
}

/* 🔴 2026-09-15 owner 지시로 이 단추가 종이 목록 **위**로 갔다 (options.js 종이몸).
   실측: 전에는 「원하는 사진 느낌을 골라 주세요」 줄과 첫 종이 칸 사이가 16px 였다. 단추가 그 사이에 끼었으니
   위아래를 **똑같이 16px** 로 준다 — 위 0px 로 두면 안내 줄에 달라붙었다(1차 실측). 아래 16px 은 `.sgroup` 의
   margin-top 16px 과 겹쳐(collapse) 16px 이 된다. */
dialog.sheet--photo .photo-paper-more{display:flex;align-items:center;justify-content:space-between;
  gap:12px;width:100%;min-height:48px;margin:16px 0;padding:12px 14px;
  border:1px solid var(--c-border);border-radius:12px;background:var(--c-surface);
  color:var(--c-text);font:inherit;font-size:14px;font-weight:650;line-height:1.4;cursor:pointer}
dialog.sheet--photo .photo-paper-more span{font-size:18px;font-weight:400}
dialog.sheet--photo .photo-paper-more:focus-visible{outline:3px solid var(--c-focus);outline-offset:2px}

/* Keep the recommendation readable alongside long magnetic size names on mobile. */
dialog.sheet--photo .photo-size-grid .oname .best{display:block;margin:4px 0 0;font-size:12px;line-height:1.5;white-space:normal}

.group-share-bar{display:flex;align-items:center;justify-content:space-between;gap:20px;padding:20px;margin:0 0 20px;border:1px solid var(--c-border);border-radius:var(--r-lg);background:var(--c-surface-point)}
.group-share-bar[hidden]{display:none!important}.group-share-bar strong{display:block;font-size:var(--t-lg)}.group-share-bar p{margin:6px 0 0;color:var(--c-text-sub);font-size:var(--t-sm)}.group-share-bar .btn{flex:none;min-height:48px}
.share-photo-batch__preview .cs-mini{width:100%;max-width:88px;margin:auto;flex:none}
@media(max-width:640px){.group-share-bar{flex-direction:column;align-items:stretch;gap:16px;padding:16px}.group-share-bar .btn{width:100%;white-space:normal}}

/* Keep the print preview readable throughout all four steps. */
@media(min-width:900px){
  dialog.sheet--photo{max-width:1320px;max-height:960px}
  dialog.sheet--photo .photo-options-body{grid-template-columns:minmax(0,1.25fr) minmax(340px,1fr)}
}
@media(min-width:600px){
  /* 🔴🔴 owner 신고(2026-09-17): 「맥북에서 인화 사이즈 선택하면 **아래 문구가 잘린다**」.
     실측 — 창 높이가 800 아래면 안내글이 미리보기 칸(.pvhold, overflow:auto)을 벗어난다:
       1440×782 13px · 1366×768 17px · 1280×720 27px · 1024×640 28px · 1152×640 45px
     1440×900 은 넘침 0 이라 멀쩡했다 — 그래서 창 크기에 따라 되다 안 되다 했다.
   🔴 까닭: 천장이 **56dvh** 라 창이 짧아져도 사진이 창에 비례해 줄 뿐,
      머리·차례·아래단추·안내글이 먹는 **고정 높이(약 360px)** 는 안 줄어든다.
      그래서 짧은 창일수록 남는 자리가 모자라진다. 비율이 아니라 **뺄셈**이어야 한다.
   🔴 380px = 실측한 고정 높이(327~358) + 여유. 이 값을 줄이면 다시 잘린다.
   🔴 너비로 묶는다 — `.cropv` 가 width:100%·height:auto 라 높이를 직접 주면
      그걸 무시하고 넘쳐서 **사진이 안내글을 덮는다**(같은 날 그렇게 고쳤다가 되돌렸다). */
  /* 🔴🔴 owner 지시(2026-09-19): 「사진이 크게 보였으면 좋겠다」 —
     실측으로 **안전한 최대**를 찾아 넣었다(1440×900 · 1440×782 · 1366×768 · 1280×720 · 1280×800):
        빼기 530 → 사진 278×370 · 넘침 0     (그전)
        빼기 470 → 사진 323×430 · 넘침 0     ← 여기까지 안전
        빼기 420 → 사진 360×480 · 넘침 10px  🔴 아래 문구가 잘린다
     🔴 사장님이 고르신 1.6배(592px)는 **넣을 수 없다.** 맥북(1440×782)·1366×768 처럼
        낮은 창에서 2026-09-17 에 고쳤던 「아래 문구 잘림」이 그대로 되살아난다.
     🔴 천장은 **580 그대로 둔다.** 760 으로 올려 봤더니 큰 창에서 아래 문구가 잘렸다
        (실측: 1440×1200 넘침 73px · 1920×1080 13px · 1680×1050 은 0). 580 이 그 경계다.
     🔴 단계 1(꾸미기) 을 따로 낮추던 규칙은 **없앴다** — 그 60px 은 화살표 넉 장 몫이었는데
        owner 지시로 화살표를 지웠다. 그래서 꾸미기 탭 사진이 특히 크게 늘어난다. */
  dialog.sheet--photo .photo-options-body[data-stage] .pvbox{
    width:min(100%,calc(clamp(180px,calc(100dvh - 470px),580px) * var(--ar,1)));max-width:none}
  /* 🔴🔴 owner 지시(2026-09-19): 「자리 옮기기는 그전 화면에서 하는 일이라 중복 —
     안내와 「가운데로 맞추기」를 빼고 **사진을 크게**」.
     꾸미기 탭은 이제 그림 아래에 아무 글도 없다. 그만큼 천장을 더 올린다.
     실측(1440×900 · 1440×782 · 1366×768 · 1280×720 · 1280×800):
        빼기 470 → 430px · 넘침 0   (다른 탭과 같던 값)
        빼기 400 → 500px · 넘침 0   ← 여기까지 안전
        빼기 370 → 530px · 넘침 11px 🔴
     🔴 이 값은 「그림 아래에 글이 없다」는 전제에 기대고 있다. 꾸미기 탭에 글을 다시
        넣으면 이 값부터 되돌려야 한다 — 안 그러면 그 글이 잘린다. */
  dialog.sheet--photo .photo-options-body[data-stage="1"] .pvbox{
    width:min(100%,calc(clamp(180px,calc(100dvh - 400px),580px) * var(--ar,1)));max-width:none}
  /* 🔴🔴 한 줄로 나란히 놓는 배치는 **버렸다** (2026-09-17 실측에서 잡혔다).
     높이는 아꼈지만 정렬이 무너졌다 — 맥북 1440×900 에서 안내글이 화살표와 **32px 겹치고**
     가운데에서 **389px 치우쳤다.** 사장님이 「배치·정렬·간격을 모두 보라」고 하신 자리다.
     🔴 전부 **가운데 세로쌓기**로 되돌린다. 높이는 아래 천장(clamp)으로 잡는다. */
  dialog.sheet--photo .cropmap{max-width:132px}
}
/* 🔴 짧은 창(높이 700 아래 · 폭 600 이상)에서는 「잘리는 곳」 그림을 접는다.
   여기에는 **자리가 없다**(실측 2026-09-17): 그림을 넣으면 1152×640 은 -36px,
   폰을 눕힌 844×390 은 -154px 만큼 안내글이 칸 밖으로 밀려난다.
   🔴 감사 ②에서 「폰 가로에 표시가 없다」고 빨강이 떴을 때 자리가 남는 줄 알고
      작게 보이도록 고쳤다가, 그 321px 이 **그림을 숨긴 상태의 값**이었음을 알고 되돌렸다.
      숫자를 볼 때 무엇을 잰 값인지 확인해야 한다.
   🔴 몇 %가 잘리는지는 **글로 그대로 남는다.** 세로로 든 폰(폭 600 미만)은 이 조건에
      안 걸리므로 그림을 그대로 본다 — 사장님이 보시는 화면이 그쪽이다. */
/* ── 폰에서 미리보기를 절반으로 (owner 신고 2026-09-17) ─────────────────
   「표현된 사진들이 너무 커서 **메뉴 선택이 너무 힘들다** · 사진 확인하는 창 자체를
    50% 작게 만들어 줘야 될 것 같다」
   실측(운영, 아이폰 393×852):
     정사각 사진 → 미리보기 칸이 창의 **50%**(428px) · 고를 것이 **4/8**만 보였다
     세로  사진 → 같음
     가로  사진 → 37%(311px) · 6/8
   🔴 천장을 **높이**로 건다. 너비로 묶어야 `.cropv`(width:100%·height:auto)가 따라온다 —
      높이를 직접 주면 그걸 무시하고 넘쳐서 글을 덮는다(같은 날 그 사고를 한 번 냈다).
   🔴 180px 은 지금의 절반쯤이다(358 → 180). 짧은 폰에서는 뺄셈으로 더 줄어든다.
   🔴 PC 는 건드리지 않는다 — 거기는 미리보기가 옆 칸에 따로 서 있다. */
/* 🔴 폰을 눕혔을 때(844×390 같은 아주 낮은 창)만 사진 천장을 더 낮춘다.
   안 낮추면 안내글이 10px 밀려 잘린다(2026-09-17 감사 ②에서 잡음).
   🔴 경계를 **520px** 로 잡는다. 처음에 700px 로 잡았더니 1152×640 같은 창까지 걸려
      사진이 오히려 커지고 안내글이 14px 잘렸다 — 고치려다 다른 데를 깨뜨린 것이다. */
@media(min-width:600px) and (max-height:520px){
  dialog.sheet--photo .photo-options-body[data-stage] .pvbox{
    width:min(100%,calc(clamp(96px,calc(100dvh - 300px),220px) * var(--ar,1)))}
  dialog.sheet--photo .photo-options-body[data-stage="1"] .pvbox{
    width:min(100%,calc(clamp(88px,calc(100dvh - 340px),220px) * var(--ar,1)))}
  dialog.sheet--photo .photo-options-body>.pvhold{padding:16px}
}
@media(max-width:599px){
  dialog.sheet--photo .photo-options-body{display:block;overflow:auto;overscroll-behavior:contain}
  dialog.sheet--photo .photo-options-body>.pvhold{padding:16px 0;overflow:visible}
  dialog.sheet--photo .photo-options-body[data-stage] .cropbox{display:flex;flex-direction:column;align-items:center;gap:12px}
  /* 🔴🔴 owner 신고(2026-09-17): 「표현된 사진들이 너무 커서 **메뉴 선택이 너무 힘들다**.
     사진 확인하는 창 자체를 **50% 작게**」.
     실측(운영 · 아이폰 393×852): 천장이 42dvh 라 정사각·세로 사진에서 미리보기 칸이
     창의 **50%**(428px)를 먹고 **고를 것이 4/8**만 보였다. 가로 사진은 37%·6/8.
   🔴 천장을 **절반**으로 내린다: 42dvh → 21dvh (그리고 420px → 210px).
      아이폰 852 기준 358 → 179 로, 말씀하신 「50% 작게」에 맞춘다.
   🔴 너비로 묶는다 — `.cropv` 가 width:100%·height:auto 라 높이를 직접 주면
      그걸 무시하고 넘쳐서 안내글을 덮는다(같은 날 그 사고를 한 번 냈다).
   🔴 **여기가 폰에서 실제로 이기는 규칙이다.** 다른 데 천장을 적어도 이 줄이 덮는다 —
      처음에 다른 자리에 적었다가 아무 변화가 없었다. 고칠 때는 이 줄을 고친다. */
  dialog.sheet--photo .photo-options-body[data-stage] .pvbox{width:min(100%,calc(min(21dvh,210px) * var(--ar,1)));max-width:none;grid-column:auto;grid-row:auto}
  dialog.sheet--photo .photo-options-body[data-stage] .photo-preview-caption{text-align:center}
  dialog.sheet--photo .photo-options-body[data-stage] .cropmsg{text-align:center;font-size:13px}
  dialog.sheet--photo .photo-step-choices{height:auto;min-height:0;overflow:visible;padding:16px 0 24px}
}

dialog.sheet--photo .photo-editor-footer .photo-bulk{flex:1 1 150px;min-width:0;font-size:14px}
@media(max-width:599px){dialog.sheet--photo .photo-editor-footer:has(.photo-bulk) .photo-prev{flex:0 0 54px;padding-inline:4px}dialog.sheet--photo .photo-editor-footer .photo-bulk{flex:1 1 0;font-size:13px;padding-inline:8px}dialog.sheet--photo .photo-editor-footer:has(.photo-bulk) .photo-primary{font-size:13px;padding-inline:8px}}

/* Programmatically focused step headings are not interactive controls. */
dialog.sheet--photo #photo-step-heading[tabindex="-1"]:focus{outline:none}
dialog.sheet--photo .photo-warning{margin:12px 0 16px;padding:12px 14px;
  border:1px solid var(--c-border);border-radius:10px;
  background:var(--c-surface-point);color:var(--c-text-sub)}

/* Color feedback without moving the bulk action. */
dialog.sheet--photo .photo-bulk{background:var(--c-surface-point);transition:background-color .2s ease,color .2s ease,border-color .2s ease}
@media(hover:hover){
  dialog.sheet--photo .photo-bulk:not(:disabled):hover{background:var(--c-btn-point-bg);color:var(--c-btn-point-fg);border-color:var(--c-btn-point-bg)}
}
dialog.sheet--photo .photo-bulk:not(:disabled):focus-visible{background:var(--c-btn-point-bg);color:var(--c-btn-point-fg);border-color:var(--c-btn-point-bg)}
@media(prefers-reduced-motion:reduce){
  dialog.sheet--photo .photo-bulk{transition:none}
}

/* ── 115 필름 효과 · 일회용 카메라 날짜 각인 ────────────────────────────
   🔴 owner 지시(2026-09-15): 「효과 자체를 클릭하면되게끔」
     그래서 **그림이 곧 단추**다. 이름표는 그림 밑에 붙는 설명일 뿐이다.
   🔴 고른 표시는 색만으로 안 알린다 — 테두리 폭 고르개(.mopt)와 같은 규칙으로
     테두리 색이 바뀌고 이름 뒤에 ✓ 가 붙는다 (options.css 위쪽 .mopt 규칙을 그대로 탄다). */
.fopt{padding:var(--s2);gap:var(--s2)}
.fopt .fpv{position:relative;display:block;border-radius:3px;overflow:hidden;
  box-shadow:0 0 0 1px rgba(var(--brand-ink-rgb),.12) inset}
.fopt .fpv i{position:absolute;inset:0;display:block}
/* 🔴 누를 수 있다는 것이 보여야 한다 — 그림 자체가 단추이기 때문이다. */
.fopt:hover .fpv{box-shadow:0 0 0 1px rgba(var(--brand-ink-rgb),.28) inset}
.fopt[aria-pressed="true"] .fpv{box-shadow:0 0 0 2px var(--c-btn-point-bg) inset}
/* 🔴🔴 owner 지시(2026-09-20): 「왜 위쪽 한 칸을 비워놨어?」
   까닭은 고른 칸 **이름 뒤의 ` ✓`** 였다. 라벨이 길어지면 칸이 그만큼 넓어져
   (실측 98 vs 90) 첫 줄이 1px 넘치고 다섯째가 다음 줄로 밀린다.
   → 이름은 그대로 두고 **`✓` 만 그림 위로 옮긴다.** 라벨 길이가 같아져 칸이 고르게
     서고, 「색만으로 알리지 않는다」는 집 규칙도 모양(✓)으로 그대로 지킨다.
   🔴 `.mname::after` 를 끄는 것은 **필름 칸(.fopt)에서만**이다. 테두리 폭
      고르개(.mopt)는 칸이 넷뿐이라 넓어져도 줄이 안 밀린다 — 거기 ✓ 는 그대로 둔다. */
.fopt[aria-pressed="true"] .mname::after{content:none}
.fopt[aria-pressed="true"] .fpv::after{content:"✓";position:absolute;right:3px;bottom:3px;
  display:grid;place-items:center;width:18px;height:18px;border-radius:50%;
  background:var(--c-btn-point-bg);color:#fff;font-size:12px;font-weight:700;line-height:1;
  box-shadow:0 1px 3px rgba(var(--brand-ink-rgb),.35)}

/* 큰 미리보기 위의 날짜 — 사진 칸 안에만 얹는다 (매트 위가 아니다) */
.cropv-stamp{position:absolute;display:block;pointer-events:none}
.cropv-stamp .stampsvg{display:block;width:100%;height:100%}

/* 날짜 고르는 칸 */
/* ── 날짜 넣기 카드 (owner 지시 2026-09-20) ──────────────────────────────
   「이쪽 디자인도 깔끔하고 위랑 어울리도록」 — 이제 「사진 테두리」·「필름 효과」와
   **같은 접는 카드**(.photo-extra)다. 카드의 테·둥글기·머리 모양은 그 규칙을 그대로 탄다.
   여기서는 카드 **안쪽**만 다듬는다. */
/* 🔴 보기는 **실제 인화되는 모습**으로 그린다 — `각인SVG()` 가 film.py 와 같은 셈법으로
   7세그먼트를 그린다. 사진 모서리처럼 어두운 칸 위에 얹어야 주황이 제 색으로 보인다
   (밝은 바탕에 주황을 놓으면 인화물과 다른 인상을 준다). */
/* 🔴🔴 **사진 모서리를 확대해 보여 준다.** 각인 높이는 사진 짧은 변의 4.2% 라
   (film.py 와 같은 값), 실제 비율로 그리면 칩이 571px 높이여야 글자가 24px 이 된다 —
   그래서 칩 안에 640×427 짜리 사진을 그려 넣고 **오른쪽 아래 귀퉁이만** 창처럼 보여 준다.
   자리·색·글자 모양은 인화와 같고, 크기만 확대된 것이다 (안 그러면 2.6px 이라 안 보인다). */
.photo-extra--stamp .film-stamp-chip{position:relative;display:block;
  width:min(220px,100%);height:64px;margin:10px 0 0;
  border-radius:10px;overflow:hidden;background:var(--brand-ink);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.10)}
.photo-extra--stamp .film-stamp-chip svg{position:absolute;right:0;bottom:0;
  width:640px;height:427px}
.film-stamp .film-stamp-on,
.photo-extra--stamp .film-stamp-on{display:flex;align-items:center;gap:var(--s2);
  min-height:var(--tap);cursor:pointer}
.film-stamp .film-stamp-eg{color:var(--c-text);font-variant-numeric:tabular-nums}
.film-stamp .film-stamp-date{display:flex;align-items:center;gap:var(--s2);
  margin-top:var(--s2);flex-wrap:wrap}
.film-stamp .film-stamp-date>span{font-size:var(--t-cap);color:var(--c-text-sub)}
.film-stamp .film-stamp-date input[type="date"]{font:inherit;color:var(--c-text);
  background:var(--c-surface);border:2px solid var(--c-border);border-radius:var(--r-md);
  padding:10px 12px;min-height:var(--tap)}
.film-stamp .film-stamp-date input[type="date"]:focus-visible{outline:3px solid var(--c-focus);outline-offset:2px}

/* 🔴 넷을 **나란히 견주는** 칸이라 줄이 어긋나면 안 된다. 폰(≤520px)에서는
   2×2 로 반듯하게 세운다 — 셋+하나로 접히면 마지막 하나가 혼자 떨어져
   「이건 다른 거구나」로 읽힌다 (실측 430px 화면). */
@media (max-width: 520px){
  /* 🔴🔴 2026-09-16 — 여기가 `.mrow:has(.fopt)` 였다. `:has()` 는 이 집 손님 화면
     바닥선(사파리 15.4)에 **없다.** 그 화면에서는 이 줄이 통째로 무시돼 2칸 격자가
     안 서고 「셋+하나」로 접혔다 — 바로 위 주석이 막으려던 그 모습이다.
     톤 격자에 `mrow--film` 이름을 붙여 이름으로 고른다. */
  .mrow--film{display:grid;grid-template-columns:1fr 1fr}
  /* 🔴 격자에서는 flex 의 `flex:0 0 100%` 가 안 먹는다 — 칸 전체를 가로지르게 한다. */
  .mrow--film .fstr-slot{grid-column:1 / -1}
  .fopt{width:100%}
  .fopt .fpv{width:100%!important;height:auto!important;aspect-ratio:var(--fpv-ar, 3 / 2)}
}

/* 고른 톤의 설명 한 줄 — 칸마다 붙이면 목록이 두 배로 길어진다 */
.film-now{margin:var(--s2) 0 0;text-align:center}
.film-now b{color:var(--c-text)}

/* ── 필름 농도 일자선 · 폰 팝업 (owner 지시 2026-09-16) ──────────────────────
   「바로 아래 일자선으로 0~200%」 · 「모바일은 … 파업창열어서 … 실시간으 사진이 변하는걸」
   🔴 슬라이더 모양은 이 집에 이미 있는 것을 따른다(collage/studio.css 의 .cs-range):
      높이 44px · accent-color 로 색만 맞춘다. 손톱(thumb)을 직접 그리지 않는다 —
      브라우저마다 다르게 그려지고 사파리 15.4 에서 손톱이 사라진 전례가 있다.
   🔴 :has()·컨테이너 질의를 쓰지 않는다 (손님 화면 바닥선 사파리 15.4). */
.fstr{display:grid;gap:6px;margin-top:14px}
.fstr-head{font-weight:600;display:flex;align-items:center;gap:8px}
.fstr-head b{font-variant-numeric:tabular-nums;color:var(--c-text-brand,var(--c-btn-point-bg))}
/* 🔴 숫자 폭을 고정한다(tabular-nums + min-width) — 안 하면 100%→95% 로 끌 때
   글자 폭이 바뀌며 일자선이 좌우로 흔들려 손가락이 따라가지 못한다. */
.fstr-head b{min-width:3.6em;display:inline-block}
.fstr input[type=range]{width:100%;height:44px;accent-color:var(--c-btn-point-bg);
  background:transparent;margin:0}
.fstr input[type=range]:focus-visible{outline:3px solid var(--c-focus);outline-offset:2px}
.fstr-hint{margin:2px 0 0}

/* 🔴🔴 owner 지시 2026-09-16: 「모바일에 이건 없애도되잖아 클릭하면 팝업으로 조정이되니까」
   폰에서는 일자선을 **안 보여 준다.** 톤을 누르면 팝업이 열리고 거기에 큰 사진과
   일자선이 함께 있으니, 여기 것은 자리만 먹고 같은 것을 두 번 묻는 셈이다.
   🔴 숨기는 일을 **CSS 가** 한다. JS 에서 화면 폭을 보고 안 그리면 폰을 돌리거나
      창을 넓혔을 때 다시 안 그려진다 (render() 는 창 크기 변화로 안 돈다).
   🔴 `display:none` 이라 일자선은 초점도 못 받고 스크린리더에도 안 잡힌다 —
      숨긴 조작칸이 탭 순서에 남는 사고가 안 난다.
   🔴 대신 한 줄(.fstr-tap)을 남긴다. 통째로 없애면 지금 농도가 몇인지 알 자리가 없고
      (접힌 칸 제목은 펼치면 안 보인다) 팝업이 있다는 것도 모른다.
   🔴 폭 기준을 768px 로 맞춘다 — options.js 의 팝업 여닫이(matchMedia)와 **같은 수**다.
      두 수가 갈라지면 그 사이 폭에서 일자선도 팝업도 없는 틈이 생긴다. */
/* 🔴 농도 칸은 톤 격자 **안**에 있고 제 줄을 통째로 차지한다 (owner 지시 2026-09-16:
   「고른 톤 줄 바로 밑」). flex-wrap 격자에서 `flex:0 0 100%` 가 줄바꿈을 만든다.
   자리(어느 줄 밑인가)는 options.js 의 농도자리맞추기() 가 노드를 옮겨 정한다. */
.fstr-slot{flex:0 0 100%;width:100%;display:grid;gap:6px}
.fstr-tap{display:none;margin:2px 0 0}
.fstr-tap b{font-variant-numeric:tabular-nums;color:var(--c-text-brand,var(--c-btn-point-bg))}
/* 🔴🔴 2026-09-16 사고 — 여기가 `.fstr,.fstr-hint` 였다. **팝업 안의 일자선도 같은
   이름**이라 폰에서 팝업 것까지 사라졌고, 「이 농도로」 단추만 남아 농도를 아예 못
   바꾸게 됐다. 손님은 100% 밖에 고를 수 없었다 — 기능이 통째로 죽은 것이다.
   숨길 것은 **칸 안의 것뿐**이므로 `--inline` 만 고른다.
   🔴 :has() 로 「팝업 밖의 것」을 고르지 않는다 (바닥선 사파리 15.4 — 규칙이 통째로
      무시되면 다시 팝업 것까지 보이거나 칸 것이 안 숨는다). 이름으로 가르는 쪽이 안전하다. */
@media (max-width:768px){
  .fstr--inline,.fstr-hint--inline{display:none}
  .fstr-tap{display:block}
}

/* 폰 팝업 — 사진이 위, 일자선이 바로 아래 */
.fstr-sheet .sbody{padding-top:12px}
/* 🔴 사진은 화면 높이의 절반까지만 — 더 크게 두면 일자선이 접혀 내려가 사장님이
   지적한 「드레그해서 위로 올려서 봐야」가 팝업 안에서 되풀이된다. */
.fstr-photo{display:block;width:100%;max-height:46dvh;border-radius:12px;overflow:hidden;
  background:var(--c-surface-alt);margin:0 auto}
.fstr-photo>i{display:block;width:100%;height:100%}

/* ── 크기 칸 세로 가운데 맞추기 (owner 지시 2026-09-19 ②) ──────────────────
   「칸 안쪽에 내용들이 세로의 가운데 정렬해줘야 되는 거 아니야?」
   🔴 화질 글이 사진창으로 나가면서 quality 줄은 **비어 있다**. 높이는 0 이 되는데
      격자의 **행 간격 2px 은 그대로 남아** 아래쪽에만 붙는다 — 실측 위 15 / 아래 17.
      2px 이라 눈으로는 「위로 쏠렸다」로 읽힌다.
   🔴 그래서 행 간격을 0 으로 두고, 필요한 간격은 **각 줄이 제 margin 으로** 갖는다.
      빈 줄은 margin 도 없으니 아무것도 안 남는다 → 어느 폭에서도 위 = 아래.
   🔴 이 세 줄은 **파일 맨 끝**에 둔다. 위쪽 미디어쿼리들이 `gap:2px 6px` 로 행 간격을
      다시 넣는데(1116·1162줄), 같은 특이도면 **나중에 쓴 쪽이 이긴다.** 미디어쿼리는
      특이도를 올리지 않는다 — 그래서 한 자리에서 세 곳을 다 덮는다. */
dialog.sheet--photo .photo-size-grid .opt{row-gap:0}
dialog.sheet--photo .photo-size-grid .odesc{margin-top:2px}
dialog.sheet--photo .photo-size-grid .oright{margin-top:7px}

/* ── 마우스로 눌렀을 때는 검은 초점 테를 안 보인다 (owner 신고 2026-09-19) ────────
   「왜 테두리 블랙이 자꾸 나오는 거야?」 — `--c-focus` 가 `--brand-ink`(rgb 43,5,20)라
   거의 검정이다. 까닭과 두 가지 발생 경로는 options.js 의 `입력방식()` 첫머리에 적었다.
   🔴🔴 `!important` 를 쓴다. 안 쓰고 (0,2,1) 로 두었더니 **팝업 닫기 단추에서 졌다** —
      `design/glass.css` 93줄에 `:root body :is(dialog.sheet,…) :is(.sx,.dclose,…):focus-visible`
      이라는 **(0,4,2)** 짜리 규칙이 있다(CDP 로 확인). 특이도를 거기 맞춰 올리면
      그 목록이 바뀌는 날 다시 진다 — 「가리키개로 왔으면 초점 테는 없다」는 뜻 자체를
      한 줄로 못 박는 편이 정직하다. glass.css 는 공유 파일이라 안 건드린다.
   🔴 **글쇠를 누르는 순간 돌아온다.** 표(`data-mouse`)가 떨어지기 때문이다.
   🔴 집에 `header-focus.css` 의 `html[data-header-input="pointer"]` 라는 같은 뜻의 표가
      있지만 **그 값을 켜 주는 코드가 어디에도 없다**(전수 훑음 0건). 죽은 규칙에
      얹지 않고 이 화면이 제 표를 든다. */
html[data-mouse] :focus-visible{outline:none!important}

/* ── 폰: 미리보기 판 아래 모서리와 그림자 (owner 지시 2026-09-20) ────────────
   「사진 아래의 백그라운드 하단의 모서리 둥글게 해주고 그 아래로 그림자 효과 좀,
    좀 더 진하게」

   🔴 실측 — 이 판(`.pvhold`)은 **PC 에서는 이미 둥글다(18px).** 폰만 0 이라
      아래가 1px 실선으로 뚝 끊겨 있었다. 그래서 폰을 PC 와 같은 18px 로 맞춘다.
      (태블릿 600~899 도 이미 14px 짜리 카드다 — 폰만 빠져 있었다)
   🔴 위 모서리는 안 둥글린다. 이 판은 `position:sticky; top:0` 이라 위가 창에 붙는다 —
      거기를 둥글리면 굴릴 때 위쪽에 빈 모서리가 생겨 떠 보인다.
   🔴 **inset 흰 줄을 같이 적는다.** box-shadow 는 속성 하나라, 그림자만 적으면
      유리 느낌을 내던 `inset 0 1px 0 rgba(255,255,255,.35)` 가 통째로 사라진다.
   🔴 두 겹으로 준다 — 멀리 퍼지는 것(진하게)과 바짝 붙는 것(경계). 한 겹만 쓰면
      진하게 할수록 뿌옇게만 번지고 판의 끝이 어디인지 안 보인다.
   🔴 `.photo-options-body` 가 `overflow:auto` 지만 그림자는 그 **안쪽**에 그려져
      잘리지 않는다(판이 통 안에 있다). 실측으로 확인했다.
   🔴🔴 선택자가 길어 보이는 까닭 — `design/glass.css` 에
      `:root body dialog.sheet--photo .photo-options-body > .pvhold` **(0,4,2)** 가
      `box-shadow: inset …` 를 박아 둔다. 짧게 쓰면 둥글기만 먹고 **그림자는 진다**
      (실제로 한 번 그렇게 내고 CDP 로 찾아냈다). 그래서 같은 앞머리에 `.pvhold` 를
      한 번 더 붙여 (0,5,2) 로 올린다 — `!important` 는 안 쓴다. 공유 파일인
      glass.css 는 안 건드린다. */
@media(max-width:599px){
  :root body dialog.sheet--photo .photo-options-body>.pvhold.pvhold{
    border-bottom-left-radius:18px;border-bottom-right-radius:18px;
    box-shadow:inset 0 1px 0 rgba(255,255,255,.35),
               0 14px 22px -8px rgba(var(--brand-ink-rgb),.34),
               0 3px 7px -3px rgba(var(--brand-ink-rgb),.20)}
}

/* ── 액자 고르개 — 액자 하나가 한 덩이 (owner 지시 2026-09-20) ──────────────────
   「모바일·PC 둘 다 이상하다 · 테두리 해야 되나 · 사진·영상 보기 한 개로」
   까닭과 바뀐 구조는 options.js 의 `액자덩이` 첫머리에 실측과 함께 적어 두었다.
   🔴 테·둥글기는 위 카드들(.photo-extra)과 **같은 1px · 14px** 이다 — 한 화면 안에서
      경계가 두 가지 굵기로 갈리면 그것만으로 어수선해 보인다.
   🔴 고른 액자 덩이는 테 색과 바탕으로 눈에 띄게 하고, 그 안에서 **어느 색을 골랐는지**는
      색칸이 따로 보여 준다(테 + ✓). 색만으로 알리지 않는다는 집 규칙 그대로다. */
/* 🔴🔴 owner 지적(2026-09-20): 「배경이 글라스 왜 아니야?」 — 맞다. 내가 `--c-surface`(불투명
   흰색)를 줘서 이 덩이만 유리가 아니었다. 집 유리는 `design/glass.css` 가 토큰으로 갖고 있고
   (`--glass-control` 등은 `:root` 에 있어 backdrop-filter 가 없는 브라우저에도 값이 있다),
   `.opt`·`.photo-extra` 는 그 목록에 들어 있는데 **새로 만든 `.frameblock`·`.fcolor` 는
   그 목록에 없어서** 아무것도 안 입었다. 같은 토큰을 그대로 쓴다 —
   숫자를 베끼지 않는다(베끼면 집 색이 바뀌는 날 여기만 남는다).
   🔴 glass.css 는 공유 파일이라 안 건드린다. 그 목록에 이름을 넣는 대신 값을 가져다 쓴다. */
dialog.sheet--photo .frameblock{border:1px solid var(--glass-control-edge);border-radius:14px;
  background:var(--glass-control);box-shadow:inset 0 1px 0 rgba(255,255,255,.22);
  padding:12px;display:grid;gap:10px}
dialog.sheet--photo .frameblock--on{border-color:var(--c-btn-point-bg);
  background:var(--glass-control-selected);box-shadow:inset 0 0 0 1px var(--c-btn-point-bg)}
dialog.sheet--photo .frameblock-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
dialog.sheet--photo .frameblock-name{font-size:15px;font-weight:700;line-height:1.3}
dialog.sheet--photo .frameblock-price{font-size:14px;font-weight:700;color:var(--c-text);
  margin-left:auto;white-space:nowrap}
/* 🔴 「사진·영상 보기」는 **줄을 통째로 차지한다.** 값 옆에 끼우면 폰(360px)에서
   액자 이름이 두 줄로 접힌다 — 실측으로 확인하고 제 줄로 내렸다. */
dialog.sheet--photo .frameblock-head .frame-detail-link{flex:1 0 100%;order:9;margin:0}
dialog.sheet--photo .frameblock-colors{display:flex;flex-wrap:wrap;gap:8px}
/* 🔴 색칸은 **색만** 보여 준다. 액자 이름·값은 머리가 한 번씩 말했다. */
/* 🔴 **유리 위에 유리를 겹치지 않는다.** 겉 덩이가 이미 반투명이라 안쪽 칸까지
   반투명을 칠하면 두 겹이 쌓여 뿌옇게 밝아진다. 집도 같은 자리에서 같은 답을 쓴다 —
   `glass.css` 130줄이 `.frame-choice-with-details` 안의 안 고른 칸을 `transparent` 로 둔다.
   그대로 따라간다: 안 고른 색칸은 테만, 고른 칸만 유리색이 든다. */
dialog.sheet--photo .fcolor{display:grid;justify-items:center;gap:6px;
  min-width:78px;padding:6px 6px 8px;
  border:1px solid var(--glass-control-edge);border-radius:12px;background:transparent;
  color:var(--c-text);font:inherit;cursor:pointer;
  transition:background-color 160ms ease,border-color 160ms ease}
dialog.sheet--photo .fcolor[aria-pressed="true"]{border-color:var(--c-btn-point-bg);
  background:var(--glass-control-selected);box-shadow:inset 0 0 0 1px var(--c-btn-point-bg)}
@media(hover:hover){
  dialog.sheet--photo .fcolor:not(:disabled):not([aria-pressed="true"]):hover{
    background:var(--glass-control-hover);border-color:rgba(63,48,57,.32)}
}
dialog.sheet--photo .fcolor:disabled{opacity:.5;cursor:default}
/* 🔴 그림 자리는 사진이 덮으므로 바탕이 거의 안 보인다. 사진을 못 받았을 때만
   보이는 자리라 **옅은 유리**로 둔다 — 불투명 회색을 두면 그 한 칸만 유리가 아니다. */
dialog.sheet--photo .fcolor-pv{display:block;width:60px;height:60px;border-radius:8px;
  overflow:hidden;background:var(--glass-control);
  box-shadow:inset 0 0 0 1px rgba(var(--brand-ink-rgb),.10)}
dialog.sheet--photo .fcolor-pv img,
dialog.sheet--photo .fcolor-pv i{display:block;width:100%;height:100%;object-fit:cover}
dialog.sheet--photo .fcolor-name{font-size:13px;font-weight:700;line-height:1.3;
  word-break:keep-all}
dialog.sheet--photo .fcolor[aria-pressed="true"] .fcolor-name::after{content:" ✓";
  color:var(--c-text-brand)}

/* ④ 내 벽에 걸어 보기 — 손님 사진으로(2026-10-01). 고른 액자 칸 안 **색 칸 아래** 맨 끝 한 줄
   (머리에 두면 줄이 생기는 순간 방금 누른 색 칸이 밀렸다 — 구현 감사 B 🔴3). 받는 중엔 [hidden] 자리표만(자리 0).
   🔴 사파리 15.4 바닥선 — color-mix · 중첩 · :has() 없음 */
dialog.sheet--photo .frameblock>.frame-ar{margin:0;min-width:0}
dialog.sheet--photo .frame-ar[hidden]{display:none!important}
dialog.sheet--photo .frame-ar-btn{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;min-height:44px;margin:0;
  padding:10px 14px;border:1.5px solid var(--brand-ink,#2B0514);border-radius:12px;background:#fff;color:var(--brand-ink,#2B0514);
  font:inherit;font-size:15px;font-weight:700;line-height:1.3;text-decoration:none;cursor:pointer}
dialog.sheet--photo .frame-ar-btn svg{flex:none}
/* 「AR」 작은 표시 — 누르면 카메라가 켜진다는 걸 미리 알린다(사장님 10-02 새벽 「내 벽에 걸어 보기 AR」) · 이름(방침 「내 벽에 걸어 보기」)은 그대로 */
dialog.sheet--photo .frame-ar-tag{flex:none;font-size:11px;line-height:1;font-weight:800;letter-spacing:.04em;padding:3px 6px;border:1.5px solid currentColor;border-radius:999px}
dialog.sheet--photo .frame-ar-btn[aria-disabled="true"]{opacity:.6;cursor:progress}
dialog.sheet--photo .frame-ar-btn:focus-visible{outline:3px solid var(--brand-ink,#2B0514);outline-offset:2px}
dialog.sheet--photo [data-frame-ar-anchor]{display:none!important}
dialog.sheet--photo .frame-ar-note{margin:6px 2px 0;font-size:13px;line-height:1.5;color:var(--c-text-sub,#472C35);overflow-wrap:anywhere}
dialog.sheet--photo .frame-ar-more{color:inherit;font-weight:700;text-decoration:underline;text-underline-offset:2px;white-space:nowrap}
dialog.sheet--photo .frame-ar-more:focus-visible{outline:3px solid var(--brand-ink,#2B0514);outline-offset:2px;border-radius:2px}
/* 안드로이드 크롬 화면 안 AR(10-01 밤) — 3D 칸은 숨기지 않는다(AR 화면 위 닫기 단추가 이 칸 안에서 나온다)
   🔴 부품이 칸 구석에 그리는 AR 아이콘은 숨긴다 — 우리 단추의 막음(여는 중·켜짐·잠김·4초)을 비켜 activateAR 을 바로 부른다(시험 화면 감사 A 🔴1) */
dialog.sheet--photo .frame-ar .ar-xr{display:block;width:100%;height:220px;margin:8px 0 0;background:var(--c-bg,#fff);border-radius:12px;--ar-button-display:none}
dialog.sheet--photo .frame-ar-state{margin:6px 2px 0;font-size:13px;line-height:1.5;font-weight:600;color:var(--c-text,#2B0514);overflow-wrap:anywhere}
dialog.sheet--photo .frame-ar-state:empty{margin:0}   /* 숨기지 않는다 — role=status 를 읽기 프로그램이 놓치지 않게(감사 A 🟡5) */
