/*
  Theme dùng chung cho toàn bộ app (trang chủ + mọi module).
  Mỗi module import file này trước, rồi mới định nghĩa CSS riêng của nó
  (xem modules/doc-song-ngu/style.css để làm ví dụ).
*/

:root{
  --paper:#F3EFE6;
  --paper-deep:#EAE3D3;
  --ink:#22262B;
  --ink-soft:#5B6470;
  --seal:#A5342A;
  --seal-dark:#7E2820;
  --seal-soft:#F3E1DE;
  --azure:#3F6C8C;
  --azure-soft:#E7EFF3;
  --jade:#4C7A6D;
  --jade-soft:#E6EFEA;
  --gold:#B8862C;
  --gold-soft:#F5EBD8;
  --plum:#7C5A8A;
  --plum-soft:#EDE6F0;
  --clay:#B4633A;
  --clay-soft:#F5E5DA;
  --teal:#3A7A82;
  --teal-soft:#E3EEF0;
  --indigo:#4A5A8C;
  --indigo-soft:#E7E9F2;
  --rose:#9C4F63;
  --rose-soft:#F1E1E5;
  --slate:#52677A;
  --slate-soft:#E2E9ED;
  --moss:#6E7A45;
  --moss-soft:#EAEDDD;
  --amber:#C99A3E;
  --amber-soft:#F6EEDA;
  --maroon:#8B3A42;
  --maroon-soft:#F0DEE0;
  --switch-on:#3C8C5C;
  --switch-off:#B4433A;
  --card-bg:#FFFFFF;
  --shadow: 0 1px 2px rgba(34,38,43,0.07), 0 4px 10px rgba(34,38,43,0.07);
  --radius: 10px;
}

*{ box-sizing:border-box; }

body{
  margin:0;
  min-height:100vh;
  background: radial-gradient(ellipse at top, #FAF8F2 0%, var(--paper) 55%, var(--paper-deep) 100%);
  font-family:'IBM Plex Sans', sans-serif;
  color:var(--ink);
}

/* padding-top nhỏ (yêu cầu thật: "thu hẹp độ cao các phần này ở tất cả
   module — header không phải nội dung cần tập trung") — cộng với 44px của
   site-header cố định là đủ, không cần thêm 24px trống nữa. */
.app-shell{ max-width:860px; margin:0 auto; padding:12px 24px 60px; }

/* ---------- header thương hiệu, dùng lại ở mọi module ---------- */
/* Thu gọn HẲN (yêu cầu thật: "tất cả các phần về đường dẫn, chỉ mục chỉ
   nằm ở khu ngang này; hiện chiếm quá nhiều trong header") — icon/đường
   dẫn/tiêu đề/mô tả co lại đáng kể để nhường chỗ dọc cho nội dung chính
   bên dưới, ÁP DỤNG TOÀN SITE (mọi trang dùng chung khối .brand này, đã
   xác nhận với Stakeholder — không chỉ riêng 1 trang). */
/* Thu gọn thêm 1 đợt (yêu cầu thật: "thu hẹp độ cao ở TẤT CẢ module —
   header không phải nội dung cần tập trung"): seal + tiêu đề nhỏ lại,
   mô tả 1 dòng + cắt bớt nếu dài, cả khối cao ~28px thay vì ~55px. */
.brand{ display:flex; align-items:center; gap:8px; margin:0 0 4px; }
/* Guard bắt buộc (xem MAP.md mục "Lưu ý CSS hay gặp lỗi") — display:flex ở
   trên tự ĐÈ MẤT display:none mặc định của [hidden] khi JS ẩn khối này qua
   .hidden=true (vd modules/flashcard/main.js ẩn header.brand lúc vocabOnly=1). */
.brand[hidden]{ display:none; }
.brand > div{ min-width:0; }
.brand-seal{
  --brand-accent: var(--seal);
  width:24px; height:24px; flex-shrink:0;
  background:var(--brand-accent); color:#fff;
  font-family:'Noto Serif SC', serif; font-weight:700; font-size:12px;
  display:flex; align-items:center; justify-content:center;
  border-radius:4px 8px 4px 7px;
  transform:rotate(-4deg);
  box-shadow:0 2px 6px color-mix(in srgb, var(--brand-accent) 35%, transparent), inset 0 0 0 1.5px rgba(255,255,255,0.22);
}
.brand h1{ font-family:'Noto Serif SC', serif; font-weight:700; font-size:0.98rem; margin:0; letter-spacing:.2px; }
.brand p{
  margin:0; font-size:0.74rem; line-height:1.3; color:var(--ink-soft);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:70ch;
}

footer{ margin:46px 0 6px; text-align:center; font-size:0.78rem; color:var(--ink-soft); }

/* ---------- ô thống kê nhỏ (stat tile), dùng ở trang chủ + module có số liệu (XP, streak...) ---------- */
.stats-row{
  display:flex; flex-wrap:wrap; gap:12px;
  margin:22px 0 6px;
}
/* Guard bắt buộc (xem MAP.md mục "Lưu ý CSS hay gặp lỗi") — display:flex ở
   trên tự ĐÈ MẤT display:none mặc định của [hidden] khi JS ẩn khối này qua
   .hidden=true (vd modules/flashcard/main.js ẩn stats-row lúc vocabOnly=1). */
.stats-row[hidden]{ display:none; }
.stat-tile{
  display:flex; flex-direction:column; gap:2px;
  background:var(--card-bg); border-radius:var(--radius); box-shadow:var(--shadow);
  padding:12px 18px; min-width:132px;
}
.stat-value{ font-family:'Noto Serif SC', serif; font-weight:700; font-size:1.5rem; color:var(--ink); line-height:1.1; }
.stat-label{ font-size:0.78rem; color:var(--ink-soft); }

/* ---------- khối credit cuối trang, dùng lại ở mọi module ---------- */
.credit{
  margin-top:22px; padding-top:20px; border-top:1px solid #E4DDCB;
  display:flex; align-items:flex-start; gap:14px;
}
.credit-seal{
  width:34px; height:34px; flex-shrink:0;
  background:var(--seal); color:#fff;
  font-family:'Noto Serif SC', serif; font-weight:700; font-size:16px;
  display:flex; align-items:center; justify-content:center;
  border-radius:4px 8px 5px 7px; transform:rotate(-4deg);
  box-shadow:0 2px 6px rgba(165,52,42,.3);
}
.credit-text p{ margin:0 0 5px; font-size:0.8rem; line-height:1.65; color:var(--ink-soft); }
.credit-text p:last-child{ margin-bottom:0; }
.credit-author{ font-size:0.85rem !important; color:var(--ink); }
.credit-text strong{ color:var(--ink); font-weight:600; }
.credit-contact strong{ color:var(--seal); }
.credit-text a{ color:var(--seal); text-decoration:underline; text-decoration-color:rgba(165,52,42,.4); }
.credit-text a:hover{ text-decoration-color:var(--seal); }

/* ---------- đồng bộ màu cụm từ (tách bằng " / " + số nhóm trong nội
   dung câu — xem src/shared/phrase-segments.js), dùng ở module Đọc đa
   ngữ và khối demo trang chủ. Tô CẢ màu chữ lẫn nền theo nhóm — màu chữ
   là tín hiệu chính (rõ nhất khi so 2 từ cạnh nhau như "mother"/"mẹ"),
   nền chỉ làm nổi bật thêm. Cụm KHÔNG gắn số (.phrase-segment-plain) giữ
   nguyên màu chữ theo ngôn ngữ như trước — chỉ cụm CÓ gắn số mới đổi màu,
   nên vẫn phân biệt được "từ có đối chiếu" và "từ không đối chiếu". ---------- */
/* Mặc định KHÔNG đậm — chỉ Hán tự (nét phức tạp, cần đậm mới nổi màu rõ)
   mới đậm. Pinyin có dấu thanh riêng, tiếng Anh/Việt đều là chữ Latin đủ
   dễ đọc — đậm hết cả 3 dòng đó chỉ gây rối mắt (đã sửa lặp lại — tách
   riêng từng ngôn ngữ trước đó cứ bị bỏ sót, sửa 1 lần cho cả 3). */
.phrase-segment{ border-radius:4px; padding:1px 4px; font-weight:400; }
.card-line-chinese .phrase-segment, .demo-line-chinese .phrase-segment{ font-weight:600; }
.phrase-segment-0{ background:var(--seal-soft); color:var(--seal); }
.phrase-segment-1{ background:var(--azure-soft); color:var(--azure); }
.phrase-segment-2{ background:var(--jade-soft); color:var(--jade); }
.phrase-segment-3{ background:var(--gold-soft); color:var(--gold); }
.phrase-segment-4{ background:var(--plum-soft); color:var(--plum); }
.phrase-segment-5{ background:var(--clay-soft); color:var(--clay); }

/* Cụm từ có audio riêng (click-to-hear) — vd "1:我@audio/wo3.mp3". Đã từng
   thử gạch chân chấm dưới chữ (bị chê đụng viền khác, rối trong khung màu
   có sẵn) rồi bỏ hẳn dấu hiệu thị giác, chỉ đổi con trỏ+tối màu khi hover.
   ĐỔI LẠI 2026-08 (yêu cầu thật, có ảnh chụp minh hoạ): user click vào cụm
   không biết trước cụm nào có audio hay không — cần 1 dấu hiệu NHÌN THẤY
   NGAY, không chỉ phát hiện qua tương tác. Dùng tam giác nhỏ góc trên-trái
   mỗi cụm (không phải gạch chân — tránh đúng lỗi cũ) tô theo currentColor
   (tự khớp màu nhóm của cụm đó): mờ/nhỏ = chưa có audio, đậm/lớn hơn (phóng
   to thêm khi hover) = đã có audio, bấm được. CHỈ hiện ở dòng tiếng Trung
   (yêu cầu thật: "chỉ để tam giác đó ở tiếng trung") — pinyin/việt không
   cần, cùng 1 câu chỉ có 1 audio nguồn (tiếng Trung), tam giác lặp ở cả 3
   dòng chỉ dư thừa/rối mắt. */
.card-line-chinese .phrase-segment, .demo-line-chinese .phrase-segment{ position:relative; padding-left:7px; }
.card-line-chinese .phrase-segment::before, .demo-line-chinese .phrase-segment::before{
  content:''; position:absolute; top:4px; left:2px; width:0; height:0;
  border-top:2px solid transparent; border-bottom:2px solid transparent; border-left:3px solid currentColor;
  opacity:0; transition:all .15s;
}
/* CHỈ hiện khi hover đúng cụm đó (yêu cầu thật: "chỉ hiện ra khi hover
   thôi") — mặc định ẩn hẳn, không chiếm sự chú ý khi chưa tương tác. */
.card-line-chinese .phrase-segment:hover::before, .demo-line-chinese .phrase-segment:hover::before{ opacity:.3; }
.phrase-segment--audible{ cursor:pointer; }
.card-line-chinese .phrase-segment--audible::before, .demo-line-chinese .phrase-segment--audible::before{
  border-top-width:3px; border-bottom-width:3px; border-left-width:5px;
}
.phrase-segment--audible:hover{ filter:brightness(0.94); }
.card-line-chinese .phrase-segment--audible:hover::before, .demo-line-chinese .phrase-segment--audible:hover::before{ opacity:1; transform:scale(1.35); }

/* "Dây liên kết" nối các cụm cùng số nhóm giữa 2 dòng ngôn ngữ kề nhau
   (modules/doc-song-ngu/main.js: drawSegmentConnections(), dùng lại ở
   modules/flashcard/main.js) — SVG phủ lên .card-lines, không chặn click
   vào chữ bên dưới. Layout xếp DỌC nhiều dòng ngôn ngữ (display:flex +
   flex-direction:column + gap) chuyển về ĐÂY (shared) 2026-08-20 — trước
   đó chỉ định nghĩa trong modules/doc-song-ngu/style.css, khiến Flashcard
   (không load file đó) chỉ nhận được "position:relative" suông: .card-
   lines rơi về display:block mặc định, gap không có tác dụng gì (gap chỉ
   hoạt động trên flex/grid container) — dòng ví dụ hiện sát nhau dù CSS
   .flash-example .card-lines{gap:18px} ghi rõ 18px, đây là NGUYÊN NHÂN
   THẬT của lỗi "chưa có khoảng cách rõ ràng giữa các dòng" đã gặp. */
.card-lines{
  position:relative;
  /* 10px cũ khiến dây nối liên kết ngôn ngữ (segment-links.js) bị dồn ép,
     đường cong gần như thẳng đứng sát nhau, rất khó nhìn theo (yêu cầu
     thật: "tạo khoảng cách rộng hơn với các ngôn ngữ... rất khó nhìn sợi
     liên kết") — tăng lên để đường cong có đủ chỗ uốn, dễ theo dõi hơn. */
  display:flex; flex-direction:column; gap:22px;
  max-width:min(680px, 90vw); overflow-x:auto; padding:3px 3px 2px;
}
.card-line{ display:flex; align-items:baseline; gap:7px; }
.segment-links{ position:absolute; top:0; left:0; pointer-events:none; overflow:visible; }
.segment-link{ fill:none; stroke-width:1.5; opacity:0.5; }
.segment-link-0{ stroke:var(--seal); }
.segment-link-1{ stroke:var(--azure); }
.segment-link-2{ stroke:var(--jade); }
.segment-link-3{ stroke:var(--gold); }
.segment-link-4{ stroke:var(--plum); }
.segment-link-5{ stroke:var(--clay); }

/* Hover vào 1 cụm từ: cụm đó + cụm cùng nhóm ở dòng khác được viền nổi
   bật, dây nối đúng cặp được tô đậm, các dây còn lại mờ hẳn đi — xem
   wireSegmentHoverHighlight() trong src/shared/segment-links.js. */
.phrase-segment[data-group]{ transition:box-shadow .12s; cursor:default; }
.phrase-segment--hover-match{ box-shadow:0 0 0 2px currentColor; }
.segment-links.has-hover .segment-link{ opacity:0.1; }
.segment-links .segment-link.is-hover-active{ opacity:1; stroke-width:2.5; }

@media (max-width:600px){
  .app-shell{ padding:12px 16px 50px; }
}

/* ĐÃ THỬ rồi BỎ (2026-09-26): tự động `zoom` toàn trang cho màn lớn, theo
   yêu cầu thật "màn to phải tăng zoom 150% mới vừa mắt". Bỏ vì `zoom` CSS
   KHÔNG thu nhỏ lại đơn vị `vh` như zoom thật của trình duyệt (Ctrl +/-)
   vẫn làm — nhiều layout dùng `height:calc(100vh - Npx)` để vừa đúng 1 màn
   hình không cần cuộn (vd modules/mind-map/style.css) tính theo `vh` GỐC
   (chưa zoom) rồi mới bị phóng to thêm theo `zoom`, kết quả CAO HƠN cả màn
   hình thật → sinh thanh cuộn thừa (xác nhận bằng ảnh chụp thật + đo
   scrollHeight/clientHeight lệch nhau). Cũng gây lỗi kép ở dây liên kết
   (xem segment-links.js: getBoundingClientRect() đã nhân zoom sẵn, gán làm
   thuộc tính SVG bị nhân zoom thêm lần nữa). Sửa hết mọi chỗ dùng `vh`
   trong toàn site để bù zoom là việc lớn, rủi ro sót — quyết định bỏ hẳn
   `zoom` tự động, để user tự zoom tay trình duyệt nếu muốn (đã xác nhận
   hiệu quả, không lỗi vì zoom thật của trình duyệt tự tính lại `vh` đúng). */

/* Tam giác ▶ của cụm chưa có audio + người xem chưa đủ quyền nghe (Free/chưa
   đăng nhập): rê vào mép trái cụm thì rõ lên, con trỏ bấm được → popup nâng cấp. */
.card-line-chinese .phrase-segment--locked::before{ cursor:pointer; }
.card-line-chinese .phrase-segment--locked:hover::before{
  opacity:.85; border-top-width:3px; border-bottom-width:3px; border-left-width:5px;
}

/* Nhãn "Premium" cạnh mục Nghe/Nói trên thanh điều hướng (khi chưa đủ quyền). */
.site-nav-lock{ font-size:0.68em; font-weight:600; opacity:.8; margin-left:2px; white-space:nowrap; }

/* Thông báo "tài khoản vừa đăng nhập ở thiết bị khác" — xem src/shared/single-device-guard.js. */
.sd-notice-overlay{
  position:fixed; inset:0; z-index:3000; display:flex; align-items:center; justify-content:center;
  padding:16px; background:rgba(34,38,43,0.55);
}
.sd-notice-card{
  width:100%; max-width:420px; padding:22px 22px 18px; background:var(--card-bg);
  border-radius:var(--radius); box-shadow:var(--shadow); border-top:4px solid var(--seal);
}
.sd-notice-title{ margin:0 0 10px; font-size:1.1rem; color:var(--ink); }
.sd-notice-text{ margin:0 0 8px; font-size:0.9rem; line-height:1.5; color:var(--ink-soft); }
.sd-notice-actions{ display:flex; gap:10px; margin-top:16px; justify-content:flex-end; flex-wrap:wrap; }
.sd-notice-btn{
  display:inline-block; padding:8px 16px; border-radius:20px; border:1.5px solid var(--seal);
  background:var(--seal); color:#fff; font-weight:600; font-size:0.85rem; cursor:pointer; text-decoration:none;
}
.sd-notice-btn:hover{ background:var(--seal-dark); border-color:var(--seal-dark); }
.sd-notice-btn--ghost{ background:transparent; color:var(--ink-soft); border-color:var(--paper-deep); }
.sd-notice-btn--ghost:hover{ background:var(--paper-deep); border-color:var(--paper-deep); }
