/* Cakela home page styles. Single stylesheet for the public storefront so the
   layout has one source of truth: compact type, uniform image tiles, and one
   readable section per cake line.
   Type: mọi tiêu đề dùng đúng font của thương hiệu (VL Brown Sugar) như chữ
   CAKELA trên logo. Font này có đủ 146 chữ tiếng Việt nhưng nét rất mảnh, nên
   chỉ dùng cho tiêu đề từ ~1.35rem trở lên; nhãn nhỏ, giá và số size giữ Nunito
   để đọc rõ. Line-height để rộng (1.26) cho dấu tiếng Việt không bị cắt. */
@font-face {
  font-family: CakelaDisplay;
  src: url("/files/VL-Brown-Sugar.ttf") format("truetype");
  font-display: swap;
}
:root {
  --bg: #fff8f1; --paper: #fffdf9; --cream: #f8efe4;
  --ink: #251914; --brown: #6e2c1d; --red: #b5221d; --muted: #7b665b;
  --line: rgba(110, 44, 29, .16); --shadow: 0 10px 30px rgba(89, 50, 31, .1);
  --radius: 10px; --container: 1200px;
  /* Lề trang: 16px trên máy nhỏ nhất, giãn dần tới 40px theo bề ngang máy, và từ
     lúc màn rộng hơn --container thì thành "phần thừa chia đôi" để nội dung căn
     giữa. Một biến lo cả ba việc nên không cần điểm ngắt riêng cho lề. */
  --gutter: max(clamp(16px, 4vw, 40px), calc((100vw - var(--container)) / 2));
  --header: 74px;
  /* Cỡ một nút dock liên hệ. Khai một chỗ vì có hai nơi phải khớp nhau: chính cái
     nút, và khoảng chừa dưới của chữ hero trên điện thoại - lệch một chút là dock
     đè lên nút bấm. */
  --dock: 46px;
  /* Bậc chữ co giãn. Cỡ lớn nhất giữ đúng như cũ (máy để bàn không to thêm chữ
     nào), chỉ máy nhỏ được co lại có kiểm soát thay vì đứng yên một con số cứng -
     nhờ vậy điện thoại đọc vừa mắt mà không phải cuộn thêm. */
  --text-xs: clamp(.66rem, .63rem + .1vw, .72rem);
  --text-sm: clamp(.79rem, .76rem + .12vw, .86rem);
  --text-md: clamp(.9rem, .88rem + .1vw, .96rem);
  --text-lg: clamp(.95rem, .92rem + .16vw, 1.02rem);
  --text-h3: clamp(1.24rem, 1.12rem + .5vw, 1.42rem);
  /* Nhịp giãn dòng giữa các khối, dùng chung cho lề trong thẻ và khoảng cách các
     phần - máy nhỏ chật thì hẹp lại, máy rộng thì thoáng ra. */
  --space-sm: clamp(8px, 1.2vw, 12px);
  --space-md: clamp(12px, 1.6vw, 18px);
  --space-lg: clamp(16px, 2.2vw, 24px);
  /* Chuyển động khai báo một chỗ: khối @media ở cuối rút ngắn quãng dịch cho điện
     thoại, không phải viết lại từng luật. Nhịp lệch giữa các khối cùng hàng do
     motion.js đặt thẳng vào transition-delay của từng khối. */
  --reveal-shift: 16px;
  --reveal-dur: .6s;
  --ease-out: cubic-bezier(.22, 1, .36, 1);
  --display: CakelaDisplay, Georgia, serif;
  --wordmark: var(--display);
  --sans: Nunito, "Segoe UI", Arial, sans-serif;
}
/* Màn rất rộng: nới khung nội dung một nhịp thay vì để hai bên trống hoác. Không
   nới nữa vì các đoạn chữ đã chặn ở 58ch, dài hơn là mỏi mắt đọc. */
@media (min-width: 1600px) { :root { --container: 1320px; } }
* { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
/* Lúc trang mới tải, chỗ đang đọc được đặt lại bằng JS (assets/scroll-keep.js). Cuộn
   mượt ở đây sẽ biến cú đặt lại đó thành một đoạn trang tự trôi trước mắt khách, nên
   tắt trong lúc tải rồi bật lại ngay khi đã về đúng chỗ: các nút trong menu vẫn cuộn
   mượt y như trước. */
html.is-booting { scroll-behavior: auto; }
body { margin: 0; background: var(--bg); color: var(--ink); font-family: var(--sans); font-size: var(--text-md); line-height: 1.6; }
body.nav-open, body.lightbox-open { overflow: hidden; }
img { display: block; max-width: 100%; }
a { color: inherit; }
/* Nút, ô nhập và <select> KHÔNG thừa hưởng font của trang: trình duyệt tự gán cho
   chúng một font riêng. Font đó dựng dấu tiếng Việt rất thô - dấu hỏi/ngã dí sát
   chữ, chữ đậm thì nhoè - nên nút "Tải thêm ảnh" trong /gallery/ (thẻ <button>)
   nhìn lệch hẳn so với mọi nút khác trên trang, vốn là thẻ <a> nên vẫn dùng Nunito.
   Khai một lần ở đây để mọi ô điều khiển dùng đúng font của trang. */
button, input, select, textarea { font-family: inherit; }
p { margin: 0; }
table { width: 100%; border-collapse: collapse; }
/* 1.26 leaves room for stacked Vietnamese marks; 1.15 clipped them. Cỡ chữ tiêu
   đề nhích lên so với font sans vì nét VL Brown Sugar mảnh hơn.
   Tên bánh và tên album do tiệm nhập nên có thể là một chuỗi dài không dấu cách;
   overflow-wrap để nó tự ngắt trong khung thay vì đẩy ngang cả trang. */
h1, h2, h3 { margin: 0; font-family: var(--display); line-height: 1.26; overflow-wrap: break-word; }
h2 { color: var(--brown); font-size: clamp(1.55rem, 1.4rem + .8vw, 2.4rem); font-weight: 700; }
h3 { color: var(--brown); font-size: var(--text-h3); font-weight: 700; }
:focus-visible { outline: 3px solid rgba(181, 34, 29, .45); outline-offset: 2px; }
.skip-link { position: absolute; top: 0; left: -9999px; z-index: 200; padding: 10px 14px; background: #fff; color: var(--brown); font-weight: 800; }
.skip-link:focus { top: 12px; left: 12px; }
/* Nhãn nhỏ giữ Nunito: chữ hoa cỡ .8rem của font tiêu đề sẽ mờ và khó đọc. */
.home-kicker { margin: 0 0 8px; color: #a4623f; font-family: var(--sans); font-size: var(--text-xs); font-weight: 800; line-height: 1.5; letter-spacing: .14em; text-transform: uppercase; }

/* Header. The wordmark keeps VL Brown Sugar at 1.6rem, well above the size
   where its hairlines break up; links stay in Nunito so the Vietnamese labels
   read cleanly at 14px.
   Cuộn xuống là JS gắn .is-scrolled: thanh thu còn 62px, nền đục thêm một chút và
   bóng sâu hơn - vừa nhường chỗ cho nội dung vừa cho biết trang đang cuộn. Chiều
   cao lúc đó nằm ở --header-now để tấm menu điện thoại luôn dán đúng đáy thanh,
   còn --header giữ nguyên 74px cho hero và scroll-margin của các mục.

   Thanh nằm ngoài luồng (position: fixed) và trang chừa sẵn đúng --header ở trên
   cùng. Trước đây thanh dính (sticky) nên nó vẫn chiếm chỗ trong luồng: lúc thu từ
   74px còn 62px là cả trang bị kéo lên 12px ngay khi khách vừa chạm cuộn - trên
   điện thoại khối chữ hero (dồn xuống đáy màn hình) nhảy lên thấy rõ nhất. Chừa chỗ
   bằng một con số cố định thì thanh thu bao nhiêu cũng không dịch được dòng nào.

   Thanh nằm trước mắt khách suốt quãng cuộn, nên nó không được nhận việc gì tính
   theo từng khung hình. Ba chỗ đã sửa, cho cả máy tính:
   - Nền đục thay cho kính mờ. backdrop-filter trên một thanh cố định bắt trình
     duyệt đọc lại rồi làm mờ cả dải phía sau mỗi khung hình cuộn, mà nền vốn đã
     gần đục nên nhìn không khác; đục thêm một nhịp (.96) còn hết cả vệt chữ chạy
     mờ sau thanh.
   - Chiều cao đổi một nhịp chứ không chuyển dần: 240ms chuyển min-height là 240ms
     trình duyệt xếp lại thanh, mỗi khung hình một lượt.
   - Huy hiệu và tên tiệm nhỏ lại bằng transform: scale - việc của card đồ hoạ.
     Bản cũ chuyển width/height của logo và font-size của tên tiệm, tức mỗi khung
     hình một lần xếp lại chữ và vẽ lại logo. Đo riêng ba transition này: quãng
     cuộn nặng nhất trên máy tính từ p95 133ms xuống 83ms. */
body.home-page { padding-top: var(--header); }
.home-header { --header-now: var(--header); position: fixed; inset: 0 0 auto; z-index: 80; min-height: var(--header-now); display: flex; align-items: center; justify-content: space-between; gap: 18px; padding: 0 var(--gutter); border-bottom: 1px solid var(--line); background: rgba(255, 252, 247, .96); box-shadow: 0 1px 0 rgba(255, 255, 255, .6), 0 8px 24px rgba(89, 50, 31, .06); transform: translateZ(0); transition: background-color .24s ease, box-shadow .24s ease; }
.home-header.is-scrolled { --header-now: 62px; background: rgba(255, 252, 247, .985); box-shadow: 0 1px 0 rgba(255, 255, 255, .7), 0 12px 30px rgba(89, 50, 31, .13); }
/* Vạch tiến độ cuộn ở mép dưới thanh. Dùng scroll-driven animation của CSS nên
   không thêm một dòng JS nào; trình duyệt chưa hỗ trợ thì chỉ là không có vạch. */
.home-header::after { content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 2px; transform: scaleX(0); transform-origin: 0 50%; background: linear-gradient(90deg, var(--red), #d9884a); }
@keyframes nav-progress { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@supports (animation-timeline: scroll()) {
  .home-header::after { animation: nav-progress linear both; animation-timeline: scroll(root block); }
}
.home-brand { display: inline-flex; align-items: center; gap: 11px; color: var(--brown); text-decoration: none; }
.home-brand img { width: 44px; height: 44px; object-fit: contain; }
/* Logo chữ ngang ở footer không phải huy hiệu vuông: ép vào ô 44x44 thì chữ chỉ
   còn cao 13px, không đọc được. Cho nó giữ đúng tỉ lệ 284:84 của bản SVG. */
.home-brand--word img { width: 132px; height: 39px; }
/* Đĩa kem sau huy hiệu để logo nổi lên khỏi nền giấy. Không vẽ thêm viền vì bản
   SVG đã có vòng tròn riêng, thêm nữa là hai vòng lồng nhau. */
.home-header .home-brand img { width: 48px; height: 48px; padding: 4px; border-radius: 50%; background: radial-gradient(circle at 50% 32%, #fff, var(--cream)); box-shadow: 0 2px 8px rgba(89, 50, 31, .14); transition: transform .2s ease, box-shadow .2s ease; }
.home-header .home-brand:hover img { transform: translateY(-1px); box-shadow: 0 7px 18px rgba(89, 50, 31, .22); }
/* Thanh gọn lại thì huy hiệu và tên tiệm nhỏ đi bằng đúng một phép scale trên thẻ
   bọc: 48px xuống 40px và 1.6rem xuống 1.42rem đều là khoảng .88. Một transform thì
   card đồ hoạ lo được, còn đổi width/height và font-size là bắt xếp lại chữ, vẽ lại
   logo suốt 240ms. transform-origin bên trái để lockup co về phía lề chứ không trôi
   vào giữa thanh. */
.home-header .home-brand { transform-origin: left center; transition: transform .24s ease; }
.home-header.is-scrolled .home-brand { transform: scale(.88); }
.home-brand__text { display: grid; }
.home-brand__name { font-family: var(--wordmark); font-size: 1.6rem; line-height: 1.2; letter-spacing: .02em; }
/* Slogan viết hoa đầu câu, có một khoảng trắng đầu dòng và hai dấu gạch dưới ở
   cuối. Bỏ text-transform: uppercase để chữ không bị hoá hoa, và pre-wrap để
   khoảng trắng đầu dòng còn nguyên - HTML gộp mất khoảng trắng đầu dòng. Dùng
   khoảng trắng thường chứ không phải &nbsp; nên ký tự đúng như tiệm viết. */
.home-brand small { display: block; margin-top: -1px; color: #a4623f; font-family: var(--sans); font-size: clamp(.6rem, .52rem + .22vw, .68rem); font-weight: 700; line-height: 1.25; letter-spacing: .04em; white-space: pre-wrap; }
.home-nav { display: flex; align-items: center; gap: 4px; }
.home-nav a { position: relative; min-height: 40px; display: inline-flex; align-items: center; padding: 8px 12px; border-radius: 999px; color: var(--brown); font-size: var(--text-sm); font-weight: 800; white-space: nowrap; text-decoration: none; transition: background-color .18s ease, color .18s ease; }
.home-nav a:hover { background: var(--cream); }
/* Gạch chân mọc từ giữa ra hai bên khi trỏ vào: cùng vị trí với vạch của mục
   đang xem nên hàng chữ không nhảy. */
.home-nav a::before { content: ""; position: absolute; left: 50%; right: 50%; bottom: 4px; height: 2px; border-radius: 2px; background: var(--red); opacity: 0; transition: left .2s ease, right .2s ease, opacity .2s ease; }
.home-nav a:hover::before, .home-nav a:focus-visible::before { left: 12px; right: 12px; opacity: 1; }
.home-nav a.is-cta::before, .home-nav a.nav-phone::before { content: none; }
/* Thin underline marks the page you are on without shifting the row height. */
.home-nav a.is-current { color: var(--red); }
.home-nav a.is-current::after { content: ""; position: absolute; left: 12px; right: 12px; bottom: 4px; height: 2px; border-radius: 2px; background: var(--red); }
/* Số bấm gọi: việc khách hay làm nhất ở tiệm bánh. Chỉ hiện khi thanh còn đủ
   rộng, còn máy hẹp thì nó nằm trong tấm menu. Phải viết kèm .home-nav vì luật
   .home-nav a ở trên đã đặt display, hơn hẳn một class trơ về độ ưu tiên. */
.home-nav a.nav-phone { display: none; gap: 7px; font-variant-numeric: tabular-nums; }
.nav-phone svg { width: 15px; height: 15px; flex: none; }
@media (min-width: 1080px) { .home-nav a.nav-phone { display: inline-flex; } }
/* Mục "Xem mẫu bánh" là đường dẫn khách bấm nhiều thứ hai sau nút đặt bánh, nên
   nó mang dáng một cái thẻ: nền kem, viền đỏ nhạt, icon ảnh và con số mẫu. Nổi hơn
   các mục chữ trơn nhưng vẫn nhường nút đặt bánh màu đỏ đặc. */
.home-nav a.nav-gallery { gap: 7px; padding: 7px 9px 7px 11px; border: 1px solid rgba(181, 34, 29, .24); background: var(--cream); transition: background-color .18s ease, border-color .18s ease, color .18s ease; }
.home-nav a.nav-gallery:hover { border-color: rgba(181, 34, 29, .46); background: #fff1e1; }
.home-nav a.nav-gallery::before { content: none; }
/* Trang thư viện: viền đậm lên thay cho gạch chân, vì gạch chân nằm trong thẻ
   có viền trông như một nét lạc. */
.home-nav a.nav-gallery.is-current { border-color: var(--red); background: #fff1e1; }
.home-nav a.nav-gallery.is-current::after { content: none; }
.i-gallery { width: 16px; height: 16px; flex: none; color: var(--red); }
.nav-gallery small { padding: 3px 7px; border-radius: 999px; background: var(--red); color: #fff; font-size: .68rem; font-weight: 800; line-height: 1.1; font-variant-numeric: tabular-nums; }
/* Nút ở hero và đường dẫn trong thẻ giá: icon lớn hơn một nhịp, ăn theo màu chữ
   của nút chứ không phải màu đỏ (nút sáng nền trắng, chữ nâu). */
.home-button .i-gallery { width: 18px; height: 18px; color: currentColor; }
.cake-card-head a { gap: 6px; }
.cake-card-head a .i-gallery { width: 15px; height: 15px; }
.home-nav a.is-cta { margin-left: 8px; padding: 10px 20px; border: 0; color: #fff; background: linear-gradient(135deg, #c9302a, #96201b); box-shadow: 0 6px 16px rgba(181, 34, 29, .26); transition: transform .18s ease, box-shadow .18s ease, filter .18s ease; }
.home-nav a.is-cta:hover { filter: brightness(1.07); transform: translateY(-1px); box-shadow: 0 10px 24px rgba(181, 34, 29, .34); }
.home-nav a.is-cta:active { transform: none; box-shadow: 0 4px 12px rgba(181, 34, 29, .3); }
/* Mục "Menu bánh" mang theo bảng con liệt kê các dòng bánh, thay cho mục "Dòng bánh"
   đứng riêng trước đây: thanh menu bớt một chỗ mà khách vẫn nhảy được thẳng tới đúng
   bảng giá. Chữ vẫn là link thật (bấm vào là tới bảng giá bánh kem), nút mũi xuống
   cạnh nó mới là cái mở bảng con - nhờ vậy màn cảm ứng chạm một lần là mở, không
   phải chạm vào chữ rồi mất luôn cả link. Máy có chuột chỉ cần trỏ vào. Bảng con
   ẩn bằng visibility chứ không phải display để nó mở ra mềm mắt mà bàn phím vẫn
   không tab vào lúc đang đóng. */
.nav-group { position: relative; display: inline-flex; align-items: center; }
.home-nav .nav-group__link { padding-right: 4px; }
.nav-group__toggle { display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; margin-right: 4px; padding: 0; border: 0; border-radius: 999px; background: transparent; color: var(--brown); cursor: pointer; transition: transform .2s ease, background-color .18s ease; }
.nav-group__toggle svg { width: 14px; height: 14px; }
.nav-group__toggle:hover { background: var(--cream); }
.nav-group__toggle[aria-expanded="true"] { transform: rotate(180deg); }
/* padding-top thay cho margin: chừa khoảng hở dưới mục menu mà chuột đi từ chữ
   xuống bảng con không rơi ra ngoài vùng hover (rơi ra là bảng đóng ngay giữa
   đường). */
.nav-dropdown { position: absolute; top: 100%; left: 0; z-index: 90; min-width: 246px; padding-top: 10px; opacity: 0; visibility: hidden; transform: translateY(-6px); transition: opacity .18s ease, transform .18s ease, visibility .18s; }
.nav-dropdown__inner { display: grid; gap: 2px; padding: 8px; border: 1px solid var(--line); border-radius: 16px; background: var(--paper); box-shadow: var(--shadow); }
.home-nav .nav-dropdown a { display: grid; gap: 1px; min-height: 0; padding: 9px 12px; border-radius: 10px; white-space: normal; }
.home-nav .nav-dropdown a::before, .home-nav .nav-dropdown a::after { content: none; }
.nav-dropdown a strong { font-size: var(--text-sm); font-weight: 800; }
.nav-dropdown a small { color: var(--muted); font-size: .72rem; font-weight: 600; line-height: 1.3; }
.nav-group.is-open > .nav-dropdown { opacity: 1; visibility: visible; transform: none; }
/* Chỉ máy có chuột thật mới mở theo hover: trên điện thoại "hover" xảy ra ngay lúc
   chạm nên bảng con sẽ tự mở rồi không cách nào đóng. */
@media (hover: hover) and (min-width: 901px) {
  .nav-group:hover > .nav-dropdown { opacity: 1; visibility: visible; transform: none; }
}
/* Nút ☰ tự thành dấu X theo aria-expanded, khỏi cần JS đổi class. */
.nav-toggle { display: none; position: relative; width: 44px; height: 44px; border: 1px solid var(--line); border-radius: 12px; background: var(--paper); color: var(--brown); cursor: pointer; }
.nav-toggle__bars, .nav-toggle__bars::before, .nav-toggle__bars::after { content: ""; position: absolute; left: 13px; width: 18px; height: 2px; border-radius: 2px; background: currentColor; transition: transform .22s ease, background-color .18s ease; }
.nav-toggle__bars { top: 21px; }
.nav-toggle__bars::before { left: 0; top: -6px; }
.nav-toggle__bars::after { left: 0; top: 6px; }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars { background: transparent; }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars::before { transform: translateY(6px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars::after { transform: translateY(-6px) rotate(-45deg); }
@keyframes nav-drop { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: none; } }
@keyframes nav-item { from { opacity: 0; transform: translateY(-5px); } to { opacity: 1; transform: none; } }


/* Hero trên cùng chiếm đúng khung nhìn đầu tiên: phần chữ căn giữa theo chiều
   dọc, hàng "dòng bánh" nằm sát đáy hero nên khách thấy ngay toàn bộ menu bánh
   mà chưa cần cuộn. 100svh là chiều cao khung nhìn nhỏ nhất của trình duyệt di
   động, cộng đúng --header nên hero không hở một dải trắng và cũng không bị
   thanh địa chỉ cắt mất hàng dòng bánh. Ảnh nền do PHP truyền vào --hero-image
   (bản WebP nhẹ nếu có, không thì ảnh gốc). */
.home-hero { position: relative; min-height: calc(100svh - var(--header)); display: grid; grid-template-rows: 1fr auto; gap: clamp(14px, 2vw, 24px); padding: clamp(20px, 3.2vw, 42px) var(--gutter) clamp(14px, 2vw, 26px); color: #fff; background-color: #2a170f; background-image: linear-gradient(90deg, rgba(29, 15, 9, .88), rgba(29, 15, 9, .58) 46%, rgba(29, 15, 9, .2)), var(--hero-image); background-position: center right; background-size: cover; background-repeat: no-repeat; }
.home-hero__content { align-self: center; width: min(660px, 100%); }
.home-hero .home-kicker { color: #ffdcb2; text-shadow: 0 2px 14px rgba(0, 0, 0, .55); }
/* Tên tiệm và câu dẫn dưới nó to hơn hẳn phần chữ còn lại của trang: đây là hai
   dòng đầu tiên khách đọc, mà chúng lại nằm trên ảnh nên để cỡ như chữ trong các
   mục bên dưới là chìm vào nền. Cỡ lớn nhất 4.8rem là mức tên tiệm còn nằm gọn
   một dòng trong khung chữ 660px của hero (đo được ngưỡng gãy dòng 77.9px) - to
   hơn nữa là "Cakela" rơi xuống dòng dưới, tên tiệm bị cắt làm hai. Điện thoại có
   luật riêng ở khối 900px.
   Câu dẫn thôi dùng --text-lg (bậc đó dành cho chữ trong các mục dưới) và có thang
   riêng co theo bề ngang máy, nên trên điện thoại nó cũng lớn thêm một nhịp.
   1.1 keeps stacked marks apart on two-line headlines. */
.home-hero h1 { color: #fff; font-size: clamp(2.6rem, 1.8rem + 3.55vw, 4.8rem); font-weight: 700; line-height: 1.12; text-wrap: balance; text-shadow: 0 12px 34px rgba(0, 0, 0, .45); }
.home-hero p:not(.home-kicker) { max-width: 54ch; margin: 16px 0 0; color: rgba(255, 255, 255, .92); font-size: clamp(1.05rem, .99rem + .48vw, 1.28rem); text-shadow: 0 2px 12px rgba(0, 0, 0, .5); }
.home-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: var(--space-lg); }
.home-button { min-height: 46px; display: inline-flex; align-items: center; justify-content: center; gap: 8px; padding: 10px 20px; border: 1px solid transparent; border-radius: 999px; font-size: var(--text-md); font-weight: 800; text-align: center; text-decoration: none; cursor: pointer; transition: transform .18s ease, box-shadow .18s ease; }
.home-button:hover { transform: translateY(-1px); }
/* Bấm xuống là nút lún nhẹ: trên điện thoại đây là phản hồi duy nhất khách nhận
   được, vì máy cảm ứng không có trạng thái trỏ chuột. */
.home-button:active { transform: scale(.985); }
.home-button.primary { background: var(--red); color: #fff; box-shadow: 0 10px 24px rgba(181, 34, 29, .28); }
.home-button.light { background: rgba(255, 255, 255, .95); color: var(--brown); box-shadow: 0 10px 24px rgba(0, 0, 0, .18); }
.home-button.outline { border-color: var(--line); background: #fff; color: var(--brown); }
/* One quiet row so the opening hours, phone and area stay above the fold. Each
   item is its own pill: a wrapped separator dot would start the second line. */
.home-hero__meta { display: flex; flex-wrap: wrap; gap: 8px; margin-top: var(--space-md) !important; color: rgba(255, 255, 255, .92) !important; font-size: var(--text-sm) !important; font-weight: 700; text-shadow: none !important; }
.home-hero__meta span { padding: 5px 13px; border: 1px solid rgba(255, 255, 255, .34); border-radius: 999px; background: rgba(29, 15, 9, .28); backdrop-filter: blur(6px); }
/* Con số "3.000+ mẫu bánh" là số ảnh thật trong các album Facebook, làm tròn xuống
   nghìn. Cho nó viền sáng hơn một chút để nổi trong hàng thẻ mà không thành nút. */

/* Hàng dòng bánh nằm trong hero: thẻ kính mờ trên ảnh, nhãn giữ Nunito để đọc rõ ở
   cỡ nhỏ trên nền ảnh - đúng như bản đang chạy ở cakela.vn. grid-auto-flow: column cho
   mọi thẻ đứng đúng một hàng dù tiệm thêm hay bớt dòng bánh: không để auto-fit tự chia
   (có những bề ngang nó cho ra 6 cột, thẻ thứ 7 nằm trơ một hàng dưới) và cũng không
   đặt cứng số cột (đặt cứng 7 thì dòng bánh thứ 8 lại trơ đúng một thẻ ở hàng dưới).
   Một hàng như vậy chỉ giữ từ 1280px trở lên, là khổ phần nội dung còn đủ 1200px; dưới
   đó hàng thẻ xuống thành hai hàng bốn thẻ - luật ở khối 1279px bên dưới.
   scroll-margin-top: mục "Dòng bánh" trên thanh menu trỏ đúng vào hàng này, mà thanh
   menu dán trên nên không chừa chiều cao của nó thì hàng thẻ nhảy tới lại nằm khuất
   sau thanh. Luật chung chỉ đặt cho main > section, hàng thẻ không phải section nên
   phải khai riêng.
   Lề phải chừa chỗ cho dock liên hệ: hai nút Zalo/Messenger nổi cố định ở góc phải đáy
   màn, rộng 46px và cách mép 12px. Màn rộng thì lề trang đã hơn 66px nên chừa 0, không
   thẻ nào bị che; từ khoảng 1360px xuống lề trang co về 40px, thiếu đúng phần chênh đó
   và thẻ cuối hàng nằm dưới dock - bấm vào là gọi Zalo chứ không nhảy tới dòng bánh.
   max() nên phép chừa tự tắt ở màn rộng, không phải đặt thêm điểm ngắt nào. */
.home-jump { align-self: end; display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: clamp(6px, .7vw, 10px); padding-right: max(0px, 66px - var(--gutter)); scroll-margin-top: calc(var(--header) + 8px); }
.home-jump a { min-height: 58px; display: grid; align-content: center; gap: 2px; padding: 9px 12px; border: 1px solid rgba(255, 255, 255, .3); border-radius: 10px; background: rgba(29, 15, 9, .34); color: #fff; text-decoration: none; backdrop-filter: blur(8px); transition: background-color .18s ease, transform .18s ease; }
.home-jump a:hover { background: rgba(181, 34, 29, .74); transform: translateY(-2px); }
.home-jump strong { font-family: var(--sans); font-size: var(--text-sm); font-weight: 800; line-height: 1.25; }
.home-jump span { overflow: hidden; color: rgba(255, 255, 255, .78); font-size: var(--text-xs); line-height: 1.3; text-overflow: ellipsis; white-space: nowrap; }
main > section { scroll-margin-top: calc(var(--header) + 8px); }
.home-section { padding: clamp(30px, 4vw, 52px) var(--gutter); }
.section-title { display: grid; gap: 6px; max-width: 760px; margin-bottom: var(--space-lg); }
.section-title p:not(.home-kicker) { color: var(--muted); }

/* Cake menu: photo grid, size table and order notes side by side. Tile counts
   always divide evenly into the column count so no row is left half empty. */
.cake-section { border-bottom: 1px solid var(--line); background: linear-gradient(180deg, #fff9f2, #fffaf6); }
/* Section header carries the two computed badges (cheapest price, number of
   sizes) on the right so the price range is visible before the table. */
.cake-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 14px clamp(16px, 2vw, 26px); margin-bottom: clamp(16px, 2.2vw, 22px); }
.cake-head .section-title { margin-bottom: 0; }
.cake-badges { display: flex; flex-wrap: wrap; gap: clamp(7px, .8vw, 10px); }
/* min-width: 0 để nhãn dài không đẩy thẻ tràn khỏi hàng trên máy hẹp. */
.cake-badge { min-width: 0; display: grid; padding: 8px clamp(12px, 1.4vw, 18px); border: 1px solid var(--line); border-radius: 999px; background: var(--paper); box-shadow: var(--shadow); color: inherit; text-align: center; text-decoration: none; }
.cake-badge small { color: var(--muted); font-size: var(--text-xs); font-weight: 800; line-height: 1.4; letter-spacing: .12em; text-transform: uppercase; }
.cake-badge strong { color: var(--red); font-family: var(--sans); font-size: var(--text-lg); font-weight: 800; line-height: 1.25; white-space: nowrap; }
/* Ba cột cao bằng nhau nghe gọn gàng, nhưng cột ảnh (8 ô vuông xếp 2 cột) luôn cao
   hơn hai thẻ chữ cả trăm px, nên phần thừa ấy phải đi đâu đó: hoặc giãn từng hàng
   giá, hoặc đọng thành một khoảng giấy trắng dưới đáy thẻ - cả hai đều là khoảng
   trắng không do nội dung sinh ra. align-items: start để mỗi khối kết thúc ở đúng
   chỗ nội dung nó hết; thẻ "Đặt bánh cần gì?" cao hơn thẻ bảng giá vì nó nhiều dòng
   hơn, chứ không phải vì cột ảnh bên cạnh dài. */
.cake-showcase { display: grid; grid-template-columns: minmax(200px, .9fr) minmax(340px, 1.25fr) minmax(220px, .85fr); gap: var(--space-md); align-items: start; }
.cake-gallery { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(7px, .9vw, 10px); align-content: start; }
/* Ô ảnh và ô chờ dùng cùng khung vuông, nên lưới không nhảy khi JS thay ô chờ
   bằng ảnh thật. */
.cake-gallery a, .feature-media a, .tile-skeleton { aspect-ratio: 1 / 1; overflow: hidden; border-radius: var(--radius); background: var(--cream); box-shadow: var(--shadow); }
/* Ô chờ không nhấp nháy nữa, chỉ là một khung kem nhạt. app.js dựng ảnh thật khi
   lưới còn cách khung nhìn 500px và xoá hết ô chờ ngay lúc đó, nên nhịp nhấp nháy
   chỉ chạy ở những lưới còn nằm ngoài màn - khách không bao giờ thấy, mà máy vẫn
   chạy đủ cả chục animation vô hạn (đo được 36 cái trên trang chủ ở điện thoại). */
.tile-skeleton { display: none; opacity: .72; }
/* Ô chờ chỉ dành cho trình duyệt có JS; tắt JS thì <noscript> nhả thẳng thẻ <a>
   vào lưới nên bố cục vẫn y như cũ. */
.has-js .tile-skeleton { display: block; }
.no-js noscript { display: contents; }
/* Ảnh lỗi cả bản dự phòng: ẩn thẻ ảnh để không hiện icon ảnh vỡ của trình duyệt,
   ô còn lại là một khung kem phẳng như ô chưa có ảnh. */
.cake-gallery a.is-broken img, .feature-media a.is-broken img { display: none; }
.cake-gallery img, .feature-media img { width: 100%; height: 100%; object-fit: cover; transition: transform .28s ease; }
.cake-gallery a:hover img, .feature-media a:hover img { transform: scale(1.04); }
.cake-menu-card, .cake-order-card { display: flex; flex-direction: column; padding: var(--space-md) clamp(14px, 1.7vw, 20px); border: 1px solid var(--line); border-radius: var(--radius); background: var(--paper); box-shadow: var(--shadow); }
/* The head is pulled out to the card edges so it reads as a title strip. */
.cake-card-head { display: flex; align-items: center; justify-content: space-between; gap: 14px; margin: calc(var(--space-md) * -1) calc(clamp(14px, 1.7vw, 20px) * -1) 12px; padding: 12px clamp(14px, 1.7vw, 20px); border-bottom: 1px solid var(--line); border-radius: var(--radius) var(--radius) 0 0; background: linear-gradient(180deg, #fff5e9, #fffdf9); }
.cake-card-head a { display: inline-flex; align-items: center; min-height: 32px; color: var(--red); font-size: var(--text-sm); font-weight: 800; white-space: nowrap; text-decoration: none; }
.cake-card-head a:hover { text-decoration: underline; }
/* Mỗi hàng giá cao đúng bằng dòng chữ trong nó (56px, 60px ở hai hàng có ghi chú
   nhỏ): bảng không nở ra cho vừa chiều cao cột nào cả. */
.cake-menu-card .home-price-table { flex: 0 0 auto; }
.cake-note { margin-top: 12px; padding-top: 10px; border-top: 1px dashed var(--line); color: var(--muted); font-size: var(--text-sm); font-weight: 700; }
/* Bốn mục cách nhau đúng 12px như nhau, không chia đều theo chiều cao cột: trước
   đây space-between đẩy chúng ra tới 25px, xa hơn cả khoảng cách giữa các hàng giá
   ngay bên cạnh, nên hai thẻ đọc lệch nhịp nhau. */
.cake-order-card dl { counter-reset: note; flex: 1 1 auto; display: grid; align-content: start; gap: 12px; margin: 0 0 14px; }
.cake-order-card dl > div { position: relative; padding-left: 32px; }
.cake-order-card dl > div::before { counter-increment: note; content: counter(note); position: absolute; top: 3px; left: 0; width: 22px; height: 22px; display: grid; place-items: center; border-radius: 50%; background: var(--cream); color: var(--brown); font-family: var(--sans); font-size: .74rem; font-weight: 800; }
.cake-order-card dt { color: var(--brown); font-size: var(--text-md); font-weight: 800; }
.cake-order-card dd { margin: 2px 0 0; color: var(--muted); font-size: var(--text-sm); line-height: 1.5; }
/* Ghi chú nhiều dòng (cốt bánh, thông tin cần cung cấp): chấm nhỏ thay cho bullet
   mặc định để không đụng cột số tròn của dl, và các ý xếp sát nhau thành một khối. */
.cake-order-card .note-list { margin: 4px 0 0; padding: 0; list-style: none; display: grid; gap: 3px; }
.cake-order-card .note-list li { position: relative; padding-left: 12px; }
.cake-order-card .note-list li::before { content: ""; position: absolute; top: .6em; left: 2px; width: 4px; height: 4px; border-radius: 50%; background: rgba(110, 44, 29, .38); }
.cake-order-card .home-button { width: 100%; }
.cake-order-actions { display: grid; gap: 8px; margin-top: auto; }

/* Price lists. The main table is zebra striped with a size chip per row, so
   eight rows can be scanned without reading every cake name. */
.home-price-table { border-collapse: separate; border-spacing: 0 3px; }
.home-price-table td { padding: 8px 10px; vertical-align: middle; transition: background-color .16s ease; }
.home-price-table tbody tr:nth-child(odd) td { background: rgba(248, 239, 228, .6); }
.home-price-table tbody tr:hover td { background: #fbe6d6; }
.home-price-table td:first-child { border-radius: 8px 0 0 8px; }
.home-price-table td:last-child { border-radius: 0 8px 8px 0; }
.home-price-table .cake-size { width: clamp(38px, 4.4vw, 52px); padding-right: 0; }
/* Giá và số size là dữ liệu cần đọc nhanh nên giữ Nunito, chỉ tiêu đề dùng font
   thương hiệu. Ô size là hình tròn nên hai chiều đi cùng một con số. */
.size-chip { --chip: clamp(30px, 3.4vw, 40px); width: var(--chip); height: var(--chip); display: grid; place-items: center; border-radius: 50%; background: #fff; color: var(--brown); font-family: var(--sans); font-size: var(--text-sm); font-weight: 800; line-height: 1; box-shadow: inset 0 0 0 1px var(--line); }
/* Two-tier cakes get the red chip, so the pairs stand out from single sizes. */
.size-chip.is-double { background: #fff0e6; color: var(--red); box-shadow: inset 0 0 0 1px rgba(181, 34, 29, .3); }
.mini-price-table td { padding: 8px 0; border-bottom: 1px solid rgba(110, 44, 29, .12); vertical-align: middle; }
.mini-price-table tr:last-child td { border-bottom: 0; }
.home-price-table td:nth-child(2), .mini-price-table td:first-child { font-size: var(--text-md); font-weight: 700; }
.home-price-table small { display: block; margin-top: 1px; color: var(--muted); font-size: var(--text-xs); font-weight: 600; }
.home-price-table td:last-child, .mini-price-table td:last-child { color: var(--red); font-family: var(--sans); font-size: var(--text-md); font-weight: 800; text-align: right; white-space: nowrap; }
.mini-price-table { margin: 14px 0 16px; }
/* Dòng "giá có thể chênh lệch" của từng dòng bánh dùng đúng kiểu .cake-note dưới
   bảng giá bánh kem; bỏ max-width của .feature-copy p để gạch đứt kéo hết bảng. */
.feature-copy .cake-note { max-width: none; margin-top: 12px; }

/* One cake line per section: copy beside a uniform 2x2 (or 3x2) photo block. */
.feature-row { display: grid; grid-template-columns: minmax(0, .95fr) minmax(0, 1.05fr); gap: clamp(20px, 3vw, 40px); align-items: center; border-bottom: 1px solid var(--line); background: #fff; }
.feature-row:nth-of-type(even) { background: linear-gradient(180deg, #fffaf5, #fff7ef); }
.feature-row.is-reverse .feature-copy { order: 2; }
.feature-copy p { max-width: 58ch; margin: 10px 0 0; color: var(--muted); }
.home-list { margin: 12px 0 16px; padding-left: 18px; color: var(--muted); font-size: var(--text-md); }
.home-list li { margin-top: 4px; }
.feature-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: var(--space-md); }
.feature-media { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(7px, .9vw, 10px); }
.feature-media.dense { grid-template-columns: repeat(3, minmax(0, 1fr)); }

/* Ô "Kể Cakela nghe về ngày vui của bạn." đặt ngay trước footer: cùng ngôn ngữ
   với hero (ảnh full-bleed, chữ trắng) nhưng chữ nằm bên phải và lớp phủ đậm dần
   sang phải, vì cakela-hp-1.jpg sáng ở nửa trái. Đây là lời mời nhắn tin cuối
   trang, không phải hero mở đầu. */
/* Ô mời đặt bánh cuối trang chiếm trọn một khung nhìn như hero đầu trang. */
.home-invite { position: relative; display: grid; align-content: center; min-height: 100svh; padding: clamp(32px, 5vw, 66px) var(--gutter); color: #fff; background-color: #2a170f; background-image: linear-gradient(90deg, rgba(29, 15, 9, .12), rgba(29, 15, 9, .5) 38%, rgba(29, 15, 9, .86)), var(--invite-image); background-position: center; background-size: cover; background-repeat: no-repeat; }
.home-invite__content { width: min(620px, 100%); margin-left: auto; }
.home-invite .home-kicker { color: #ffdcb2; text-shadow: 0 2px 14px rgba(0, 0, 0, .55); }
.home-invite h2 { color: #fff; font-size: clamp(1.85rem, 1.35rem + 2.5vw, 3.7rem); line-height: 1.14; text-wrap: balance; text-shadow: 0 12px 34px rgba(0, 0, 0, .45); }
.home-invite p:not(.home-kicker) { max-width: 54ch; margin: 14px 0 0; color: rgba(255, 255, 255, .92); font-size: var(--text-lg); text-shadow: 0 2px 12px rgba(0, 0, 0, .5); }
.home-invite .home-hero__meta { margin-top: var(--space-lg) !important; }

/* Contact dock, footer, lightbox */
/* Dock liên hệ neo góc phải. env(safe-area-inset-*) để trên iPhone nó không nằm
   dưới vạch home hay trong tai màn hình khi máy quay ngang. */
.floating-actions { position: fixed; right: max(12px, env(safe-area-inset-right)); bottom: max(12px, env(safe-area-inset-bottom)); z-index: 60; display: grid; gap: 8px; }
.floating-actions a { width: var(--dock); height: var(--dock); display: grid; place-items: center; border: 1px solid var(--line); border-radius: 50%; background: #fff; box-shadow: var(--shadow); transition: transform .18s ease, box-shadow .18s ease; }
.floating-actions a:hover { transform: translateY(-2px); box-shadow: 0 14px 28px rgba(89, 50, 31, .2); }
.floating-actions a:active { transform: scale(.94); }
.floating-actions img { width: 24px; height: 24px; object-fit: contain; }
/* Cột giữa (menu mạng xã hội) chỉ cần vừa nội dung, hai cột chữ chia phần còn
   lại - nhờ vậy không cần chỉnh tay ở từng bề ngang. */
.home-footer { display: grid; grid-template-columns: minmax(0, 1.2fr) auto minmax(0, 1.2fr); gap: var(--space-lg); padding: clamp(26px, 3vw, 34px) var(--gutter) max(clamp(26px, 3vw, 34px), env(safe-area-inset-bottom)); border-top: 1px solid var(--line); background: var(--paper); }
.home-footer p { margin: 6px 0 0; color: var(--muted); font-size: var(--text-sm); }
.home-footer a { color: var(--brown); font-weight: 800; text-decoration: none; }
/* Vùng bấm của link footer đủ 44px cho ngón tay, không chỉ cao bằng dòng chữ. */
.home-footer nav a { display: inline-flex; align-items: center; min-height: 44px; }
.home-footer nav { display: grid; align-content: start; }
.home-footer iframe { width: 100%; height: clamp(180px, 20vw, 260px); border: 0; border-radius: var(--radius); }
.lightbox { position: fixed; inset: 0; z-index: 110; display: grid; place-items: center; padding: clamp(14px, 2.4vw, 24px); background: rgba(24, 15, 10, .92); opacity: 0; visibility: hidden; transition: .2s ease; }
.lightbox.is-open { opacity: 1; visibility: visible; }
/* svh: trên điện thoại 86vh tính cả phần thanh địa chỉ che mất, ảnh bị cắt đáy. */
.lightbox img { max-width: min(1100px, 92vw); max-height: 86vh; max-height: 86svh; border-radius: var(--radius); object-fit: contain; transform: scale(.97); transition: transform .26s var(--ease-out); }
.lightbox.is-open img { transform: none; }
.lightbox [data-lightbox-close] { position: absolute; top: max(12px, env(safe-area-inset-top)); right: max(12px, env(safe-area-inset-right)); width: 44px; height: 44px; border: 0; border-radius: 50%; background: #fff; color: var(--brown); font-size: 1.4rem; cursor: pointer; }

/* ---------- Chuyển động ----------
   Chỉ chạy hai thứ trình duyệt vẽ được trên card đồ hoạ: opacity và transform.
   Không đụng tới width/height/top/left hay box-shadow theo thời gian vì mỗi khung
   hình như vậy bắt tính lại layout cả trang - đó mới là thứ gây giật.
   Mỗi khối động một lần rồi thôi, và motion.js tháo hết class của hiệu ứng ngay sau
   đó: khối đã hiện thì trở lại đúng một phần tử thường, không còn luật reveal nào
   dính vào. Nhấp nháy vô hạn chỉ còn ở ô chờ ảnh trong thư viện, và chỉ khi ô đó
   đang ở trong màn chờ ảnh về thật - máy yếu và pin điện thoại không phải trả giá
   cho thứ khách không nhìn thấy.
   Máy đặt "giảm chuyển động" thì khối @media cuối file tắt sạch. */

/* Hero: chữ trồi lên một nhịp ngay khi trang hiện. Hai dòng trên cùng chỉ dịch
   chỗ chứ không mờ dần - chữ tiêu đề là phần trình duyệt lấy làm mốc đo "bao lâu
   thì thấy nội dung chính", cho nó mờ từ 0 là tự khai chậm thêm nửa giây. */
@keyframes hero-rise { from { transform: translateY(14px); } to { transform: none; } }
@keyframes hero-fade { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
/* backwards chứ không phải both: nhịp cuối của hai keyframe này đúng bằng trạng
   thái thường của phần tử, nên không cần giữ lại kết quả sau khi chạy xong. Giữ
   (both) thì animation treo lại trên phần tử mãi, lớp vẽ riêng của nó không được
   thu về, mà luật hover của thẻ dòng bánh cũng bị animation đè - trỏ chuột vào
   không thấy thẻ nấc lên nữa. */
.home-hero__content > * { animation: hero-rise .55s var(--ease-out) backwards; }
.home-hero__content > *:nth-child(2) { animation-delay: .05s; }
.home-hero__content > *:nth-child(3) { animation-delay: .1s; }
.home-hero__content > .home-actions { animation-name: hero-fade; animation-delay: .16s; }
.home-hero__content > .home-hero__meta { animation-name: hero-fade; animation-delay: .22s; }
.home-jump a { animation: hero-fade .5s var(--ease-out) backwards; }
.home-jump a:nth-child(1) { animation-delay: .26s; }
.home-jump a:nth-child(2) { animation-delay: .31s; }
.home-jump a:nth-child(3) { animation-delay: .36s; }
.home-jump a:nth-child(4) { animation-delay: .41s; }
.home-jump a:nth-child(5) { animation-delay: .46s; }
.home-jump a:nth-child(6) { animation-delay: .51s; }
.home-jump a:nth-child(7) { animation-delay: .56s; }
/* Tiệm thêm dòng bánh thì các thẻ dôi ra hiện cùng nhau ở nhịp cuối, thay vì
   không có luật nào rồi hiện ngay từ mili-giây đầu - trước cả thẻ thứ nhất. */
.home-jump a:nth-child(n + 8) { animation-delay: .61s; }

/* Các khối dưới hero hiện dần khi cuộn tới. .motion-ready do motion.js gắn vào
   <html>, nên khi tắt JavaScript mọi thứ hiện sẵn - không bao giờ có trang trắng.
   Quãng dịch và thời gian lấy từ hai biến ở :root, nên khối @media cuối file rút gọn
   cho điện thoại bằng hai dòng thay vì viết lại từng luật.

   Nhịp lệch giữa các khối cùng hàng không còn đi qua biến --reveal-delay nữa: biến tự
   định nghĩa thì di truyền, gắn nó vào một khối là trình duyệt phải tính lại kiểu cho
   cả cây con bên trong - rồi lúc dọn class lại tính thêm một lượt nữa. Giờ motion.js
   đặt thẳng transition-delay lên chính khối đó, thuộc tính này không di truyền nên chỉ
   một phần tử phải tính lại. Đo trên trang chủ (CPU x4, cuộn dài): 200ms tính lại style
   xuống còn 170ms, khung hình dài quá 32ms từ 35 còn 26 - mà mắt nhìn y như cũ. */
.motion-ready .reveal { opacity: 0; transform: translateY(var(--reveal-shift)); transition: opacity var(--reveal-dur) ease, transform var(--reveal-dur) var(--ease-out); }
.motion-ready .reveal.is-visible { opacity: 1; transform: none; }
/* Ảnh đăng ký lẻ (ô album, ảnh trong album - do JS nạp về sau) phóng nhẹ từ 96%
   thay vì dịch lên: ảnh vuông dịch dọc trông như bị xô, còn phóng thì mềm. */
.motion-ready .reveal.is-zoom { transform: scale(.96); }
.motion-ready .reveal.is-zoom.is-visible { transform: none; }
/* Trước đây từng dòng chữ trong khối và từng ô ảnh trong lưới còn hiện lệch nhịp
   riêng, mỗi phần tử một transition. Đo trên trang chủ (CPU x4, một quãng cuộn dài):
   để nguyên thì 39 khung hình dài quá 32ms và 293ms tính lại style; bỏ nhịp lệch của
   phần con, chỉ giữ hiệu ứng của cả khối, còn 24 khung và 194ms - đúng một nửa chỗ
   nặng nhất trên trang. Lý do: mỗi transition bắt đầu và kết thúc là một lượt tính
   lại style cho phần tử đó, cả trang có tới tám chục phần tử con nên cứ cuộn nhanh
   qua ba bốn khối là main thread không kịp thở. Gắn will-change cũng đã thử: card đồ
   hoạ nhận việc vẽ nhưng số lượt tính style không giảm, nên không cứu được.
   Khối vẫn mờ dần và trồi lên như cũ, chữ và ảnh bên trong đi cùng khối - nhìn gọn
   hơn mà máy yếu cuộn không khựng. */

/* Từ 1279px xuống: tám dòng bánh xuống hai hàng bốn thẻ, không chạy tiếp sang phải.
   Ở khổ này phần nội dung không còn đủ 1200px, chia tám thẻ vào một hàng thì mỗi thẻ
   hẹp dưới 141px - tên bánh xuống ba dòng, câu mô tả bị ba chấm cắt gần hết.
   Trước đây khổ này cho hàng thẻ trượt ngang, nhưng thẻ cuối bị mép màn cắt mất hơn
   nửa: khách phải biết là kéo được mới thấy bốn dòng bánh còn lại, mà trên máy tính
   không ai nghĩ tới chuyện kéo ngang một hàng nút. Phóng to trang trên máy tính
   (Ctrl +) cũng rơi đúng vào khổ này, nên đó là cảnh khách gặp thật.
   Bốn cột chia hết tám dòng bánh thành hai hàng bằng nhau, không hàng nào trơ một thẻ,
   và mỗi thẻ rộng gần gấp đôi nên tên bánh với câu mô tả đủ chỗ trên một dòng. */
@media (max-width: 1279px) {
  .home-jump { grid-auto-flow: row; grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

@media (max-width: 1100px) {
  .cake-showcase { grid-template-columns: 1fr; }
  .cake-gallery { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .feature-row, .feature-row.is-reverse { grid-template-columns: 1fr; }
  .feature-row.is-reverse .feature-copy { order: 0; }
  .home-footer { grid-template-columns: 1fr 1fr; }
  .home-footer iframe { grid-column: 1 / -1; }
}
@media (max-width: 900px) {
  /* Below the tablet width the nav becomes a drawer, so the hero copy takes the
     full width and both photo bands turn their scrim vertical: the photos are
     pale at the top and the text needs the dark end of the gradient behind it.
     Ảnh nền cũng đổi sang bản 900px để máy điện thoại không tải bản 1600px. */
  /* Điện thoại: hàng dòng bánh ra khỏi hero, tụt xuống thành một dải giấy riêng bên
     dưới - đúng kiểu trang cakela.vn/old. Cách làm: hero thôi tự đặt chiều cao, thay
     vào đó ô đầu của lưới (phần chữ) mới là ô cao trọn một màn hình. Nhờ vậy ảnh hero
     chiếm đúng khung nhìn đầu tiên còn dải thẻ bắt đầu ngay dưới mép màn, khách cuộn
     một nhịp là thấy. Đặt chiều cao lên ô lưới chứ không đặt lên chính dải thẻ vì
     chiều cao dải thẻ còn tuỳ số dòng bánh tiệm bán, không có con số nào đặt cứng được.
     Lề trên dưới của hero về 0 và row-gap về 0: hai thứ đó nằm ngoài ô cao trọn màn
     nên còn để lại thì mép ảnh hụt xuống dưới dải thẻ thành một vệt ảnh lạc. Lề trên
     dưới của phần chữ chuyển vào .home-hero__content, lề trái phải vẫn do hero lo.
     Ảnh hero nằm ở ô đầu của lưới (.home-hero__content) chứ không nằm trên cả khối
     hero nữa. Trước đây nó nằm trên cả khối, mà khối đó cao gần gấp đôi màn hình (một
     màn ảnh cộng dải tám thẻ dòng bánh xếp dọc), nên background-size: cover phải kéo
     tấm ảnh ngang 3:2 phủ một khung dọc cao 1463px: ảnh bị phóng hơn năm lần, khách
     chỉ còn thấy một sợi dọc chưa tới một phần mười tấm ảnh và nhoè, còn hơn nửa dưới
     tấm ảnh thì nằm khuất sau dải giấy - đó là chỗ ảnh hero trên điện thoại nhìn rất
     tệ.
     Đặt ảnh vào đúng ô cao một màn hình vẫn chưa đủ: khung 390x770 vẫn là khung dọc mà
     tấm ảnh thì ngang, nên cover chỉ cho khách thấy một sợi dọc bằng một phần ba bề ngang
     ảnh - đúng khúc tủ kính trống, còn bánh với tấm bảng CAKELA thì nằm ngoài sợi đó.
     Nên ảnh giờ là một dải ngang ở đầu ô: cao 52% ô, bề ngang để auto cho đúng tỉ lệ ảnh,
     nhờ vậy khách thấy gần hai phần ba bề ngang - tủ kính, mấy chiếc bánh trên kệ và tấm
     bảng CAKELA cùng vào khung. Dưới dải ảnh là nền nâu đặc cho phần chữ: lớp phủ chuyển
     sang nâu kín ở 48% ô, tức là trước mép dưới dải ảnh, nên chỗ nối không để lại đường
     kẻ ngang nào. Máy càng ngắn thì phần chữ càng dâng lên cao trong dải ảnh, nhưng lúc
     đó nó nằm trên khúc lớp phủ đã gần kín nên chữ trắng vẫn đọc được.
     Cỡ ảnh tính theo chiều cao (52%) chứ không theo bề ngang: mép dải chỉ phụ thuộc đúng
     con số đó, tiệm đổi ảnh hero khổ nào trong /admin/ thì chỗ nối vẫn nằm y chỗ cũ. Lớp
     cover thứ hai dưới cùng để chặn một nước: ảnh dựng đứng thì dải ngang hẹp hơn bề ngang
     máy, không có lớp đó là hai bên hở nền nâu.
     Dải này dùng bản 1600px chứ không phải bản 900px: nó chỉ hiện hai phần ba tấm ảnh nên
     trên màn retina bản 900px phải phóng hơn 1,3 lần, chữ trên hộp bánh nhoè hẳn. */
  .home-hero { min-height: 0; grid-template-rows: minmax(calc(100svh - var(--header)), auto) auto; row-gap: 0; padding-top: 0; padding-bottom: 0; background-color: var(--bg); background-image: none; }
  .home-invite { background-image: linear-gradient(180deg, rgba(29, 15, 9, .3), rgba(29, 15, 9, .55) 45%, rgba(29, 15, 9, .82)), var(--invite-image-small, var(--invite-image)); }
  .home-invite__content { width: 100%; margin-left: 0; }
  /* Phần chữ dồn xuống đáy ô cao trọn màn chứ không căn giữa - đúng cách trang cũ làm
     trên điện thoại. Căn giữa thì chữ nằm lửng ở khoảng giữa ảnh, chừa lại một khoảng
     ảnh trống trơn cao gần ba trăm pixel phía dưới (chỗ đó trước đây là hàng dòng bánh
     ngồi). Dồn xuống đáy còn được cái nữa: vệt tối của lớp phủ đậm nhất ở đáy nên chữ
     trắng nằm đúng chỗ dễ đọc nhất.
     Ô này giờ mang luôn ảnh hero nên phải stretch (không còn "end") để nó cao trọn ô
     lưới, còn chữ dồn xuống đáy bằng align-content: end. Lề âm hai bên đúng bằng lề
     trang cho ảnh chạy sát mép máy - cùng cách dải thẻ bên dưới làm - và lề trong trả
     lại đúng con số đó nên chữ vẫn thẳng hàng với mọi mục khác. */
  .home-hero__content { align-self: stretch; display: grid; align-content: end; width: auto; margin: 0 calc(var(--gutter) * -1); padding: clamp(20px, 3.2vw, 42px) var(--gutter) clamp(18px, 3.4vw, 28px); background-color: #2a170f; background-image: linear-gradient(180deg, rgba(29, 15, 9, .16), rgba(29, 15, 9, .32) 20%, rgba(29, 15, 9, .88) 40%, #2a170f 48%), var(--hero-image), var(--hero-image); background-position: center, 74% top, center; background-size: cover, auto 52%, cover; background-repeat: no-repeat; }
  /* Tên tiệm to hết mức còn nằm gọn một dòng. Ngưỡng đó tỉ lệ thuận với bề ngang máy
     (khung chữ = bề ngang trừ hai lề trang) nên đo bằng vw là đủ, không cần điểm ngắt
     nào: 40,6px ở máy 390px và 37,4px ở máy 360px, đều còn dưới ngưỡng gãy dòng đo
     được. Chặn trên 3.9rem để chỗ nối với khổ máy tính không nhảy bậc. */
  .home-hero h1 { font-size: min(10.4vw, 3.9rem); }
  /* Ba ô chữ nhỏ dưới câu dẫn nằm trên khúc nền nâu đã đục, nên lớp làm mờ phía sau
     không đổi được pixel nào - chỉ tốn thêm một lớp vẽ mỗi khung hình lúc cuộn. */
  .home-hero__meta span { backdrop-filter: none; }
  /* Dải giấy: nền --paper cùng đúng màu dải dòng bánh của trang cũ, một đường chỉ mảnh
     ở mép dưới tách nó với phần bánh kem tiếp theo. Lề trên dưới 14/16px cho dải có
     thân hình riêng chứ không dính vào hai khối trên dưới. Lề âm hai bên vẫn giữ nên
     dải chạy sát mép máy và ăn trọn bề ngang.
     Thẻ xếp thành cột dọc, mỗi dòng bánh một hàng ăn trọn bề ngang - đúng như trang
     cakela.vn/old. Khổ trên xếp bốn thẻ một hàng vì hàng thẻ còn nằm trong hero, còn
     từ đây dải đã ra khỏi hero nên hết ràng buộc chiều cao: thẻ cao thêm, chữ to thêm
     và tám dòng bánh cùng hiện, tên với câu mô tả đủ chỗ nên không còn ba chấm cắt câu.
     Lề âm hai bên khai ngay ở đây, không còn thừa hưởng từ khối 1100px như hồi khối đó
     giữ hàng trượt ngang.
     Số cột tự chia theo bề ngang thật: điện thoại một cột, máy 560-880px hai cột, máy
     tính bảng nằm ngang ba cột - cùng nhịp chia của trang cũ, không cần thêm điểm ngắt
     nào. min(100%, 250px) để ở 320px thẻ không bao giờ rộng hơn dải. Khe 10px thay khe
     6px của hàng ngang: thẻ nào cũng cao 74px trở lên nên khe hẹp làm chúng dính thành
     một khối liền.
     Không còn chừa 54px cuối hàng cho dock liên hệ: chỗ chừa đó là vì hàng trượt ngang
     dừng ngay dưới hai nút Zalo/Messenger nên thẻ cuối không bấm được. Cột dọc thì dock
     chỉ che phần đang ở đáy màn, cuộn một nhịp là thẻ ra khỏi chỗ bị che. */
  .home-jump { grid-auto-flow: row; grid-template-columns: repeat(auto-fill, minmax(min(100%, 250px), 1fr)); gap: 10px; margin: 0 calc(var(--gutter) * -1); padding: 14px var(--gutter) 16px; border-bottom: 1px solid var(--line); background: var(--paper); }
  /* Thẻ cao và rộng thêm một nhịp cho tên bánh dài, chữ to hơn, dòng mô tả được xuống
     hai dòng thay vì cắt bằng ba chấm - thẻ đã ăn trọn bề ngang nên phần lớn câu hiện
     đủ, ba chấm ở đây chỉ làm khách phải đoán.
     Đây là chỗ duy nhất thẻ đổi màu: nền trắng, chữ nâu. Ở khổ máy tính thẻ là kính mờ
     nằm trên ảnh hero nên chữ trắng mới đọc được; từ đây thẻ nằm trên dải giấy sáng, giữ
     nguyên kính mờ thì thành một vệt tối đè lên giấy mà chữ trắng thì mất hẳn. Viền lấy
     màu chỉ của trang thay cho viền trắng mờ (trên giấy nó vô hình), bóng đổ nhạt cho
     thẻ tách khỏi dải, và backdrop-filter tắt hẳn - nền đã đục thì làm mờ phía sau chỉ
     tốn thêm một lớp vẽ cho mỗi thẻ.
     Bỏ luôn hiệu ứng hiện dần lúc tải trang: nó là một nhịp trong màn chào của hero, mà
     dải thẻ giờ nằm dưới mép màn - hiệu ứng chạy xong từ lâu trước khi khách cuộn tới. */
  .home-jump a { min-height: 74px; padding: 11px 13px; border-color: var(--line); background-color: #fff; color: var(--brown); box-shadow: 0 2px 6px rgba(89, 50, 31, .07); backdrop-filter: none; animation: none; }
  /* Trỏ vào thì thẻ giấy hửng lên màu kem, không lấy màu đỏ của thẻ kính mờ: đỏ dưới
     chữ nâu là gần như không đọc được. Cửa sổ máy tính kéo hẹp lại cũng vào đúng khổ
     này nên vẫn có chuột trỏ vào thật. */
  .home-jump a:hover { background-color: #ffeedb; }
  .home-jump strong { font-size: var(--text-md); }
  .home-jump span { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; color: var(--muted); font-size: var(--text-sm); white-space: normal; }
}
/* Điện thoại dựng dọc: dock liên hệ giữ đúng dáng chồng dọc như trên máy tính, nên
   chỗ nhường cho nó chuyển từ lề dưới sang lề phải.
   Cột dock cao 154px (ba nút 46px + hai khe 8px) đứng ở góc phải đáy màn, mà chữ hero
   thì dồn xuống đáy: hai nút "Xem menu bánh" / "Xem mẫu bánh" trải hết bề ngang nên
   mép phải của chúng nằm đúng dưới cột dock - bấm vào mép phải nút là trúng nút Zalo.
   Chừa 66px bên phải cho riêng hàng nút và hàng thẻ giờ mở cửa (hai thứ nằm trong tầm
   cao của dock) là hết đè, mà không mất dòng chữ nào theo chiều dọc như cách chừa cả
   một khoảng lề dưới trước đây - chỗ đó giờ để dành cho tên tiệm và câu dẫn đã to lên.
   Lề dưới còn lại một nhịp mỏng, chỉ đủ để chữ không dính vạch home của iPhone. Số chừa
   tính từ chính --dock nên đổi cỡ nút là hai chỗ tự khớp. Máy nằm ngang không lấy luật
   này: ở đó chữ hero không dồn xuống đáy nên dock không đè lên nút nào. */
@media (max-width: 900px) and (orientation: portrait) {
  .home-hero .home-actions, .home-hero .home-hero__meta { padding-right: calc(var(--dock) + 20px); }
  .home-hero__content { padding-bottom: max(18px, calc(env(safe-area-inset-bottom, 0px) + 8px)); }
}
/* Chỉ khoảng 901-1000px là hết chỗ cho slogan: menu ngang bảy mục vẫn còn hiện
   mà bề ngang đã hẹp, để slogan lại là logo và menu dính vào nhau. Từ 900px trở
   xuống menu gộp vào nút ☰ nên chỗ trống thừa sức chứa slogan. */
@media (min-width: 901px) and (max-width: 1000px) {
  .home-brand small { display: none; }
}
/* Menu gộp vào nút ☰ từ 900px trở xuống. Trước đây là 780px, nhưng ở 800px năm
   nhãn tiếng Việt đã phải xuống hai dòng ("Tea-" / "break"), nhìn rất rối. */
@media (max-width: 900px) {
  .nav-toggle { display: block; }
  /* Điện thoại: thanh trên cùng đứng yên đúng một cỡ, không thu nhỏ nữa. Máy tính vẫn
     gọn lại khi cuộn (chiều cao đổi một nhịp, lockup co bằng transform - xem khối
     header ở trên), ở đây thì cả phép co ấy cũng tắt: màn hẹp thì 12px chiều cao
     không đổi được gì, mà nhịp cuộn đầu trên máy yếu đỡ được một việc. Nền đục và
     translateZ(0) giờ là luật chung cho cả hai khổ, ở đây chỉ còn giữ đúng màu giấy
     của trang thay cho nền kem mờ. */
  .home-header, .home-header.is-scrolled { --header-now: var(--header); background: var(--bg); box-shadow: 0 1px 0 rgba(255, 255, 255, .6), 0 6px 18px rgba(89, 50, 31, .09); transform: translateZ(0); transition: none; }
  .home-header .home-brand img, .home-header.is-scrolled .home-brand img { width: 48px; height: 48px; transition: transform .2s ease, box-shadow .2s ease; }
  .home-brand__name, .home-header.is-scrolled .home-brand__name { font-size: 1.6rem; transition: none; }
  .home-header .home-brand, .home-header.is-scrolled .home-brand { transform: none; transition: none; }
  /* Vạch tiến độ cuộn tắt trên điện thoại: nó là animation chạy theo thanh cuộn nên mỗi
     khung hình trình duyệt phải tính lại style một lượt - đo được 183 lượt cho một quãng
     cuộn, tắt đi còn 93. Một vạch 2px không đáng một nhịp khựng. */
  .home-header::after { content: none; }
  /* max-height + overflow-y: khi máy quay ngang chỉ còn ~360px chiều cao, bảy mục
     menu cao hơn cả màn hình. Body đang bị khoá cuộn lúc menu mở, nên không có
     hai dòng này thì mục "Đặt bánh" ở cuối không cách nào bấm tới được.
     overscroll-behavior: contain để kéo hết tấm menu không lôi luôn cả trang. */
  .home-nav { position: fixed; inset: var(--header-now) 0 auto; display: none; max-height: calc(100dvh - var(--header-now)); padding: 12px 18px max(16px, env(safe-area-inset-bottom)); overflow-y: auto; overscroll-behavior: contain; border-bottom: 1px solid var(--line); background: var(--bg); box-shadow: var(--shadow); }
  .home-nav.is-open { display: grid; animation: nav-drop .22s ease both; }
  /* Từng mục hiện lệch nhau một nhịp rất ngắn cho tấm menu đổ xuống mềm mắt.
     Máy đặt giảm chuyển động thì khối @media cuối file đã tắt hết. */
  .home-nav.is-open a { animation: nav-item .26s ease both; }
  .home-nav.is-open a:nth-child(2) { animation-delay: .03s; }
  .home-nav.is-open a:nth-child(3) { animation-delay: .06s; }
  .home-nav.is-open a:nth-child(4) { animation-delay: .09s; }
  .home-nav.is-open a:nth-child(5) { animation-delay: .12s; }
  .home-nav.is-open a:nth-child(6) { animation-delay: .15s; }
  .home-nav.is-open a:nth-child(7) { animation-delay: .18s; }
  .home-nav a { min-height: 46px; border-radius: 10px; }
  .home-nav a::before { content: none; }
  .home-nav a.nav-phone { display: inline-flex; }
  .home-nav a.nav-gallery { justify-content: flex-start; padding-left: 12px; }
  .home-nav a.nav-gallery small { margin-left: auto; }
  .home-nav a.is-cta { margin: 8px 0 0; justify-content: center; }
  .home-nav a.is-current::after { left: 12px; right: auto; width: 18px; bottom: 8px; }
  /* Tấm menu trên điện thoại là một cột dọc, nên bảng con mở xuống ngay dưới mục
     chứ không nổi lên trên nội dung: một vạch dọc bên trái cho thấy đây là mấy
     mục con của "Menu bánh". Ở đây bắt buộc phải bấm nút mũi xuống mới mở, nên
     display: none là đủ - không cần giữ hiệu ứng mờ dần của bản máy tính. */
  .nav-group { display: grid; grid-template-columns: 1fr auto; align-items: center; }
  .nav-group__toggle { width: 40px; height: 40px; margin: 0; }
  .nav-dropdown { position: static; grid-column: 1 / -1; display: none; min-width: 0; padding-top: 0; opacity: 1; visibility: visible; transform: none; transition: none; }
  .nav-group.is-open > .nav-dropdown { display: block; }
  .nav-dropdown__inner { gap: 0; margin: 2px 0 6px 12px; padding: 0 0 0 10px; border: 0; border-left: 2px solid var(--line); border-radius: 0; background: transparent; box-shadow: none; }
}
@media (max-width: 780px) {
  .cake-gallery, .feature-media, .feature-media.dense { gap: 7px; }
  .cake-badges { width: 100%; }
  .cake-badge { flex: 1 1 auto; }
  .home-footer { grid-template-columns: 1fr; }
  /* Điện thoại: quãng dịch ngắn lại một chút. Màn nhỏ nên khối vào khung nhìn gần
     như cùng lúc, dịch 16px như máy tính trông giật cục. */
  :root { --reveal-shift: 10px; --reveal-dur: .5s; }
}
@media (max-width: 560px) {
  .cake-gallery { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .home-price-table .cake-size { width: 44px; }
  .size-chip { width: 34px; height: 34px; font-size: .78rem; }
}
@media (max-width: 420px) {
  .home-actions { display: grid; }
  .home-actions .home-button, .feature-actions .home-button { width: 100%; }
}
/* Máy quay ngang, màn thấp (điện thoại nằm ngang, cửa sổ bị kéo dẹt). Hai khối
   cao trọn màn hình phải nhả ràng buộc chiều cao, nếu không chữ bị nén tới mức
   chỉ đọc được nửa đoạn. Lề trái phải cộng thêm safe-area vì lúc nằm ngang tai
   màn iPhone ăn vào đúng hai bên. */
@media (max-height: 560px) and (orientation: landscape) {
  .home-hero, .home-invite { min-height: auto; }
  .home-hero { padding-top: clamp(16px, 3vh, 26px); padding-bottom: clamp(12px, 2.5vh, 20px); }
  .home-invite { padding-top: clamp(22px, 5vh, 40px); padding-bottom: clamp(22px, 5vh, 40px); }
  .home-hero h1 { font-size: clamp(1.95rem, 1.35rem + 2.3vw, 3rem); }
  .home-invite h2 { font-size: clamp(1.5rem, 1.1rem + 2vw, 2.3rem); }
  .home-hero, .home-invite, .home-section, .home-footer { padding-left: max(var(--gutter), env(safe-area-inset-left)); padding-right: max(var(--gutter), env(safe-area-inset-right)); }
  .home-jump { margin-left: 0; margin-right: 0; padding-left: 0; padding-right: 0; }
}
/* Điện thoại nằm ngang: khối trên vừa nhả ràng buộc chiều cao của hero, nên ô cao
   trọn màn ở hàng đầu cũng phải nhả theo - màn chỉ còn hơn 300px, bắt phần chữ chiếm
   trọn màn rồi mới tới dải thẻ thì khách phải cuộn hai lần cho một hàng nút. Lề trên
   dưới của hero về 0 vì lúc này lề nằm ở .home-hero__content; để cả hai thì phần chữ
   bị đẩy xuống hai lần, còn lề dưới lại chèn một vệt ảnh nằm dưới dải thẻ. */
@media (max-width: 900px) and (max-height: 560px) and (orientation: landscape) {
  .home-hero { grid-template-rows: auto auto; padding-top: 0; padding-bottom: 0; }
  /* Nằm ngang thì ô chữ không còn cao trọn màn, nên dải ảnh tính theo 52% ô chỉ còn
     chừng 150px và bề ngang của nó không phủ hết máy. Ở khổ này ảnh trở về kiểu cũ: phủ
     trọn ô, chữ nằm trên ảnh với lớp phủ đủ tối để đọc. Lề âm cộng thêm safe-area cho ảnh
     chạy sát mép cả khi tai màn ăn vào hai bên, giống cách dải giấy bên dưới làm. */
  .home-hero__content { margin-left: calc(max(var(--gutter), env(safe-area-inset-left, 0px)) * -1); margin-right: calc(max(var(--gutter), env(safe-area-inset-right, 0px)) * -1); padding: clamp(14px, 3vh, 24px) max(var(--gutter), env(safe-area-inset-right, 0px)) clamp(12px, 2.5vh, 20px) max(var(--gutter), env(safe-area-inset-left, 0px)); background-image: linear-gradient(180deg, rgba(29, 15, 9, .32), rgba(29, 15, 9, .58) 45%, rgba(29, 15, 9, .86)), var(--hero-image); background-position: 62% center; background-size: cover; }
  /* Trả lại lề âm cho dải giấy ăn trọn bề ngang: khối trên bỏ lề âm từ hồi dải còn nằm
     trong hero trên ảnh, giờ dải có nền riêng nên bỏ lề âm là nó thành một khối giấy
     lửng lơ, hai bên hở ra ảnh hero. Lề âm lấy đúng con số lề của hero (đã cộng
     safe-area) mới trừ hết được, còn lề trong đặt lại đúng con số đó cho thẻ vẫn thẳng
     hàng với phần chữ và không lọt vào tai màn. */
  .home-jump { margin-left: calc(max(var(--gutter), env(safe-area-inset-left, 0px)) * -1); margin-right: calc(max(var(--gutter), env(safe-area-inset-right, 0px)) * -1); padding-left: max(var(--gutter), env(safe-area-inset-left, 0px)); padding-right: max(var(--gutter), env(safe-area-inset-right, 0px)); }
}
/* Màn cảm ứng: bỏ hết hiệu ứng "nâng lên khi trỏ vào". Trên điện thoại trạng
   thái hover bị dính lại sau khi chạm, thẻ cứ nằm lệch cho tới lúc chạm chỗ
   khác. Phản hồi khi chạm đã có :active lo. */
@media (hover: none) {
  .cake-gallery a:hover img, .feature-media a:hover img { transform: none; }
  .home-button:hover, .floating-actions a:hover { transform: none; box-shadow: var(--shadow); }
  /* Thẻ dòng bánh chỉ bỏ quãng nâng lên, không lấy bóng đổ của luật trên: ở khổ máy
     tính thẻ là kính mờ nằm trên ảnh nên vốn không có bóng nào, còn trên điện thoại thẻ
     giấy đã có bóng nhạt riêng - gán bóng chung vào là mỗi thẻ mọc một quầng xám. */
  .home-jump a:hover { transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { scroll-behavior: auto !important; transition-duration: .01ms !important; animation-duration: .01ms !important; }
  /* Ô ảnh chờ tải nhấp nháy vô hạn: rút thời lượng xuống .01ms là nó nháy cực
     nhanh, còn tệ hơn. Phải tắt hẳn và giữ một mức mờ cố định. */
  .photo-skeleton, .album-card.is-near:not(.is-loaded) .album-card__media { animation: none !important; opacity: .7; }
}



