/* =============================================================================
 * CỬA HÀNG › BỐ CỤC THẺ SẢN PHẨM trên ĐIỆN THOẠI / MÁY TÍNH BẢNG   (build 846)
 * File: client/public/mobile-shop-846.css        (nạp SAU 779/787/830/836/840)
 *
 * MỤC TIÊU (theo ảnh mẫu người chơi gửi — khổ NGANG, 4 thẻ một hàng):
 *   [ảnh tàu]  →  [tên tàu]  →  [thanh trạng thái / nút mua] xếp DỌC trong thẻ,
 *   lưới TỰ CHỌN SỐ CỘT theo bề ngang thật, chữ dài tự xuống dòng (không "…",
 *   không bị xén), tàu luôn nằm TRỌN trong ô ảnh, danh sách cuộn dọc mượt.
 *
 * ---------------------------------------------------------------- VÌ SAO CẦN
 * (1) LƯỚI KHOÁ CỨNG. shop-responsive-779 khoá `repeat(4)`, mobile-shop-bag-787
 *     khoá `repeat(2)`, mobile-repair-830 khoá `repeat(4)!important` (rot90) và
 *     shop-text-836 khoá `repeat(3)!important` (rot90). Lưới auto-fill của
 *     ui/shopgrid.ts chỉ có 1 lần #id nên KHÔNG bao giờ có hiệu lực trên bản
 *     thật. Hệ quả: 360px và 430px cùng 2 cột (thẻ 162 vs 197px), 768px vẫn 3
 *     cột thẻ 170px, còn máy nằm ngang 932px chỉ 3 cột thẻ 255px — không khổ nào
 *     đúng. Ở đây trả lại auto-fill với bề ngang cột theo clamp().
 *
 * (2) TÀU KHÔNG NẰM GỌN TRONG Ô. Ô ảnh `.sf-art` đang là 1.4 (787) / 1.45 (830)
 *     nhưng chiều cao tối thiểu, bo góc và cách kẹp ảnh thì mỗi lớp một kiểu.
 *     Ở đây gom về MỘT núm vặn `--msx-art-a`: ô có aspect-ratio cố định, ảnh
 *     `object-fit:contain` + trần `max-width/max-height:100%` ⇒ tàu dọc hay tàu
 *     ngang đều nằm trọn, không bao giờ tràn sang tên/nút.
 *     ⚠ GHI CHÚ CHO NGƯỜI SỬA SAU: công thức cân cỡ thân tàu
 *     (`img.sp-card-skin.sk-on` trong shopframe.ts) HIỆN KHÔNG CHẠY trên bản
 *     thật — shop-responsive-779 ghim `left/top/width/height/transform` bằng
 *     `!important` ở 2 lần #id nên mọi thẻ đều rơi về kiểu contain 86%. File này
 *     KHÔNG gỡ cái ghim đó (đổi hành vi cân cỡ là việc khác, cần duyệt riêng),
 *     nhưng vẫn gán `--sk-a: var(--msx-art-a)` cho đúng: ngày nào gỡ ghim thì
 *     công thức đã sẵn đúng tỉ lệ ô, không phải đi sửa lại lần nữa.
 *
 * (3) CHỮ DÀI BỊ XÉN Ở THANH TRẠNG THÁI. `.sf-price` là container `size` (đơn vị
 *     cqh) nên buộc phải có chiều cao CỐ ĐỊNH (36px / 26px) → nhãn dài của các
 *     tiếng khác ("NHẬN MIỄN PHÍ", "БЕСПЛАТНО ПОЛУЧИТЬ", "KOSTENLOS ERHALTEN")
 *     xuống 2 dòng là tràn ra ngoài rồi bị `.sf-card{overflow:hidden}` cắt.
 *     Thêm nữa shop-text-836 đặt `.sc-sb-text{font-size:14px!important}` nên
 *     vòng lặp tự co chữ trong ui/statusbar.ts (ghi font-size INLINE) đã CHẾT —
 *     không còn cơ chế nào cứu chữ dài. Ở đây: bỏ `container-type:size`, cấp
 *     thẳng `--sc-sb-fs/--sc-sb-gem/--sc-sb-gap` bằng px (không còn cqh nào để
 *     hỏng), trả `.sc-sb-main` về luồng và cho thanh CAO TỰ DO từ min-height.
 *
 * (4) VÙNG CUỘN. Bổ sung `overscroll-behavior:contain` + chừa đáy theo lề an
 *     toàn (thanh gesture) + khoá cuộn ngang. KHÔNG đụng `touch-action` của
 *     body.rot90 — mobile-repair-830 CỐ Ý đặt `none` ở đó (trục chạm bị xoay 90°
 *     nên cuộn native sai chiều, JS lo); mọi rule chạm ở đây đều nằm sau
 *     `body:not(.rot90)`.
 *
 * ------------------------------------------------------------------- PHẠM VI
 * PC KHÔNG ĐỔI MỘT PIXEL: khối (0) chỉ KHAI BÁO biến (không sinh rule vẽ), mọi
 * khối còn lại đều bị chặn bởi `max-width: 820px` / `max-width: 1023.98px` +
 * `max-height: 540px`, hoặc bởi `body.rot90`. Breakpoint PC của cửa hàng là
 * 1024px nên không rule nào ở đây khớp trên máy tính.
 *
 * ĐỘ ƯU TIÊN: 5 lần `#shopframe` — phải thắng 779/787 (2 lần), 830 (3 lần +
 * !important), 836 (3 lần, và 4 lần + !important ở nhánh rot90), 840 (4 lần).
 * Chỗ nào bên kia dùng !important thì bên này cũng phải !important.
 * ========================================================================== */

/* ---------------------------------------------------------------------------
 * (0) NÚM VẶN — khai báo ở MỌI khổ màn. Chỉ là biến, không vẽ gì, nên PC an toàn
 *     tuyệt đối. Muốn chỉnh bố cục thì sửa ở đây, đừng sửa rải rác bên dưới.
 *
 *     --msx-col    bề ngang TỐI THIỂU một cột (đầu vào của auto-fill)
 *     --msx-art-a  tỉ lệ ô ảnh tàu (rộng/cao) — ĐỒNG THỜI là --sk-a
 *     --msx-bar-h  chiều cao TỐI THIỂU thanh trạng thái (cao hơn nếu chữ 2 dòng)
 *     --msx-name-h chiều cao TỐI THIỂU vùng tên (cao hơn nếu tên 2–3 dòng)
 * ------------------------------------------------------------------------- */
#shopframe#shopframe#shopframe#shopframe#shopframe {
  --msx-col: 150px;
  --msx-gap: 10px;
  --msx-pad: 10px;
  --msx-inner-gap: 6px;
  --msx-art-a: 1.55;
  --msx-bar-h: 38px;
  --msx-name-h: 34px;
  --msx-radius: 14px;
  /* Cỡ chữ/biểu tượng của thanh trạng thái — px TUYỆT ĐỐI, thay cho clamp(cqh)
     của ui/statusbar.ts (xem lý do (3) ở đầu file). */
  --msx-sb-fs: 14px;
  --msx-sb-gem: 19px;
  /* Cỡ chữ huy hiệu góc — xem ghi chú ở rule .sf-card bên dưới. */
  --msx-badge-fs: 10px;
}

/* ===========================================================================
 * (1) ĐIỆN THOẠI DỌC + MÁY TÍNH BẢNG (<=820px) và ĐIỆN THOẠI NẰM NGANG
 *     (<=540px chiều cao, <1024px bề ngang).
 *
 *     Gộp hai điều kiện vào MỘT @media để phần thân thẻ chỉ viết một lần — khổ
 *     nào lệch thì chỉ cần đổi NÚM VẶN ở các khối (2)(3)(4) bên dưới.
 *     body.rot90 (máy dọc 414×896, game tự xoay) CŨNG khớp `max-width:820px`
 *     nên thừa hưởng toàn bộ khối này; khối (4) chỉ chỉnh lại số đo.
 * ======================================================================== */
@media (max-width: 820px),
       (orientation: landscape) and (max-height: 540px) and (max-width: 1023.98px) {

  /* --- 1.1 Cột giữa co được thì .sf-scroll mới cuộn (min-height:0 bắt buộc) -- */
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-stage,
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-mid {
    min-width: 0; min-height: 0;
  }

  /* --- 1.2 VÙNG CUỘN DANH SÁCH ------------------------------------------- */
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-scroll {
    flex: 1 1 auto; min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;                 /* không bao giờ đẻ cuộn NGANG        */
    overscroll-behavior: contain;       /* cuộn hết không kéo sang canvas game */
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
    /* Đáy chừa thêm lề an toàn (thanh gesture / tai thỏ). --sfl-safe-b do
       shop-landscape-840.css tính, ĐÃ quy đổi đúng trục cả khi body.rot90. */
    padding: 2px 4px calc(10px + var(--sfl-safe-b, 0px)) 2px;
    scroll-padding-block: 8px;
  }
  /* Chạm: chỉ đặt cho khung KHÔNG xoay — xem ghi chú (4) ở đầu file. */
  body:not(.rot90) #shopframe#shopframe#shopframe#shopframe#shopframe .sf-scroll {
    touch-action: pan-y;
  }

  /* --- 1.3 LƯỚI TỰ XẾP ---------------------------------------------------
     minmax(min(--msx-col, 100%), 1fr): `min(...,100%)` là chốt chặn để khung
     hẹp hơn một cột cũng KHÔNG tràn ngang (bẫy kinh điển của auto-fill).
     align-items:start ⇒ thẻ tên 1 dòng không bị kéo cao bằng thẻ tên 3 dòng. */
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(var(--msx-col), 100%), 1fr));
    gap: var(--msx-gap);
    align-items: start;
    min-width: 0;
  }
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-grp { grid-column: 1 / -1; }

  /* --- 1.4 THẺ -----------------------------------------------------------
     Xếp DỌC: ảnh (order 1) · tên (order 2) · thanh trạng thái (order 3) —
     đúng thứ tự trên ảnh mẫu. align-items:stretch để tên và thanh luôn rộng
     hết thẻ; height:auto để thẻ TỰ GIÃN khi chữ xuống dòng. */
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card[class] {
    display: flex; flex-direction: column; align-items: stretch;
    gap: var(--msx-inner-gap);
    width: 100%; min-width: 0;
    height: auto; min-height: var(--sf-tap, 44px); max-height: none;
    aspect-ratio: auto;
    padding: var(--msx-pad) !important;
    border-radius: var(--msx-radius);
    overflow: hidden;                   /* quầng sáng tràn không phá lưới     */
    transform: none;
    /* ui/shoprarity.ts tính cỡ chữ huy hiệu = clamp(10px, 10px/--sf-fit, 22px)
       để BÙ NGƯỢC phép `transform: scale(--sf-fit)` của tấm cửa hàng. Nhưng
       shop-responsive-779 đã đặt `.sf-panel{transform:none}` từ lâu ⇒ tấm KHÔNG
       còn bị co, trong khi JS vẫn ghi --sf-fit ≈ 0,28 trên máy 360px ⇒ huy hiệu
       phình lên đúng trần 22px và "NUEVO" bị cắt thành "NU…". Ở đây trả về cỡ
       px thật, ngang với PC. */
    --sf-badge-fs: var(--msx-badge-fs);
  }
  /* Khung 9-slice card_*.webp đã bị 779 tắt — chốt lại cho chắc. */
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card .sp-card-frame { display: none; }
  /* Thẻ là <button>: bỏ hiệu ứng nhấc lên của chuột, giữ phản hồi khi CHẠM. */
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card:hover { transform: none; }
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card:active { transform: scale(.98); }

  /* --- 1.5 Ô ẢNH TÀU -----------------------------------------------------
     aspect-ratio cố định + --sk-a ĐỒNG BỘ (lý do (2) ở đầu file). Trần quầng
     sáng hạ về 100% vì ô có overflow:hidden — 106% như PC sẽ xén mất quầng. */
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card .sf-art {
    order: 1;
    width: 100%; height: auto; min-height: 0; max-height: none;
    aspect-ratio: var(--msx-art-a);
    flex: 0 0 auto; align-self: stretch; margin: 0; padding: 0;
    overflow: hidden; border-radius: 10px;
    --sk-a: var(--msx-art-a);
    --sk-tw: 84%;    /* thân tàu đạt tối đa 84% bề ngang ô  */
    --sk-th: 86%;    /* … 86% bề cao ô                      */
    --sk-gwm: 100%;  /* thân + quầng KHÔNG vượt mép ô       */
    --sk-ghm: 100%;
  }
  /* Chốt chặn cuối: dù công thức cân cỡ có ra số nào, ảnh cũng không được lớn
     hơn ô ⇒ tàu KHÔNG BAO GIỜ đè lên tên / nút. aspect-ratio của <img> giữ
     nguyên nên kẹp chiều cao là chiều ngang tự co theo, không méo. */
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card .sf-art > img {
    max-width: 100%; max-height: 100%;
    object-fit: contain; object-position: center;
  }
  /* Nhánh CHƯA đo được cỡ thân (không có .sk-on): giữ kiểu contain trong vùng
     an toàn 7% — an toàn ở mọi tỉ lệ ô. */
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card .sp-card-skin:not(.sk-on) {
    left: 7% !important; top: 7% !important;
    width: 86% !important; height: 86% !important;
    transform: none !important;
  }

  /* --- 1.6 TÊN TÀU — xuống dòng thoải mái, KHÔNG "…", KHÔNG xén ----------- */
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card .sf-card-n {
    order: 2; position: static; inset: auto;
    display: flex; align-items: center; justify-content: center;
    width: 100%; max-width: 100%;
    height: auto; min-height: var(--msx-name-h);
    flex: 0 0 auto;
    margin: 0; padding: 0 2px;
    background: none !important; border: 0; border-image: none !important;
    overflow: visible; transform: none;
  }
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card .sf-nm {
    display: block; width: 100%; max-width: 100%;
    position: static; transform: none;
    white-space: normal;
    overflow-wrap: anywhere;            /* tên Đức/Nga dài vẫn ngắt được      */
    word-break: normal;                 /* … nhưng không ngắt bừa giữa từ     */
    line-break: auto;                   /* CJK ngắt đúng luật của nó          */
    text-align: center;
    overflow: visible; text-overflow: clip;
    max-height: none; -webkit-line-clamp: none;
    text-shadow: none; letter-spacing: 0;
  }

  /* --- 1.7 THANH TRẠNG THÁI / NÚT MUA ------------------------------------
     container-type: normal ⇒ bỏ ràng buộc "phải có chiều cao cố định" của
     `container-type: size`; đổi lại phải TỰ cấp --sc-sb-* vì clamp(...cqh...)
     mất chỗ dựa (xem (3) đầu file). */
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card .sf-price {
    order: 3; position: static; inset: auto; transform: none;
    display: flex; align-items: center; justify-content: center;
    width: 100%; max-width: 100%;
    height: auto !important;
    min-height: var(--msx-bar-h) !important;
    aspect-ratio: auto;
    flex: 0 0 auto;
    margin: 0; padding: 6px 8px;
    border: 0; border-image: none !important; border-radius: 10px;
    container-type: normal;
    overflow: visible;
    --sc-sb-fs: var(--msx-sb-fs);
    --sc-sb-gem: var(--msx-sb-gem);
    --sc-sb-gap: 6px;
    --sc-sb-side: 6px;
  }
  /* MainContentArea đang là `position:absolute; inset:0` — với thanh cao tự do
     thì nó KHÔNG đóng góp chiều cao (thanh sẽ dẹp 0). Trả về luồng. */
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card .sf-price > .sc-sb-main {
    position: static; inset: auto;
    display: flex; flex-flow: row nowrap;
    align-items: center; justify-content: center;
    gap: var(--sc-sb-gap);
    width: 100%; min-width: 0;
    padding: 0; height: auto; transform: none;
  }
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card .sf-price .sc-sb-text {
    position: static; display: block; flex: 0 1 auto;
    min-width: 0; max-width: 100%;
    white-space: normal;                /* chữ dài XUỐNG DÒNG, không cắt "…"  */
    overflow: visible; overflow-x: visible; text-overflow: clip;
    overflow-wrap: anywhere; word-break: normal;
    line-height: 1.25 !important;
    padding: 0; text-align: center;
    /* Độ dời canh mực của ui/statusbar.ts tính cho thanh MỘT DÒNG; ở đây chữ có
       thể 2 dòng nên bỏ, để flex canh giữa. */
    transform: none !important;
    text-shadow: none;
  }
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card .sf-price .sc-sb-gem {
    position: static; flex: 0 0 auto;
    width: var(--sc-sb-gem); height: var(--sc-sb-gem);
    transform: none;
  }
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card .sf-price .sc-sb-deco,
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card .sf-price::before,
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card .sf-price::after {
    display: none !important;
  }
  /* Màu thanh theo ảnh mẫu: trạng thái MIỄN PHÍ và ĐÃ CÓ cùng hệ xanh lá, giá
     tiền giữ hệ xanh dương/vàng như cũ. */
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card .sf-price.sc-sb--free {
    background: #12382f !important; color: #7BE8A8;
  }
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card .sf-price.own {
    background: #12382f !important; color: #98edc7;
  }

  /* --- 1.8 Huy hiệu góc: không được đẩy bố cục, không được che tên -------- */
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card > .sf-new,
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card > .sf-rar {
    position: absolute; z-index: 2; pointer-events: none; margin: 0;
  }
  /* Trần cũ 50% (shoprarity.ts) cắt "NUEVO" thành "NU…" ở thẻ 163px. Nới cho
     nhãn MỚI 62% và huy hiệu bậc hiếm 36% — tổng 98% nên hai góc KHÔNG BAO GIỜ
     chạm nhau. (Huy hiệu bậc hiếm vẫn rơi về CHẤM MÀU khi thẻ quá hẹp: đó là
     quyết định CÓ CHỦ Ý của shoprarity.ts, file này không lật lại.) */
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card > .sf-new {
    top: 6px; right: 6px; left: auto; max-width: calc(48% - 10px);
  }
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card > .sf-rar {
    top: 6px; left: 6px; right: auto; max-width: calc(52% - 10px);
  }
  /* Hai trần cộng lại = 100% ⇒ hai huy hiệu ở hai góc KHÔNG BAO GIỜ chạm nhau.
     Thẻ hẹp thì huy hiệu bậc hiếm rơi về CHẤM MÀU thay vì "Huyền th…" — đúng
     kết luận đã ghi trong ui/shoprarity.ts, chỉ nới ngưỡng từ 150px lên 240px
     cho khớp cỡ thẻ thật của bố cục này (điện thoại 138–196px, tablet ~156px).
     Nhãn MỚI thì NGƯỢC LẠI: luôn hiện đủ chữ, vì nó chỉ 1 từ ngắn. */
  @container (max-width: 240px) {
    #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card > .sf-rar { padding: .3em; gap: 0; }
    #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card > .sf-rar::before { width: .9em; height: .9em; }
    #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card > .sf-rar > .sf-rar-t { display: none; }
  }
}

/* ===========================================================================
 * (2) ĐIỆN THOẠI DỌC — NÚM VẶN THEO BỀ NGANG THẬT
 *     Cột dùng 40vw để 360/375/390/414/430 đều ra ĐÚNG 2 cột nhưng thẻ NỞ theo
 *     máy (162 → 197px) thay vì cùng một cỡ như trước.
 * ======================================================================== */
@media (max-width: 600px) and (min-height: 541px) {
  #shopframe#shopframe#shopframe#shopframe#shopframe {
    --msx-col: clamp(140px, 38vw, 200px);
    --msx-gap: clamp(8px, 2.4vw, 13px);
    --msx-pad: clamp(8px, 2.2vw, 12px);
    --msx-inner-gap: clamp(5px, 1.6vw, 8px);
    --msx-art-a: 1.55;
    --msx-bar-h: 38px;
    --msx-name-h: 34px;
    --msx-badge-fs: clamp(9px, 2.6vw, 11px);
  }

  /* KHUNG TRÀN VIỀN — giống ảnh mẫu (cửa hàng phủ kín màn, không phải tấm nổi).
     mobile-repair-830 đang đặt `#shopframe{padding:12px 14px}` +
     `.sf-panel{width:94%}` cho MỌI thiết bị cảm ứng ⇒ trên máy 360px mất 46px
     (≈13% bề ngang) chỉ để lấy cái viền — vừa đủ để lưới tụt từ 2 cột xuống 1.
     shop-landscape-840 đã làm y hệt việc này cho khổ NGANG và rot90; đây là nốt
     còn thiếu cho khổ DỌC. Lề tai thỏ dồn vào .sf-panel để nền vẫn phủ tới mép.
     Chặn `max-width:600px` nên tablet/PC không khớp. */
  #shopframe#shopframe#shopframe#shopframe#shopframe {
    padding: 0 !important;
    align-items: stretch; justify-content: stretch;
  }
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-panel {
    position: relative; left: auto; top: auto; transform: none;
    width: 100% !important; height: 100% !important;
    max-width: 100% !important; max-height: 100% !important;
    min-width: 0 !important; min-height: 0 !important;
    margin: 0 !important; border: 0 !important; border-radius: 0 !important;
    padding:
      max(10px, var(--sfl-safe-t, 0px))
      max(10px, var(--sfl-safe-r, 0px))
      max(8px,  var(--sfl-safe-b, 0px))
      max(10px, var(--sfl-safe-l, 0px)) !important;
    gap: 8px !important;
    overflow: hidden;
  }
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-panel > * { min-width: 0; min-height: 0; }
}

/* Máy rất hẹp (<=360px): hạ sàn một nấc để 2 cột không bóp nghẹt chữ. */
@media (max-width: 360px) and (min-height: 541px) {
  #shopframe#shopframe#shopframe#shopframe#shopframe {
    --msx-col: 142px;
    --msx-gap: 8px;
    --msx-pad: 8px;
    --msx-bar-h: 34px;
    --msx-name-h: 32px;
    --msx-sb-fs: 13px;
    --msx-sb-gem: 17px;
  }
}

/* Máy rất hẹp THẬT SỰ (<=320px, iPhone SE1): một cột, thẻ rộng hết khung. */
@media (max-width: 320px) and (min-height: 541px) {
  #shopframe#shopframe#shopframe#shopframe#shopframe { --msx-col: 100%; --msx-art-a: 2; }
}

/* ===========================================================================
 * (3) MÁY TÍNH BẢNG DỌC (601–820px) — menu trái đã là cột dọc 144px nên bề
 *     ngang còn lại ít hơn tưởng; 21vw cho ra 3 cột ở 768×1024 (thẻ ~171px).
 * ======================================================================== */
@media (min-width: 601px) and (max-width: 820px) and (min-height: 541px) {
  #shopframe#shopframe#shopframe#shopframe#shopframe {
    --msx-col: clamp(146px, 19.5vw, 190px);
    --msx-gap: 12px;
    --msx-pad: 11px;
    --msx-inner-gap: 7px;
    --msx-art-a: 1.5;
    --msx-bar-h: 40px;
    --msx-name-h: 36px;
    --msx-sb-fs: 14px;
    --msx-sb-gem: 19px;
  }
}

/* ===========================================================================
 * (4) ĐIỆN THOẠI NẰM NGANG THẬT (khung nhìn báo landscape)
 *     Chiều cao là thứ khan hiếm ⇒ ô ảnh NÔNG hơn (1.75) và thanh thấp hơn.
 *     Bề ngang dư ⇒ 3–5 cột tuỳ máy (667→3, 844/932→4).
 * ======================================================================== */
@media (orientation: landscape) and (max-height: 540px) and (max-width: 1023.98px) {
  #shopframe#shopframe#shopframe#shopframe#shopframe {
    --msx-col: clamp(140px, 19vw, 182px);
    --msx-gap: 8px;
    --msx-pad: 7px;
    --msx-inner-gap: 4px;
    --msx-art-a: 1.95;
    --msx-bar-h: 30px;
    --msx-name-h: 28px;
    --msx-sb-fs: 13px;
    --msx-sb-gem: 17px;
  }
}

/* ===========================================================================
 * (5) body.rot90 — MÁY DỌC, GAME TỰ XOAY 90° BẰNG CSS.
 *
 *     KHÔNG dùng @media: khung nhìn THẬT vẫn báo portrait (414×896) nên mọi
 *     ngưỡng `orientation:landscape` / `max-height` đều trượt — chính là cái bẫy
 *     đã ghi trong ui/shoptap.ts và shop-landscape-840.css.
 *     Cũng KHÔNG dùng vw/vh ở đây: trục đã bị hoán (vw = chiều cao bố cục).
 *     Số đo vì thế là px tuyệt đối.
 *
 *     Phải !important + 5 lần #id: mobile-repair-830 khoá `repeat(4)!important`
 *     (3 id) và shop-text-836 khoá `repeat(3)!important` (4 id) cho nhánh này.
 * ======================================================================== */
body.rot90 #shopframe#shopframe#shopframe#shopframe#shopframe {
  --msx-col: 156px;
  --msx-gap: 8px;
  --msx-pad: 7px;
  --msx-inner-gap: 4px;
  --msx-art-a: 1.95;
  --msx-bar-h: 30px;
  --msx-name-h: 28px;
  --msx-sb-fs: 12.5px;
  --msx-sb-gem: 17px;
}
body.rot90 #shopframe#shopframe#shopframe#shopframe#shopframe .sf-grid {
  grid-template-columns: repeat(auto-fill, minmax(min(var(--msx-col), 100%), 1fr)) !important;
  gap: var(--msx-gap) !important;
  align-items: start !important;
}
body.rot90 #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card[class] {
  height: auto !important; max-height: none !important;
  padding: var(--msx-pad) !important;
  gap: var(--msx-inner-gap) !important;
  border-radius: 12px !important;
}
body.rot90 #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card .sf-art {
  aspect-ratio: var(--msx-art-a) !important;
  height: auto !important; min-height: 0 !important; max-height: none !important;
  --sk-a: var(--msx-art-a);
}
body.rot90 #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card .sf-card-n {
  height: auto !important; min-height: var(--msx-name-h) !important;
}
body.rot90 #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card .sf-price {
  height: auto !important; min-height: var(--msx-bar-h) !important;
}

/* ===========================================================================
 * (6) Không hiệu ứng khi người dùng đã tắt chuyển động.
 * ======================================================================== */
@media (prefers-reduced-motion: reduce) {
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card,
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-card * {
    transition: none !important; animation: none !important;
  }
  #shopframe#shopframe#shopframe#shopframe#shopframe .sf-scroll { scroll-behavior: auto; }
}
