/* SaLy Build — base.css: TỆP SINH RA, KHÔNG SỬA TRỰC TIẾP. Sửa ở brands/_shared/kit-src/ rồi chạy: node scripts/build-app-kit.mjs
   Bộ thiết kế dùng chung cho mọi thương hiệu: font, token, phần tử nền, bố cục, thành phần .saly-* ("API giao diện" của app — app
   không sửa tệp này). Chỉ dùng biến; màu thương hiệu nằm ở /_brand/brand.css. */

/* ==== kit-src/00-fonts.css ==== */
/* Font tự lưu trữ (SIL OFL 1.1, Google Fonts) — chỉ tập Latin + Vietnamese.
   Inter (thân, wght 400–700), Montserrat (tiêu đề, wght 500–800), Dancing Script (chỉ .saly-accent, wght 400–700).
   Oswald không còn khai báo ở đây (tiêu đề đã chuyển sang Montserrat); tệp oswald-*.woff2 vẫn giữ trong fonts/ cho bản cũ. */
@font-face { font-family: "Inter"; font-style: normal; font-weight: 400 700; font-display: swap; src: url("/_shared/fonts/inter-vietnamese.woff2") format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 400 700; font-display: swap; src: url("/_shared/fonts/inter-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Montserrat"; font-style: normal; font-weight: 500 800; font-display: swap; src: url("/_shared/fonts/montserrat-vietnamese.woff2") format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; }
@font-face { font-family: "Montserrat"; font-style: normal; font-weight: 500 800; font-display: swap; src: url("/_shared/fonts/montserrat-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Dancing Script"; font-style: normal; font-weight: 400 700; font-display: swap; src: url("/_shared/fonts/dancing-script-vietnamese.woff2") format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; }
@font-face { font-family: "Dancing Script"; font-style: normal; font-weight: 400 700; font-display: swap; src: url("/_shared/fonts/dancing-script-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }

/* ==== kit-src/05-brand-fallback.css ==== */
/* Màu dự phòng khi thương hiệu CHƯA có brand.css (ví dụ thương hiệu mới chưa nhận bộ màu): xám trung tính, đủ tương phản, để nền
   thanh dính đáy, nút, thẻ không thành trong suốt. brand.css nạp SAU base.css nên ghi đè toàn bộ khi có. Cùng bộ màu trung tính với
   thẻ chia sẻ (brands/_shared/share-card/card.css). */
:root {
  --brand-primary: #1F2328;
  --brand-primary-strong: #000000;
  --brand-on-primary: #FFFFFF;
  --brand-secondary: #1F2328;
  --brand-on-secondary: #FFFFFF;
  --brand-surface: #F6F7F9;
  --brand-surface-alt: #FFFFFF;
  --brand-text: #1F2328;
  --brand-muted: #57606A;
  --brand-danger: #CF222E;
  --brand-border: #D0D7DE;
  --chart-1: #1F2328;
  --chart-2: #57606A;
  --chart-3: #8C959F;
  --chart-4: #AFB8C1;
  --chart-5: #D0D7DE;
  --chart-6: #EAEEF2;
}

/* ==== kit-src/10-tokens.css ==== */
/* Token chung — giống nhau ở mọi thương hiệu. Màu gốc nằm ở /_brand/brand.css (--brand-*); ở đây chỉ có token PHÁI SINH từ màu đó.
   color-mix() chỉ được viết trong bộ dùng chung (lint không quét brands/_shared); app chỉ dùng var(--tint-…), var(--elev-…).
   Token phái sinh (--tint-*, --hero-deep, --elev-*, --safe-*, --tap) được khai lại y hệt trong shell.css vì vỏ ở Shadow DOM
   phải tự tính từ brand.css nạp lại bên trong (test app-kit-tokens giữ hai nơi trùng nhau).
   Quy tắc màu chữ: --brand-primary / --brand-primary-strong KHÔNG BAO GIỜ làm màu chữ (2.11:1 và 1.34:1 trên nền trang) —
   chỉ làm nền nút chính, vạch nhấn, thanh tiến độ; chữ nhấn dùng --brand-secondary. */
:root {
  /* Chữ: tiêu đề Montserrat (chữ thường), thân Inter 16/1.6, Dancing Script chỉ cho một câu nhấn .saly-accent */
  --font-body: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  --font-heading: "Montserrat", "Inter", system-ui, -apple-system, "Segoe UI", Arial, sans-serif;
  --font-accent: "Dancing Script", "Segoe Script", cursive;

  /* Thang chữ 12/14/16/18/20/24/30/38 — cỡ lớn co giãn theo khung nhìn (điện thoại ~360px → laptop) */
  --text-xs: 0.75rem;
  --text-sm: 0.875rem;
  --text-base: 1rem;
  --text-md: 1.125rem;
  --text-lg: 1.25rem;
  --text-xl: clamp(1.375rem, 1.25rem + 0.5vw, 1.5rem);
  --text-2xl: clamp(1.625rem, 1.4rem + 0.9vw, 1.875rem);
  --text-display: clamp(1.875rem, 1.5rem + 1.6vw, 2.375rem);

  /* Bo góc: --radius cũ giữ nguyên = --radius-md */
  --radius: 16px;
  --radius-sm: 12px;
  --radius-md: 16px;
  --radius-lg: 20px;
  --radius-xl: 28px;
  --radius-pill: 999px;

  /* Khoảng cách lưới 4/8: --space-1…6 giữ nguyên, thêm 7 (48) và 8 (64) */
  --space-1: 0.25rem; --space-2: 0.5rem; --space-3: 0.75rem; --space-4: 1rem; --space-5: 1.5rem; --space-6: 2rem;
  --space-7: 3rem; --space-8: 4rem;
  --gutter: var(--space-4); /* lề hai bên nội dung; 24px từ 768px */

  /* Sắc độ: màu thương hiệu pha lên nền thẻ — nền an toàn cho chữ --brand-text (≥11:1 ở cả 2 thương hiệu) */
  --tint-primary-1: color-mix(in srgb, var(--brand-primary) 8%, var(--brand-surface-alt));
  --tint-primary-2: color-mix(in srgb, var(--brand-primary) 14%, var(--brand-surface-alt));
  --tint-primary-3: color-mix(in srgb, var(--brand-primary) 24%, var(--brand-surface-alt));
  --tint-secondary-1: color-mix(in srgb, var(--brand-secondary) 6%, var(--brand-surface-alt));
  --tint-secondary-2: color-mix(in srgb, var(--brand-secondary) 10%, var(--brand-surface-alt));
  --tint-secondary-3: color-mix(in srgb, var(--brand-secondary) 16%, var(--brand-surface-alt));
  --tint-danger-1: color-mix(in srgb, var(--brand-danger) 10%, var(--brand-surface-alt));
  --hero-deep: color-mix(in srgb, var(--brand-secondary) 75%, var(--brand-text)); /* đáy dải hero đậm, chữ --brand-on-secondary */

  /* Độ nổi: bóng pha từ màu chữ của thương hiệu (không đen thuần). 1 = thẻ nghỉ, 2 = thẻ nổi/nút chính/thanh dính, 3 = tấm trượt/toast */
  --elev-1: 0 1px 2px color-mix(in srgb, var(--brand-text) 6%, transparent), 0 2px 8px -2px color-mix(in srgb, var(--brand-text) 6%, transparent);
  --elev-2: 0 8px 20px -8px color-mix(in srgb, var(--brand-text) 14%, transparent), 0 2px 6px -2px color-mix(in srgb, var(--brand-text) 6%, transparent);
  --elev-3: 0 24px 48px -16px color-mix(in srgb, var(--brand-text) 22%, transparent), 0 8px 16px -8px color-mix(in srgb, var(--brand-text) 10%, transparent);

  /* Chuyển động: chỉ transform/opacity; vào dùng ease-out, ra dùng ease-in và ngắn hơn (~65%) */
  --dur-fast: 150ms; /* nhấn, rê, đổi màu */
  --dur: 220ms;      /* tab, chip, toast vào, mở/đóng mục */
  --dur-slow: 320ms; /* tấm trượt, chuyển bước */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in: cubic-bezier(0.4, 0, 1, 1);

  /* Lớp chồng */
  --z-base: 0;
  --z-sticky: 20;
  --z-overlay: 40;
  --z-toast: 50;

  /* Chạm và vùng an toàn (cần viewport-fit=cover để env() có giá trị khác 0) */
  --tap: 3rem; /* 48px — mọi điều khiển */
  --icon-sm: 1rem;    /* <saly-icon size="sm"> 16px */
  --icon-md: 1.25rem; /* mặc định 20px — cạnh chữ, trong nút */
  --icon-lg: 1.5rem;  /* 24px — thanh đáy, ô icon */
  --tabbar-h: 3.5rem; /* thanh đáy 56px; dùng chung cho chiều cao thanh và phần nội dung chừa đáy */
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
}
@media (min-width: 768px) {
  :root { --gutter: var(--space-5); }
}

/* ==== kit-src/20-elements.css ==== */
/* Phần tử nền: trang, tiêu đề, chữ, liên kết, focus, danh sách. Tiêu đề Montserrat chữ thường (không in hoa ở đâu cả),
   line-height 1.3: đo bằng Chromium, mực dấu chồng (Ẩ, Ỗ) của dòng dưới + chân dấu (Ự, ỵ) của dòng trên cao 1.27em với
   Montserrat 700 → 1.25 vừa chạm nhau, 1.3 còn khe ~1px ở mọi cỡ tiêu đề. */
*, *::before, *::after { box-sizing: border-box; }
/* Thuộc tính hidden luôn thắng display của lớp .saly-* và của app trên màn hình (kit.js và app ẩn nút/tab/bước/nội dung tấm bằng
   hidden). Bản in không dùng !important: app nào chủ ý in cả phần đang ẩn (vd. .buoc[hidden] { display: grid } trong @media print)
   vẫn in được. Vỏ <saly-header>/<saly-footer> không bị ảnh hưởng: :host của vỏ đặt display !important trong Shadow DOM, thắng
   !important của trang. */
[hidden] { display: none; }
@media screen { [hidden] { display: none !important; } }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }
body {
  margin: 0; min-height: 100vh; min-height: 100dvh; display: flex; flex-direction: column;
  font-family: var(--font-body); font-size: var(--text-base); line-height: 1.6; color: var(--brand-text);
  background: var(--brand-surface); -webkit-font-smoothing: antialiased;
}
saly-header, saly-footer { display: block; flex: none; }
saly-header { min-height: calc(4.25rem + var(--safe-top)); } /* giữ chỗ tới khi vỏ dựng xong (68px + vùng an toàn), tránh nhảy bố cục */
/* Nội dung cần đăng nhập nằm trong <saly-auth-gate> (light DOM): ẩn cho tới khi SDK nâng cấp phần tử, tránh lộ nháy trước khi có cổng */
saly-auth-gate:not(:defined) { display: none; }

h1, h2, h3, h4 {
  margin: 0 0 var(--space-3); font-family: var(--font-heading); font-weight: 600; line-height: 1.3;
  color: var(--brand-text); text-wrap: balance; overflow-wrap: break-word;
}
h1 { font-size: var(--text-display); font-weight: 700; letter-spacing: -0.01em; color: var(--brand-secondary); }
h2 { font-size: var(--text-xl); font-weight: 700; letter-spacing: -0.01em; }
h3 { font-size: var(--text-lg); }
h4 { font-size: var(--text-md); }
p, ul, ol { margin: 0 0 var(--space-4); }
p { text-wrap: pretty; }
:where(ul, ol) { padding-inline-start: var(--space-5); }
:where(li)::marker { color: var(--brand-secondary); }
a { color: var(--brand-secondary); text-underline-offset: 0.15em; }
a:hover { text-decoration-thickness: 2px; }
img, svg { max-width: 100%; height: auto; }
button, input, select, textarea { font: inherit; color: inherit; }
input[type="checkbox"], input[type="radio"] { width: 1.25rem; height: 1.25rem; margin: 0; accent-color: var(--brand-secondary); }
hr { margin: var(--space-5) 0; border: 0; border-top: 1px solid var(--brand-border); }
:focus-visible { outline: 3px solid var(--brand-secondary); outline-offset: 2px; }
::selection { background: var(--tint-primary-3); color: var(--brand-text); }

/* Chữ: câu dẫn, chữ phụ, một câu nhấn viết tay (Dancing Script chỉ ở đây), số liệu căn cột */
.saly-lead { font-size: var(--text-md); color: var(--brand-muted); }
.saly-muted { color: var(--brand-muted); }
.saly-accent { font-family: var(--font-accent); font-size: 1.75rem; font-weight: 700; line-height: 1.2; color: var(--brand-secondary); }
.saly-num { font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }
.saly-sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* Giảm chuyển động: tắt mọi chuyển tiếp/hoạt ảnh của bộ dùng chung và của app */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; scroll-behavior: auto !important; }
}
/* Nhóm ô: bỏ viền/lề mặc định của trình duyệt; tiêu đề nhóm cùng kiểu nhãn ô (app không phải tự viết lại) */
fieldset { min-width: 0; margin: 0; padding: 0; border: 0; }
legend { padding: 0; margin-bottom: var(--space-2); font-weight: 600; }

/* ==== kit-src/30-layout.css ==== */
/* Bố cục — ưu tiên điện thoại (375–440px), mở rộng ở 768px/1024px. Lề hai bên = --gutter, không nhỏ hơn vùng an toàn
   (iPhone nằm ngang ở chế độ toàn màn hình). */
.saly-main {
  flex: 1 0 auto; width: 100%; max-width: 72rem; margin: 0 auto;
  padding: var(--space-5) max(var(--gutter), var(--safe-right)) 3rem max(var(--gutter), var(--safe-left));
}
/* App hay đặt .saly-main thành grid/flex: con trực tiếp không được phình theo bảng rộng (bảng đã cuộn trong .saly-table).
   :where → độ ưu tiên 0, mọi CSS của app vẫn thắng. */
:where(.saly-main) > * { min-width: 0; }
.saly-stack { display: grid; gap: var(--space-4); }
.saly-stack > * { margin: 0; }
.saly-stack > *, .saly-grid > * { min-width: 0; } /* chặn bảng/tab rộng làm phình cột grid trên điện thoại */
.saly-grid { display: grid; gap: var(--space-4); grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr)); }
.saly-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }

@media (min-width: 768px) {
  .saly-main { padding-top: var(--space-6); padding-bottom: 4rem; }
  .saly-grid--2, .saly-grid--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1024px) { .saly-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* ==== kit-src/41-surfaces.css ==== */
/* Bề mặt và khối nội dung: thẻ, hero, đầu mục, cặp nhãn–giá trị, vạch ngăn, avatar, ô icon, cỡ <saly-icon>.
   Chiều sâu bằng bóng mềm (--elev-*), không bằng viền đậm. Chữ chỉ --brand-text / --brand-muted / --brand-secondary / --brand-on-*;
   --brand-primary chỉ làm nền, vạch, chấm nhấn — không bao giờ làm màu chữ. */

/* Thẻ: nền trắng bo 20, bóng bậc 1. --flat bỏ bóng; --tinted nền sắc độ màu chính; --interactive cả thẻ là một đích bấm. */
.saly-card {
  padding: var(--space-5) var(--space-4); background: var(--brand-surface-alt); border: 1px solid var(--brand-border);
  border-radius: var(--radius-lg); box-shadow: var(--elev-1);
}
.saly-card > :last-child { margin-bottom: 0; }
@media (min-width: 768px) { .saly-card { padding: var(--space-6); } }
.saly-card--flat { box-shadow: none; }
.saly-card--tinted { background: var(--tint-primary-1); border-color: transparent; box-shadow: none; }
.saly-card--interactive {
  display: block; color: inherit; text-decoration: none; cursor: pointer; -webkit-tap-highlight-color: transparent; touch-action: manipulation;
  transition: transform 100ms var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}
.saly-card--interactive:active { transform: scale(0.99); }
@media (hover: hover) { .saly-card--interactive:hover { box-shadow: var(--elev-2); } }

/* Ô icon: ô vuông bo 14 nền sắc độ, icon màu phụ (dùng trong hero, danh sách, lợi ích, trạng thái rỗng) */
.saly-icon-tile {
  display: inline-grid; place-items: center; flex: none; width: var(--tap); height: var(--tap); border-radius: 14px;
  color: var(--brand-secondary); background: var(--tint-primary-2);
}
.saly-icon-tile--lg { width: 4rem; height: 4rem; border-radius: var(--radius-lg); }

/* <saly-icon name="…">: kit.js vẽ SVG nét trong Shadow DOM; ở đây giữ chỗ đúng cỡ theo token (--icon-md 20 mặc định, sm 16,
   lg 24) để bố cục không nhảy trước khi thẻ được định nghĩa hay khi tên icon không có. Màu = currentColor của phần tử cha. */
saly-icon { display: inline-block; flex: none; width: var(--icon-md); height: var(--icon-md); vertical-align: middle; }
saly-icon[size="sm"] { width: var(--icon-sm); height: var(--icon-sm); }
saly-icon[size="lg"] { width: var(--icon-lg); height: var(--icon-lg); }
.saly-icon-tile saly-icon:not([size]) { width: var(--icon-lg); height: var(--icon-lg); }

/* Hero đầu app: eyebrow (chữ thường) + tiêu đề + một câu + vài số liệu nhỏ. Mặc định (= --soft) dải sắc độ màu chính → trắng,
   vạch màu chính 4px phía trên; --solid dải màu phụ → --hero-deep, chữ --brand-on-secondary. Bo 20, không ảnh nền. */
.saly-hero {
  display: grid; gap: var(--space-3); margin: 0 0 var(--space-5); padding: var(--space-5) var(--space-4);
  border-radius: var(--radius-lg); background: linear-gradient(160deg, var(--tint-primary-2), var(--brand-surface-alt) 75%);
  box-shadow: inset 0 4px 0 var(--brand-primary), var(--elev-1);
}
.saly-hero > * { margin: 0; }
.saly-hero__eyebrow { font-size: var(--text-sm); font-weight: 600; line-height: 1.4; color: var(--brand-secondary); }
.saly-hero__title {
  font-family: var(--font-heading); font-size: var(--text-display); font-weight: 800; line-height: 1.3; letter-spacing: -0.02em;
  color: var(--brand-secondary); text-wrap: balance;
}
.saly-hero__lead { max-width: 40rem; font-size: var(--text-md); color: var(--brand-text); }
.saly-hero__meta { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-5); margin: 0; }
.saly-hero__meta > div { display: grid; gap: 0; min-width: 0; }
.saly-hero__meta dt { font-size: var(--text-sm); color: var(--brand-muted); }
.saly-hero__meta dd { margin: 0; font-family: var(--font-heading); font-size: var(--text-lg); font-weight: 700; font-variant-numeric: tabular-nums; color: var(--brand-text); }
.saly-hero__actions { display: flex; flex-wrap: wrap; gap: var(--space-3); padding-top: var(--space-1); }
.saly-hero--solid { color: var(--brand-on-secondary); background: linear-gradient(160deg, var(--brand-secondary), var(--hero-deep)); box-shadow: var(--elev-2); }
.saly-hero--solid .saly-hero__eyebrow, .saly-hero--solid .saly-hero__title, .saly-hero--solid .saly-hero__lead,
.saly-hero--solid .saly-accent, .saly-hero--solid .saly-hero__meta dt, .saly-hero--solid .saly-hero__meta dd { color: var(--brand-on-secondary); }
/* Nhãn trên hero đậm: nền màu chính, chữ on-primary (chữ nhấn không tô màu chính) */
.saly-hero--solid .saly-badge { color: var(--brand-on-primary); background: var(--brand-primary); }
.saly-hero--solid :focus-visible { outline-color: var(--brand-on-secondary); }
@media (min-width: 768px) { .saly-hero { padding: var(--space-6); } }

/* Đầu mục: eyebrow + tiêu đề bên trái, một liên kết/hành động phụ bên phải */
.saly-section { margin: 0 0 var(--space-6); }
.saly-section > :last-child { margin-bottom: 0; }
.saly-section__head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: var(--space-2) var(--space-4); margin: 0 0 var(--space-4); }
.saly-section__head > * { margin: 0; }
.saly-section__eyebrow { margin: 0 0 var(--space-1); font-size: var(--text-sm); font-weight: 600; color: var(--brand-secondary); }
.saly-section__title { margin: 0; font-size: var(--text-xl); }
.saly-section__action { display: inline-flex; align-items: center; gap: var(--space-1); min-height: var(--tap); font-weight: 600; }

/* Cặp nhãn–giá trị: <dl class="saly-kv"><div><dt>Vốn</dt><dd>100 triệu</dd></div>…</dl> — giá trị căn phải, số căn cột */
.saly-kv { display: grid; gap: 0; margin: 0 0 var(--space-4); }
.saly-kv > div { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: var(--space-1) var(--space-4); padding: var(--space-3) 0; border-bottom: 1px solid var(--brand-border); }
.saly-kv > div:last-child { border-bottom: 0; }
.saly-kv dt { color: var(--brand-muted); }
.saly-kv dd { margin: 0; font-weight: 600; font-variant-numeric: tabular-nums; text-align: right; color: var(--brand-text); }

/* Vạch ngăn: <hr class="saly-divider"> hoặc <div class="saly-divider" role="separator">hoặc</div> (chữ ở giữa) */
.saly-divider { display: flex; align-items: center; gap: var(--space-3); margin: var(--space-5) 0; border: 0; font-size: var(--text-sm); color: var(--brand-muted); }
.saly-divider::before, .saly-divider::after { content: ""; flex: 1; border-top: 1px solid var(--brand-border); }
.saly-divider:empty::after { content: none; }

/* Avatar: ảnh tròn hoặc chữ cái đầu */
.saly-avatar {
  display: inline-grid; place-items: center; flex: none; width: 2.5rem; height: 2.5rem; overflow: hidden; border-radius: 50%;
  font-family: var(--font-heading); font-size: var(--text-sm); font-weight: 700; line-height: 1; color: var(--brand-secondary); background: var(--tint-secondary-2);
}
.saly-avatar img { width: 100%; height: 100%; object-fit: cover; }
.saly-avatar--lg { width: 3.5rem; height: 3.5rem; font-size: var(--text-lg); }

/* ==== kit-src/42-buttons.css ==== */
/* Nút: bo tròn hết cỡ, cao ≥48px (--sm chỉ gọn chữ và lề ngang, vẫn 48px), cách nhau ≥8px (.saly-actions gap 12px).
   Một nút chính (nền màu chính) mỗi màn/bước; hành động khác là --secondary (viền màu phụ) hoặc --ghost (chỉ chữ).
   Rê chuột: nền đậm lên trong 150ms. Nhấn: thu nhỏ .98 trong 100ms (chỉ transform). aria-busy="true": vòng xoay thay nhãn,
   giữ nguyên kích thước nút. */
.saly-btn {
  position: relative; display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  min-width: var(--tap); min-height: var(--tap); padding: var(--space-2) var(--space-5); border: 0; border-radius: var(--radius-pill);
  font-size: var(--text-base); font-weight: 600; line-height: 1.25; text-align: center; text-decoration: none; cursor: pointer;
  color: var(--brand-on-primary); background: var(--brand-primary); box-shadow: var(--elev-1);
  transition: transform 100ms var(--ease-out), background-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
  -webkit-tap-highlight-color: transparent; touch-action: manipulation;
}
.saly-btn:active { transform: scale(0.98); }
.saly-btn:focus-visible { outline-offset: 3px; }
.saly-btn--secondary { color: var(--brand-secondary); background: var(--brand-surface-alt); box-shadow: inset 0 0 0 2px var(--brand-secondary); }
.saly-btn--ghost { color: var(--brand-secondary); background: transparent; box-shadow: none; }
/* Nút nguy hiểm (xoá…): đỏ thương hiệu chỉ đạt 4.42:1 làm nền chữ trắng ở SaLy Academy → nền sắc độ đỏ + viền đỏ 2px, chữ màu chữ */
.saly-btn--danger { color: var(--brand-text); background: var(--tint-danger-1); box-shadow: inset 0 0 0 2px var(--brand-danger); }
.saly-btn--block { display: flex; width: 100%; }
.saly-btn--sm { padding: var(--space-1) var(--space-4); font-size: var(--text-sm); }
.saly-btn--lg { min-height: 3.5rem; padding: var(--space-3) var(--space-6); font-size: var(--text-md); }
/* Nút chỉ có icon: tròn 48×48, BẮT BUỘC aria-label */
.saly-btn--icon { width: var(--tap); height: var(--tap); padding: 0; flex: none; }
@media (hover: hover) {
  .saly-btn:not(:disabled, [aria-disabled="true"]):hover { background: var(--brand-primary-strong); box-shadow: var(--elev-2); }
  .saly-btn--secondary:not(:disabled, [aria-disabled="true"]):hover { background: var(--tint-secondary-2); box-shadow: inset 0 0 0 2px var(--brand-secondary); }
  .saly-btn--ghost:not(:disabled, [aria-disabled="true"]):hover { background: var(--tint-secondary-2); box-shadow: none; }
  .saly-btn--danger:not(:disabled, [aria-disabled="true"]):hover { background: var(--tint-danger-1); box-shadow: inset 0 0 0 3px var(--brand-danger); }
}
.saly-btn:disabled, .saly-btn[aria-disabled="true"] { cursor: not-allowed; opacity: 0.55; box-shadow: none; transform: none; }

/* Đang tải: nhãn trong suốt (giữ chỗ) bằng -webkit-text-fill-color — color giữ nguyên nên phép đo tương phản không báo nhầm —
   vòng xoay 20px giữa nút cùng màu chữ của biến thể */
.saly-btn[aria-busy="true"] { -webkit-text-fill-color: transparent; cursor: progress; pointer-events: none; }
.saly-btn[aria-busy="true"] > * { visibility: hidden; }
.saly-btn[aria-busy="true"]::after {
  content: ""; position: absolute; top: 50%; left: 50%; width: 1.25rem; height: 1.25rem; margin: -0.625rem 0 0 -0.625rem;
  border: 2px solid var(--brand-on-primary); border-right-color: transparent; border-radius: 50%;
  animation: saly-spin 0.8s linear infinite;
}
.saly-btn--secondary[aria-busy="true"]::after, .saly-btn--ghost[aria-busy="true"]::after { border-color: var(--brand-secondary); border-right-color: transparent; }
.saly-btn--danger[aria-busy="true"]::after { border-color: var(--brand-text); border-right-color: transparent; }
@keyframes saly-spin { to { transform: rotate(360deg); } }

/* Nút nổi (FAB): ô 56px bo 20 ở mép phải, một hành động chính của màn (vd. "Thêm khoản"), BẮT BUỘC aria-label.
   Đặt là con CUỐI của .saly-main: position: sticky dính đáy màn khi cuộn, và vì sticky không ra khỏi .saly-main nên khi cuộn hết
   trang nút dừng ở cuối nội dung, không bao giờ đè chân trang (không cần chừa đáy). Có thanh đáy → đứng trên thanh đáy (48-app-shell.css). */
.saly-fab {
  position: sticky; bottom: calc(var(--space-4) + var(--safe-bottom)); z-index: var(--z-sticky);
  display: grid; place-items: center; width: 3.5rem; height: 3.5rem; margin: var(--space-4) 0 0 auto; padding: 0; border: 0; border-radius: var(--radius-lg);
  color: var(--brand-on-primary); background: var(--brand-primary); box-shadow: var(--elev-2); cursor: pointer; text-decoration: none;
  transition: transform 100ms var(--ease-out), background-color var(--dur-fast) var(--ease-out);
  -webkit-tap-highlight-color: transparent; touch-action: manipulation;
}
.saly-fab:active { transform: scale(0.96); }
.saly-fab:focus-visible { outline-offset: 3px; }
@media (hover: hover) { .saly-fab:hover { background: var(--brand-primary-strong); } }

/* ==== kit-src/43-forms.css ==== */
/* Ô nhập và lựa chọn — chữ 16px (iOS không tự phóng to), cao ≥48px, nhãn luôn hiện. Viền đạt ≥3:1 với nền thẻ và nền trang
   (pha 60% màu chữ); rê chuột viền màu chữ; focus viền + vòng màu phụ. Không dùng màu chính làm viền (cam/vàng chỉ 1.3–2.3:1).
   Lỗi: aria-invalid="true" + .saly-field__error (chữ màu chữ, vạch đỏ) — không chỉ đổi màu viền. */
.saly-field { display: flex; flex-direction: column; gap: var(--space-2); min-width: 0; }
:where(.saly-field, .saly-note) { margin: 0 0 var(--space-4); } /* :where = độ ưu tiên 0 → .saly-stack điều khiển khoảng cách */
.saly-field > label, .saly-field__label { font-size: 0.9375rem; font-weight: 600; line-height: 1.4; }
.saly-field__hint { font-size: var(--text-sm); color: var(--brand-muted); }
.saly-field__error { padding-left: var(--space-2); border-left: 3px solid var(--brand-danger); font-size: var(--text-sm); font-weight: 600; }
.saly-check { display: flex; align-items: center; gap: var(--space-3); min-height: var(--tap); cursor: pointer; }
.saly-input, .saly-select {
  display: block; width: 100%; min-height: var(--tap); padding: var(--space-3) var(--space-4); font-size: var(--text-base); line-height: 1.4;
  color: var(--brand-text); background-color: var(--brand-surface-alt); appearance: none;
  border: 1px solid color-mix(in srgb, var(--brand-text) 60%, var(--brand-surface-alt)); border-radius: var(--radius-sm);
  transition: border-color var(--dur-fast) var(--ease-out);
}
textarea.saly-input { min-height: 6rem; resize: vertical; }
.saly-input::placeholder { color: var(--brand-muted); opacity: 1; }
.saly-input:hover, .saly-select:hover { border-color: var(--brand-text); }
.saly-input:focus-visible, .saly-select:focus-visible { outline: 2px solid var(--brand-secondary); outline-offset: 0; border-color: var(--brand-secondary); }
.saly-input[aria-invalid="true"], .saly-select[aria-invalid="true"] { border-color: var(--brand-danger); }
/* Ô số: bỏ nút tăng/giảm của trình duyệt (khó bấm trên điện thoại, che chữ số); số căn theo cột. Cần tăng/giảm → .saly-stepper-input */
.saly-input[type="number"] { -moz-appearance: textfield; font-variant-numeric: tabular-nums; }
.saly-input[type="number"]::-webkit-inner-spin-button, .saly-input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.saly-input:disabled, .saly-select:disabled { background-color: var(--brand-surface); cursor: not-allowed; }
.saly-select {
  padding-right: 2.75rem; cursor: pointer; background-repeat: no-repeat; background-size: 0.375rem 0.375rem;
  background-image: linear-gradient(45deg, transparent 50%, var(--brand-text) 50%), linear-gradient(135deg, var(--brand-text) 50%, transparent 50%);
  background-position: calc(100% - 1.375rem) 52%, calc(100% - 1rem) 52%;
}

/* Ô có đơn vị trước/sau: <div class="saly-input-group"><span class="saly-input-group__addon">đ</span><input class="saly-input">
   <span class="saly-input-group__addon">/ tháng</span></div>. Khung (viền, focus) nằm ở nhóm; ô bên trong bỏ viền. */
.saly-input-group {
  display: flex; align-items: stretch; width: 100%; min-height: var(--tap); overflow: hidden;
  background-color: var(--brand-surface-alt); border: 1px solid color-mix(in srgb, var(--brand-text) 60%, var(--brand-surface-alt));
  border-radius: var(--radius-sm); transition: border-color var(--dur-fast) var(--ease-out);
}
.saly-input-group:hover { border-color: var(--brand-text); }
.saly-input-group:focus-within { outline: 2px solid var(--brand-secondary); outline-offset: 0; border-color: var(--brand-secondary); }
.saly-input-group:has([aria-invalid="true"]) { border-color: var(--brand-danger); }
.saly-input-group > .saly-input, .saly-input-group > .saly-select { flex: 1 1 auto; min-width: 0; width: auto; border: 0; border-radius: 0; outline: 0; }
.saly-input-group__addon {
  display: flex; align-items: center; flex: none; padding: 0 var(--space-3); font-size: var(--text-base); white-space: nowrap;
  color: var(--brand-muted); background: var(--brand-surface);
}

/* Bộ tăng/giảm: <div class="saly-stepper-input"><button class="saly-stepper-input__btn" aria-label="Giảm">…</button>
   <input class="saly-input" type="number" inputmode="numeric"><button class="saly-stepper-input__btn" aria-label="Tăng">…</button></div>.
   Nút 48×48 hai đầu, số căn giữa. Hành vi tăng/giảm do app (hoặc kit.js) gắn. */
.saly-stepper-input { display: inline-flex; align-items: center; gap: var(--space-2); max-width: 100%; }
.saly-stepper-input > .saly-input { width: 6rem; min-width: 0; text-align: center; }
.saly-stepper-input__btn {
  display: inline-grid; place-items: center; flex: none; width: var(--tap); height: var(--tap); padding: 0; border: 0; border-radius: 50%;
  font-size: var(--text-lg); font-weight: 700; line-height: 1; cursor: pointer; color: var(--brand-secondary);
  background: var(--brand-surface-alt); box-shadow: inset 0 0 0 2px var(--brand-secondary);
  transition: transform 100ms var(--ease-out), background-color var(--dur-fast) var(--ease-out); touch-action: manipulation; -webkit-tap-highlight-color: transparent;
}
.saly-stepper-input__btn:active { transform: scale(0.94); }
.saly-stepper-input__btn:disabled { cursor: not-allowed; opacity: 0.55; transform: none; }
@media (hover: hover) { .saly-stepper-input__btn:not(:disabled):hover { background: var(--tint-secondary-2); } }

/* Thẻ lựa chọn lớn (quiz, khảo sát): <label class="saly-choice"><input type="radio" name="…"> <span class="saly-choice__body">
   <span class="saly-choice__title">…</span><span class="saly-choice__desc">…</span></span></label> (ô icon .saly-icon-tile tuỳ chọn).
   Đang chọn: nền sắc độ + viền màu phụ 2px + nút radio/checkbox thật được đánh dấu — không chỉ đổi màu. */
.saly-choice {
  display: flex; align-items: center; gap: var(--space-3); min-height: 4rem; padding: var(--space-3) var(--space-4); cursor: pointer;
  border-radius: var(--radius-lg); background: var(--brand-surface-alt);
  box-shadow: inset 0 0 0 1px var(--tint-secondary-3), var(--elev-1);
  transition: transform 100ms var(--ease-out), background-color var(--dur-fast) var(--ease-out); -webkit-tap-highlight-color: transparent;
}
.saly-choice > input { flex: none; order: 9; }
.saly-choice__body { display: grid; flex: 1; gap: 2px; min-width: 0; }
.saly-choice__title { font-weight: 600; line-height: 1.4; }
.saly-choice__desc { font-size: var(--text-sm); color: var(--brand-muted); }
.saly-choice:active { transform: scale(0.99); }
.saly-choice:has(input:checked) { background: var(--tint-primary-2); box-shadow: inset 0 0 0 2px var(--brand-secondary); }
.saly-choice:has(input:focus-visible) { outline: 3px solid var(--brand-secondary); outline-offset: 2px; }
.saly-choice:has(input:disabled) { cursor: not-allowed; opacity: 0.55; }
@media (hover: hover) { .saly-choice:not(:has(input:checked, input:disabled)):hover { background: var(--tint-primary-1); } }

/* ==== kit-src/44-data-display.css ==== */
/* Hiển thị dữ liệu: bảng (thẻ dọc trên điện thoại), kết quả, chỉ số, danh sách, thẻ món, nhãn, ghi chú, khung biểu đồ.
   Số Montserrat 700 / chữ số căn cột (tabular-nums). Sắc độ dùng --tint-* của 10-tokens.css. */

/* Bảng — bọc <table> trong <div class="saly-table"> để cuộn ngang trên điện thoại */
.saly-table { width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }
.saly-table table, table.saly-table { width: 100%; border-collapse: collapse; font-size: 0.9375rem; }
.saly-table th, .saly-table td { padding: var(--space-3) var(--space-4); text-align: left; vertical-align: middle; border-bottom: 1px solid var(--brand-border); }
.saly-table thead th { font-weight: 600; white-space: nowrap; color: var(--brand-on-secondary); background: var(--brand-secondary); }
.saly-table tbody tr:hover { background: var(--tint-primary-2); }
.saly-table tfoot td, .saly-table tfoot th { font-weight: 700; border-bottom: 0; }
.saly-table .saly-num { text-align: right; }
/* Biến thể thẻ dọc: dưới 640px mỗi dòng thành một thẻ, mỗi ô hiện nhãn cột từ data-label="…" (app ghi trên từng <td>).
   Đầu bảng vẫn còn cho trình đọc màn hình (ẩn bằng kỹ thuật sr-only). */
@media (max-width: 639.98px) {
  .saly-table--cards { overflow: visible; }
  .saly-table--cards table, table.saly-table--cards, .saly-table--cards tbody, .saly-table--cards tfoot { display: block; }
  .saly-table--cards thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .saly-table--cards tr {
    display: grid; gap: 0; margin: 0 0 var(--space-3); padding: var(--space-2) var(--space-4); border-radius: var(--radius-md);
    background: var(--brand-surface-alt); border: 1px solid var(--brand-border); box-shadow: var(--elev-1);
  }
  .saly-table--cards tbody tr:hover { background: var(--brand-surface-alt); }
  .saly-table--cards th, .saly-table--cards td {
    display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: var(--space-1) var(--space-4);
    padding: var(--space-2) 0; text-align: right; border-bottom: 1px solid var(--brand-border);
  }
  .saly-table--cards tr > :last-child { border-bottom: 0; }
  .saly-table--cards td::before, .saly-table--cards th::before { content: attr(data-label); font-weight: 600; text-align: left; color: var(--brand-muted); }
  .saly-table--cards td:not([data-label])::before, .saly-table--cards th:not([data-label])::before { content: none; }
  .saly-table--cards tfoot tr { background: var(--tint-secondary-1); }
}

/* Khối kết quả và chỉ số — số Montserrat 700, chữ số căn cột. --highlight: kết quả chính của màn (nền màu phụ). */
.saly-result {
  display: grid; gap: var(--space-1); padding: var(--space-4) var(--space-5); border-radius: var(--radius-lg);
  background: var(--tint-secondary-2); border-left: 4px solid var(--brand-secondary);
}
.saly-result__label { font-size: 0.9375rem; font-weight: 600; }
.saly-result__value { font-family: var(--font-heading); font-size: clamp(1.75rem, 1.5rem + 1vw, 2.25rem); font-weight: 700; line-height: 1.3; color: var(--brand-secondary); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.saly-result__note { font-size: var(--text-sm); color: var(--brand-muted); }
.saly-result--highlight { color: var(--brand-on-secondary); background: linear-gradient(160deg, var(--brand-secondary), var(--hero-deep)); border-left-color: var(--brand-primary); box-shadow: var(--elev-2); }
.saly-result--highlight .saly-result__value, .saly-result--highlight .saly-result__note { color: var(--brand-on-secondary); }
.saly-result--highlight :focus-visible { outline-color: var(--brand-on-secondary); }
.saly-stat {
  display: grid; gap: var(--space-1); padding: var(--space-4); background: var(--brand-surface-alt); border: 1px solid var(--brand-border);
  border-top: 4px solid var(--brand-primary); border-radius: var(--radius-lg); box-shadow: var(--elev-1);
}
.saly-stat__label { font-size: var(--text-sm); font-weight: 500; color: var(--brand-muted); }
.saly-stat__value { font-family: var(--font-heading); font-size: 1.75rem; font-weight: 700; line-height: 1.3; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.saly-stat__note { font-size: 0.8125rem; color: var(--brand-muted); }

/* Danh sách (thay bảng nhiều cột trên điện thoại): <ul class="saly-list"><li class="saly-list-item">…</li></ul>, hoặc
   <li><a class="saly-list-item" href="…">…</a></li> khi cả dòng bấm được. Con: __media (ô icon/ảnh/avatar), __body (__title,
   __subtitle), __value (số căn phải), __chevron (mũi tên vẽ bằng CSS, trang trí). */
.saly-list {
  display: grid; margin: 0 0 var(--space-4); padding: 0; list-style: none; overflow: hidden;
  background: var(--brand-surface-alt); border: 1px solid var(--brand-border); border-radius: var(--radius-lg); box-shadow: var(--elev-1);
}
.saly-list > li { margin: 0; }
/* Dòng bấm được: <li> đệm 4px quanh liên kết/nút → hai dòng liền nhau cách ≥8px (4 + vạch 1 + 4), nền khi rê bo tròn bên trong */
.saly-list > li:not(.saly-list-item) { padding: var(--space-1); }
.saly-list > li + li { border-top: 1px solid var(--brand-border); }
.saly-list-item {
  display: flex; align-items: center; gap: var(--space-3); min-height: 3.5rem; padding: var(--space-3) var(--space-4);
  color: inherit; text-decoration: none;
}
:is(a, button).saly-list-item {
  width: 100%; min-height: 3rem; padding: var(--space-2) var(--space-3); border: 0; border-radius: var(--radius-md); font: inherit; text-align: left;
  cursor: pointer; background: transparent; -webkit-tap-highlight-color: transparent;
  transition: background-color var(--dur-fast) var(--ease-out), opacity 100ms var(--ease-out);
}
:is(a, button).saly-list-item:active { opacity: 0.7; }
:is(a, button).saly-list-item:focus-visible { outline-offset: -3px; }
@media (hover: hover) { :is(a, button).saly-list-item:hover { background: var(--tint-primary-1); } }
.saly-list-item__media { display: grid; place-items: center; flex: none; }
.saly-list-item__media > img { width: var(--tap); height: var(--tap); border-radius: var(--radius-sm); object-fit: cover; }
.saly-list-item__body { display: grid; flex: 1; gap: 2px; min-width: 0; }
.saly-list-item__title { font-weight: 600; line-height: 1.4; overflow-wrap: anywhere; }
.saly-list-item__subtitle { font-size: var(--text-sm); line-height: 1.45; color: var(--brand-muted); }
.saly-list-item__value { flex: none; font-family: var(--font-heading); font-weight: 700; font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }
.saly-list-item__chevron { flex: none; width: 0.625rem; height: 0.625rem; margin-right: var(--space-1); color: var(--brand-muted); border-top: 2px solid currentColor; border-right: 2px solid currentColor; transform: rotate(45deg); }

/* Thẻ món: ảnh tỉ lệ 4:3 cố định (giữ chỗ, không nhảy), tên, mô tả 1–2 dòng, giá căn cột + nhãn. Điện thoại: ảnh vuông 88px bên
   trái, chữ bên phải (một cột danh sách món); từ 768px: ảnh trên, chữ dưới (đặt trong .saly-grid). __media có thể là <img> hoặc
   <div> chứa ô icon khi chưa có ảnh. */
.saly-menu-card {
  display: grid; grid-template-columns: 5.5rem minmax(0, 1fr); align-items: start; gap: var(--space-3); margin: 0; padding: var(--space-3);
  background: var(--brand-surface-alt); border: 1px solid var(--brand-border); border-radius: var(--radius-lg); box-shadow: var(--elev-1);
}
.saly-menu-card__media {
  display: grid; place-items: center; width: 100%; aspect-ratio: 1; overflow: hidden; border-radius: var(--radius-md);
  object-fit: cover; color: var(--brand-secondary); background: var(--tint-primary-2);
}
.saly-menu-card__media saly-icon { width: 2rem; height: 2rem; } /* icon thay ảnh: 32px */
.saly-menu-card__body { display: grid; gap: var(--space-1); min-width: 0; }
.saly-menu-card__body > * { margin: 0; }
.saly-menu-card__title { font-family: var(--font-heading); font-size: var(--text-md); font-weight: 700; line-height: 1.3; color: var(--brand-text); }
.saly-menu-card__desc { font-size: var(--text-sm); line-height: 1.5; color: var(--brand-muted); }
.saly-menu-card__foot { display: flex; flex-wrap: nowrap; align-items: center; justify-content: space-between; gap: var(--space-2); padding-top: var(--space-1); }
.saly-menu-card__price { font-family: var(--font-heading); font-size: var(--text-md); font-weight: 700; font-variant-numeric: tabular-nums; color: var(--brand-secondary); }
@media (min-width: 768px) {
  .saly-menu-card { grid-template-columns: minmax(0, 1fr); padding: 0 0 var(--space-4); overflow: hidden; }
  .saly-menu-card__media { aspect-ratio: 4 / 3; border-radius: 0; }
  .saly-menu-card__body { padding: 0 var(--space-4); }
}

/* Ghi chú và nhãn — nền sắc độ, chữ --brand-text; vạch trái màu thương hiệu chỉ để trang trí */
.saly-note { padding: var(--space-3) var(--space-4); font-size: 0.9375rem; border-radius: var(--radius-sm); background: var(--tint-primary-3); border-left: 4px solid var(--brand-primary-strong); }
.saly-note--success { background: var(--tint-secondary-2); border-left-color: var(--brand-secondary); }
.saly-note--danger { background: var(--tint-danger-1); border-left-color: var(--brand-danger); }
.saly-note > :last-child { margin-bottom: 0; }
.saly-badge { display: inline-flex; align-items: center; gap: var(--space-1); min-height: 1.75rem; padding: 0 var(--space-3); font-size: 0.8125rem; font-weight: 600; line-height: 1; white-space: nowrap; border-radius: var(--radius-pill); background: var(--tint-primary-3); }
.saly-badge--secondary { color: var(--brand-secondary); background: var(--tint-secondary-2); }
.saly-badge--danger { color: var(--brand-text); background: var(--tint-danger-1); box-shadow: inset 0 0 0 1px var(--brand-danger); }

/* Khung biểu đồ Chart.js (responsive cần khung có chiều cao) */
.saly-chart { position: relative; width: 100%; height: 18rem; }

/* ==== kit-src/45-selection-and-progress.css ==== */
/* Chọn và tiến độ: thẻ chuyển (tabs), điều khiển phân đoạn, chip, thanh bước, thanh tiến độ.
   Trạng thái chọn = nền màu phụ (tab, phân đoạn) hoặc nền sắc độ + viền màu phụ + dấu kiểm (chip) — đạt ≥3:1, không chỉ đổi màu.
   Các đích bấm cao ≥48px, cách nhau ≥8px. */

/* Thẻ chuyển (tabs): <div class="saly-tabs" role="tablist"><button role="tab" aria-selected="true">…
   Thẻ đang chọn nền màu phụ + chữ "on-secondary": trạng thái chọn đạt ≥3:1 so với nền thẻ (màu chính chỉ 1.3–2.1:1). */
.saly-tabs { display: flex; gap: var(--space-2); padding: var(--space-1); overflow-x: auto; scrollbar-width: none; background: var(--brand-surface-alt); border: 1px solid var(--brand-border); border-radius: var(--radius-pill); }
.saly-tabs > button, .saly-tabs > [role="tab"] {
  flex: 1 0 auto; min-height: var(--tap); padding: 0 var(--space-4); border: 0; border-radius: var(--radius-pill);
  font-size: 0.9375rem; font-weight: 600; white-space: nowrap; color: var(--brand-text); background: transparent; cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-out), transform 100ms var(--ease-out); -webkit-tap-highlight-color: transparent;
}
.saly-tabs > :active { transform: scale(0.98); }
.saly-tabs > :hover { background: var(--tint-primary-3); }
.saly-tabs > [aria-selected="true"], .saly-tabs > .is-active { color: var(--brand-on-secondary); background: var(--brand-secondary); box-shadow: var(--elev-1); }
.saly-tabs > :focus-visible { outline-offset: -3px; }
.saly-tabs > [aria-selected="true"]:focus-visible, .saly-tabs > .is-active:focus-visible { outline-color: var(--brand-on-secondary); }

/* Điều khiển phân đoạn (chọn MỘT giá trị, các phần rộng bằng nhau): <div class="saly-segmented" role="radiogroup" aria-label="…">
   <label><input type="radio" name="ky" checked> Ngày</label>… — hoặc <button aria-pressed="true">. Phần chọn nền màu phụ. */
.saly-segmented {
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: var(--space-2); padding: var(--space-1);
  border-radius: var(--radius-pill); background: var(--tint-secondary-2);
}
.saly-segmented > label, .saly-segmented > button {
  position: relative; display: flex; align-items: center; justify-content: center; gap: var(--space-2); min-width: 0; min-height: var(--tap);
  padding: 0 var(--space-3); border: 0; border-radius: var(--radius-pill); font-size: 0.9375rem; font-weight: 600; line-height: 1.25;
  text-align: center; color: var(--brand-text); background: transparent; cursor: pointer; -webkit-tap-highlight-color: transparent;
  transition: background-color var(--dur-fast) var(--ease-out), transform 100ms var(--ease-out);
}
.saly-segmented > label > input { position: absolute; width: 1px; height: 1px; margin: 0; opacity: 0; pointer-events: none; }
.saly-segmented > :active { transform: scale(0.98); }
.saly-segmented > :has(input:checked), .saly-segmented > [aria-pressed="true"], .saly-segmented > [aria-checked="true"] {
  color: var(--brand-on-secondary); background: var(--brand-secondary); box-shadow: var(--elev-1);
}
.saly-segmented > :has(input:focus-visible) { outline: 3px solid var(--brand-secondary); outline-offset: 2px; }
.saly-segmented > :focus-visible { outline-offset: 2px; }

/* Chip (giá trị nhanh "100 triệu", lọc nhóm món): <button class="saly-chip" aria-pressed="false">…</button> hoặc
   <label class="saly-chip"><input type="checkbox" class="saly-sr-only"> Trà sữa</label>. Nhóm chip: .saly-chips (xuống dòng), .saly-chips--scroll (một hàng cuộn ngang). */
.saly-chips { display: flex; flex-wrap: wrap; gap: var(--space-2); }
:where(.saly-chips) { margin: 0 0 var(--space-4); } /* :where = độ ưu tiên 0 → .saly-stack/.saly-field điều khiển khoảng cách */
.saly-field > .saly-chips { margin: 0; }
.saly-chips--scroll { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; padding-bottom: 2px; }
.saly-chip {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2); flex: none; min-height: var(--tap);
  padding: 0 var(--space-4); border: 0; border-radius: var(--radius-pill); font-size: 0.9375rem; font-weight: 600; line-height: 1.25;
  white-space: nowrap; text-decoration: none; cursor: pointer; color: var(--brand-text); background: var(--brand-surface-alt);
  box-shadow: inset 0 0 0 1px var(--tint-secondary-3);
  transition: background-color var(--dur-fast) var(--ease-out), transform 100ms var(--ease-out); -webkit-tap-highlight-color: transparent; touch-action: manipulation;
}
.saly-chip:active { transform: scale(0.97); }
@media (hover: hover) { .saly-chip:hover { background: var(--tint-primary-1); } }
.saly-chip[aria-pressed="true"], .saly-chip[aria-checked="true"], .saly-chip[aria-selected="true"], .saly-chip:has(input:checked) {
  background: var(--tint-primary-2); box-shadow: inset 0 0 0 2px var(--brand-secondary);
}
/* Dấu kiểm vẽ bằng CSS (màu phụ) khi đang chọn */
.saly-chip[aria-pressed="true"]::before, .saly-chip[aria-checked="true"]::before, .saly-chip[aria-selected="true"]::before, .saly-chip:has(input:checked)::before {
  content: ""; flex: none; width: 0.375rem; height: 0.75rem; margin: -0.125rem 0.125rem 0 0; color: var(--brand-secondary);
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor; transform: rotate(45deg);
}
.saly-chip:has(input:focus-visible) { outline: 3px solid var(--brand-secondary); outline-offset: 2px; }

/* Thanh bước — kit.js (salyUI.steps / [data-saly-steps]) dựng: <div class="saly-steps"><p class="saly-steps__label" aria-live="polite">
   Bước 2/5 · Thông tin quán</p><ol class="saly-steps__list"><li><button class="saly-steps__item" data-state="done|current|todo"
   aria-current="step">Tên bước</button></li>…</ol></div>. Mỗi bước một vạch mảnh 6px giữa vùng chạm 48px (chữ tên bước chỉ cho trình
   đọc màn hình); bước đã xong và đang làm tô màu phụ. Trang tĩnh không dùng kit: <span class="saly-steps__item" data-state="…">
   (không phải nút, chỉ cao bằng vạch). */
.saly-steps { display: grid; gap: var(--space-1); margin: 0 0 var(--space-4); }
.saly-steps__label { margin: 0; font-size: var(--text-sm); font-weight: 600; color: var(--brand-secondary); }
.saly-steps__list { display: flex; gap: var(--space-2); margin: 0; padding: 0; list-style: none; }
.saly-steps__list > li { display: flex; flex: 1; min-width: 0; margin: 0; }
.saly-steps__item {
  position: relative; display: block; flex: 1; min-width: 0; height: 0.375rem; margin: 0; padding: 0; overflow: hidden; border: 0;
  border-radius: var(--radius-pill); font-size: 0; background: transparent;
}
.saly-steps__item::before { content: ""; position: absolute; left: 0; right: 0; top: 50%; height: 0.375rem; margin-top: -0.1875rem; border-radius: var(--radius-pill); background: var(--tint-secondary-3); }
.saly-steps__item[data-state="done"]::before, .saly-steps__item[data-state="current"]::before { background: var(--brand-secondary); }
button.saly-steps__item { min-width: var(--tap); height: var(--tap); cursor: pointer; border-radius: var(--radius-sm); -webkit-tap-highlight-color: transparent; }
button.saly-steps__item:disabled { cursor: default; }
button.saly-steps__item:focus-visible { outline-offset: 0; }

/* Thanh tiến độ: <div class="saly-progress" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="40"
   aria-label="…"><span class="saly-progress__bar"></span></div>; app đặt chiều rộng thanh bằng el.style.width = '40%'.
   Không có aria-valuenow → chạy qua lại (đang chờ, không biết bao lâu). */
.saly-progress { position: relative; height: 0.5rem; overflow: hidden; border-radius: var(--radius-pill); background: var(--tint-secondary-3); }
.saly-progress__bar { display: block; width: 0; height: 100%; border-radius: inherit; background: var(--brand-secondary); }
.saly-progress:not([aria-valuenow]) .saly-progress__bar { width: 40%; animation: saly-progress-indeterminate 1.4s var(--ease-out) infinite; }
@keyframes saly-progress-indeterminate { from { transform: translateX(-100%); } to { transform: translateX(250%); } }

/* ==== kit-src/46-feedback.css ==== */
/* Trạng thái và phản hồi: thông báo (alert), trạng thái rỗng, khung chờ (skeleton), thông báo nổi (toast — kit.js dựng).
   Mọi màn có dữ liệu cần đủ 4 trạng thái: đang tải (skeleton / nút aria-busy), rỗng, lỗi (alert + nút Thử lại), xong (toast).
   Loại thông báo luôn có ô icon + chữ, không chỉ đổi màu. */

/* Thông báo: <div class="saly-alert saly-alert--danger" role="alert"><span class="saly-alert__icon"><saly-icon name="…"></saly-icon>
   </span><div class="saly-alert__body"><p class="saly-alert__title">…</p><p>…</p></div><button class="saly-btn saly-btn--sm
   saly-btn--secondary">Thử lại</button></div>. role="alert" cho lỗi, role="status" cho thông tin/thành công. */
.saly-alert {
  display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: start; gap: var(--space-2) var(--space-3);
  margin: 0 0 var(--space-4); padding: var(--space-3) var(--space-4); border-radius: var(--radius-md); background: var(--tint-secondary-1);
  box-shadow: inset 0 0 0 1px var(--brand-border);
}
.saly-alert__icon {
  display: inline-grid; place-items: center; width: 2rem; height: 2rem; border-radius: 50%;
  color: var(--brand-on-secondary); background: var(--brand-secondary);
}
.saly-alert__icon saly-icon { width: var(--icon-md); height: var(--icon-md); }
.saly-alert__body { display: grid; gap: 2px; min-width: 0; padding-top: 0.25rem; }
.saly-alert__body > * { margin: 0; }
.saly-alert__title { font-weight: 700; }
.saly-alert > .saly-btn, .saly-alert__actions { grid-column: 2; justify-self: start; }
.saly-alert__actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.saly-alert--success { background: var(--tint-secondary-2); }
.saly-alert--danger { background: var(--tint-danger-1); }
.saly-alert--danger .saly-alert__icon { color: var(--brand-on-secondary); background: var(--brand-danger); }
.saly-alert--info .saly-alert__icon { color: var(--brand-secondary); background: var(--tint-secondary-3); }
@media (min-width: 640px) {
  .saly-alert { grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; }
  .saly-alert > .saly-btn, .saly-alert__actions { grid-column: 3; }
  .saly-alert__body { padding-top: 0; }
}

/* Trạng thái rỗng: ô icon 64 (icon 32) + tiêu đề + một câu + một nút */
.saly-empty { display: grid; justify-items: center; gap: var(--space-3); padding: var(--space-6) var(--space-4); text-align: center; }
.saly-empty > * { margin: 0; }
.saly-empty__icon {
  display: grid; place-items: center; width: 4rem; height: 4rem; border-radius: var(--radius-lg);
  color: var(--brand-secondary); background: var(--tint-primary-2);
}
.saly-empty__icon saly-icon { width: 2rem; height: 2rem; }
.saly-empty__title { font-family: var(--font-heading); font-size: var(--text-lg); font-weight: 700; line-height: 1.3; color: var(--brand-text); }
.saly-empty__text { max-width: 28rem; color: var(--brand-muted); }

/* Khung chờ: khối sắc độ nhạt nhấp nháy 1.2s (chỉ opacity); giảm chuyển động → đứng yên. Đặt aria-hidden="true" trên khung chờ và
   aria-busy="true" trên vùng đang tải. --text: một dòng chữ; --circle: avatar; mặc định khối cao 6rem. */
.saly-skeleton {
  display: block; height: 6rem; border-radius: var(--radius-md); background: var(--tint-secondary-2);
  animation: saly-skeleton-pulse 1.2s ease-in-out infinite alternate;
}
.saly-skeleton--text { height: 1em; margin: 0.3em 0; border-radius: var(--radius-pill); }
.saly-skeleton--text:last-child { width: 60%; }
.saly-skeleton--circle { width: 2.5rem; height: 2.5rem; border-radius: 50%; }
@keyframes saly-skeleton-pulse { from { opacity: 1; } to { opacity: 0.45; } }

/* Thông báo nổi (kit.js: salyUI.toast(chữ, {type: 'success'|'error'|'info', action})). kit.js tạo MỘT
   <div class="saly-toast-region" aria-live="polite"> (con của body) rồi thêm <div class="saly-toast saly-toast--success|--error|--info"
   data-state="open"><saly-icon name="…"></saly-icon><p class="saly-toast__text">Đã lưu</p><button class="saly-toast__action">Hoàn tác
   </button></div>. Tự ẩn sau 4 giây: data-state="closing" (hoạt ảnh ra 150ms)
   rồi gỡ. Không cướp focus. Vị trí: đáy màn, phía trên thanh đáy/thanh nút dính/nút nổi (48-app-shell.css đẩy lên). */
.saly-toast-region {
  position: fixed; right: 0; bottom: calc(var(--space-4) + var(--safe-bottom)); left: 0; z-index: var(--z-toast);
  display: grid; justify-items: center; gap: var(--space-2); padding: 0 max(var(--gutter), var(--safe-right)) 0 max(var(--gutter), var(--safe-left));
  pointer-events: none;
}
.saly-toast {
  display: flex; align-items: center; gap: var(--space-3); width: min(100%, 30rem); min-height: var(--tap); padding: var(--space-2) var(--space-2) var(--space-2) var(--space-4);
  border-radius: var(--radius-md); font-size: 0.9375rem; font-weight: 500; line-height: 1.4; color: var(--brand-on-secondary);
  background: var(--hero-deep); box-shadow: var(--elev-3); pointer-events: auto;
  animation: saly-toast-in var(--dur) var(--ease-out);
}
.saly-toast > saly-icon { flex: none; }
.saly-toast__text { flex: 1; min-width: 0; margin: 0; padding: var(--space-1) 0; }
.saly-toast__action {
  flex: none; min-height: var(--tap); padding: 0 var(--space-3); border: 0; border-radius: var(--radius-sm); font: inherit; font-weight: 700;
  color: var(--brand-on-secondary); background: transparent; text-decoration: underline; text-underline-offset: 0.15em; cursor: pointer;
}
.saly-toast__action:focus-visible, .saly-toast :focus-visible { outline-color: var(--brand-on-secondary); outline-offset: -3px; }
/* Loại: vạch màu bên trái (trang trí) + ô icon; chữ luôn on-secondary trên nền đậm */
.saly-toast--success { box-shadow: inset 4px 0 0 var(--brand-primary), var(--elev-3); }
.saly-toast--error { box-shadow: inset 4px 0 0 var(--brand-danger), var(--elev-3); }
.saly-toast[data-state="closing"] { animation: saly-toast-out var(--dur-fast) var(--ease-in) forwards; }
@keyframes saly-toast-in { from { opacity: 0; transform: translateY(0.75rem); } }
@keyframes saly-toast-out { to { opacity: 0; transform: translateY(0.5rem); } }

/* ==== kit-src/47-overlays.css ==== */
/* Lớp phủ do kit.js dựng (app không tự viết): tấm trượt salyUI.openSheet(), hộp xác nhận salyUI.confirm().
   Hợp đồng DOM (kit.js tạo, chữ qua textContent; lớp mờ và khung là con của body):
     <div class="saly-sheet-backdrop" data-state="open|closing"></div>   lớp mờ phủ kín, chạm vào để đóng
     <div class="saly-sheet" role="dialog" aria-modal="true" data-state="open|closing">
       <div class="saly-sheet__handle"></div>                                tay nắm (trang trí, chỉ trên điện thoại)
       <div class="saly-sheet__head"><h2 class="saly-sheet__title">…</h2>
         <button class="saly-btn saly-btn--ghost saly-btn--icon saly-sheet__close" aria-label="Đóng">…</button></div>
       <div class="saly-sheet__body">…nội dung app (hoặc <p class="saly-sheet__text">)…</div>
     </div>
     <div class="saly-dialog" role="alertdialog" aria-modal="true" data-state="…"> __title, __text, __actions (nút .saly-btn) </div>
   html[data-saly-layer="open"] khoá cuộn nền. Vào: keyframes khi data-state="open"; ra: keyframes khi "closing" (kit đọc thời lượng
   tính được rồi gỡ; giảm chuyển động → thời lượng ~0, kit đóng ngay). Dưới 1024px: tấm trượt từ đáy, bo trên 28, cao tối đa 90% màn;
   từ 1024px: hộp giữa màn rộng 32rem. Hộp xác nhận luôn giữa màn, rộng tối đa 24rem. */
.saly-sheet-backdrop { position: fixed; inset: 0; z-index: var(--z-overlay); background: var(--hero-deep); opacity: 0.55; }
.saly-sheet-backdrop[data-state="open"] { animation: saly-fade-in var(--dur) var(--ease-out); }
.saly-sheet-backdrop[data-state="closing"] { animation: saly-fade-out var(--dur-fast) var(--ease-in) forwards; }
html[data-saly-layer="open"] { overflow: hidden; }

.saly-sheet, .saly-dialog {
  position: fixed; z-index: calc(var(--z-overlay) + 1); display: flex; flex-direction: column; margin: 0; padding: 0;
  border: 0; color: var(--brand-text); background: var(--brand-surface-alt); box-shadow: var(--elev-3); overscroll-behavior: contain;
}
.saly-sheet:focus, .saly-dialog:focus { outline: none; } /* kit focus vào khung khi mở; vòng focus chỉ trên điều khiển */
.saly-sheet {
  inset: auto 0 0 0; width: 100%; max-height: 90vh; max-height: 90dvh; padding-bottom: var(--safe-bottom);
  border-radius: var(--radius-xl) var(--radius-xl) 0 0;
}
.saly-sheet[data-state="open"] { animation: saly-sheet-in var(--dur-slow) var(--ease-out); }
.saly-sheet[data-state="closing"] { animation: saly-sheet-out 200ms var(--ease-in) forwards; }
.saly-sheet__handle { flex: none; width: 2.5rem; height: 0.25rem; margin: var(--space-2) auto 0; border-radius: var(--radius-pill); background: var(--tint-secondary-3); }
.saly-sheet__head {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); flex: none;
  padding: var(--space-2) max(var(--space-2), var(--safe-right)) var(--space-2) max(var(--space-5), var(--safe-left));
}
.saly-sheet__title, .saly-dialog__title { margin: 0; font-size: var(--text-lg); font-weight: 700; line-height: 1.3; color: var(--brand-text); }
.saly-sheet__close { flex: none; }
.saly-sheet__body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: var(--space-2) max(var(--space-5), var(--safe-right)) var(--space-5) max(var(--space-5), var(--safe-left)); }
.saly-sheet__body > :last-child { margin-bottom: 0; }
.saly-sheet__text, .saly-dialog__text { margin: 0 0 var(--space-4); color: var(--brand-muted); }

/* Hộp xác nhận */
.saly-dialog {
  inset: 50% auto auto 50%; width: min(calc(100% - 2 * var(--gutter)), 24rem); max-height: calc(100dvh - 2 * var(--space-5)); overflow-y: auto;
  padding: var(--space-5); border-radius: var(--radius-lg); transform: translate(-50%, -50%);
}
.saly-dialog[data-state="open"] { animation: saly-dialog-in var(--dur) var(--ease-out); }
.saly-dialog[data-state="closing"] { animation: saly-dialog-out var(--dur-fast) var(--ease-in) forwards; }
.saly-dialog__title { margin-bottom: var(--space-2); }
.saly-dialog__actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--space-3); }
.saly-dialog__actions > .saly-btn { flex: 1 1 8rem; }

@media (min-width: 1024px) {
  .saly-sheet {
    inset: 50% auto auto 50%; width: min(calc(100% - 2 * var(--gutter)), 32rem); max-height: min(85vh, 48rem);
    padding-bottom: 0; border-radius: var(--radius-xl); transform: translate(-50%, -50%);
  }
  .saly-sheet[data-state="open"] { animation-name: saly-dialog-in; }
  .saly-sheet[data-state="closing"] { animation-name: saly-dialog-out; animation-duration: var(--dur-fast); }
  .saly-sheet__handle { display: none; }
  .saly-sheet__head { padding-top: var(--space-4); }
}

@keyframes saly-fade-in { from { opacity: 0; } }
@keyframes saly-fade-out { to { opacity: 0; } }
@keyframes saly-sheet-in { from { transform: translateY(100%); } }
@keyframes saly-sheet-out { to { transform: translateY(100%); } }
@keyframes saly-dialog-in { from { opacity: 0; transform: translate(-50%, -50%) scale(0.96); } }
@keyframes saly-dialog-out { to { opacity: 0; transform: translate(-50%, -50%) scale(0.96); } }

/* ==== kit-src/48-app-shell.css ==== */
/* Khung app điện thoại: thanh đáy (.saly-tabbar), thanh tiêu đề màn con (.saly-appbar), thanh nút chính dính đáy
   (.saly-sticky-cta), chừa đáy cho vật dính đáy (thanh đáy / thanh nút / nút nổi), bố cục laptop (.saly-main--split/--narrow),
   chế độ toàn màn hình (display-mode: standalone).

   Quy tắc vật dính đáy (đã kiểm bằng verifier thật ở spike S3, phương án a):
   - Vật cố định ở đáy cao ĐÚNG bằng phần trang chừa đáy (cùng một biểu thức); lệch 1px là đè lên chân trang khi cuộn hết →
     verifier báo "che vỏ". Vì vậy vạch phân cách vẽ bằng box-shadow INSET, không border-top, không bóng hắt lên trên.
   - Trang tự chừa đáy bằng body:has(…) { padding-bottom } — app không phải làm gì.
   - Mỗi màn một vật dính đáy: thanh đáy HOẶC thanh nút; nút nổi (sticky trong .saly-main, không cần chừa đáy) đi được cùng thanh đáy. Có cả thanh đáy và thanh nút thì thanh nút
     nằm ngay trên thanh đáy, chừa đáy cộng dồn đúng một lần (vùng an toàn chỉ tính một lần). */

/* ---- Thanh đáy: <nav class="saly-tabbar" aria-label="…"> là con ĐẦU của <main class="saly-main">, 2–5 mục
   <a class="saly-tabbar__item" href="…" aria-current="page"><saly-icon name="…" aria-hidden="true"></saly-icon>
   <span class="saly-tabbar__label">Sổ</span></a>. Dưới 1024px: cố định đáy, cao --tabbar-h (56px) + vùng an toàn.
   Từ 1024px: thanh điều hướng ngang đầu nội dung (position: static). Mục đang chọn: chữ màu phụ đậm + vạch màu phụ (không chỉ màu). */
.saly-tabbar {
  position: fixed; right: 0; bottom: 0; left: 0; z-index: var(--z-sticky);
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: var(--space-2);
  box-sizing: border-box; height: calc(var(--tabbar-h) + var(--safe-bottom)); margin: 0;
  padding: 0 max(var(--space-2), var(--safe-right)) var(--safe-bottom) max(var(--space-2), var(--safe-left));
  background: var(--brand-surface-alt); box-shadow: inset 0 1px 0 var(--brand-border);
}
.saly-tabbar__item {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; min-width: var(--tap); height: var(--tabbar-h);
  padding: var(--space-1); font-size: var(--text-xs); font-weight: 500; line-height: 1.2; text-align: center; text-decoration: none;
  color: var(--brand-muted); -webkit-tap-highlight-color: transparent; touch-action: manipulation; transition: opacity 100ms var(--ease-out);
}
.saly-tabbar__item:active { opacity: 0.7; }
.saly-tabbar__item > svg, .saly-tabbar__item > saly-icon { flex: none; width: var(--icon-lg); height: var(--icon-lg); }
.saly-tabbar__label { max-width: 100%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.saly-tabbar__item[aria-current="page"] { font-weight: 700; color: var(--brand-secondary); box-shadow: inset 0 3px 0 var(--brand-secondary); }
.saly-tabbar__item:focus-visible { outline-offset: -3px; }

/* ---- Thanh nút chính dính đáy (điện thoại): <div class="saly-sticky-cta"><button class="saly-btn">Lưu</button>…</div> (1–2 nút).
   Cao đúng 48px + 2×12px + vùng an toàn. Từ 1024px: nằm yên trong dòng nội dung (hàng nút cuối khối). */
.saly-sticky-cta {
  position: fixed; right: 0; bottom: 0; left: 0; z-index: var(--z-sticky);
  display: flex; align-items: center; gap: var(--space-3); box-sizing: border-box; margin: 0;
  height: calc(var(--tap) + 2 * var(--space-3) + var(--safe-bottom));
  padding: var(--space-3) max(var(--gutter), var(--safe-right)) calc(var(--space-3) + var(--safe-bottom)) max(var(--gutter), var(--safe-left));
  background: var(--brand-surface-alt); box-shadow: inset 0 1px 0 var(--brand-border);
}
.saly-sticky-cta > .saly-btn { flex: 1 1 0; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.saly-sticky-cta > .saly-btn--icon { flex: none; }

@media (max-width: 1023.98px) {
  body:has(.saly-tabbar) { padding-bottom: calc(var(--tabbar-h) + var(--safe-bottom)); }
  body:has(.saly-sticky-cta) { padding-bottom: calc(var(--tap) + 2 * var(--space-3) + var(--safe-bottom)); }
  body:has(.saly-tabbar):has(.saly-sticky-cta) { padding-bottom: calc(var(--tabbar-h) + var(--tap) + 2 * var(--space-3) + var(--safe-bottom)); }
  /* Thanh nút đứng ngay trên thanh đáy: vùng an toàn đã nằm trong thanh đáy, không đệm lần hai */
  body:has(.saly-tabbar) .saly-sticky-cta { bottom: calc(var(--tabbar-h) + var(--safe-bottom)); height: calc(var(--tap) + 2 * var(--space-3)); padding-bottom: var(--space-3); }
}
@media (min-width: 1024px) {
  .saly-tabbar {
    position: static; display: flex; flex-wrap: wrap; gap: var(--space-2); height: auto; margin: 0 0 var(--space-5); padding: 0;
    background: none; box-shadow: inset 0 -1px 0 var(--brand-border);
  }
  .saly-tabbar__item { flex-direction: row; gap: var(--space-2); height: auto; min-height: var(--tap); padding: 0 var(--space-4); font-size: 0.9375rem; }
  .saly-tabbar__item[aria-current="page"] { box-shadow: inset 0 -3px 0 var(--brand-secondary); }
  .saly-sticky-cta {
    position: static; justify-content: flex-end; height: auto; margin: var(--space-5) 0 0; padding: 0; background: none; box-shadow: none;
  }
  .saly-sticky-cta > .saly-btn { flex: 0 1 auto; }
}

/* ---- Nút nổi (42-buttons.css, sticky trong .saly-main — không cần chừa đáy): có thanh đáy thì dính ngay trên thanh đáy */
@media (max-width: 1023.98px) {
  body:has(.saly-tabbar) .saly-fab { bottom: calc(var(--tabbar-h) + var(--safe-bottom) + var(--space-4)); }
}

/* ---- Thông báo nổi đứng trên vật dính đáy */
body:has(.saly-fab) .saly-toast-region { bottom: calc(3.5rem + 2 * var(--space-4) + var(--safe-bottom)); }
@media (max-width: 1023.98px) {
  body:has(.saly-tabbar) .saly-toast-region { bottom: calc(var(--tabbar-h) + var(--safe-bottom) + var(--space-3)); }
  body:has(.saly-sticky-cta) .saly-toast-region { bottom: calc(var(--tap) + 3 * var(--space-3) + var(--safe-bottom)); }
  body:has(.saly-tabbar):has(.saly-sticky-cta) .saly-toast-region { bottom: calc(var(--tabbar-h) + var(--tap) + 3 * var(--space-3) + var(--safe-bottom)); }
  body:has(.saly-tabbar):has(.saly-fab) .saly-toast-region { bottom: calc(var(--tabbar-h) + 3.5rem + 2 * var(--space-4) + var(--safe-bottom)); }
}

/* ---- Thanh tiêu đề màn con: <header class="saly-appbar"><a class="saly-appbar__back" href="…" aria-label="Quay lại">
   <saly-icon name="arrow-left"></saly-icon></a><h1 class="saly-appbar__title">Thêm khoản chi</h1>
   <div class="saly-appbar__actions">…</div></header> — con đầu của .saly-main; dính đầu màn khi cuộn. */
.saly-appbar {
  position: sticky; top: 0; z-index: var(--z-sticky); display: flex; align-items: center; gap: var(--space-2);
  margin: 0 0 var(--space-4); padding: var(--space-2) 0; background: var(--brand-surface);
}
.saly-appbar__back {
  display: inline-grid; place-items: center; flex: none; width: var(--tap); height: var(--tap); margin-left: calc(-1 * var(--space-2));
  border: 0; border-radius: 50%; color: var(--brand-secondary); background: transparent; text-decoration: none; cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-out), transform 100ms var(--ease-out); -webkit-tap-highlight-color: transparent;
}
.saly-appbar__back:active { transform: scale(0.94); }
@media (hover: hover) { .saly-appbar__back:hover { background: var(--tint-secondary-2); } }
.saly-appbar__title { flex: 1; min-width: 0; margin: 0; font-size: var(--text-lg); font-weight: 700; line-height: 1.3; letter-spacing: 0; color: var(--brand-text); }
.saly-appbar__actions { display: flex; align-items: center; gap: var(--space-2); flex: none; }

/* ---- Bố cục laptop (≥1024px), đặt trên <main>: --split = cột nhập 5/12 + cột kết quả/form 7/12 (cột .saly-main__aside dính khi
   cuộn); thanh đáy, thanh tiêu đề, hero, .saly-main__full chiếm cả hàng. --narrow = một cột 40rem giữa màn (nhiều bước, quiz).
   Dưới 1024px cả hai là một cột như thường. */
@media (min-width: 1024px) {
  .saly-main--split { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: var(--space-5) var(--space-6); align-items: start; }
  .saly-main--split > * { margin-top: 0; margin-bottom: 0; }
  .saly-main--split > :is(.saly-tabbar, .saly-appbar, .saly-hero, .saly-main__full, .saly-sticky-cta, .saly-fab) { grid-column: 1 / -1; }
  .saly-main--split > .saly-fab { justify-self: end; }
  .saly-main--split > .saly-main__aside { position: sticky; top: var(--space-5); }
  .saly-main--narrow { max-width: calc(40rem + 2 * var(--gutter)); }
}

/* ---- Chế độ toàn màn hình (app đã cài, display-mode: standalone): chừa vùng an toàn ở đáy khi không có vật dính đáy (vật dính
   đáy đã tự tính --safe-bottom, selector của chúng cụ thể hơn nên không đệm hai lần); ẩn thứ chỉ hợp với trình duyệt. */
@media (display-mode: standalone) {
  body { padding-bottom: var(--safe-bottom); }
  .saly-browser-only { display: none; }
}
@media not all and (display-mode: standalone) {
  .saly-standalone-only { display: none; }
}

/* ==== kit-src/90-print.css ==== */
/* In kết quả: nền trắng, bỏ bóng và nút bấm, không cắt đôi thẻ; bỏ thanh đáy, thanh nút dính, nút nổi, thông báo nổi, lớp phủ.
   Đứng cuối để thắng mọi tệp thành phần 4x-*.css. */
@media print {
  body { background: var(--brand-surface-alt); }
  body:has(.saly-tabbar), body:has(.saly-sticky-cta) { padding-bottom: 0; }
  .saly-card, .saly-stat, .saly-result, .saly-list, .saly-menu-card, .saly-hero { box-shadow: none; break-inside: avoid; }
  .saly-btn, .saly-tabs, .saly-tabbar, .saly-sticky-cta, .saly-fab, .saly-toast-region, .saly-sheet, .saly-sheet-backdrop, .saly-dialog { display: none; }
  .saly-appbar, .saly-main--split > .saly-main__aside { position: static; }
}
