/* 사진 올리기 — 🔴 tokens.css 변수만 쓴다. 색·크기를 직접 박지 않는다. */

/* ── 사진 고르는 자리 ─────────────────────────────────────
   🔴 손가락으로 누를 자리를 크게 잡는다. 첫 화면의 유일한 행동이다. */
/* 🔴🔴 2026-08-14 (owner 지시: 통일감) — 점선 회색 상자를 **흰 카드**로 바꿨다.
   다른 화면(장바구니·고르기·관리자)이 전부 흰 카드인데 여기만 점선이라 홀로 튀었다.
   끌어놓기는 그대로 된다 — `.drop.over` 가 받는다. */
.drop{border:1px solid var(--c-border);border-radius:var(--r-lg);
  padding:var(--s5);text-align:left;margin:var(--s5) 0;
  /* 🔴 뒤에 있던 `background:var(--c-surface-soft)` 가 흰 카드를 덮어써 회색으로 만들었다.
     한 규칙에 background 를 두 번 적어 두었던 것 — 하나로 정리한다. */
  background:var(--c-surface);
  box-shadow:0 1px 3px rgba(var(--brand-ink-rgb),.05);
  transition:border-color var(--m-base) var(--m-ease),
             background var(--m-base) var(--m-ease)}
.drop.over{border-color:var(--c-btn-point-bg);background:var(--c-surface-point)}
.drop-t{font-size:var(--t-lg);font-weight:700;margin-bottom:var(--s2)}
.drop .btn{margin-top:var(--s5)}

/* ── 전체 설정 ────────────────────────────────────────────
   owner 결정: 10~30장 기준. "전부 같은 크기로" 가 기본이고 개별 변경은 예외다. */
.bulk .opts{display:grid;gap:var(--s3);margin-top:var(--s4)}
@media (min-width:600px){ .bulk .opts{grid-template-columns:repeat(3,1fr)} }
.bulk .field{margin-bottom:0}
/* 🔴 select 는 16px 미만이면 iOS 가 화면을 확대한다 */
select.input{font-size:var(--t-body);appearance:auto}

/* ── 사진 격자 ────────────────────────────────────────────
   모바일 3열 · 태블릿 4열 · PC 6열. 30장을 한눈에 보는 게 목적이다.
   🔴 아주 좁은 폰(~359px)에서는 2열로. 3열이면 한 칸이 88px 밖에 안 돼
      수량 버튼과 사진이 모두 답답해진다. */
/* ── 사진 격자 ─────────────────────────────────────────────
   🔴 owner 지시(2026-08-02): 「사진이 좀 더 예쁘고 심플하게, 가로 세로가 잘 정렬되면」

   그전 문제: 격자 칸이 모두 같은 폭이라, 세로 사진은 길고 가로 사진은 납작해서
   **한 줄의 아래가 들쭉날쭉**했다. 정사각형으로 잘라 맞추면 인물의 머리가 잘렸다.

   🔴 그래서 「줄맞춤(justified)」으로 간다 — 구글 포토·플리커가 쓰는 방식이다.
     · 한 줄 안의 사진은 **높이가 모두 같다**
     · 폭은 사진 원래 비율대로 — 가로 사진은 넓게, 세로 사진은 좁게
     · 줄 끝이 화면 오른쪽에 딱 맞는다
   결과: 자르지 않으면서도 줄이 반듯하다.

   🔴 어떻게 되는가 (계산)
     각 칸에 flex-grow 와 flex-basis 를 **둘 다 비율(--ar)에 비례**해서 준다.
     그러면 남은 자리가 비율대로 나뉘어 폭_i ∝ 비율_i 가 정확히 성립하고,
     높이_i = 폭_i / 비율_i 는 **한 줄에서 상수**가 된다.
     한쪽만 비례시키면 (예: grow 를 전부 1) 높이가 어긋난다.

   🔴 --base 는 「줄 높이의 기준」이다. 크면 사진이 크고 한 줄에 적게 들어간다. */
/* 🔴 2026-08-05 — 칸 폭을 하나로 맞춰 봤다가 **사장님 지시로 되돌렸다.**
     「옛날 방식이 좋지. 가로 사진도 있고 세로 사진도 있잖아」
     맞는 말이다. 폭을 맞추려면 사진 가장자리를 잘라야 하는데,
     가로·세로가 섞인 사진첩에서는 잘리는 양이 사진마다 크게 다르다.
     → **자르지 않는 줄맞춤(justified)** 으로 되돌린다. 폭이 제각각인 것은 그 값이다.
     🔴 다만 **정렬은 되돌리지 않는다** — 제목과 사진 격자의 왼쪽 선을 맞춘 것(본문 760px 안)은
        그대로 둔다. 그건 자르기와 상관없는 별개의 고침이었다. */
/* 🔴🔴 owner 지적(2026-08-24): 「크기 맞춤이 잘 안 맞잖아」 — 마지막 남은 어긋남이 여기였다.
   flex 기본값은 `align-items:stretch` 라, 한 줄에서 **제일 큰 칸의 높이까지 다른 칸이 늘어난다.**
   사진 높이는 줄맞춤이 이미 맞춰 주므로, 늘어난 만큼은 전부 **설정줄 글자 수 차이**다:
     「4×6 · 반광택 · 기본 액자 · 화이트」는 폰에서 두 줄로 접히고 「4×6 · 광택」은 한 줄이다.
   그 차이가 짧은 쪽 칸 **아래 빈 자리**로 남았다 (실측 폰390 18px · 폰320 40px).
   → 칸을 늘리지 않는다. 카드는 제 내용만큼만 서고, 아래가 한 줄만큼 들쭉날쭉해진다.
   🔴 PC 는 **한 픽셀도 안 바뀐다** (실측 1440: 켜나 끄나 칸 높이 402·402·402 그대로).
      글이 한 줄에 들어가는 폭에서는 애초에 늘어날 일이 없기 때문이다.
   🔴 사진 크기는 어디서도 안 바뀐다 (세 화면 전수 대조 — 사진 높이 전부 같음). */
.grid{list-style:none;display:flex;flex-wrap:wrap;gap:var(--s3);margin:var(--s5) 0;
  align-items:flex-start;
  --base:105px}
/* 🔴 아주 좁은 폰(~359px)은 한 번 더 내린다.
   실측 — 320px 에서 격자가 272px 이라 105 로는 가로 사진 두 장(327px)이 안 들어가
   한 장씩 떨어졌다. 1.5 × 85 × 2 + 간격 12 = 267 ≤ 272 — 두 장이 선다.
   한 장 130px 이면 아래 「− 1장 +」 줄도 답답하지 않다 (3열 88px 은 예전에 기각됐다). */
@media (max-width:359px){ .grid{--base:85px} }
@media (min-width:600px){  .grid{--base:150px} }
@media (min-width:1024px){ .grid{--base:230px} }
/* 🔴 2026-08-05 실측 — 폰 390 에서 **한 줄에 사진 한 장**뿐이었다.
     줄맞춤은 칸 폭이 `비율 × --base` 다. 가로 사진(3:2)이면 1.5 × 150 = 225px 이라
     두 장이면 462px — 격자 폭 342px 을 넘어 다음 줄로 넘어간다.
     그래서 가로 사진은 늘 한 장씩 차지했다 (세로 사진만 3장씩 들어갔다).
   → 폰 기준값을 105 로 내린다. 1.5 × 105 × 2 + 간격 12 = 327 ≤ 342 — 두 장이 선다.
     🔴 110 으로 잡았다가 342 로 **딱 맞아떨어져** 반올림 한 번에 한 장으로 떨어졌다.
        여유를 15px 둔다 — 경계에 정확히 붙이면 기기마다 결과가 갈린다. */
/* 🔴 마지막 줄이 억지로 늘어나지 않게 막는다. 사진 한 장만 남았을 때
     화면 전체 폭으로 커지면 우스꽝스럽다. 보이지 않는 채움을 하나 둔다. */
.grid::after{content:"";flex-grow:1e6}
/* 🔴🔴 owner 지시(2026-08-20): 「액자가 같은 사이즈로, 세로로 돼 있는지 가로로 돼 있는지
   — 이것뿐인데」. 줄맞춤 격자는 줄마다 높이가 달라져서, 같은 4×6 액자가
   세로 164×238 · 가로 158×110 으로 그려졌다 (실측). 실물은 같은 액자를 눕힌 것뿐이다.
   → 액자를 두른 칸(.ph--frame)은 격자 늘림에서 빼고 **실물 mm 비례**로 고정한다:
     폭 = 인화지 짧은변(101.6mm = 4×6) 기준 --base × (종이폭mm ÷ 101.6).
     세로 4×6 = 105×158, 가로 4×6 = 158×105 — 같은 네모를 돌린 것이 된다.
     5×7·A4 는 실물대로 더 크게 나온다. 큰 크기가 격자 폭을 넘으면 줄어들되(max-width)
     비율은 aspect-ratio 가 지키므로 모양은 안 깨진다. */
/* 🔴 .ph 의 flex 규칙(아래 114줄대)과 세기가 같으면 **뒤에 적힌 쪽**이 이긴다.
   이 규칙은 파일 앞쪽이라 그냥 두면 지워진다 — 겹클래스로 세기를 올려 이긴다. */
/* 🔴🔴 owner 지적(2026-08-24): 「크기 맞춤이랑 이런 것들이 잘 안 맞잖아 · 잘 맞춰질 수 없나?」
   위 방식(실물 mm 로 고정 · `flex-grow:0`)은 **액자 칸만 줄맞춤에서 빠지게** 만든다.
   그래서 옆 칸들이 남은 폭을 다 먹고, 액자 칸 혼자 작게 남았다
   (실측 PC1440: 액자 345×320 · 옆 칸 501×458 — 한 줄에 있는데 크기가 딴판이다).
   → 액자 칸도 **다른 칸과 같은 잣대로** 줄맞춤에 넣는다. 그래야 한 줄이 나란히 선다.
   🔴 사장님 선택이 2026-08-20 「실물대로 크게」에서 2026-08-24 「크기를 맞춰라」로 바뀐 것이다.
      잃는 것: 4×6 액자와 A3+ 액자가 화면에서 **같은 크기**로 보인다(비율만 다르다).
      지키는 것: 같은 크기·같은 방향 액자는 여전히 서로 **똑같은 모양**이다.

   🔴🔴 그냥 `--ar`(인화지 비율)로 넣으면 **11px 이 어긋난다** (실측).
      까닭: 액자 칸의 겉모습은 인화지가 아니라 **인화지 + 나무테**다.
        칸 폭 W · 테 비율 f 라 하면  매트 폭 = W(1-2f) · 매트 높이 = W(1-2f)/ar
        겉 높이 = W(1-2f)/ar + 2fW  →  **겉 비율 = ar / ((1-2f) + 2f·ar)**
      줄맞춤은 「폭 = 비율 × 줄높이」로 도는 장치라, 넣는 비율이 겉 비율이어야 높이가 맞는다.
   🔴 f 는 짧은 변의 5% 다(--fmpad 와 같은 값·같은 사연). 폭 기준 비율로 바꾸면
      가로(폭=긴 변)는 0.05/ar · 세로(폭=짧은 변)는 0.05 — 즉 `0.05 / max(1, ar)` 하나로 쓴다.
      JS 를 안 고쳐도 되게 **CSS 안에서** 구한다 (options.js · cart.js 둘 다 손대지 않는다).
   🔴 max() 는 사파리 13.1 부터다 — 이 집 바닥선(15.4)보다 아래라 안전하다. */
.grid .ph.ph--frame{
  --fmp:calc(.05 / max(1, var(--ar, 1)));
  --arf:calc(var(--ar, 1) / (1 - 2 * var(--fmp) + 2 * var(--fmp) * var(--ar, 1)));
  flex-grow:calc(var(--arf));flex-shrink:1;
  flex-basis:calc(var(--arf) * var(--base));
  max-width:100%}
/* 🔴🔴 owner 지적(2026-08-24): 「설정완료 하면 폼이 변하는데 왜 그러는거야」
   액자를 고른 칸 **아래에 커다란 흰 빈 자리**가 생기고 있었다.
   까닭 (운영 화면 PC1440 실측):
     · 액자 칸은 위 규칙으로 `flex-grow:0` 이라 **줄맞춤에서 빠진다**(실물 mm 비례 고정).
     · 그러면 옆 칸들이 남은 폭을 다 먹어 **줄 높이가 318 → 458** 로 커진다.
     · 그런데 `.grid` 는 flex 기본값(align-items:stretch)이라 액자 칸이 그 458 까지
       **늘어난다.** 안에 든 것은 320 뿐이니 아래 **138px 이 흰 채로 남는다.**
   → 액자 칸만 늘어나지 않게 한다. 빈 자리 138px → 0 (실측).
   🔴 사장님 선택(2026-08-24): 「실물 크기 차이는 지키고 빈 자리만 없앤다」.
      그래서 위의 `flex-grow:0`(2026-08-20 「액자는 같은 사이즈로」)은 **그대로 둔다** —
      4×6 액자와 A3+ 액자가 화면에서도 실물만큼 다르게 보이는 것이 그 규칙이다.
      대신 줄 아래가 들쭉날쭉해지는 것은 사장님이 아시고 고르신 값이다.
   🔴 `align-items` 로 `.grid` 전체를 바꾸지 않는다. 그러면 **액자 없는 칸까지** 안 늘어나
      줄마다 바닥이 어긋난다 — 지금 멀쩡한 화면을 건드리게 된다.
   🔴 이 규칙은 /options/ 와 /cart/ 가 **함께** 읽는다 (둘 다 .grid + .ph--frame 을 쓴다).
      한쪽만 고치면 두 화면이 갈라진다.
   🔴🔴 2026-08-24 두 번째 고침 — 여기 있던 `.grid .ph.ph--frame{align-self:flex-start}` 를
      **없앴다.** 같은 일을 위 `.grid{align-items:flex-start}` 가 **모든 칸에** 해 주기 때문이다.
      액자 칸만 따로 두면 규칙이 두 벌이 되고, 언젠가 한쪽만 고쳐진다. */
/* 🔴 CSS 백분율 안여백은 **폭** 기준이라, 가로 액자(폭=긴 변)의 나무 테가
   세로 액자보다 50% 두꺼워졌다 (실측 5.25px vs 7.9px). 같은 액자를 눕힌 것뿐인데
   테 두께가 달라지면 안 된다 → 짧은 변 기준 값(--fmpad)을 화면 쪽이 계산해 준다. */
.ph--frame .phfm{padding:var(--fmpad, 5%)}

/* 🔴 2026-08-05 owner 지적: 「디자인도 정렬이 안 되고」 · 「3개 페이지 밸런스 좋게 한 거 맞냐」
     PC 1440 실측(스샷 + 좌표):
        제목·안내·배송막대 :  364 ~ 1076  (폭 712)
        사진 격자         :  120 ~ 1320  (폭 1200)   ← 좌우로 **244px 씩 튀어나감**
     제목과 사진의 왼쪽 선이 244px 어긋나 있었다. 한 화면에 기준선이 둘이면 흐트러져 보인다.

     🔴 왜 이렇게 돼 있었나: 「PC 에서 사진이 167px 밖에 안 된다」를 고치려고
        **격자만** 본문(760px) 밖으로 뺐다. 넓히기는 했지만 기준선을 깨뜨렸다.

     🔴 한 번 더 실측(같은 날 20시대) — 본문을 1200 으로 넓혀 봤더니
        이번에는 **장바구니와 어긋났다.** PC 1440 에서 제목 왼쪽이
        사진 올리기 144 / 어떻게 만들까요 144 / **장바구니 364**.
        사장님 지적 「디자인도 3개 페이지 밸런스 좋게 한 거 맞냐」 — 아니었다.

     🔴 그래서 넓히는 쪽을 접는다. **세 화면 모두 같은 본문 폭(760px)** 을 쓴다.
        격자를 본문 밖으로 빼는 규칙도, 본문을 넓히는 규칙도 **둘 다 없앤다** —
        `.grid` 는 그냥 본문 안에 있다 (위 flex 규칙만 남는다).
        사진이 작아질 걱정은 없다: 줄맞춤 격자는 **줄을 꽉 채우므로**
        폭이 좁아지면 한 줄에 적게 넣고 대신 한 장을 크게 만든다. 실측으로 확인한다. */

/* 🔴 owner 지시: 「사진의 테두리도 (좀 더 심플하게)」
     1px 회색 테두리 + 4px 모서리라 딱딱했다. 테두리를 없애고 모서리를 키우면
     사진 자체에 눈이 간다. 대신 아주 옅은 그림자로 바탕에서 떼어 놓는다
     (테두리는 선이 보이고, 그림자는 안 보이면서 경계를 만든다).
   🔴 그림자 색은 브랜드 먹색(#2B0514)의 아주 옅은 농도다 — 회색 그림자는 차갑다. */
/* 🔴🔴 2026-08-14 사장님 지시 — 「사진들도 각지게 해 줘야지 그래야 맞지」.
   액자를 각지게 했는데 **칸이 둥글어** 액자 위 모서리가 도로 잘려 보였다.
   칸을 각지게 하면 액자와 사진이 같은 모양이 된다 — 실제 액자·인화지가 그렇다.
   🔴 이 파일은 /upload/ 와 /options/ 가 함께 읽는다. 두 화면이 같이 각져야
      사진을 올리다 고르는 화면으로 넘어갈 때 모양이 안 바뀐다. */
.ph{position:relative;border:0;border-radius:0;
  overflow:hidden;background:var(--c-surface-alt);
  box-shadow:0 1px 3px rgba(var(--brand-ink-rgb),.07), 0 6px 16px rgba(var(--brand-ink-rgb),.05);
  flex-grow:calc(var(--ar,1));flex-shrink:1;
  flex-basis:calc(var(--ar,1) * var(--base));
  /* 🔴🔴 2026-08-14 실측 — 320px 에서 **세로 사진 칸이 57px** 이 됐다.
     마지막 줄에 혼자 남은 칸은 기준 높이(--base 85px) 그대로라, 세로 비율(0.667)이면
     57px 밖에 안 된다. 그 안에 딱지를 넣으니 「■ …」 「4×…」 로 **읽을 수가 없었다**
     (제일 중요한 「사진이 선명하지 않아요」가 안 읽혔다).
     → 딱지가 들어갈 만큼은 확보한다. 설정 딱지 74px + 안여백 = 104px. */
  min-width:104px}
/* 🔴 aspect-ratio 로 자리를 미리 잡는다. 썸네일이 도착할 때 화면이 밀리지 않게. */
/* 🔴 사진은 **자르지 않는다.** 위 격자가 폭을 비율대로 나눠 주므로
     aspect-ratio 만 맞추면 원본 그대로 들어간다.
   🔴 --ar 이 없을 때(옛 자료·불러오기 전)를 대비해 1 을 기본으로 둔다 —
     값이 없으면 aspect-ratio 가 통째로 무시돼 높이가 0 이 된다. */
.ph .im{display:block;width:100%;aspect-ratio:var(--ar,1);object-fit:cover;
  background:var(--c-surface-alt)}
.ph .im--pending{display:flex;align-items:center;justify-content:center;
  font-size:var(--t-cap);color:var(--c-text-mute)}

/* 장수 조절
   🔴 감사(2026-07-30): --tap 을 44 → 48px 로 올리자 **320px 폰에서 넘쳤다.**
      320 − 좌우여백 32 − 간격 24 = 264 / 3열 = 한 칸 88px
      그 안에 48px 버튼 두 개 = 96px → 8px 초과. 숫자 자리는 아예 없다.
      "모바일 편하게" 하려고 키운 값이 정작 모바일을 깨뜨렸다.
   → **누르는 높이는 48px 을 지키고, 가로만 칸에 맞춰 늘어나게** 한다.
      세로 48px 이면 손가락으로 누르는 데 지장이 없다 (WCAG 는 44px 이 최소).
      좁은 화면에서는 2열로 떨어뜨려 한 칸을 더 넓게 쓴다. */
.ph .qty{display:flex;align-items:center;justify-content:space-between;
  border-top:1px solid var(--c-border);background:var(--c-surface)}
.ph .qty button{flex:1 1 0;min-width:0;min-height:var(--tap);border:0;background:none;
  font:inherit;font-size:var(--t-lg);cursor:pointer;color:var(--c-text)}
.ph .qty b{flex:0 0 auto;padding:0 2px;font-size:var(--t-cap)}
.ph .qty button[disabled]{color:var(--c-text-mute);cursor:not-allowed}
.ph .qty b{font-variant-numeric:tabular-nums}

/* 🔴 접근성 감사(2026-07-30): 이 버튼이 32×32 였다 — WCAG 2.5.5(44px) 위반.
   작은 썸네일 위라 보이는 원까지 44px 로 키우면 사진을 가린다.
   **보이는 원은 32px 로 두고 누르는 자리만 44px 로 넓힌다.**
   (자리를 넓히는 것이 목적이지 크게 그리는 것이 목적이 아니다) */
.ph .del{position:absolute;top:0;right:0;
  width:var(--tap);height:var(--tap);padding:0;border:0;background:none;
  color:var(--c-text);font:inherit;line-height:1;cursor:pointer;
  display:grid;place-items:center}
/* 🔴 owner 지시(2026-08-02): 「뒷배경이 보이고 블랙 원형 안에 흰색 x 로 해줘야지.
     그래야 사진을 좀 더 명확하게 확인할 수 있지」

   그전에는 **꽉 찬 흰 원**이었다. 사진 오른쪽 위 모서리를 32px 만큼 통째로 가려서,
   거기 얼굴이 있으면 안 보였다 (사장님 촬영본에서 실제로 그랬다).

   🔴 반투명 검정으로 바꾼다 — 뒤 사진이 비쳐 보인다.
     · 흰 사진 위     검정 원이 또렷하다
     · 어두운 사진 위 흰 ✕ 가 또렷하다
     어느 사진에서도 안 사라진다. 흰 원은 밝은 사진 위에서 묻혔다.
   🔴 흰 ✕ 는 반투명 검정(.55) 위에서 대비 7:1 이상이다 —
     사진이 아무리 밝아도 합성된 바탕이 충분히 어둡다.
   🔴 누르는 자리 44px 는 그대로 (위 규칙). 보이는 원만 바뀐다. */
.ph .del i{display:grid;place-items:center;width:32px;height:32px;
  border-radius:var(--r-pill);border:0;
  background:rgba(0,0,0,.55);color:#FFFFFF;font-style:normal;
  /* 뒤 사진이 살짝 흐려져 ✕ 가 더 또렷해진다. 지원 안 하는 브라우저는 그냥 반투명이다 */
  -webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}
.ph .del:hover i{background:rgba(0,0,0,.72)}
.ph .del:active i{transform:scale(var(--m-press))}

/* 🔴 흐릴 수 있는 사진을 **막지는 않는다.** 알리고 손님이 정한다.
   색만으로 알리지 않는다 — 배지에 글자와 기호가 함께 들어간다 (WCAG 1.4.1). */
/* 🔴 owner 지시(2026-08-02): 「이 효과 역시 뒷배경이 보이도록 해줘야지」
     ✕ 단추와 **같은 이유**다 — 꽉 찬 흰 띠가 사진 아래를 가렸다.
   🔴 반투명 먹색 위 흰 글자. 어떤 사진 위에서도 읽힌다.
     색만으로 안 알린다 (WCAG 1.4.1) — ● 기호와 글자가 함께 있다.
     기호 색만 바꿔 「확인 필요」와 「많이 흐려요」를 구별한다. */
.ph .flag{position:absolute;left:var(--s2);bottom:calc(var(--tap) + var(--s2));
  font-size:var(--t-cap);font-weight:700;padding:3px var(--s2);border-radius:var(--r-sm);
  background:rgba(var(--brand-ink-rgb),.62);color:var(--brand-white);border:0;
  -webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}
/* 🔴 기호는 어두운 바탕 위라 **밝은 쪽**을 쓴다. 원래 색은 흰 바탕 기준이라 안 보인다. */
.flag--warn .dot{color:#FFC98A}
.flag--bad  .dot{color:#FF9E9A}
.ph--bad{border-color:var(--c-text-error);border-width:2px}

/* 실패한 사진 — 그 칸만 표시하고 나머지는 그대로 둔다 */
.ph--fail{border-color:var(--c-text-error);border-width:2px}
.ph .fail{padding:var(--s3);font-size:var(--t-cap);color:var(--c-text-error);
  text-align:center;line-height:1.5}
/* 🔴 같은 이유로 36px → 44px */
.ph .fail button{margin-top:var(--s2);min-height:var(--tap)}

/* 올리는 중인 칸 */
.ph--up .im{opacity:.35}
.ph .up{position:absolute;left:0;right:0;bottom:0;height:4px;background:var(--c-surface-alt)}
.ph .up i{display:block;height:100%;background:var(--c-btn-bg);
  transition:width var(--m-fast) linear}

/* 하단 고정 바 안의 요약 */
.sticky .grow .sub{margin-top:2px}

/* ═══ 한 장씩 올라가는 상황 (owner 지시 2026-08-02) ═══════════
   🔴 「3 / 10」과 막대만 있으면 **어느 사진이 잘 올라갔는지** 모른다.
      30장을 올리고 1장이 실패하면 그 1장을 영영 못 찾는다. */
.uplist{list-style:none;margin:var(--s3) 0 0;padding:0;
  /* 🔴 30장이면 목록이 화면을 다 먹는다. 상자 안에서만 넘긴다. */
  max-height:min(46vh,300px);overflow-y:auto;overscroll-behavior:contain}
.uprow{display:grid;grid-template-columns:1fr auto auto;gap:var(--s2);
  align-items:center;padding:var(--s2) 0;border-top:1px solid var(--c-border);
  font-size:var(--t-cap)}
.uprow:first-child{border-top:0}
/* 파일 이름은 길다. 가운데를 줄이지 말고 뒤를 자른다 — 앞이 더 알아보기 쉽다 */
.upname{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.upsize{color:var(--c-text-sub);font-variant-numeric:tabular-nums}
.upst{white-space:nowrap;color:var(--c-text-sub)}
/* 🔴 색만으로 알리지 않는다 — ✓ · ✕ 기호를 글자에 함께 넣었다 (WCAG 1.4.1) */
.upst--go{color:var(--c-text)}
.upst--ok{color:var(--c-text-success)}
.upst--no{color:var(--c-text-error);font-weight:700}
/* 실패한 줄은 배경으로도 표시한다 — 목록이 길면 글자색만으로는 안 띈다 */
.uprow--fail{background:var(--c-surface-alt);border-radius:var(--r-md);
  padding-left:var(--s2);padding-right:var(--s2)}

/* 🔴 줄여서 올린 사진의 「원래 크기 → 줄인 크기」 (2026-08-02).
   손님이 자기 사진에 무슨 일이 있었는지 알 수 있어야 한다. 말없이 바꾸지 않는다. */
.upcut{color:var(--c-text-sub);font-weight:600;white-space:nowrap}

/* 🔴 배지 안 기호 — 기울임이 아니라 그냥 글자다 */
.flag .dot{font-style:normal}

/* ── 심플하게 (owner 지시 2026-08-02) ──────────────────────
   「배경 없이 좀 더 심플하게 정렬해서 버튼들도, 색상 조합을 좀 더 멋지게,
     여성스럽고 세련되도록」

   🔴 흰 카드 상자를 없앤다. 사진이 주인공인 화면인데 상자가 먼저 보였다.
     상자 대신 **여백**으로 묶는다 — 여백은 색이 없어서 사진을 안 방해한다. */
.bulk--bare{background:none;border:0;box-shadow:none;padding:0;
  margin:var(--s5) 0 var(--s2)}
.bulk--bare .row.sb{align-items:center}
.bulk--bare > .sub{margin-top:var(--s2);color:var(--c-text-sub)}
/* 🔴 「어떻게 만들까요?」의 고르는 칸은 상자가 필요하다 — 셋을 한 덩어리로 묶어야
     손님이 「이 셋이 한 벌」임을 안다. 거기는 여백을 넉넉히 두고 선만 아주 옅게. */
.bulk--bare .opts{margin-top:var(--s4);padding:var(--s4) 0 0;
  border-top:1px solid var(--c-border)}

/* 🔴 정렬 1 (owner 선택 2026-08-02) — 장수·안내가 왼쪽에 쌓이고
     단추가 그 두 줄의 **세로 가운데**에 선다.
     그전에는 첫 줄에만 붙어 오른쪽 위에 붕 떠 보였다. */
.bulk--bare .lay1{display:flex;align-items:center;gap:var(--s4)}
.bulk--bare .lay1 .txt{flex:1;min-width:0}
.bulk--bare .lay1 > b,
.bulk--bare .lay1 .txt > b{font-size:var(--t-lg)}
.bulk--bare .lay1 .sub{margin:2px 0 0}
/* 🔴 좁은 폰에서는 단추가 글줄을 밀어 「사진 더 / 올리기」로 접힌다.
     접히면 두 줄이 되어 세로 가운데 맞춤이 무너진다 — 줄바꿈을 막는다. */
.bulk--bare .lay1 .btn{white-space:nowrap;flex:0 0 auto}
/* 🔴🔴 2026-08-14 실측 — 폰에서 안내 글이 **98px 칸에 갇혀 5줄**이 됐고
   320px 에서는 **28px 칸에 18줄**, 한 글자씩 세로로 떨어졌다 (사장님 화면 그대로).
   까닭: 단추 둘이 `flex:0 0 auto` 라 안 줄어드는데 글칸만 `flex:1` 로 짜부라졌다.
   → 좁은 화면에서는 글이 **제 줄을 통째로** 쓰고 단추는 아랫줄로 내려간다. */
@media (max-width:520px){
  .bulk--bare .lay1{flex-wrap:wrap}
  .bulk--bare .lay1 .txt{flex:1 1 100%}
}

/* 🔴 단추 C (owner 선택) — 바탕도 테두리도 없이 글자 + 핑크 ＋ 동그라미.
     사진이 주인공인 화면이라 단추가 조용한 쪽을 고르셨다.
   🔴 바탕이 없어도 **누르는 자리는 44px 그대로**다 (.btn 의 min-height).
     보이는 것만 가벼워지는 것이지 손가락 기준을 깎는 것이 아니다.
   🔴 대비: 글자는 먹색 17.29:1 · ＋ 는 핑크 위 흰색 5.14:1. */
.btn--plus{background:none;border:0;border-radius:var(--r-pill);
  color:var(--c-text);font-weight:700;padding:0 var(--s3);gap:6px}
.btn--plus .plus{display:grid;place-items:center;width:22px;height:22px;
  border-radius:999px;background:var(--c-btn-point-bg);color:var(--c-btn-point-fg);
  font-size:15px;line-height:1}
/* 🔴 색만으로 알리지 않는다 — 바탕이 옅게 깔리고 ＋ 가 살짝 커진다 */
.btn--plus:hover{background:var(--c-surface-point);opacity:1}
.btn--plus:hover .plus{transform:scale(1.12)}
.btn--plus .plus{transition:transform var(--m-fast) var(--m-ease)}
/* 🔴🔴 2026-08-14 사장님 지적 — 「사진 더 올리기랑 구글포토 버튼 디자인이 통일감이 없는데」.
   맞다. 짝을 이루는 두 단추가 하나는 **채운 검정**, 하나는 **테두리 없는 핑크 동그라미**였다.
   → 모양을 하나로 맞춘다. 다만 **주 행동만 핑크**로 남긴다 —
     둘 다 핑크면 무엇이 주 행동인지 사라진다 (2026-08-02 사장님이 고르신 뜻이 그것이었다). */
.btn--plus--sub .plus{background:var(--c-surface-alt);color:var(--c-text)}
.btn--plus--sub:hover{background:var(--c-surface-alt)}

/* 🔴 하단 고정 바도 심플하게. 진한 선 대신 아주 옅은 그림자로 띄운다 —
     선은 화면을 자르고, 그림자는 위에 얹힌 느낌을 준다. */
/* 🔴 하단 바 모양(윗선 대신 그림자)은 **shop.css 로 옮겼다** (owner 지시 2026-08-10:
   「다른 페이지랑 디자인이 일관성있으면 좋겠다」).
   여기 있는 동안에는 /upload/ 와 (이 파일을 같이 읽는) /options/ 만 그림자였고,
   /cart/ · /order/ · /products/print/ 는 1px 선이었다 — 손님이 주문까지 가는 길에서
   바 모양이 중간에 바뀌었다. 실측으로 확인한 값이다(윗선 0px vs 1px). */
.sticky .in .btn{border-radius:var(--r-pill)}

/* 🔴 owner 지시(2026-08-02) — 하단 바에 단추 하나만 남았을 때는 **가운데**에 둔다.
     그전에는 왼쪽 문구가 자리를 반 차지해 단추가 오른쪽으로 밀려 있었다.
   🔴 폭을 안 재면 PC 에서 760px 짜리 알약이 되어 우스꽝스럽다.
     폰에서는 꽉 차고(자리가 없으니까), PC 에서는 380px 로 묶어 가운데에 세운다. */
/* 🔴🔴 2026-08-13 — 「통일」이 무엇인지 사장님과 두 번 주고받아 정해진 값이다.
     ① 「하단 버튼 통일해달라」 → 오른쪽 정렬로 맞췄더니
     ② 「다음 버튼이 가운데 있어야 되지 않아?」 → 맞다. 이 화면은 **왼쪽이 비어** 있다.
   결론: **크기·모양은 세 화면이 똑같이, 자리만 이 화면에서 가운데.**
     고르는 화면·장바구니  왼쪽 장수/합계 + 오른쪽 단추 399×48
     사진 올리기          왼쪽 없음      + 가운데 단추 399×48   ← 폭이 같아야 한다
   🔴 폭 399 는 다른 두 화면의 실측값이다(본문 760 − 왼쪽 349 − 사이 12).
      그 둘을 바꾸면 여기도 같이 봐야 한다. 380 이던 옛 값으로 되돌리지 말 것. */
.sticky--one .in{justify-content:center}
.sticky--one .in .btn{flex:0 1 auto;width:100%;max-width:399px}

/* ── 「어디서 가져올까요?」 두 칸 (owner 지시 2026-08-14) ──────────────────
   🔴 /options/ 의 `.opt` 와 **같은 결**로 짠다: 테두리 2px · 왼쪽 그림 · 오른쪽 화살표.
     화면마다 고르는 모양이 다르면 손님이 매번 새로 배워야 한다. */
.pickq{font-size:var(--t-prod);margin:0 0 var(--s4)}
.pickrow{display:grid;grid-template-columns:auto minmax(0,1fr) auto;
  align-items:center;gap:2px var(--s3);
  width:100%;text-align:left;padding:var(--s4);margin-bottom:var(--s3);
  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)}
.pickrow:hover{border-color:var(--c-text-sub)}
.pickrow:focus-visible{outline:3px solid var(--c-focus);outline-offset:2px}
/* 🔴 주 행동은 **핑크**다 — 다른 화면의 주요 단추(주문하기·이 사진만)와 같은 색.
   그전에는 검정이라 이 화면만 달랐다. */
.pickrow--main{border-color:var(--c-btn-point-bg);background:var(--c-surface-point)}
/* 🔴 자리를 **못 박는다.** 안 정해 두면 브라우저가 알아서 채우는데,
   그 결과 화살표가 그림과 글자 **사이**에 끼고 글이 오른쪽으로 밀렸다 (실측). */
.pickico{grid-column:1;grid-row:1 / span 2;display:grid;place-items:center;
  width:44px;height:44px;border-radius:var(--r-md);
  background:var(--c-surface-alt);font-size:20px;line-height:1}
.pickrow--main .pickico{background:var(--c-btn-point-bg);color:var(--brand-white)}
.pickinfo{grid-column:2;display:flex;flex-direction:column;gap:2px;min-width:0}
.pickinfo b{font-size:var(--t-btn)}
.pickgo{grid-column:3;grid-row:1 / span 2;font-size:20px;color:var(--c-text-sub);line-height:1}

/* 🔴 끌어놓기는 **PC 에서만** 알린다. 폰에서는 할 수 없는 일이다. */
.dragtip{display:none;margin-top:var(--s3);text-align:center}
@media (min-width:700px){ .dragtip{display:block} }

/* 규격은 접어 둔다 — 궁금하실 때만 */
.pickmore{margin-top:var(--s3);border-top:1px solid var(--c-border);padding-top:var(--s3)}
.pickmore > summary{cursor:pointer;font-size:var(--t-cap);color:var(--c-text-sub);
  min-height:var(--tap);display:flex;align-items:center}
.pickmore p{margin:var(--s2) 0 0}

/* 처음 오신 분께 한 번만 뜨는 안내 (owner 지시 2026-08-14) */
.hello{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--s4)}
.hello > li{display:flex;align-items:flex-start;gap:var(--s3)}
.hello > li > b{flex:0 0 auto;display:grid;place-items:center;
  width:28px;height:28px;border-radius:999px;
  background:var(--c-btn-point-bg);color:var(--brand-white);font-size:var(--t-cap)}
.hello > li > span{display:flex;flex-direction:column;gap:2px;min-width:0}

/* ── 구글포토 가져오는 중 로딩 창 (owner 지시 2026-08-14) ────────────────
   「사진 가져오는 중일 때 팝업으로 로딩창을 보여주면 더 좋을 것 같은데?」
   🔴 화면 위 띠는 사진이 몇 장 있으면 위로 밀려 눈에 안 들어온다. 가운데에 띄운다. */
dialog.gload{width:min(360px,90vw)}
.gload-wrap{display:flex;flex-direction:column;align-items:center;gap:var(--s3);
  padding:var(--s5) 0 var(--s3);text-align:center}
.gload-say{font-weight:700;margin:0}
/* 돌아가는 고리 — transform 만 움직인다 (이 집 규칙). 그림 파일을 받지 않는다. */
.gload-ring{width:44px;height:44px;border-radius:999px;
  border:4px solid var(--c-border);
  border-top-color:var(--c-btn-point-bg);
  animation:gspin 900ms linear infinite}
@keyframes gspin{to{transform:rotate(360deg)}}
/* 🔴 「동작 줄이기」를 켠 분에게는 안 돌린다 — 대신 색으로 「돌고 있음」을 남긴다. */
@media (prefers-reduced-motion:reduce){
  .gload-ring{animation:none;border-color:var(--c-btn-point-bg)}
}
dialog.gload .dfoot{justify-content:center}

/* ── 「다 올라갔어요」 창 (owner 지시 2026-08-24) ──────────────────────────
   「됐어요 이게 이미지 업로드완료 후 팝업으로 나오면 좋을 것 같은데 — 디자인 통일성 생각해서」
   🔴 껍데기(dialog.detail · .dhead / .dbody / .dfoot / .dclose)는 shop.css 것을 **그대로** 쓴다.
      여기 있는 것은 창 **안쪽** 규칙뿐이다. 껍데기를 여기서 손대면 바로 위 안내창·로딩창과
      갈라진다 — 한 화면 안에서 창 세 개가 다르게 생기는 순간 손님은 다른 기능인 줄 안다.
   🔴 폭은 로딩창(360px)과 안내창(560px 기본) 사이에 둔다. 글이 몇 줄뿐이라 560px 은 휑하고,
      360px 은 단추 두 개가 한 줄에 안 선다 (실측). */
dialog.updone{width:min(400px,90vw)}
/* 🔴 제목의 초점 테두리를 지우는 규칙은 shop.css 로 옮겼다 (2026-08-24) —
   `dialog.detail .dhead h2[tabindex="-1"]:focus`. 주문서의 「확인이 필요한 사진」 창도
   같은 것이 필요해졌기 때문이다. 여기 다시 적지 않는다. 두 벌이 되면 한쪽만 고쳐진다. */
.updone-wrap{display:flex;flex-direction:column;align-items:center;gap:var(--s3);
  padding:var(--s3) 0 var(--s2);text-align:center}
/* 🔴 동그라미는 안내창 번호(.hello > li > b)와 **같은 옷**이다 — 핑크 바탕·흰 글자·완전한 원.
   크기만 로딩 고리(.gload-ring)와 맞춰 44px 로 둔다. 세 창의 가운데 그림이 같은 자리에 선다.
   🔴 대비: 핑크 #E51566 위 흰 ✓ 5.14:1 (tokens.css 실측값) — 큰 글자라 AAA 통과. */
.updone-mark{display:grid;place-items:center;width:44px;height:44px;border-radius:999px;
  background:var(--c-btn-point-bg);color:var(--brand-white);font-size:22px;line-height:1}
/* 🔴 나타나는 움직임은 「좋음」 딱지가 쓰는 qpop(shop.css)을 **그대로** 가져온다.
   새 움직임을 지으면 같은 뜻의 표시가 화면마다 다르게 움직인다.
   🔴 `.js-motion` 아래에만 둔다 — 「동작 줄이기」를 켜신 분에게는 motion-init.js 가
      그 표시를 떼므로 저절로 꺼진다. 창은 움직임 없이도 똑같이 읽힌다. */
.js-motion .updone-mark{animation:qpop .5s var(--m-ease) both}
.updone-n{margin:0;font-size:var(--t-prod);line-height:var(--t-prod-lh)}
/* 장수만 우리 색으로. 문장 전체를 핑크로 칠하면 읽기 힘들고 단추와 다툰다 */
.updone-n b{color:var(--c-btn-point-bg)}
/* 부가 안내(이미 올리신 사진 · 동영상 · 장수 상한) — 「됐어요」보다 조용해야 한다 */
.updone-more{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:2px}
.updone-more li{font-size:var(--t-cap);color:var(--c-text-sub)}
/* 🔴 .dfoot 은 한 줄 오른쪽 정렬이고 **사이 간격이 없다** (지금까지 단추가 하나뿐이었다).
   두 개를 나란히 세우므로 우리 최소 간격을 준다.
   🔴🔴 owner 지시(2026-08-24): 「사진 더 올리기 · 다음 버튼이 가운데로 오면 좋을 것 같은데」
      이 창은 **왼쪽에 아무것도 없어서** 오른쪽 정렬이 허전하다 — 사장님이 하단 고정 바를
      가운데로 옮기라고 하셨을 때(2026-08-13)와 **같은 까닭**이다.
      같은 화면의 구글포토 로딩창(`dialog.gload .dfoot`)도 이미 가운데다. 셋 중 둘이 가운데가 된다.
   🔴 단추 **크기·모양은 안 건드린다.** 자리만 옮긴다 (하단 바 때 정하신 그대로). */
.updone .dfoot{gap:var(--tap-gap);justify-content:center}
/* 🔴 좁은 폰에서는 두 단추가 한 줄에 안 선다 (실측: 320px 에서 넘친다).
   위아래로 쌓고 전폭으로 둔다 — **주 행동이 위**다. 선물 화면 팝업(.gift-invite-acts)이
   이미 그 차례라 같게 맞춘다. DOM 은 「보조 → 주 행동」 순서이므로 column-reverse 로 뒤집는다
   (읽어 주는 기계에는 PC 와 같은 차례로 들린다). */
@media (max-width:400px){
  .updone .dfoot{flex-direction:column-reverse;align-items:stretch}
  .updone .dfoot .btn{width:100%}
}
.shared-upload-guide[hidden]{display:none!important}
.shared-upload-guide{display:flex;flex-wrap:wrap;gap:4px 10px;margin:8px 0 12px;font-size:13px;line-height:1.6;color:var(--c-text-sub)}
.shared-upload-guide b{color:var(--c-text)}
.shared-upload-done{margin-top:8px}
