/*
 * Lớp hình thức: chữ serif, phân tầng bằng khoảng trắng thay vì viền.
 *
 * Nạp SAU style.css và shell.css nên thắng chúng ở những chỗ khai lại. Để riêng một tệp chứ không
 * sửa thẳng style.css: bỏ tệp này khỏi index.html là về đúng hình thức cũ trong một dòng — thứ
 * đáng có khi đổi hình thức của MỌI màn cùng lúc trên một hệ thống đang chạy thật.
 */

/* ---------- Bảng màu ----------
 * Khai ở :root nên áp cả khi người dùng CHƯA chọn sáng/tối (lúc ấy @media dưới đây quyết).
 * theme.css khai lại trên [data-theme] cho lựa chọn tường minh — đặc hiệu hơn nên thắng.
 */
:root {
  --bg: #f3f2f2;
  --surface: #f3f2f2;
  --ink: #201e1d;
  --ink-soft: #605d5d;
  --line: #d7d3d3;
  --seal: #006786;
  --seal-soft: #e9f8ff;
  --ok: #1c6b3f;
  --warn: #8a5a00;
  --err: #aa0b56;
  --radius: 2px;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #17181a;
    --surface: #17181a;
    --ink: #e8e5e0;
    --ink-soft: #a9aab0;
    --line: #33363a;
    --seal: #99e0ff;
    --seal-soft: #123a48;
    --ok: #5ecb96;
    --warn: #e3b341;
    --err: #ff90b1;
  }
}

/* ---------- Chữ ----------
 * Cỡ thân 16px thay vì 15px: đây là công cụ đọc, người dùng nhìn nó cả buổi, và một phần không
 * nhỏ là người trên 45 tuổi đọc trên màn hình dùng chung ở khoảng cách xa hơn màn hình cá nhân.
 */
body {
  font-family: "Source Serif 4", Charter, Georgia, "Times New Roman", serif;
  font-size: var(--fs-l);
  line-height: 1.55;
}
input, select, textarea, button { font-family: inherit; }
.page-title { font-size: var(--fs-xxl); letter-spacing: -.01em; line-height: 1.15; }
.page-lead { font-size: var(--fs-l); max-width: 68ch; text-wrap: pretty; }
h2 { font-size: var(--fs-xl); letter-spacing: -.005em; }
h3 { font-size: var(--fs-l); }
p.hint { font-size: var(--fs-m); text-wrap: pretty; }
/* Mã, phiên bản, số hiệu: giữ chữ đơn cách. Serif tỉ lệ làm 0 và O, 1 và l gần nhau — trên một
   màn hình mà nhầm một ký tự là nhầm một mã bệnh thì đó không phải chuyện thẩm mỹ. */
code, pre, .uri, .ops-value, .stat div span, td.num, th.num {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
}
code { font-size: max(var(--fs-xs), .88em); }

/* ---------- Thẻ CÓ viền và nền ----------
 * Bản trước gỡ hết viền/nền của `.card`, `.catalog-card`, `.ops-card` và phân tầng bằng khoảng
 * trắng. Ý ấy hợp lý trên một trang ít khối, nhưng màn Tổng quan bày bốn thẻ danh mục cạnh nhau
 * và bảng điều khiển vận hành bày hàng chục thẻ số: không có viền thì ranh giới giữa hai thẻ chỉ
 * còn là khoảng trống, và mắt phải đoán con số nào thuộc thẻ nào. Người dùng yêu cầu trả lại.
 *
 * Không khai lại giá trị ở đây — chỉ THÔI ghi đè, để `style.css` (.card) và `shell.css`
 * (.catalog-card, .ops-card) trở lại làm nguồn sự thật. Chép giá trị sang tệp thứ hai là dựng
 * ngay một bản sao sẽ lệch.
 *
 * Giữ lại hai thứ của bản kia vì chúng độc lập với viền: khoảng cách rộng hơn giữa các thẻ, và
 * màu mức cảnh báo mang vào CON SỐ (viền trái màu của `.ops-card` từ shell.css cũng trở lại, hai
 * thứ nói cùng một điều ở hai chỗ mắt hay nhìn).
 */
.ops-card.warn .ops-value { color: var(--warn); }
.ops-card.alert .ops-value { color: var(--err); }
.ops-cards { gap: 30px 34px; }
.catalog-cards { gap: 30px 34px; }

/* Bảng: chỉ giữ đường kẻ dưới mỗi dòng — không viền ngoài, không sọc. */
.tablewrap { margin: 0; }
th {
  font-size: var(--fs-xs);
  letter-spacing: .06em;
  text-transform: uppercase;
  font-weight: 600;
  border-bottom-width: 1.5px;
  border-bottom-color: var(--ink);
}
td { padding: 9px 12px 9px 0; }
th { padding: 6px 12px 6px 0; }

/* Thanh trên là đầu trang báo: nền giấy, chữ mực, một đường dày ngăn với thân trang.
   Nền xanh đặc cũ ép mọi thứ khác phải cạnh tranh với nó về độ đậm. */
.app-header {
  background: var(--bg);
  color: var(--ink);
  border-bottom: 2px solid var(--ink);
  padding: 13px 22px;
}
.app-header .brand strong { font-size: var(--fs-xl); font-weight: 600; letter-spacing: -.01em; }
.app-header .brand span { font-size: var(--fs-xs); opacity: .7; }
.app-header .pill { background: var(--seal-soft); color: var(--seal); }
.app-header .act.ghost { color: var(--seal); border-color: var(--line); }
.hamburger { color: var(--ink); border-color: var(--line); }
.app-header .logo { background: transparent; padding: 0; }

/* Trong suốt CHỈ ở khổ rộng, nơi thanh bên nằm trong dòng chảy và dùng chung nền trang.
   Ở ≤860px nó là lớp phủ và phải đục — xem khối media trong `shell.css`. Không đặt điều kiện ở
   đây thì luật này thắng luật kia (cùng độ đặc hiệu, tệp này nạp sau) và chữ chồng lên chữ. */
@media (min-width: 861px) {
  .sidebar { background: transparent; }
}
.nav-item, .nav-group { font-size: var(--fs-l); }

/* Nút: viền mảnh, không bóng, không bo tròn — mực trên giấy. */
button.act {
  border-radius: 2px;
  border-width: 1px;
  font-weight: 600;
  letter-spacing: .01em;
}
button.act:hover { background: var(--seal-soft); color: var(--seal); }
button.act.ghost:hover { background: var(--seal-soft); }
input, select, textarea { border-radius: 2px; background: transparent; }
input:hover, select:hover, textarea:hover { border-color: var(--ink-soft); }
.pill { border-radius: 2px; white-space: nowrap; }


/* Ô tìm của chế độ Tra cứu: to hẳn lên, đây là thứ đầu tiên mắt gặp. */
.tcn-dau h1 { font-size: var(--fs-xxl); letter-spacing: -.015em; }
.tcn-o input { font-size: var(--fs-xl); }
.tcn-ct { background: transparent; }

/* ---------- LOINC: bảng 17 cột không chịu nổi trần 1180px của `main` ----------
 * `shell.css` đặt `main { max-width: 1180px }` cho mọi màn — đúng với văn bản và biểu mẫu, sai với
 * một bảng 17 cột: trên màn 2000px, bảng dừng ở ~1230px và cột "Tên đầy đủ" bị bẻ thành sáu dòng
 * trong khi hơn một phần ba bề ngang bỏ trống. Bỏ trần CHỈ khi khung LOINC đang hiện (cùng lối
 * `:has()` + `:not([hidden])` như hai màn xác thực trong `shell.css`): khung ấy `hidden` ở mọi
 * danh mục khác, và cả pane Tra cứu lẫn section đều `hidden` khi rời màn.
 */
main:has(> #view-catalog:not([hidden]) > #pane-tracuu:not([hidden]) > #loinc-search-root:not([hidden])) {
  max-width: none;
}

/* ---------- LOINC: ngăn lọc đẩy bảng, không chồng lên bảng ----------
 * Khung LOINC thành grid hai cột. Cột một là ngăn lọc, rộng 0 khi đóng nên bảng chiếm hết bề
 * ngang; mở ra thì cột giãn và bảng thu lại vừa phần còn lại. Hàng tìm kiếm và thanh công cụ trải
 * hết hai cột — chúng thuộc cả bảng lẫn ngăn lọc, không thuộc riêng bên nào.
 */
.loinc-search {
  display: grid;
  grid-template-columns: 0 minmax(0, 1fr);
  grid-template-rows: auto auto minmax(0, 1fr);
  /* Chỉ chuyển động bề rộng cột. Bảng dịch sang trong 160ms thì mắt theo được là nó DỊCH, chứ
     không phải trang vừa vẽ lại thành một bố cục khác. */
  transition: grid-template-columns .16s ease;
}
.loinc-search.co-loc { grid-template-columns: calc(var(--filters-w) + 24px) minmax(0, 1fr); }
.loinc-search > form.ls-search { grid-column: 1 / -1; grid-row: 1; }
.loinc-search > nav.ls-toolbar { grid-column: 1 / -1; grid-row: 2; }
.loinc-search > aside.ls-filters { grid-column: 1; grid-row: 3; }
.loinc-search > .ls-tablewrap { grid-column: 2; grid-row: 3; margin-left: 14px; }
.loinc-search.co-loc > .ls-tablewrap { margin-left: 0; }

.loinc-search > aside.ls-filters {
  /* Về dòng chảy bình thường: bỏ hết toạ độ của bản nổi cũ. */
  position: sticky;
  top: 14px;
  left: auto;
  bottom: auto;
  width: auto;
  margin: 0 10px 10px 14px;
  /* Không còn nổi trên bảng thì không cần đổ bóng — bóng ở đây chỉ làm hai khối cùng mặt phẳng
     trông như hai tầng. */
  box-shadow: none;
  /* Nhóm Class có hàng trăm giá trị. Trong dòng chảy mà không chặn chiều cao thì ngăn lọc dài
     hơn cả bảng, và người dùng cuộn xuống mất hút cả hai. Dính (sticky) để nó theo mắt khi cuộn. */
  max-height: calc(100vh - 190px);
  min-height: 0;
}

@media (max-width: 900px) {
  /* Màn hẹp không đủ chỗ cho hai cột: ngăn lọc nằm TRÊN bảng, vẫn đẩy chứ không chồng. */
  .loinc-search, .loinc-search.co-loc { grid-template-columns: minmax(0, 1fr); }
  .loinc-search > form.ls-search, .loinc-search > nav.ls-toolbar { grid-column: 1; }
  .loinc-search > aside.ls-filters {
    grid-column: 1;
    grid-row: 3;
    position: static;
    margin: 0 14px 10px;
    max-height: 52vh;
  }
  .loinc-search > .ls-tablewrap,
  .loinc-search.co-loc > .ls-tablewrap { grid-column: 1; grid-row: 4; margin-left: 14px; }
}

/* Biểu tượng quay của nút đang gọi máy chủ — xem `js/nut-dang-chay.js` để biết vì sao nó có.
   `currentColor` để nó hợp với cả nút đặc lẫn nút ghost mà không cần biến màu riêng. */
.quay {
  display: inline-block;
  width: .85em;
  height: .85em;
  margin-right: .5em;
  vertical-align: -.1em;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: quay-tron .7s linear infinite;
}
@keyframes quay-tron { to { transform: rotate(360deg); } }
/* Người tắt hiệu ứng chuyển động vẫn phải BIẾT nút đang bận: giữ vòng tròn, bỏ phần quay. */
@media (prefers-reduced-motion: reduce) {
  .quay { animation: none; border-top-color: currentColor; opacity: .45; }
}
button.act[aria-busy="true"] { cursor: progress; opacity: .85; }

/* ---------- Màn giám sát & hạn mức (giam-sat-don-vi.js) ----------
 * Mỗi đơn vị một THẺ trong lưới tự xếp: không có bề ngang cố định nên không bao giờ tràn ngang.
 * `min-width: 0` + `overflow-wrap: anywhere` là để một đường dài như
 * /api/v1/concepts/{conceptId}/descendants không chống đẩy thẻ rộng ra.
 */
.gs-tom-tat { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; margin-bottom: 10px; }
.gs-tom-tat > div { border: 1px solid var(--line); padding: 10px 12px; border-radius: 4px; min-width: 0; }
.gs-tom-tat b { display: block; font-size: 1.3em; line-height: 1.2; }
.gs-tom-tat span { font-size: .85em; color: var(--ink-soft); }
.gs-tom-tat .gs-do b { color: var(--err); }
.gs-tom-tat .gs-vang b { color: var(--warn); }
.gs-chu-thich { margin: 4px 0 14px; }

.gs-luoi { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 380px), 1fr)); gap: 14px; align-items: start; }
.gs-the { border: 1px solid var(--line); border-radius: 4px; padding: 14px; min-width: 0; overflow-wrap: anywhere;
  display: flex; flex-direction: column; gap: 10px; background: var(--bg); }
.gs-the-vang { border-left: 4px solid var(--warn); }
.gs-the-do { border-left: 4px solid var(--err); }
.gs-the-ngung { background: color-mix(in srgb, var(--err) 5%, var(--bg)); }
.gs-the-dau { display: flex; justify-content: space-between; align-items: center; gap: 10px; flex-wrap: wrap; }
.gs-ten { font-size: 1.05em; min-width: 0; }
.gs-ten code { font-size: .85em; color: var(--ink-soft); }
.gs-nhan { font-size: var(--fs-xs); font-weight: 700; letter-spacing: .03em; padding: 2px 8px; border-radius: 3px; border: 1px solid currentColor; white-space: nowrap; }
.gs-nhan-ngung { color: var(--err); }
.gs-nhan-noi { color: var(--ok); }
.gs-nhan-im { color: var(--ink-soft); font-weight: 400; }
.gs-ghi-ngung { font-size: .9em; padding: 8px 10px; border-radius: 3px; background: color-mix(in srgb, var(--err) 9%, transparent); }

.gs-cham { display: inline-block; width: 10px; height: 10px; border-radius: 50%; margin-right: 6px; vertical-align: middle; }
.gs-cham-do { background: var(--err); color: var(--err); animation: gs-nhay 1s ease-in-out infinite; }
.gs-cham-vang { background: var(--warn); color: var(--warn); animation: gs-nhay 1.6s ease-in-out infinite; }
@keyframes gs-nhay { 0%, 100% { opacity: 1; box-shadow: 0 0 0 0 currentColor; } 50% { opacity: .35; box-shadow: 0 0 0 5px transparent; } }
@media (prefers-reduced-motion: reduce) { .gs-cham-do, .gs-cham-vang { animation: none; } }

.gs-luot { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; text-align: center; }
.gs-luot > div { border: 1px solid var(--line); border-radius: 3px; padding: 6px 4px; min-width: 0; }
.gs-luot b { display: block; font-size: 1.1em; font-variant-numeric: tabular-nums; }
.gs-luot span { font-size: var(--fs-xs); color: var(--ink-soft); }
.gs-luot .gs-co-loi b { color: var(--err); }
.gs-cuoi { margin: 0; }

.gs-dung-so { display: flex; justify-content: space-between; gap: 8px; font-size: .9em; }
.gs-dung-so i { font-weight: 400; color: var(--ink-soft); }
.gs-thanh { height: 5px; background: var(--line); border-radius: 3px; margin-top: 3px; overflow: hidden; }
.gs-thanh i { display: block; height: 100%; }

.gs-dau-hieu { display: flex; flex-direction: column; gap: 6px; }
.gs-dh { font-size: .9em; padding: 6px 8px; border-radius: 3px; background: color-mix(in srgb, var(--warn) 8%, transparent); }
.gs-dh b { display: block; }
.gs-dh span { color: var(--ink); }

.gs-sua { border-top: 1px solid var(--line); padding-top: 10px; display: flex; flex-direction: column; gap: 8px; }
.gs-sua-tieu-de { font-weight: 700; font-size: .9em; }
.gs-o-hang { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.gs-o { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.gs-o-nhan { font-size: .8em; color: var(--ink-soft); }
.gs-o-tt { font-size: var(--fs-xs); color: var(--ink-soft); }
/* Ô nhập phải NHÌN RA là ô nhập: viền rõ và nền hơi lệch khỏi nền thẻ. Nền lấy từ CÁC BIẾN của
   theme (--ink trộn vào --bg) chứ không gõ cứng một màu: người dùng chọn sáng/tối bằng nút trong
   ứng dụng (theme.css, [data-theme]) thắng cài đặt của máy, và một màu cứng chỉ đảo theo
   prefers-color-scheme thì cho chữ gần trắng trên nền trắng khi máy sáng mà người dùng chọn tối
   (bot rà PR #165 bắt được). Bản đầu dùng nền trong suốt của `input` chung nên trông như bị khoá. */
.gs-o input, .gs-ghi-chu {
  width: 100%; box-sizing: border-box; padding: 7px 8px; font-size: 1em;
  color: var(--ink); background: color-mix(in srgb, var(--ink) 5%, var(--bg));
  border: 1px solid var(--ink-soft); border-radius: 3px;
}
.gs-o input { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-variant-numeric: tabular-nums; }
.gs-o input::placeholder, .gs-ghi-chu::placeholder { color: var(--ink-soft); opacity: .7; }
.gs-o input:focus, .gs-ghi-chu:focus { outline: 2px solid var(--seal); outline-offset: 1px; border-color: var(--seal); }

.gs-hanh-dong { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; border-top: 1px solid var(--line); padding-top: 10px; }
.gs-gian { flex: 1 1 auto; }
.gs-hanh-dong button.act { padding: 6px 12px; }
.gs-nut-ngung { color: var(--err); border-color: var(--err); }

.gs-nhat-ky { margin-top: 16px; border: 1px solid var(--line); padding: 14px; border-radius: 4px; min-width: 0; }
.gs-nhat-ky .tablewrap { max-height: 420px; overflow: auto; }
.gs-nk-dau { display: flex; justify-content: space-between; align-items: center; gap: 10px; flex-wrap: wrap; }
.gs-nk-dau h3 { margin: 0; }
.gs-nk-nut { display: flex; gap: 6px; flex-wrap: wrap; }
.gs-nk-nut a.act { text-decoration: none; padding: 6px 10px; }
.ops-lien-ket { margin-top: 8px; font-size: .85em; }
