/* ============================================================================
   THẺ TẢI ẢNH (dropzone) — NGUỒN DUY NHẤT cho .up-card / .up-drop / .up-empty /
   .up-preview và khuôn workspace 2 cột của trang tool.

   TẠI SAO CÓ FILE NÀY: trước đây mỗi trang tool tự chép một bản .up-* vào thẻ
   <style> của mình, rồi mỗi lần sửa lại đắp thêm một lớp đè ở cuối. Riêng
   tang-do-phan-giai.php từng khai báo .up-drop 13 lần với 4 mốc breakpoint
   (900/760/600/560) chồng nhau — phần lớn là code CHẾT (bị selector đặc hiệu
   hơn đè), nên không ai đọc ra rule nào đang thật sự chạy và mỗi lần sửa một
   trang là một trang khác lệch.

   QUY ƯỚC KHI DÙNG:
   - MỌI trang tool mới PHẢI dùng file này, KHÔNG chép .up-* vào <style> trang và
     KHÔNG đặt tiền tố riêng (.km-/.rb-/…) cho thẻ tải ảnh. Tiền tố riêng = một
     bản sao nữa, sửa một trang là các trang khác lệch.
   - Cần đổi chiều cao / lề ô thả cho một trang: ĐỔI BIẾN --dz-* trên .up-card,
     ĐỪNG viết thêm rule .up-drop đè lên.
   - KHÔNG dùng height/max-height cứng cho .up-drop. Ô thả phải nở theo nội dung
     vì bên trong nó còn có tab "1 ảnh | Hàng loạt" (JS chèn), gợi ý dán ảnh và
     lưới ảnh hàng loạt — ép chiều cao là tràn/cắt ngay.
   - Nạp file này TRƯỚC thẻ <style> của trang để trang vẫn đè được khi thật sự
     cần một ngoại lệ.

   MARKUP CHUẨN (id là của trang, class là của component):
     <section class="section section-line up-workspace up-split" id="…">
       <div class="shell">
         <div class="section-head up-workspace-head">…</div>
         <div class="up-grid">
           <div class="up-card" id="xxCard">
             <div class="up-upload-side">
               <label class="up-drop" id="xxDrop">
                 <input type="file" id="xxInput" accept="image/…">
                 <div class="up-empty">
                   <icon><h2>…</h2><p class="muted">hạn mức</p>
                   <p class="paste-hint"><kbd>Ctrl</kbd><i>+</i><kbd>V</kbd> …</p>
                 </div>
                 <img class="up-preview" id="xxPreview" alt="Ảnh đã chọn">
                 <i class="up-upload-spinner"></i>
               </label>
             </div>
             <div class="up-settings-side">… tuỳ chọn + .run + .note …</div>
           </div>
           <div class="…-results">… cột kết quả của trang …</div>
         </div>
       </div>
     </section>
   JS chỉ bật/tắt STATE trên .up-card: has-image | uploading | dragover | batch-mode.
   ========================================================================== */

/* ---------- Khung section workspace (nền + khoảng neo cuộn) ---------- */
.up-workspace{scroll-margin-top:72px;background:color-mix(in srgb,var(--soft) 42%,transparent)}
.up-workspace-head{align-items:center}
.up-workspace-head .eyebrow{margin-bottom:13px}
.up-workspace-head h2{font-size:clamp(30px,4vw,46px)}

/* ---------- Vỏ thẻ + các biến điều khiển ---------- */
.up-card{
  --dz-min-h:320px;          /* chiều cao tối thiểu ô thả (desktop) */
  --dz-pad:16px;             /* lề trong ô thả */
  --dz-radius:20px;
  --dz-border:2px dashed color-mix(in srgb,var(--ink) 16%,var(--line));
  --dz-bg:color-mix(in srgb,var(--soft) 36%,var(--card));
  --dz-bg-hover:color-mix(in srgb,var(--acid) 8%,var(--card));
  position:relative;
  display:grid;
  grid-template-columns:minmax(0,1fr);
  gap:0;
  margin:0;
  padding:20px;
  background:var(--card);
  border:1px solid var(--line);
  border-radius:22px;
  box-shadow:var(--shadow);
}

/* ---------- Khuôn workspace 2 cột (thẻ tải ảnh | cột kết quả) ---------- */
.up-workspace.up-split .up-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:20px;align-items:stretch}
/* grid-template-rows:1fr auto dồn phần dư xuống ô thả (flex:1) chứ không hở dưới
   cụm cấu hình. min-height GIỮ BẰNG số với .rb-card ở xoa-nen.php để hai tool cao y hệt. */
@media(min-width:901px){
  .up-workspace.up-split .up-card{min-height:640px;grid-template-rows:1fr auto}
  /* Biến thể compact (trang ẩn hết mức phóng/định dạng/model, vd /lam-net-phuc-hoi-khuon-mat):
     bỏ chiều cao sàn, nếu không phần dư biến thành khoảng trống TRONG khung dashed. */
  .up-workspace.up-split--compact .up-card{min-height:0;--dz-min-h:240px}
}

/* ---------- Hai cột trong thẻ ---------- */
.up-upload-side,.up-settings-side{min-width:0}
.up-upload-side{display:flex;flex-direction:column}
.up-settings-side{display:flex;flex-direction:column;gap:10px;padding:10px 0 2px}
.up-settings-side .options{flex:0;display:flex;flex-direction:column;gap:8px;margin:0}
.up-settings-side .option-label{font-size:9px;line-height:1.2}
.up-settings-side .run{min-height:50px;margin-top:0;border-radius:13px;font-size:15px;line-height:1.2}
.up-settings-side .run .old-price{font-size:13px}
.up-settings-side .note{margin:0;font-size:10px}
.up-upload-side .pixel-preview{margin-top:10px}

/* ---------- Ô thả ---------- */
.up-drop{
  position:relative;
  flex:1;
  min-height:var(--dz-min-h);
  padding:var(--dz-pad);
  display:grid;
  place-items:center;
  overflow:hidden;
  text-align:center;
  cursor:pointer;
  border:var(--dz-border);
  border-radius:var(--dz-radius);
  background:var(--dz-bg);
  transition:border-color .2s,background .2s;
  /* Để phần bên trong đo theo BỀ RỘNG Ô THẢ (@container bên dưới) thay vì theo
     bề rộng màn hình — ô thả nằm trong cột co giãn nên hai thứ đó khác nhau. */
  container-type:inline-size;
}
.up-drop input{display:none}

/* Hover đổi màu thì mọi thiết bị dùng được; hiệu ứng DỊCH CHUYỂN chỉ mở cho máy
   có chuột thật — trên cảm ứng :hover dính lại sau khi chạm, trông như lỗi. */
@media(hover:hover) and (pointer:fine){
  .up-drop:hover{border-color:var(--ink);background:var(--dz-bg-hover)}
  .up-drop:hover .tool-icon{transform:translateY(-4px) scale(1.06);background:var(--acid);color:#171714}
}
@media(hover:none){
  .up-drop:active{border-color:var(--ink);background:var(--dz-bg-hover)}
}
/* Đang kéo file vào cửa sổ: viền acid cho biết thả được (JS toggle .dragover trên .up-card). */
.up-card.dragover .up-drop{border-color:var(--acid);background:color-mix(in srgb,var(--acid) 9%,var(--card))}

/* ---------- Trạng thái rỗng ---------- */
.up-empty{max-width:100%;min-width:0}
.up-empty .tool-icon{margin-left:auto;margin-right:auto;transition:transform .2s,background .2s}
.up-drop .up-empty .tool-icon{width:58px;height:58px;border-radius:17px;box-shadow:0 10px 26px color-mix(in srgb,var(--acid) 35%,transparent)}
.up-drop h2{margin:16px 0 6px}
/* Dòng hạn mức (định dạng · dung lượng · megapixel) dài và thay đổi theo tool —
   cho xuống dòng thoải mái thay vì đẩy ngang làm vỡ ô. */
.up-drop .up-empty p{font-size:12px;font-weight:500;letter-spacing:0;overflow-wrap:anywhere}

/* Gợi ý dán ảnh: chỉ có nghĩa với máy có bàn phím + chuột, và chỉ khi ô thả đủ rộng. */
.up-drop .up-empty p.paste-hint{display:none;margin-top:15px;align-items:center;justify-content:center;gap:6px;font-size:11px;font-weight:600;color:var(--muted)}
.paste-hint i{font-style:normal;font-weight:800}
.paste-hint kbd{font:800 10px ui-monospace,monospace;letter-spacing:.04em;padding:4px 8px;border:1px solid var(--line);border-bottom-width:2px;border-radius:7px;background:var(--card);color:var(--ink)}
@media(hover:hover) and (pointer:fine){
  @container (min-width:300px){
    .up-drop .up-empty p.paste-hint{display:flex}
  }
}

/* ---------- Ảnh đã chọn ---------- */
.up-preview{display:none;position:absolute;z-index:1;inset:0;width:100%;height:100%;object-fit:contain;border-radius:12px;transition:filter .2s,transform .25s}
.up-card.has-image .up-empty{display:none}
.up-card.has-image .up-preview{display:block}
/* Nút "đổi ảnh" nổi lên khi rê chuột vào ảnh đã chọn. */
.up-card.has-image .up-drop:after{
  content:'';position:absolute;z-index:3;left:50%;top:50%;
  transform:translate(-50%,-45%) scale(.82);
  width:58px;height:58px;border-radius:16px;
  background-color:var(--acid);
  background-image:url('/assets/svgs/regular/upload.svg');
  background-position:center;background-repeat:no-repeat;background-size:25px;
  box-shadow:0 12px 35px rgba(0,0,0,.28);
  opacity:0;transition:opacity .2s,transform .2s;
}
@media(hover:hover) and (pointer:fine){
  .up-card.has-image .up-drop:hover:after{opacity:1;transform:translate(-50%,-50%) scale(1)}
  .up-card.has-image .up-drop:hover .up-preview{filter:brightness(.58);transform:scale(1.015)}
}

/* ---------- Đang tải ảnh lên ---------- */
.up-upload-spinner{display:none;position:absolute;z-index:5;top:50%;left:50%;width:42px;height:42px;margin:-21px 0 0 -21px;border:3px solid rgba(255,255,255,.32);border-top-color:var(--acid);border-radius:50%;animation:upSpin .8s linear infinite}
.up-card.uploading .up-upload-spinner{display:block}
.up-card.uploading .up-preview{filter:blur(7px) brightness(.7)}
@keyframes upSpin{to{transform:rotate(360deg)}}
/* Khung xương cho các ô đang chờ ảnh — dùng chung một rule cho cả ô thả lẫn thumb
   hàng loạt (biến --skel-* và @keyframes skelSweepBg định nghĩa ở site.css):
   - ô thả khi đã bắt đầu đọc/nén file mà chưa có ảnh xem trước
   - thumb trong lưới hàng loạt và trong danh sách file khi chưa gắn <img>
   Trước đây các chỗ này chỉ là mảng xám trơ, nhìn như đang lỗi. */
.up-card.uploading:not(.has-image) .up-drop:before,
.batch-drop-thumb.is-uploading:not(:has(img)):before,
.batch-file-thumb.is-uploading:not(:has(img)):before{
  content:'';position:absolute;z-index:4;inset:0;
  border-radius:inherit;
  background:linear-gradient(90deg,transparent,var(--skel-glow),transparent) -60% 0/60% 100% no-repeat var(--skel-base);
  animation:skelSweepBg 1.35s infinite;
}
@media(prefers-reduced-motion:reduce){
  .up-card.uploading:not(.has-image) .up-drop:before,
  .batch-drop-thumb.is-uploading:not(:has(img)):before,
  .batch-file-thumb.is-uploading:not(:has(img)):before{animation:none;background-image:none}
}

/* ---------- Tab "1 ảnh | Hàng loạt" (upscale-modal.js chèn trước ô thả) ---------- */
.up-mode-tabs{display:flex;gap:4px;margin-bottom:10px;padding:4px;border:1px solid var(--line);border-radius:12px;background:var(--soft)}
.up-mode-tabs button{flex:1;min-width:0;height:34px;border:0;border-radius:9px;background:transparent;color:var(--muted);font-size:11.5px;font-weight:800;cursor:pointer;transition:background .15s,color .15s}
.up-mode-tabs button.active{background:var(--card);color:var(--ink);box-shadow:0 2px 8px rgba(0,0,0,.08)}

/* ---------- Lưới ảnh hàng loạt hiển thị ngay trong ô thả ---------- */
.batch-drop-gallery{display:none}
.batch-drop-gallery.show{
  position:absolute;z-index:2;inset:12px;
  display:grid;
  /* 3 cột × 2 hàng = đúng 6 ô xem trước, phần dư JS gom vào nhãn "+N" (.batch-more).
     minmax(0,…) ở CẢ hai chiều để ô không phình theo ảnh bên trong — trước đây có 3 lớp
     grid-template-columns đè nhau (3 cột / 6 cột / 3 cột) nên thumb lúc bẹp lúc hở. */
  grid-template-columns:repeat(3,minmax(0,1fr));
  grid-template-rows:repeat(2,minmax(0,1fr));
  gap:9px;padding-bottom:35px;
  border-radius:12px;background:var(--card);
  cursor:pointer;transition:filter .2s;
}
.batch-drop-thumb{position:relative;min-width:0;min-height:0;border-radius:9px;overflow:hidden;display:grid;place-items:center;background:var(--soft);color:var(--muted)}
.batch-drop-thumb img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:center;transition:filter .2s,transform .25s}
.batch-more{position:absolute;right:15px;bottom:40px;min-width:38px;height:28px;padding:0 8px;border-radius:99px;display:grid;place-items:center;background:var(--acid);color:#171714;font-size:11px;box-shadow:0 5px 15px rgba(0,0,0,.2)}
.batch-drop-count{position:absolute;left:0;right:0;bottom:7px;display:flex;align-items:center;justify-content:center;gap:9px;text-align:center;color:var(--muted);font-size:9px;font-weight:750}
.batch-drop-count span{color:var(--muted)}
.batch-drop-count button{border:0;background:transparent;color:var(--ink);font-size:9px;font-weight:900;text-decoration:underline;text-decoration-color:var(--acid);text-decoration-thickness:2px;text-underline-offset:3px}
.batch-drop-gallery.show:after{
  content:'Quản lý ảnh';position:absolute;z-index:4;left:50%;top:50%;
  transform:translate(-50%,-42%) scale(.92);
  padding:10px 31px 10px 14px;border-radius:99px;
  background-color:var(--acid);color:#171714;font-size:10px;font-weight:900;
  background-image:url('/assets/svgs/regular/arrow-up-right.svg');
  background-position:right 12px center;background-repeat:no-repeat;background-size:10px;
  box-shadow:0 10px 28px rgba(0,0,0,.25);
  opacity:0;transition:opacity .2s,transform .2s;
}
@media(hover:hover) and (pointer:fine){
  .batch-drop-gallery.show:hover .batch-drop-thumb img{filter:brightness(.58);transform:scale(1.035)}
  .batch-drop-gallery.show:hover:after{opacity:1;transform:translate(-50%,-50%) scale(1)}
}
.batch-drop-gallery.show:active:after{transform:translate(-50%,-50%) scale(.96)}
/* Ảnh đang up nền: mờ ảnh + spinner nhỏ (đặt trên chính ô, vì phần tử con bị JS thay). */
.batch-file-thumb{position:relative}
.batch-file-thumb.is-uploading:after,.batch-drop-thumb.is-uploading:after{content:'';position:absolute;inset:0;width:15px;height:15px;margin:auto;border:3px solid rgba(127,127,127,.35);border-top-color:var(--acid);border-radius:50%;animation:batchSpin .8s linear infinite}
.batch-drop-thumb.is-uploading:after{width:21px;height:21px}
.batch-file-thumb.is-uploading img,.batch-drop-thumb.is-uploading img{filter:brightness(.72)}
/* Spinner phải nằm TRÊN lớp khung xương ở dưới. */
.batch-file-thumb.is-uploading:after,.batch-drop-thumb.is-uploading:after{z-index:5}
/* Khai ở đây chứ KHÔNG để trang tự khai: trước đây @keyframes batchSpin chỉ có trong
   <style> của tang-do-phan-giai.php, nên trang khác dùng component thì spinner đứng im. */
@keyframes batchSpin{to{transform:rotate(360deg)}}

/* ---------- Chế độ hàng loạt ---------- */
.up-card.batch-mode .up-preview{display:none}
.up-card.batch-mode .up-empty{display:block}
.up-card.batch-mode .batch-drop-gallery.show~.up-preview,
.up-card.batch-mode .batch-drop-gallery.show~.up-empty{visibility:hidden}
.up-card.batch-mode.has-image .up-drop:after{content:none;display:none}
.up-card.batch-mode.has-image .up-drop:hover .up-preview{filter:none;transform:none}
.up-card.batch-mode .pixel-preview{display:none}

/* ---------- Responsive: CHỈ đổi biến, không đụng tới rule ở trên ----------
   Một mốc duy nhất cho bố cục (900px) và một mốc cho điện thoại (560px). */
@media(max-width:900px){
  .up-workspace.up-split .up-grid{grid-template-columns:1fr}
  .up-workspace.up-split .up-card{max-width:680px;width:100%;margin:0 auto}
  .up-card{--dz-min-h:260px}
}
@media(max-width:560px){
  .up-workspace .up-card{padding:11px}
  .up-card{--dz-pad:10px}
  .batch-drop-gallery.show{inset:8px;gap:6px;padding-bottom:32px}
}
