/* Thanh điều hướng đáy kiểu ứng dụng điện thoại.
   Mặc định ẨN. Chỉ hiện khi trang chạy dạng webapp (đã cài lên màn hình
   chính, class .la-webapp do base_site.html gắn) và màn hình hẹp - nên
   trên web máy tính bàn không có gì thay đổi. */

.app-nav,
.app-tren,
.app-sheet,
.app-sheet-nen,
.app-menu-trai,
.app-menu-nen { display: none; }
.app-mo-sheet,
.app-mo-menu { display: none; }   /* checkbox điều khiển bảng Cá nhân / menu trái */
.app-mo-tim { display: none; }     /* checkbox điều khiển ô tìm kiếm */
/* Bảng thông báo và nền chắn của nó KHÔNG cần luật ẩn riêng: cả hai nằm
   trong .app-tren, mà thẻ đó đã `display: none` ngay dòng trên - display:
   none gỡ cả cây con, kể cả thẻ position: fixed bên trong. */

/* Số đỡ tạm cho lúc script đo chưa chạy. Khai ở đây thay vì viết vào phần
   dự phòng của var(): calc() lồng trong var() lồng trong calc() có máy
   không phân tích nổi, hỏng cả dòng khai báo là mất luôn chỗ chừa.

   SỐ NÀY PHẢI KHỚP CHIỀU CAO THẬT ĐO ĐƯỢC: 52px phần thanh (đo ở máy rộng
   430px, đệm đáy tối thiểu 4px đã trừ ra) CỘNG đệm đáy thật - đệm ấy theo
   vùng vuốt Home của từng máy (xem .app-nav), nên phải tính bằng cùng một
   biểu thức max(...) ở đây, không ghi cứng được.
   (Calc của chính biến này thì không sao - thứ hỏng là calc() viết trong
   phần DỰ PHÒNG của var(), như ghi chú ngay trên.)
   Trước đây để 78px - đoán theo icon 22px + nhãn 11.5px. Lệch 8px, mà
   #container lấy nó làm chỗ chừa cuối trang, nên MỖI LẦN TẢI TRANG bố cục
   nhảy 8px ngay khi script đo chạy xong: bấm nút nào cũng thấy phần cuối
   trang giật một cái. Script vẫn giữ nguyên để lo trường hợp máy đặt cỡ chữ
   hệ thống to hơn - lúc đó thanh cao thật sự khác. */
:root {
  /* THANH NỔI (xem .la-webapp .app-nav): 54px thân thanh (đệm đáy 6px) CỘNG
     khoảng hở dưới thanh - chỗ chừa cuối trang tính từ MÉP TRÊN thanh tới
     đáy màn hình, nên khoảng hở nằm trong số này. */
  --app-nav-cao: calc(54px + max(8px, calc(env(safe-area-inset-bottom, 0px) - 12px)));
  --app-tren-cao: 56px;
}

/* ===== CHUYỂN TRANG MÀ HAI THANH ĐỨNG YÊN ==============================
   Ứng dụng dựng trang ở máy chủ nên bấm nút nào cũng là tải lại cả trang.
   Trước đây điều đó có nghĩa: thanh trên và thanh đáy biến mất rồi vẽ lại,
   nhìn ra một cú chớp - "giật cục" đúng như người dùng nói.

   `@view-transition` bảo trình duyệt tự chụp trang cũ, chụp trang mới, rồi
   chuyển cảnh giữa hai ảnh đó. Phần tử nào có `view-transition-name` GIỐNG
   NHAU ở cả hai trang thì nó coi là MỘT phần tử và giữ nguyên, không cho
   tan rồi hiện lại.

   Đặt tên cho hai thanh, rồi tắt luôn hoạt ảnh của chúng: kết quả là hai
   thanh đứng im tuyệt đối trong lúc phần nội dung đổi.

   ĐÂY KHÔNG PHẢI LÀ BỎ TẢI LẠI TRANG. Trang vẫn tải lại, trạng thái vẫn
   dựng lại từ máy chủ - chỉ có điều mắt không còn thấy hai thanh nhấp nháy.
   Muốn thật sự không tải lại thì phải viết lại thành ứng dụng một trang,
   việc lớn hơn nhiều và rủi ro hơn nhiều.

   Chỉ bật ở màn hình hẹp: hai thanh này vốn chỉ có ở đó, còn bản web máy
   tính thì giữ nguyên như cũ, không đụng tới.

   Máy không hỗ trợ (trình duyệt cũ) thì bỏ qua cả khối, chuyển trang y như
   trước - không hỏng gì. */
/* ⛔ ĐÃ TẮT (2026-10-19). Safari trên iPhone chụp hai thanh lệch khi trang
   tràn lên dải giờ (viewport-fit=cover): ảnh chụp thanh đáy NHẢY LÊN đúng
   một dải giờ, dưới nó một dải trống; và ảnh chụp không có logo / biểu tượng
   / mặt kính mờ - còn trơ một đĩa xám (người dùng chụp màn hình báo cả hai).
   spa.js đã giữ hai thanh đứng yên ở hầu hết lần chuyển trang (không dựng
   lại chúng); chuyển cảnh này chỉ còn chạy ở mấy lần tải trang kiểu thường
   - đúng những lần lỗi hiện ra. Bỏ hẳn cho chắc: mất một nhịp hoà mờ lúc
   tải hẳn trang, đổi lại không còn ảnh chụp nào để mà lệch.
@media (max-width: 860px) {
  @view-transition { navigation: auto; }
}
*/


@media (max-width: 860px) {
  /* --- Thanh trên -------------------------------------------------------
     Nút tìm kiếm bên trái, chuông bên phải. Dán dính đỉnh màn hình và ăn
     luôn phần tai thỏ, để dải màu chạy hết lên trên cùng.

     KHÔNG còn logo EVN ở đây: nó chỉ lặp lại thứ đã có ở nút giữa thanh
     đáy (logo EVN là một trong ba logo thay phiên), mà lại chiếm đúng góc
     dễ bấm nhất bằng một thứ không bấm được. Nút tìm dời vào chỗ đó.

     Cùng nền và cùng kiểu nút với thanh đáy (Neumorphism) - hai thanh kẹp
     trên dưới cùng một trang mà khác tông thì nhìn như hai phần mềm. */
  /* Trừ trang đăng nhập: lúc đó chưa đăng nhập, tìm kiếm lẫn thông báo đều
     vô nghĩa, mà thẻ đăng nhập lại là một khối canh giữa màn hình. */
  .la-webapp body:not(.login) .app-tren {
    --app-tren-nut-co: 40px;
    display: block;
    /* FIXED, KHÔNG PHẢI STICKY.
       -------------------------------------------------------------------
       Người dùng báo: sau khi hai thanh đều có view-transition-name thì
       thanh ĐÁY đứng yên hẳn, riêng thanh TRÊN vẫn nháy.

       Khác biệt về cấu trúc duy nhất còn lại giữa hai thanh là chỗ này:
       thanh đáy đã `fixed`, thanh trên còn `sticky` (tức vẫn nằm trong
       dòng chảy của #container). Đổi nốt cho hai thanh giống hệt nhau.

       NÓI THẲNG CHO NGƯỜI SỬA SAU: chưa chứng minh được cơ chế. Đã dựng
       trình duyệt không giao diện đo thử hai giả thuyết và CẢ HAI ĐỀU SAI:
         - "sticky trôi theo dòng cuộn": đo ở cuộn 0 và cuộn 300, kể cả khi
           giả lập tai thỏ 47px, thanh sticky vẫn ghim đúng đỉnh 0 y như
           fixed. Không trôi.
         - "có trang nào đó thiếu .app-tren nên mất phần tử chung": không
           template con nào ghi đè block header, thanh có mặt ở mọi trang
           đã đăng nhập.
       Nên đây là sửa theo kiểu làm cho giống cái đang chạy tốt, không phải
       theo kiểu đã bắt được thủ phạm. Ai lần ra cơ chế thật thì sửa lại
       ghi chú này.

       Đổi sang fixed là thanh KHÔNG còn chiếm chỗ trong dòng nữa, nên phải
       chừa chỗ ở đầu #container - y như đã chừa ở cuối trang cho thanh đáy.
       Thiếu phần chừa đó thì nội dung chui lên nằm dưới thanh. */
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 40;
    margin: 0;
    /* CHỪA THÊM 12px DƯỚI DẢI GIỜ cho hàng 🔍 / lời chào / 🔔 ra khỏi VỆT
       NHOÈ của iOS 26. Dải giờ để trong suốt (black-translucent, người dùng
       chọn giữ để đổi nền là dải đổi màu ngay) thì iOS tự vẽ một lớp nhoè mờ
       dần loang xuống dưới dải giờ - đè lên nửa trên hai nút (người dùng báo
       nhiều lần). CSS không tắt được lớp ấy, nên hạ hàng nút xuống thấp hơn.
       min(12px, inset): máy KHÔNG có dải giờ đè lên trang (inset 0 - Android,
       máy tính) thì không chừa thêm gì. Script cuối base_site.html đo lại
       chiều cao thanh nên chỗ chừa đầu trang tự theo. */
    padding-top: calc(env(safe-area-inset-top, 0px)
                      + min(12px, env(safe-area-inset-top, 0px)));
    background: var(--nm-light, #ffffff);
    /* Nét mép 0 2px 0 dùng --nm-dark: đây là một ĐƯỜNG KẺ đặc, đúng việc
       của màu đó. Còn lớp toả rộng phải là mực tối trong suốt - --nm-dark
       toả ra 16px thì thành mảng sáng phủ lên nội dung, cùng lỗi đã làm
       hai bên nút thanh đáy hiện mảng trắng (xem .app-nav-nen). */
    box-shadow: 0 2px 0 var(--nm-dark, #c5cedb),
                0 6px 14px rgba(31, 42, 58, 0.10);
    /* Tên để trình duyệt nhận ra "vẫn là thanh đó" khi sang trang khác, nhờ
       vậy nó giữ nguyên thay vì cho tan rồi hiện lại. Tên phải DUY NHẤT
       trong một trang - hai phần tử cùng tên là trình duyệt bỏ cuộc, không
       chuyển cảnh gì cả. Xem khối @view-transition ở đầu tệp. */
    /* (Từng có view-transition-name: pl-thanh-tren - đã bỏ cùng khối
       @view-transition đầu tệp.) */
  }
  .app-tren-thanh {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 12px;
  }
  /* Khối co giãn đẩy chuông về sát mép phải, và mang luôn LỜI CHÀO.
     Gộp vào một khối thay vì thêm thẻ mới: lúc mở ô tìm, lời chào tự nhường
     chỗ theo luật ẩn .app-tren-dan sẵn có, khỏi phải khai thêm luật ẩn nữa.

     Tên dài thì cắt bớt bằng dấu ba chấm chứ không cho xuống dòng - xuống
     dòng là thanh cao vọt lên, đẩy cả trang tụt xuống. */
  .app-tren-dan {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    font-size: 13.5px;
    font-weight: 600;
    color: var(--nm-ink, #1f2a3a);
  }
  /* Logo EVN cuối lời chào, thay chỗ emoji 👋 cũ.

     ĐO BẰNG `em`, KHÔNG BẰNG `px`: cỡ chữ của dòng này là 13.5px, nhưng máy
     nào đặt cỡ chữ hệ thống to hơn thì chữ to theo mà con số px thì đứng
     yên - logo sẽ tụt lại thành một chấm nhỏ xíu bên cạnh dòng chữ to. Để
     theo `em` là nó luôn cao đúng bằng chữ, y như emoji trước đây.

     1.15em vì emoji thường vẽ cao hơn chữ hoa một chút; để đúng 1em thì
     logo trông nhỏ hơn cái nó vừa thay.

     vertical-align âm kéo logo xuống cho tâm nó ngang tâm hàng chữ - mặc
     định `baseline` là đáy logo nằm trên đường chân chữ, nhìn như bị nhấc
     bổng lên. Con số -0.13em là ĐO RA chứ không ước: ở -0.22em tâm logo nằm
     thấp hơn tâm hàng chữ 1,2px, bù đúng 1,2px/13.5px ≈ 0.09em thì khớp.
     Tâm emoji 👋 cũ cũng nằm đúng chỗ ấy, nên logo mới ngồi y chỗ cái nó
     vừa thay. */
  .app-tren-evn {
    height: 1.15em;
    width: auto;
    vertical-align: -0.13em;
    /* ĐĨA LÓT SÁNG.
       Logo EVN là sao xanh đậm viền tròn xanh đậm, nền trong suốt. Đặt lên
       thanh nền TỐI thì xanh đậm trên xám đậm gần như chìm hẳn - đo ảnh
       chụp thấy chỉ còn lờ mờ. Đúng vấn đề đã gặp với logo ở nút giữa thanh
       đáy, và chữa bằng đúng biến đã dùng ở đó (xem .app-nav-giua-vong), để
       hai chỗ cùng một logo thì cùng một cách xử lý.

       `border-radius: 50%` cho đĩa lót trùng khít vòng tròn sẵn có của
       logo, không lòi ra bốn góc. Nền sáng thì đĩa trắng nằm trên thanh
       trắng - không ai thấy, mà cũng không hại gì. */
    background: var(--nm-nut-giua, #ffffff);
    border-radius: 50%;
    /* Khối cha có overflow: hidden + ellipsis; ảnh không được co lại thành
       méo khi tên người dùng dài. */
    flex: none;
  }
  /* Nút nổi mềm rồi lõm khi chạm, đúng kiểu các nút khác của theme. */
  .app-tren-nut {
    display: grid;
    place-items: center;
    /* Một con số cho cả nút lẫn bề rộng lúc đóng của vỏ ô tìm - hai thứ đó
       phải bằng nhau thì lúc đóng vỏ mới trùng khít lên nút, không hở. */
    width: var(--app-tren-nut-co, 40px);
    height: var(--app-tren-nut-co, 40px);
    flex: none;
    padding: 0;
    border: 0;
    border-radius: 50%;
    font-size: 18px;
    line-height: 1;
    cursor: pointer;
    color: var(--nm-ink-soft, #64748b);
    background: var(--nm-bg, #e9edf2);
    box-shadow: var(--nm-out-sm, 3px 3px 7px #c5cedb, -3px -3px 7px #fff);
    -webkit-appearance: none;
    appearance: none;
    -webkit-tap-highlight-color: transparent;
  }
  .app-tren-nut:active {
    box-shadow: var(--nm-in-sm, inset 2px 2px 5px #c5cedb, inset -2px -2px 5px #fff);
  }

  /* --- Nút 📷 "Chụp ảnh để tìm" (thay chỗ chuông thông báo cũ) -----------
     Là <label> bọc ô chọn tệp mở camera (static/js/camera-tim.js). Biểu
     tượng vẽ bằng SVG nét đơn, cỡ theo `font-size` của nút. */
  .app-camera svg,
  .app-tren-ca-nhan svg,
  .app-tren-menu svg { display: block; width: 1.2em; height: 1.2em; }

  /* --- Ô tìm kiếm: vỏ thuốc giãn từ trái sang phải ----------------------
     CHÍNH BIỂU MẪU là cái vỏ. Đóng: rộng đúng một nút, bo 999px nên nhìn ra
     hình tròn - y hệt nút 🔍 cũ. Mở: rộng 100%, thành ô tìm dài hết hàng.

     Vì sao chuyển `width` chứ không phải transform: scaleX - cách hay được
     mách để chạy mượt hơn: scaleX kéo giãn CẢ NỘI DUNG, kính lúp bị bè ra
     và chữ trong ô méo suốt lúc chạy. Chuyển width thì nút giữ nguyên hình,
     phần thừa bị overflow: hidden xén, nhìn đúng như vén màn từ trái sang.

     Chữ trong ô KHÔNG xuống dòng nên lúc vỏ còn hẹp nó chỉ bị xén bớt chứ
     không dồn dòng - vì thế không thấy nhảy chữ trong lúc chạy.

     Không dùng display: none cho trạng thái đóng: đổi display thì chuyển
     cảnh không chạy, ô sẽ bụp ra một phát. */
  /* BÓNG ĐẶT Ở CHÍNH CÁI VỎ, không đặt ở nút bên trong. `overflow: hidden`
     cắt THẺ CON chứ không cắt bóng của chính thẻ mang nó - nên bóng ở vỏ thì
     toả ra ngoài bình thường, còn bóng ở nút con thì bị xén cụt.

     Đây là lỗi đã gặp thật: hồi nút còn tự mang bóng, vỏ rộng đúng bằng nút
     nên đường xén trùng khít mép nút, bóng ngoài mất sạch và nút thành một
     đĩa phẳng viền cắt cụt - nhìn ra "đổ bóng méo mó".

     Lúc đóng vỏ nổi lên (--nm-out-sm) đúng như một cái nút; lúc mở nó lõm
     xuống (--nm-in-sm) đúng như một ô nhập. */
  .app-tren-tim {
    display: flex;
    align-items: center;
    flex: none;
    width: var(--app-tren-nut-co, 40px);
    /* GHIM CẢ CHIỀU CAO, không để nội dung quyết định. Ô nhập bên trong cao
       41px kéo vỏ cao theo, thành 40x41 - bo 999px trên hộp chữ nhật ra hình
       bầu dục ĐỨNG chứ không tròn, nhìn lệch hẳn với nút chuông 40x40. Đây
       là lỗi đã gặp thật: "nút tìm kiếm không tròn trịa như nút chuông". */
    height: var(--app-tren-nut-co, 40px);
    min-width: 0;
    overflow: hidden;
    border-radius: 999px;
    background: var(--nm-bg, #e9edf2);
    box-shadow: var(--nm-out-sm, 3px 3px 7px #c5cedb, -3px -3px 7px #fff);
    /* box-shadow KHÔNG nằm trong danh sách chuyển cảnh: nổi và lõm là hai
       kiểu bóng khác loại (inset), trình duyệt không nội suy được nên nó
       nhảy phịch ở giữa quãng - đổi ngay từ đầu lại gọn mắt hơn. */
    transition: width 0.3s ease, background-color 0.3s ease;
  }
  .app-mo-tim:checked ~ .app-tren-thanh .app-tren-tim {
    width: 100%;
    box-shadow: var(--nm-in-sm, inset 2px 2px 5px #c5cedb, inset -2px -2px 5px #fff);
  }
  /* Mở ra thì khoảng đệm và nút 📷 nhường hết chỗ cho ô tìm. */
  .app-mo-tim:checked ~ .app-tren-thanh .app-tren-dan { display: none; }
  /* Nút 📷 nhường chỗ - thiếu dòng này thì mở ô tìm ra, ô giãn hết bề
     ngang và đẩy nút lòi một nửa ra mép phải màn hình. */
  .app-mo-tim:checked ~ .app-tren-thanh .app-camera,
  .app-mo-tim:checked ~ .app-tren-thanh .app-tren-ca-nhan,
  .app-mo-tim:checked ~ .app-tren-thanh .app-tren-menu { display: none; }

  /* Ba nút NẰM TRONG vỏ đều để PHẲNG: nền và bóng nổi đã do vỏ lo. Để chúng
     tự mang bóng nổi nữa thì vừa chồng hai lớp bóng, vừa bị mép vỏ xén cụt
     (xem .app-tren-tim). Riêng bóng LÕM lúc nhấn thì giữ - bóng inset vẽ bên
     trong thẻ nên không có gì để mà xén. */
  .app-tren-mo,
  .app-tren-gui,
  .app-tren-dong {
    background: none;
    box-shadow: none;
  }
  .app-tren-mo:active,
  .app-tren-gui:active,
  .app-tren-dong:active {
    box-shadow: var(--nm-in-sm, inset 2px 2px 5px #c5cedb, inset -2px -2px 5px #fff);
  }

  /* Hai cái 🔍 chồng chỗ: nhãn (mở ô) lúc đóng, nút gửi lúc mở. */
  .app-tren-gui,
  .app-tren-dong { display: none; }
  .app-mo-tim:checked ~ .app-tren-thanh .app-tren-mo { display: none; }
  .app-mo-tim:checked ~ .app-tren-thanh .app-tren-gui,
  .app-mo-tim:checked ~ .app-tren-thanh .app-tren-dong { display: grid; }
  .app-tren-dong { font-size: 22px; }

  .app-tren-o {
    flex: 1 1 auto;
    min-width: 0;
    box-sizing: border-box;
    /* Cao bằng vỏ chứ không tự cao theo đệm dọc: đệm dọc làm ô cao hơn vỏ,
       vừa bị xén vừa kéo vỏ méo (xem .app-tren-tim). Kéo giãn cho hết chiều
       cao vỏ thì vùng chạm cũng rộng đúng bằng ô nhìn thấy. */
    align-self: stretch;
    padding: 0 6px;
    border: 0;
    background: transparent;
    box-shadow: none;
    font-family: inherit;
    /* 16px LÀ BẮT BUỘC, không phải chọn cho đẹp: Safari trên iPhone tự
       PHÓNG TO cả trang khi chạm vào ô nhập có cỡ chữ dưới 16px, phóng rồi
       không tự thu lại. Đây đúng là "ô tìm kiếm bị phóng to" người dùng gặp.
       Cách chữa bằng user-scalable=no thì chặn luôn cả phóng to bằng tay -
       không dùng. */
    font-size: 16px;
    color: var(--nm-ink, #1f2a3a);
  }
  .app-tren-o:focus { outline: none; }
  /* Bỏ nút ✕ mặc định của type="search" trên WebKit: đã có nút đóng riêng,
     hai dấu ✕ cạnh nhau thì không biết cái nào đóng ô, cái nào xoá chữ. */
  .app-tren-o::-webkit-search-cancel-button { -webkit-appearance: none; }

  /* Thanh trên thay hẳn dải logo cũ của Django admin. Trang đăng nhập nằm
     ngoài: ở đó chưa có thanh trên lẫn thanh đáy. */
  .la-webapp body:not(.login) #header { display: none; }

  /* Thanh tìm kiếm RIÊNG của từng trang: bỏ hết, chỉ còn ô tìm trên thanh
     trên. Hai thanh cùng làm một việc trên một màn hình vốn đã hẹp là thừa,
     mà thanh trong trang lại chiếm nguyên một hàng.

     Chỉ ẩn ở bản webapp: mở bằng trình duyệt thường thì KHÔNG có thanh trên,
     ẩn nốt thanh trong trang là mất hẳn đường tìm kiếm.

     Ô tìm trên thanh trên tự gửi về đúng trang đang mở (xem `tim_kiem_url`
     trong base_site.html), nên không mất chức năng nào. */
  .la-webapp .tl-timkiem,          /* Kho tài liệu */
  .la-webapp .tb-tim,              /* thiết bị PLC / bảng mã lỗi */
  .la-webapp .tk-tim { display: none; }   /* chính trang kết quả tìm kiếm */

  /* --- Trang Hỏi AI: bỏ HẾT khung, còn mỗi khung chat -------------------
     Bỏ CẢ BA: thanh trên (lời chào, ô tìm, chuông), dòng đường dẫn, và cả
     thanh đáy năm mục. Người dùng yêu cầu trang này rộng rãi nhất có thể
     trên điện thoại - đây là trang duy nhất của dự án bỏ hết khung.

     BỎ THANH ĐÁY LÀ MẤT HẾT LỐI RA, nên hoi_ai.html có thêm nút "←" nhỏ ở
     góc trên trái (.ai-ve). Bỏ thanh đáy mà quên nút ấy thì vào trang này
     xong không còn đường nào thoát ra ngoài đóng hẳn ứng dụng.

     VÌ SAO KHÔNG ĐẶT LUẬT NÀY TRONG hoi-ai.css. Tệp đó chỉ nạp ở trang Hỏi
     AI, nhưng spa.js chỉ THÊM stylesheet của trang mới chứ không gỡ
     stylesheet của trang cũ - đặt ở đấy thì ghé Hỏi AI một lần là thanh
     trên và thanh đáy biến mất ở MỌI trang sau đó. Móc vào lớp trên <body>
     mới đúng: spa.js chép `body.className` theo từng trang.

     Chọn `html.la-webapp body.trang-hoi-ai` chứ không `.la-webapp body...`:
     luật bật thanh trên là `.la-webapp body:not(.login) .app-tren` - cùng
     số lớp, hoà nhau, phải trông vào thứ tự dòng trong tệp mới thắng. Thêm
     `html` là hơn hẳn, khỏi phụ thuộc vị trí. */
  html.la-webapp body.trang-hoi-ai .app-tren,
  html.la-webapp body.trang-hoi-ai nav[aria-label="Breadcrumbs"],
  html.la-webapp body.trang-hoi-ai .app-nav {
    display: none;
  }

  /* --- Thanh đáy -------------------------------------------------------- */
  /* THANH NỔI, TÁCH KHỎI VIỀN MÁY (người dùng: "bo tròn và tách biệt với viền
     điện thoại như kiểu Facebook"). Cách mép trái/phải 10px, nằm TRÊN vạch
     vuốt Home thay vì phủ xuống nó, bốn góc bo tròn (xem .app-nav-nen).
     Khoảng hở dưới = vùng vuốt trừ 12px như đệm đáy cũ (vạch vuốt chỉ chiếm
     ~13px dưới cùng), tối thiểu 8px ở máy có nút Home. Thân thanh vì thế
     không còn phải chừa vùng vuốt: đệm đáy chỉ còn 6px. Chỗ khoét quanh nút
     EVN giữa và các nút GIỮ NGUYÊN - chỉ đổi khung ngoài. */
  .la-webapp .app-nav {
    display: flex;
    position: fixed;
    left: 10px; right: 10px;
    bottom: max(8px, calc(env(safe-area-inset-bottom, 0px) - 12px));
    z-index: 50;
    justify-content: space-around;
    align-items: stretch;
    /* Chừa vùng vuốt/tai thỏ của iPhone. Lề ngang mỏng để năm mục đủ chỗ. */
    /* ĐỆM ĐÁY = VÙNG VUỐT HOME TRỪ 12px, không cộng trọn.

       Từ khi trang khai viewport-fit=cover (để dải giờ của iPhone trong suốt,
       xem base_site.html), env(safe-area-inset-bottom) trả về thật 34px ở máy
       Face ID. Cộng trọn vào thì thanh cao vọt từ 70 lên 105px, dưới nhãn là
       một khoảng trống lớn - người dùng báo "dải icon phía dưới quá to".
       Thanh tab gốc của iOS cũng để nhãn lấn một phần vào vùng ấy: vạch vuốt
       chỉ chiếm ~13px dưới cùng, chừa 22px là nhãn vẫn cách vạch ~10px.
       max(4px, ...) cho máy không có vùng vuốt (nút Home) vẫn còn mép thở.

       ĐỆM TRÊN GIỮ NGUYÊN 8px: vòng tròn nút giữa định vị theo mép trên của
       mục (translate 13px), và chỗ khoét cong của nền thanh đã tính đồng
       tâm với vị trí ấy - đổi đệm trên là khe hở quanh nút lệch đi. */
    padding: 8px 6px 6px;
    /* Nền và đường viền do hai lớp ::before / ::after vẽ - xem bên dưới. */
    background: transparent;
    /* Nút Hỏi AI nhô lên trên mép thanh - có overflow: hidden ở đây là phần
       nhô lên bị cắt cụt. */
    overflow: visible;
    /* KHÔNG view-transition-name: xem khối @view-transition (đã tắt) đầu tệp. */
  }

  /* BÀN PHÍM ĐANG BẬT -> GIẤU HẲN THANH ĐÁY.
     Thanh là `position: fixed` nên nó nổi ngay trên bàn phím, ăn mất một
     dải màn hình đúng lúc màn hình hẹp nhất - mà đang gõ thì chẳng ai bấm
     năm nút ấy. Lớp `ban-phim` do script cuối base_site.html gắn lên <html>
     khi đo được visualViewport thu lại.

     `display: none` chứ không `opacity: 0`: phải THỰC SỰ mất chỗ thì script
     đo mới trả --app-nav-cao về 0, nhờ vậy mọi chỗ đang chừa chỗ cho thanh
     tự thu lại theo - khỏi phải khai thêm luật nào ở từng trang. */
  .la-webapp.ban-phim .app-nav { display: none; }

  /* --- Nền thanh: khoét cong quanh nút giữa, và bóng đổ bám theo đường cong
     -----------------------------------------------------------------------
     Mép trên của thanh vát cong xuống ôm lấy nút, và cả thanh nổi lên bằng
     bóng đổ - không dùng đường viền.

     Vì sao không dùng box-shadow của chính .app-nav: box-shadow bám theo hộp
     viền, nó vẽ một vệt thẳng CẮT NGANG chỗ khoét - nhìn như thanh bị gạch
     một đường qua nút.

     Vì sao phải tách làm HAI thẻ lồng nhau: trên cùng một thẻ, trình duyệt
     áp `filter` TRƯỚC rồi mới cắt bằng `mask`, nên bóng vẫn ra hình chữ
     nhật. Đặt bóng ở thẻ ngoài và hình khoét ở lớp con thì bóng mới bám
     theo hình đã cắt.

     Và vì sao không đặt luôn filter lên <nav>: filter áp cho cả cây con,
     mọi chữ và icon trong thanh sẽ bị hắt bóng theo, nhìn nhoè hết. Thẻ
     .app-nav-nen rỗng nên không dính vấn đề đó. */
  .app-nav-nen {
    position: absolute;
    inset: 0;
    z-index: 0;
    /* MÀU BÓNG PHẢI LÀ MỰC TỐI TRONG SUỐT, KHÔNG PHẢI --nm-dark.
       Đây là lỗi đã gặp thật, biểu hiện: hai mảng trắng đục hai bên nút.

       --nm-dark (#c5cedb) chỉ "tối" khi đứng cạnh màu trắng; so với nền
       trang (#e9edf2) nó gần như cùng tông và là một màu SÁNG tuyệt đối.
       Lấy nó làm bóng thì không ra bóng mà thành một đám mây xanh-trắng
       nhạt phủ lên nền. Bóng lại bám theo hình ĐÃ KHOÉT nên nó toả ra từ
       hai vai thanh rồi tràn vào khoảng trống hai bên nút - đúng chỗ nhìn
       ra "mảng trắng không phải nền". Đo trên nền tương phản: bản cũ đổ
       trung bình 101/255 mực sáng vào vùng đó, bản này còn 14.7 (bỏ hẳn
       bóng cũng đã là 14.5, tức phần bóng này gần như không đóng góp mờ).

       Hạ xuống MỘT lớp, sát và rất nhạt: thanh nổi lên là nhờ ranh giới
       màu (mặt --nm-light trên nền --nm-bg) và nét mép --nm-dark của lớp
       ::before, không phải nhờ bóng. Bóng chỉ để đỡ khô. */
    filter: drop-shadow(0 -1px 2px rgba(31, 42, 58, 0.13));
    /* Thanh nổi: bo góc + bóng đổ mềm phía dưới cho tách khỏi nội dung.
       box-shadow chỉ vẽ NGOÀI hộp nên không lọt vào chỗ khoét giữa. */
    border-radius: 27px;
    box-shadow: 0 8px 24px rgba(15, 23, 42, 0.20), 0 1px 3px rgba(15, 23, 42, 0.12);
  }
  /* Chỗ khoét là một đường VẼ TAY bằng SVG, không phải một đường tròn.

     Vì sao không dùng đường tròn nữa: cắt bằng đường tròn thì hai chỗ nó
     gặp mép thẳng của thanh luôn là hai góc gãy. Bo góc bằng đường tròn nhỏ
     tiếp xúc thì chỉ tù được vài pixel - muốn bo to hơn là đường tròn bo ăn
     sâu quá nửa chiều cao thanh, khoét mất cả một mảng. Đường cong vuốt dài
     từ mép thẳng xuống ôm đáy nút chỉ vẽ được bằng đường Bezier.

     Hình vẽ (toạ độ trong SVG, gốc ở mép trên thanh, y hướng xuống):

         M0 -1 H20                          mép thẳng (tràn lên 1px, xem dưới)
         C47.3 -1 51.89 10.32 58.79 17.21   vuốt xuống, tiếp tuyến NGANG ở đầu
         A30 30 0 0 0 101.21 17.21          CUNG TRÒN ĐỒNG TÂM VỚI NÚT
         C108.11 10.32 112.7 -1 140 -1      lặp lại đối xứng
         H160 V56 H0 Z                      phần thân thanh

     Khúc giữa là CUNG TRÒN đồng tâm với nút (tâm 80/-4, bán kính 30 = 25 của
     nút cộng 5px hở). Đáy Bezier phẳng thì khoảng hở phình ra ở giữa mà bó
     lại hai bên hông, nhìn không ra ôm nút; cung đồng tâm cho khoảng hở ĐÚNG
     5px suốt dọc.

     Hai đầu cung đặt ở 45 độ so với phương thẳng đứng:
     80 -+ 30*sin45 = 58.79 / 101.21, cao độ -4 + 30*cos45 = 17.21.

     Rộng 120px (từ 20 tới 140) mà chỉ sâu 26px - tỉ lệ hơn 4:1, nét vuốt rất
     mềm. Sâu hơn nữa thì đụng nhãn "Hỏi AI" (nhãn bắt đầu ở 31px).

     Hai khúc Bezier hai bên chỉ làm một việc: nối mép thẳng vào đầu cung mà
     không gãy. Điểm điều khiển đầu cùng cao độ mép thẳng (tiếp tuyến ngang);
     điểm điều khiển cuối đặt dọc tiếp tuyến của cung tại điểm nối (hướng
     0.707/0.707), nên chỗ nối trơn cả hai phía.

     KHÔNG ĐƯỢC CÓ CHỖ THẮT: bán kính cong NHỎ NHẤT dọc khúc Bezier phải >=
     bán kính cung. Thắt xuống dưới là giữa đường có một điểm cong hơn cả cung
     ôm nút - nhìn ra đúng một nếp gãy, dù hai đầu đã trơn. Đây là lỗi đã gặp
     thật: hồi cung còn 34, bản rộng 126px thắt còn 29px giữa khúc vuốt.

     Muốn hết thắt thì phải đủ RỘNG, không con số điều khiển nào thay được:
     bề rộng hẹp nhất còn giữ được bán kính nhỏ nhất đúng bằng cung là khoảng
     4 lần bán kính cung (34 -> 138px, 30 -> 120px, 27 -> 108px). Hẹp hơn là
     thắt, dò hết dải điểm điều khiển vẫn thắt.

     KHỚP CẢ ĐỘ CONG ở chỗ nối vào cung, không chỉ khớp tiếp tuyến - đây là
     chỗ trước kia bị nhìn ra thành góc nhọn. Tiếp tuyến liền mà độ cong nhảy
     bậc thì mắt vẫn đọc ra một nếp gãy: bản cũ nối cung ở 75 độ, khúc Bezier
     gần như thẳng rồi đâm thẳng vào cung, bán kính cong ngay tại điểm nối chỉ
     còn ~1.7px cạnh cung 34px lúc bấy giờ - hai chục lần chênh nhau.

     Ép độ cong bằng cách đặt hai điểm điều khiển: cung 45 độ cho khúc Bezier
     đủ dài để uốn từ từ, và khoảng cách hai điểm điều khiển tính ngược từ
     công thức độ cong đầu mút của Bezier bậc ba

         R = |P3-P2|^3 / ( (2/3) * |(P3-P2) x (P1-P2)| )

     sao cho R tại điểm nối đúng bằng bán kính cung.

     Chạy dọc đường cong, bán kính giãn ĐỀU MỘT CHIỀU từ ~99px ở mép thẳng
     xuống 30px lúc vào cung, không lúc nào tụt xuống dưới rồi vọt lên lại -
     không còn chỗ nào đổi đột ngột.

     Ghép bằng BỐN lớp mask cộng dồn (mặc định là hợp phần hiện, khỏi cần
     mask-composite): thân trái, thân phải, ô SVG 160x56 ở giữa trên, và
     phần thân dưới ô SVG. Cách này giữ đúng cỡ SVG - kéo giãn một lớp SVG
     cho vừa cả thanh thì đường cong méo theo bề ngang màn hình.

     HAI CHỖ CHỐNG VỆT MỜ - đều là lỗi đã gặp thật, thỉnh thoảng hiện ra một
     mảng trắng nhạt hai bên nút:

     1. Đoạn thẳng trong ô SVG vẽ từ y = -1 chứ không phải y = 0. Vẽ đúng
        mép trên thì hàng điểm ảnh đầu tiên bị khử răng cưa, độ đục chỉ còn
        khoảng một nửa - nền thanh chỗ đó loang ra, lộ nội dung trang phía
        sau. Cho hình tràn lên trên 1px là hàng đó đặc hoàn toàn.

     2. Ba lớp còn lại chờm vào ô SVG 1px (79 thay vì 80, 55 thay vì 56).
        Chia đôi bề ngang màn hình lẻ thì mép hai lớp rơi vào giữa điểm ảnh,
        để sát nhau là hở một sợi chỉ - chờm lên nhau thì không bao giờ hở.
        Chỗ chờm nằm trên phần ĐẶC của hình nên không che mất đường cong. */
  .app-nav-nen::before,
  .app-nav-nen::after {
    content: "";
    position: absolute;
    left: 0; right: 0; bottom: 0;
    -webkit-mask-image:
      linear-gradient(#000, #000),
      url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='56' viewBox='0 0 160 56'%3E%3Cpath d='M0 -1H20C47.3 -1 51.89 10.32 58.79 17.21A30 30 0 0 0 101.21 17.21C108.11 10.32 112.7 -1 140 -1H160V56H0Z' fill='%23000'/%3E%3C/svg%3E"),
      linear-gradient(#000, #000),
      linear-gradient(#000, #000);
    -webkit-mask-position: left top, center top, center bottom, right top;
    -webkit-mask-size:
      calc(50% - 79px) 100%, 160px 56px,
      160px calc(100% - 55px), calc(50% - 79px) 100%;
    -webkit-mask-repeat: no-repeat;
    mask-image:
      linear-gradient(#000, #000),
      url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='56' viewBox='0 0 160 56'%3E%3Cpath d='M0 -1H20C47.3 -1 51.89 10.32 58.79 17.21A30 30 0 0 0 101.21 17.21C108.11 10.32 112.7 -1 140 -1H160V56H0Z' fill='%23000'/%3E%3C/svg%3E"),
      linear-gradient(#000, #000),
      linear-gradient(#000, #000);
    mask-position: left top, center top, center bottom, right top;
    mask-size:
      calc(50% - 79px) 100%, 160px 56px,
      160px calc(100% - 55px), calc(50% - 79px) 100%;
    mask-repeat: no-repeat;
  }
  /* ĐƯỜNG MÉP vẽ trước, MẶT THANH đè lên sau - thứ tự tự nhiên của ::before
     rồi ::after, KHÔNG dùng z-index âm.

     Đường mép là hai lớp NỀN chồng nhau, không phải bóng: bóng bản chất là
     toả mờ dần, không bao giờ thành một nét. Cũng không trông cậy vào
     z-index âm hay filter - trình duyệt điện thoại hay bỏ qua cả hai (z-index
     âm trong thẻ có filter; filter trên thẻ con của position: fixed), mất
     một cái là mất sạch đường viền. Hai lớp nền chồng nhau thì chỉ là tô
     màu, không có gì để mà hỏng.

     Mép cao hơn 3px nên lộ ra đúng 3px ở trên cùng, chạy suốt cả đoạn thẳng
     lẫn đoạn cong quanh nút vì hai lớp dùng CHUNG một bộ mask. */
  .app-nav-nen::before {
    top: -3px;
    /* Thanh nổi: đường mép chạy QUANH cả thanh (tràn 1px trái/phải/dưới),
       không chỉ mép trên. Tràn đều hai bên nên ô SVG khoét (center top) vẫn
       đồng tâm với lớp mặt thanh. */
    left: -1px; right: -1px; bottom: -1px;
    border-radius: 28px;
    background: var(--nm-dark, #c5cedb);
  }
  /* Mặt thanh: --nm-light (TRẮNG ở nền sáng, xám nhạt ở nền tối), không phải
     --nm-bg hay --nm-surface. --nm-bg đúng bằng màu nền trang nên thanh lẫn
     hẳn vào nội dung; --nm-surface chỉ chênh khoảng 17 mức màu, mắt cũng
     không thấy. Chênh hẳn một bậc thì mép thanh tự hiện ra bằng chính ranh
     giới màu, không phụ thuộc vào bóng. */
  .app-nav-nen::after {
    top: 0;
    border-radius: 27px;
    background: var(--nm-light, #ffffff);
  }

  .app-nav-o {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    /* Đệm trong mỗi mục 3px (trước 8px): thanh thấp đi 10px mà nhãn "Hỏi
       AI" của mục giữa vẫn bắt đầu ở ~31px, dưới đáy chỗ khoét (26px). */
    padding: 3px 1px;
    min-width: 0;
    /* Nổi lên trên hai lớp nền ::before / ::after. */
    position: relative;
    z-index: 1;
    /* Mục "Cá nhân" là <label>, các mục khác là <a>: gỡ nền, viền, cỡ chữ
       mặc định của trình duyệt để tất cả nằm cùng một khuôn. */
    background: none;
    border: 0;
    font-family: inherit;
    -webkit-appearance: none;
    appearance: none;
    border-radius: var(--nm-r-sm, 12px);
    text-decoration: none !important;
    color: var(--nm-ink-soft, #64748b) !important;
    -webkit-tap-highlight-color: transparent;
  }
  .app-nav-icon { font-size: 19px; line-height: 1; }
  /* Icon dạng ảnh (TeamPLC dùng ảnh PLC thật thay emoji). Cao theo 1em nên
     tự co lại đúng tỉ lệ ở ngưỡng màn hình hẹp, không phải khai lại số.
     1.05em cho khối ảnh nhìn nặng ngang các emoji bên cạnh - glyph emoji
     vẽ cao hơn ô chữ một chút. */
  .app-nav-anh {
    display: block;
    height: 1.05em; width: auto;
    object-fit: contain;
  }
  /* --- Nút Hỏi AI nổi lên giữa thanh ------------------------------------
     Vòng tròn nhô hẳn lên trên mép thanh bằng margin-top ÂM chứ không
     position: absolute: nút vẫn là một ô của flex nên hai mục trái và hai
     mục phải tự chia đều hai bên, không phải căn tay.

     Nhãn "Hỏi AI" nằm ngoài vòng tròn nên vẫn trong thanh, ngang hàng với
     nhãn của bốn mục kia.

     overflow phải để mặc định (visible) trên .app-nav, nếu không phần nhô
     lên bị cắt cụt. */
  /* Nhãn dồn xuống đáy để ngang hàng với nhãn bốn mục kia - vòng tròn đã
     tách khỏi dòng chảy (position: absolute) nên mục này thấp hơn hẳn.

     KHÔNG ghim bề ngang: mục này thừa `flex: 1 1 0` của .app-nav-o nên năm
     mục chia đều nhau. Bản trước ghim 120px cho bằng bề ngang chỗ khoét, ô
     giữa vì thế rộng gần gấp đôi bốn ô kia, nhìn lệch hẳn.

     Bỏ ghim mà vẫn an toàn: chỗ khoét rộng 126px ở ngay mép trên thanh,
     nhưng KHUNG NỀN của mục đang mở chỉ bắt đầu từ 8px (padding của thanh)
     trở xuống - ở cao độ đó đường biên đã là cung tròn, chỉ còn rộng
     2*căn(34² - 12²) ~= 64px, hẹp hơn một ô (70px trên máy 360px). Đường
     cong vì thế không chạm khung nền của "An toàn" hay "TeamPLC". */
  .app-nav-giua {
    position: relative;
    justify-content: flex-end;
  }
  /* Định vị TUYỆT ĐỐI chứ không dùng lề âm: lề âm thì vị trí vòng tròn phụ
     thuộc vào chiều cao của nhãn và của các mục bên cạnh, đổi cỡ chữ một
     chút là tâm dịch đi, không còn khớp tâm chỗ khoét nữa.

     bottom: 100% đặt đáy vòng tròn ngay mép trên của mục (= 8px dưới mép
     thanh, đúng bằng padding). translateY(13px) hạ xuống, cho TÂM vòng tròn
     nằm ở 8 - 50 + 13 + 25 = -4px so với mép thanh, tức đáy nút ở 21px -
     nông hơn đáy đường cong (26px) đúng 5px.

     Đường cong sâu thêm thì nút phải hạ theo đúng bấy nhiêu, nếu không
     khoảng hở dưới đáy nút rộng ra mà hai bên hông lại hẹp lại.

     ĐỔI CỠ NÚT LÀ PHẢI VẼ LẠI CẢ CHỖ KHOÉT, không chỉ sửa mấy con số ở đây.
     Bán kính cung bằng bán kính nút cộng 5px hở; nút nhỏ đi mà giữ nguyên
     cung thì hở phình ra gấp đôi, nút nhìn như bơi giữa chỗ vát. Cả bộ số
     (cung, bề rộng, hai điểm điều khiển) đều phải tính lại - xem khối chú
     thích của .app-nav-nen::before. */
  .app-nav-giua-vong {
    position: absolute;
    left: 50%;
    bottom: 100%;
    transform: translate(-50%, 13px);
    display: grid;
    place-items: center;
    width: 50px; height: 50px;
    border-radius: 50%;
    background: var(--nm-nut-giua, #fff);
    box-shadow: var(--nm-nut-giua-bong, 0 6px 16px rgba(31, 42, 58, 0.26));
  }
  /* BA logo thay phiên nhau, mỗi logo đúng 3 giây (chu kỳ 9s).
     Bản thân vòng xoay là hoạt ảnh CSS thuần - chạy được ngay cả khi script
     hỏng, chỉ mất tính liền mạch chứ không đứng hình.

     Có VÀI DÒNG SCRIPT trong base_site.html chỉ để DỜI PHA: hoạt ảnh CSS đếm
     giờ từ lúc trang tải xong, nên mỗi lần chuyển trang logo lại quay về cái
     đầu tiên - nhìn như bấm nút nào cũng "reset" logo. Script neo pha vào
     đồng hồ máy để vòng xoay chạy liền mạch qua các lần tải trang. CSS không
     có cách nào biết giờ hiện tại, nên chỗ này buộc phải có script.

     Script đọc thời lượng ngược lại TỪ CSS (getComputedStyle) chứ không ghi
     cứng số, nên sửa nhịp ở đây là bên kia tự theo.

     Cả ba nằm CHỒNG ở cùng một ô lưới (grid-area: 1/1) - .app-nav-giua-vong
     đã là display: grid; place-items: center nên mỗi ảnh tự canh giữa. Xếp
     chồng chứ không thay src: đổi src thì lần đầu mỗi ảnh phải tải xong mới
     hiện, nút nháy trống một nhịp.

     Mẹo ĐỘ TRỄ ÂM: cả ba dùng chung một bộ @keyframes, chỉ lệch pha nhau.
     Trễ ÂM nghĩa là hoạt ảnh coi như đã chạy được bấy nhiêu ngay từ lúc bắt
     đầu, nên ảnh 2 vào đúng giây thứ 3, ảnh 3 vào giây thứ 6. Nếu dùng trễ
     DƯƠNG thì trong lúc chờ chưa có hoạt ảnh nào áp, cả ba cùng nằm ở
     opacity gốc - nháy đè lên nhau ở nhịp đầu.

     CHUYỂN MỀM bằng phép HOÀ ĐỐI XỨNG: ảnh cũ mờ đi trong 0.6s, ảnh mới
     hiện lên trong đúng 0.6s đó. Mốc 33.334% (hết lượt) của ảnh này trùng
     khít mốc 0% của ảnh kia, nên hai nét mờ luôn khớp nhau.

     Vì sao tổng không bị hụt: hai đầu dùng CÙNG một kiểu chạy ease-in-out
     trên cùng độ dài, nên độ đục của ảnh mới luôn đúng bằng phần vừa mất
     của ảnh cũ - cộng lại luôn bằng 1, không có nhịp nào cả hai cùng nhạt.
     Đổi kiểu chạy ở một trong hai đầu là hỏng tính chất này.

     ĐÃ THỬ VÀ PHẢI BỎ - "chỉ hiện dần, không bao giờ mờ đi, ảnh mới đè lên
     ảnh cũ" (kèm một @keyframes đảo z-index theo lượt). Nghe hợp lý vì lớp
     dưới luôn đục nên không hụt màu, nhưng ba logo này NỀN TRONG SUỐT: lớp
     trên không che nổi lớp dưới, dựng ra thấy cả ba logo chồng lên nhau
     cùng lúc. Mẹo đó chỉ dùng được với ảnh đặc.

     THÊM/BỚT LOGO là phải sửa bốn chỗ: số ảnh trong base_site.html, hai mốc
     33.334%/40% dưới đây, các dòng animation-delay, và tổng thời lượng 9s
     (= số logo x 3s). */
  
  .app-nav-giua-anh {
    display: block;
    grid-area: 1 / 1;
    width: 35px; height: 35px;
    object-fit: contain;
    opacity: 0;
    animation: app-nav-doi-logo 9s ease-in-out infinite;
  }

  /* Tạm dừng cho tới khi script neo xong pha - CHỈ khi máy có JavaScript.

     Hoạt ảnh bắt đầu chạy ngay lúc phần tử được vẽ, rồi script mới đổi
     `animation-delay` để bắt vào đồng hồ thật. Đổi delay của một hoạt ảnh
     ĐANG CHẠY thì nó nhảy phắt sang khung hình khác - mỗi lần tải trang là
     logo giật một cái ngay giữa thanh đáy.

     Dừng trước rồi cho chạy sau khi đã neo thì không còn khung hình nào sai
     để mà nhảy.

     Lớp `.co-js` do script trong <head> gắn. Máy tắt JavaScript thì không có
     lớp đó, hoạt ảnh chạy bình thường như cũ - vòng xoay vẫn phải sống được
     khi không có script.

     ĐẶT SAU khối .app-nav-giua-anh, không đặt trước: bài kiểm tra tách
     khối bằng split(".app-nav-giua-anh {")[1], để luật này lên trước là
     nó lấy nhầm. */
  .co-js .app-nav-giua-anh { animation-play-state: paused; }

  /* ⛔ PHA LÚC DỪNG PHẢI CÓ ĐÚNG MỘT LOGO ĐANG HIỆN.
     ------------------------------------------------------------------
     Ba ảnh đều `opacity: 0`, và khi hoạt ảnh DỪNG thì độ mờ lấy theo
     khung hình tại pha đang đứng. Nên pha lúc dừng quyết định nút giữa có
     hình hay là một vòng tròn TRẮNG TRƠN.

     Bản trước là -0s / -6s / -3s: rơi vào 0% (mờ), 66,7% (mờ) và 33,334%
     (đục). Có hình, nhưng ĐÚNG BẰNG MAY: 33,334% là khung hình cuối cùng
     còn đục, lệch thêm một phần nghìn là tắt. Đổi số logo, đổi mốc keyframe
     hay đổi thời lượng - bất cứ thứ nào - đều có thể làm cả ba cùng tắt mà
     chẳng ai nhận ra cho tới khi người dùng gửi ảnh chụp màn hình trắng.

     Nay dời cả ba đi 1 giây: -1s / -4s / -7s. Giãn cách vẫn 3s như cũ, nên
     vòng xoay không đổi. Nhưng pha lúc dừng thành 11,1% / 44,4% / 77,8% -
     ảnh đầu nằm GIỮA vùng đục [6,667% .. 33,334%], cách hai mép hơn 4%.
     Có hình là do tính toán, không phải do may. */
  .app-nav-giua-anh:nth-child(1) { animation-delay: -1s; }
  .app-nav-giua-anh:nth-child(2) { animation-delay: -4s; }
  .app-nav-giua-anh:nth-child(3) { animation-delay: -7s; }
  @keyframes app-nav-doi-logo {
    0%       { opacity: 0; }    /* bắt đầu hiện dần  */
    6.667%   { opacity: 1; }    /* 0.6s: đục hẳn     */
    33.334%  { opacity: 1; }    /* 3.0s: hết lượt    */
    40%      { opacity: 0; }    /* 3.6s: mờ hẳn      */
    100%     { opacity: 0; }
  }
  /* LƯỚI AN TOÀN: hoạt ảnh hỏng thì ĐỨNG YÊN ở logo đầu, đừng để trắng.

     Lớp này do script neo gắn vào khi nó đo được CẢ BA ảnh cùng trong
     suốt - nghĩa là lớp hợp thành của hoạt ảnh đã hỏng theo một cách
     không lường trước. Mất vòng xoay còn hơn để người dùng nhìn một vòng
     tròn trắng trơn giữa thanh đáy.

     Thắng được luật `.co-js ...` nhờ nhiều hơn một lớp, nên không cần
     `!important`; script cũng xoá mấy thuộc tính đặt thẳng trên thẻ trước
     khi gắn lớp này. */
  .app-nav-giua-vong.logo-tinh .app-nav-giua-anh {
    animation: none;
    opacity: 0;
  }
  .app-nav-giua-vong.logo-tinh .app-nav-giua-anh:first-child { opacity: 1; }

  /* Máy đã bật "giảm chuyển động": đứng yên ở logo bảo trì. Ảnh nhấp nháy
     đều đặn là thứ gây khó chịu đúng kiểu tuỳ chọn này muốn tránh. */
  @media (prefers-reduced-motion: reduce) {
    .app-nav-giua-anh { animation: none; }
    .app-nav-giua-anh:first-child { opacity: 1; }
  }
  .app-nav-giua:active .app-nav-giua-vong {
    box-shadow: 0 2px 8px rgba(31, 42, 58, 0.3);
  }
  /* Mục giữ chỗ: bỏ phản hồi khi chạm - bấm mà lõm xuống rồi không xảy ra
     gì thì tưởng máy treo.

     Làm mờ RIÊNG nhãn chứ không mờ cả mục: mờ cả mục thì vòng tròn trắng
     cũng nhạt theo, bóng đổ mất tác dụng và nút hết nổi lên - mà nổi lên
     tách khỏi thanh mới là điểm chính của nút này. */
  .app-nav-cho { cursor: default; }
  .app-nav-cho .app-nav-ten { opacity: 0.6; }
  .app-nav-cho:active { box-shadow: none; }
  .app-nav-cho:active .app-nav-giua-vong {
    box-shadow: 0 6px 16px rgba(31, 42, 58, 0.26);
  }

  /* Năm mục nên nhãn phải gọn, không được xuống dòng làm lệch chiều cao. */
  .app-nav-ten {
    font-size: 10.5px; font-weight: 600;
    white-space: nowrap; max-width: 100%; overflow: hidden;
    text-overflow: ellipsis;
  }
  /* Máy hẹp (dưới 400px): thu lại cho đủ chỗ bốn mục kèm nút giữa. Nhãn
     dài nhất là "Trang chủ" - đây là cỡ vừa đủ để nó không bị cắt ở máy
     320px. */
  @media (max-width: 400px) {
    .app-nav-o { padding: 3px 0; gap: 2px; }
    .app-nav-icon { font-size: 17px; }
    .app-nav-ten { font-size: 9.5px; }
    /* Vòng tròn VÀ logo bên trong giữ nguyên cỡ ở mọi màn hình: thu vòng
       tròn lại thì tâm dịch đi, phải tính lại cả bán kính cung lẫn bề rộng
       chỗ khoét cho khớp - không đáng. Logo cũng để nguyên 35px cho khỏi
       lệch tỉ lệ với vòng tròn.

       ĐỪNG khai lại cỡ logo ở đây: từng có dòng 38px sót lại từ hồi cỡ nền
       là 40px, hoá ra máy màn hình HẸP lại hiện logo TO HƠN máy màn rộng. */
    /* Đổi MỘT biến là cả nút lẫn bề rộng lúc đóng của vỏ ô tìm cùng co lại.
       Cỡ CHỮ TRONG Ô thì tuyệt đối không hạ xuống dưới 16px - xem
       .app-tren-o, dưới 16px là iPhone tự phóng to cả trang. */
    .la-webapp body:not(.login) .app-tren { --app-tren-nut-co: 36px; }
    /* Nút nhỏ đi thì thanh thấp đi theo: 36 + 8 + 8 = 52px, không còn là
       56px như số đỡ tạm ở đầu tệp. Phải sửa luôn số đỡ tạm, vì nó là thứ
       #container dùng để chừa chỗ TRONG LÚC CHỜ đoạn đo của base_site.html
       chạy. Để nguyên 56px thì mở trang nào nội dung cũng tụt lên 4px một
       cái - đúng kiểu giật mà cả việc này đang đi chữa, lại còn ở ngay đầu
       trang.

       Đặt ở :root chứ KHÔNG đặt cùng chỗ với --app-tren-nut-co: biến đặt
       trên .app-tren chỉ chảy xuống con của nó, mà #container lại là CHA
       của .app-tren - đặt ở đó thì #container không thấy gì. */
    :root {
      --app-tren-cao: 52px;
      /* Thanh đáy ở cỡ này đo được 51.85px (máy 393px, đệm đáy tối thiểu
         4px) - cộng đệm đáy thật theo vùng vuốt Home như ở :root đầu tệp. */
      --app-nav-cao: calc(49.85px + max(8px, calc(env(safe-area-inset-bottom, 0px) - 12px)));
    }
    .app-tren-nut { font-size: 16px; }
  }

  /* Mục đang mở: lõm xuống + đổi màu, giống các nút khác trong theme. */
  .app-nav-o.active {
    color: var(--nm-accent, #2563eb) !important;
    box-shadow: var(--nm-in-sm, inset 2px 2px 5px #c5cedb, inset -2px -2px 5px #fff);
  }
  .app-nav-o:active {
    box-shadow: var(--nm-in-sm, inset 2px 2px 5px #c5cedb, inset -2px -2px 5px #fff);
  }

  /* Chừa chỗ để thanh không che phần cuối trang.

     Chỗ chừa đặt trên #container chứ KHÔNG phải body, và phải gỡ
     height: 100% trước. Django admin đặt `html, body { height: 100% }` và
     `#container { height: 100% }`: trang dài hơn màn hình thì nội dung TRÀN
     ra ngoài hộp body, mà padding-bottom của một hộp bị tràn không được
     tính vào vùng cuộn - cuộn hết cỡ vẫn dừng ở đáy nội dung, phần chừa
     nằm đâu đó giữa trang. Chừa bao nhiêu cũng vô ích, nút cuối trang
     (Nộp bài, submit-row...) vẫn bị thanh che.

     Đổi sang min-height thì body cao theo nội dung, lúc đó phần chừa mới
     thật sự nằm cuối vùng cuộn.

     box-sizing: border-box để trang ngắn không bị dôi ra một đoạn cuộn
     thừa: phần chừa nằm trong 100dvh chứ không cộng thêm vào.

     --app-nav-cao là chiều cao ĐO ĐƯỢC của thanh, do script cuối
     base_site.html ghi vào. Đo thay vì đoán vì thanh cao lên khi máy đặt cỡ
     chữ hệ thống to hơn. env(safe-area-inset-bottom) không cộng thêm lần
     nữa - nó là padding của chính .app-nav nên đã nằm trong số đo.

     Trừ trang đăng nhập (body.login): trang đó bỏ hẳn block footer nên
     không có thanh đáy để mà tránh, mà #container của nó lại là thẻ đăng
     nhập `margin: 50px auto; max-width: 480px` - kéo cao 100dvh là hỏng bố
     cục. */
  .la-webapp body:not(.login) {
    height: auto !important;
  }
  .la-webapp body:not(.login) #container {
    height: auto !important;
    min-height: 100vh;
    min-height: 100dvh;
    box-sizing: border-box;
    /* Chừa chỗ cho thanh trên (nay đã fixed) và thanh đáy.
       Hai con số đều do script cuối base_site.html ĐO THẬT rồi ghi vào, vì
       thanh cao lên khi máy đặt cỡ chữ hệ thống to hơn. 12px là khoảng hở
       cũ giữa thanh trên và nội dung. */
    padding-top: calc(var(--app-tren-cao) + 12px) !important;
    padding-bottom: calc(var(--app-nav-cao) + 10px) !important;
  }

  /* Trang Hỏi AI bỏ cả hai thanh, nên phải TỰ chừa hai vùng an toàn.
     Bình thường `env(safe-area-inset-top)` là padding của chính .app-tren
     và `env(safe-area-inset-bottom)` là padding của .app-nav - cả hai đã
     nằm trong --app-tren-cao / --app-nav-cao. Hai thanh biến mất thì hai
     biến ấy về 0 và phần chừa mất theo: dòng chat đầu tiên chui lên nằm
     dưới đồng hồ iPhone (đã thấy lúc chụp thử), còn ô soạn thì đè lên vạch
     vuốt ở đáy. */
  html.la-webapp body.trang-hoi-ai #container {
    padding-top: calc(env(safe-area-inset-top, 0px) + 8px) !important;
    /* Ô soạn SÁT ĐÁY hơn (người dùng: "thanh nhập liệu nằm hơi xa mép
       dưới"): chừa vùng vuốt TRỪ 20px chứ không cộng thêm 8px - vạch vuốt
       chỉ chiếm ~13px dưới cùng, ô soạn (cộng 6px đệm của .ai-soan-neo) cách
       mép dưới ~20px ở máy Face ID, ~8px ở máy có nút Home. Cùng số với
       `bottom` của .ai-soan-neo trong hoi-ai.css. */
    padding-bottom: max(2px, calc(env(safe-area-inset-bottom, 0px) - 20px)) !important;
  }

  /* Khoảng hở cuối trang cộng dồn từ nhiều chỗ: #content tự chừa 20px, khối
     cuối cùng thường còn margin-bottom của nó, rồi mới tới phần chừa ở
     trên - ba lớp chồng nhau thành một mảng trống rộng. Dọn hai lớp kia đi
     để khoảng hở đúng bằng con số khai một chỗ duy nhất. */
  .la-webapp body:not(.login) #content { padding-bottom: 0; }
  .la-webapp body:not(.login) #content-main > :last-child,
  .la-webapp body:not(.login) #content > :last-child { margin-bottom: 0; }

  /* Bỏ hẳn khối #user-tools khỏi header: đổi giao diện / xem trang web /
     đổi mật khẩu / thoát đã có trong mục "Cá nhân" ở thanh đáy, còn lời
     chào "Chào mừng bạn, ..." thì trùng với dòng "Chào buổi sáng, ..."
     ngay bên dưới. Trên trình duyệt thường (không phải webapp) vẫn giữ,
     vì lúc đó chưa có thanh đáy để thay thế. */
  .la-webapp #user-tools { display: none; }

  /* Dải logo cũ của Django admin: xem luật ẩn ở khối "Thanh trên" phía
     trên - thanh tím đã thay hẳn chỗ đó. */

  /* --- Bảng MENU TRÁI (nút ⋯ ở trang chủ) trượt ra từ mép trái ----------
     Cùng mẹo checkbox với bảng "Cá nhân". Nền, bóng, nút × lấy y kiểu bảng
     ấy để hai bảng trông cùng một bộ. */
  .la-webapp .app-menu-nen {
    display: block;
    position: fixed; inset: 0; z-index: 60;
    background: rgba(31, 42, 58, 0.45);
    opacity: 0; visibility: hidden;
    transition: opacity 0.18s ease;
    touch-action: none;
  }
  .la-webapp .app-menu-trai {
    display: flex; flex-direction: column;
    position: fixed; top: 0; bottom: 0; left: 0; z-index: 61;
    width: min(300px, 82vw);
    box-sizing: border-box;
    overflow-y: auto; overscroll-behavior: contain;
    padding: calc(env(safe-area-inset-top, 0px) + 10px) 12px
             calc(16px + env(safe-area-inset-bottom, 0px));
    border-radius: 0 22px 22px 0;
    background: var(--nm-bg, #e9edf2);
    box-shadow: 10px 0 30px rgba(31, 42, 58, 0.22);
    transform: translateX(-105%);
    transition: transform 0.22s ease;
  }
  .la-webapp .app-mo-menu:checked ~ .app-menu-nen { opacity: 1; visibility: visible; }
  .la-webapp .app-mo-menu:checked ~ .app-menu-trai { transform: translateX(0); }
  .la-webapp:has(.app-mo-menu:checked),
  .la-webapp body:has(.app-mo-menu:checked) { overflow: hidden; }
  .app-menu-dau {
    display: flex; align-items: center; gap: 12px;
    padding: 8px 4px 14px 10px;
  }
  .app-menu-ten {
    flex: 1; font-size: 17px; font-weight: 700;
    color: var(--nm-ink, #1f2a3a);
  }
  .app-menu-ds { display: flex; flex-direction: column; gap: 8px; }
  .app-menu-muc {
    display: flex; align-items: center; gap: 12px;
    padding: 12px 14px; border-radius: 14px;
    font-size: 15px; font-weight: 600; text-decoration: none;
    color: var(--nm-ink, #1f2a3a);
    background: var(--nm-bg, #e9edf2);
    box-shadow: var(--nm-out-sm, 3px 3px 7px #c5cedb, -3px -3px 7px #fff);
  }
  .app-menu-muc:active {
    box-shadow: var(--nm-in-sm, inset 2px 2px 5px #c5cedb, inset -2px -2px 5px #fff);
  }
  .app-menu-trong {
    margin: 6px 10px; font-size: 13.5px;
    color: var(--nm-ink-soft, #64748b);
  }
  /* --- MỤC YÊU THÍCH (tài liệu ♥) - static/js/yeu-thich.js ---------------
     Mỗi dòng: nút Xoá đỏ nằm DƯỚI, bên phải; thẻ tài liệu nằm trên, vuốt
     sang trái thì trượt đi để lộ nút. Nút Xoá chỉ hiện lúc đang vuốt / đã lộ
     - nền menu là kính trong suốt, để sẵn thì màu đỏ ánh qua thẻ. */
  /* Tiêu đề Mục yêu thích là nút gập / sổ (<details>): ♥ Tên ··· [số] › */
  .app-yt-dau {
    display: flex; align-items: center; gap: 10px;
    padding: 12px 14px; border-radius: 14px; cursor: pointer; list-style: none;
    font-size: 15px; font-weight: 600; color: var(--nm-ink, #1f2a3a);
    background: var(--nm-bg, #e9edf2);
    box-shadow: var(--nm-out-sm, 3px 3px 7px #c5cedb, -3px -3px 7px #fff);
    -webkit-tap-highlight-color: transparent; user-select: none; -webkit-user-select: none;
  }
  .app-yt-dau::-webkit-details-marker { display: none; }
  .app-yt-dau:active { box-shadow: var(--nm-in-sm, inset 2px 2px 5px #c5cedb, inset -2px -2px 5px #fff); }
  .app-yt-ten { flex: 1; min-width: 0; }
  .app-yt-so {
    min-width: 22px; padding: 1px 7px; border-radius: 999px; box-sizing: border-box;
    text-align: center; font-size: 12.5px; font-weight: 800; color: #fff; background: #ef4444;
  }
  .app-yt-mui { width: 18px; height: 18px; flex: none; color: var(--nm-ink-soft, #64748b);
                transition: transform .2s ease; }
  .app-yt[open] .app-yt-mui { transform: rotate(90deg); }
  .app-yt[open] .app-yt-dau { margin-bottom: 10px; }
  .app-yt-tim { color: #ef4444; font-size: 17px; line-height: 1; }
  .app-yt-ds { display: flex; flex-direction: column; gap: 8px; }
  .app-yt-dong { position: relative; border-radius: 14px; overflow: hidden; }
  .app-yt-xoa {
    position: absolute; top: 0; right: 0; bottom: 0; width: 84px;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
    border: 0; border-radius: 14px; background: #dc2626; color: #fff; cursor: pointer;
    font: inherit; font-size: 12px; font-weight: 700;
    visibility: hidden;
  }
  .app-yt-xoa svg { width: 20px; height: 20px; }
  .app-yt-dang .app-yt-xoa, .app-yt-lo .app-yt-xoa { visibility: visible; }
  .app-yt-mo {
    position: relative; z-index: 1;
    display: flex; align-items: center; gap: 12px; min-width: 0;
    padding: 10px 12px; border-radius: 14px;
    text-decoration: none !important; color: var(--nm-ink, #1f2a3a) !important;
    background: var(--nm-bg, #e9edf2);
    box-shadow: var(--nm-out-sm, 3px 3px 7px #c5cedb, -3px -3px 7px #fff);
    /* Vuốt ngang là của mình, cuộn dọc vẫn của trình duyệt. Tắt kéo-thả /
       menu nhấn giữ của iOS trên liên kết, không thì vuốt thành kéo link. */
    touch-action: pan-y; user-select: none; -webkit-user-select: none;
    -webkit-user-drag: none; -webkit-touch-callout: none;
    -webkit-tap-highlight-color: transparent;
  }
  .app-yt-icon { font-size: 22px; line-height: 1; flex: none; }
  .app-yt-mo .app-menu-chu b { font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .app-yt-goi { margin: 8px 6px 0; font-size: 11.5px; color: var(--nm-ink-soft, #64748b); }
  .app-yt-goi[hidden], .app-yt-trong[hidden] { display: none; }

  /* Cá nhân luôn nằm DƯỚI CÙNG menu: bảng là cột flex, khối này đẩy hết
     khoảng trống lên trên nó. */
  .app-menu-cuoi {
    margin-top: auto; padding-top: 12px;
    border-top: 1px solid var(--kinh-vien, rgba(100, 116, 139, .25));
  }
  .app-menu-ca-nhan { cursor: pointer; -webkit-tap-highlight-color: transparent; }
  .app-menu-ca-nhan svg { width: 26px; height: 26px; flex: none; color: var(--nm-ink-soft, #64748b); }
  .app-menu-chu { display: flex; flex-direction: column; min-width: 0; line-height: 1.25; }
  .app-menu-chu small { font-size: 12px; font-weight: 500; color: var(--nm-ink-soft, #64748b);
                        overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  /* --- Bảng "Cá nhân" trượt lên từ đáy ---------------------------------- */
  .la-webapp .app-sheet-nen {
    display: block;
    position: fixed; inset: 0; z-index: 60;
    background: rgba(31, 42, 58, 0.45);
    opacity: 0; visibility: hidden;
    transition: opacity 0.18s ease;
    /* Chặn chạm-kéo xuyên qua lớp nền làm trang phía sau cuộn theo. */
    touch-action: none;
  }
  .la-webapp .app-sheet {
    display: block;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 61;
    max-height: 80vh; overflow-y: auto;
    /* Cuộn hết nội dung trong bảng thì dừng, không đẩy tiếp trang phía sau. */
    overscroll-behavior: contain;
    padding: 8px 12px calc(16px + env(safe-area-inset-bottom, 0px));
    border-radius: 22px 22px 0 0;
    background: var(--nm-bg, #e9edf2);
    box-shadow: 0 -10px 30px rgba(31, 42, 58, 0.22);
    transform: translateY(100%);
    /* ĐÓNG THÌ ẨN HẲN, không chỉ đẩy xuống dưới mép khung. iOS 26 vẽ trang
       lấn ra sau thanh kính "^ v ✓" của bàn phím, nên bảng nấp ngay dưới mép
       khung lộ ra thành mảng nền vàng có vạch vuốt và tên người dùng sau thanh
       ấy (người dùng chụp màn hình trang Hỏi AI, 28/10/2026). `visibility`
       đổi TRỄ 0.22s lúc đóng cho hoạt ảnh trượt xuống chạy hết đã. */
    visibility: hidden;
    transition: transform 0.22s ease, visibility 0s linear 0.22s;
  }
  /* Mở bảng: checkbox được tick (bấm vào mục "Cá nhân"). */
  .la-webapp .app-mo-sheet:checked ~ .app-sheet-nen { opacity: 1; visibility: visible; }
  .la-webapp .app-mo-sheet:checked ~ .app-sheet {
    transform: translateY(0);
    visibility: visible;
    transition: transform 0.22s ease, visibility 0s;
  }

  /* Bảng đang mở thì khoá cuộn cả trang phía sau - nếu không, vuốt trên
     bảng sẽ kéo trang bên dưới trôi theo. Khoá ở cả <html> lẫn <body>:
     tuỳ trình duyệt mà phần tử cuộn thật là cái nào. */
  .la-webapp:has(.app-mo-sheet:checked),
  .la-webapp body:has(.app-mo-sheet:checked) {
    overflow: hidden;
  }

  .app-sheet-dau {
    display: flex; align-items: center; gap: 12px;
    padding: 12px 10px 14px;
  }
  /* Thanh vuốt nhỏ ở trên cùng cho giống ứng dụng. */
  .app-sheet-dau::before {
    content: ""; position: absolute; top: 8px; left: 50%;
    width: 40px; height: 4px; margin-left: -20px; border-radius: 999px;
    background: rgba(127, 145, 170, 0.4);
  }
  .app-sheet-ten {
    flex: 1; font-size: 15px; font-weight: 700;
    color: var(--nm-ink, #1f2a3a);
  }
  /* Dấu × màu ĐỎ: cùng một màu với mục "Thoát" ở cuối bảng - hai thứ duy
     nhất trong bảng này làm biến mất cái gì đó.

     Dùng var(--nm-red) chứ không ghi cứng #dc2626: biến đó có bản riêng cho
     nền tối (#f87171), ghi cứng bản nền sáng thì trên nền tối tương phản tụt
     xuống 2.78 - dưới cả ngưỡng chữ to. */
  .app-sheet-dong {
    width: 32px; height: 32px; flex: none; cursor: pointer;
    display: grid; place-items: center;
    font-size: 20px; line-height: 1; border-radius: 50%;
    color: var(--nm-red, #dc2626);
    background: var(--nm-bg, #e9edf2);
    box-shadow: var(--nm-out-sm, 3px 3px 7px #c5cedb, -3px -3px 7px #fff);
  }
  /* Bấm vào thì lõm xuống như mọi nút khác của theme - nút tròn mà bấm
     không phản hồi gì thì tưởng bấm trượt. */
  .app-sheet-dong:active {
    box-shadow: var(--nm-in-sm, inset 2px 2px 5px #c5cedb, inset -2px -2px 5px #fff);
  }

  .app-nhom {
    padding: 12px 12px 8px;
    font-size: 11px; font-weight: 700; letter-spacing: 0.07em;
    text-transform: uppercase; color: var(--nm-ink-soft, #64748b);
  }

  /* Mỗi chức năng là một dòng danh sách. */
  .app-dong {
    display: flex; align-items: center; gap: 14px; width: 100%;
    padding: 14px 16px; margin-bottom: 8px;
    border: 0; cursor: pointer; text-align: left;
    border-radius: var(--nm-r-sm, 12px);
    font-size: 14.5px; font-family: inherit;
    color: var(--nm-ink, #1f2a3a) !important; text-decoration: none !important;
    background: var(--nm-bg, #e9edf2);
    box-shadow: var(--nm-out-sm, 3px 3px 7px #c5cedb, -3px -3px 7px #fff);
    box-sizing: border-box;
  }
  .app-dong:active {
    box-shadow: var(--nm-in-sm, inset 2px 2px 5px #c5cedb, inset -2px -2px 5px #fff);
  }

  /* Nút đổi nền sáng/tối mang thêm lớp .theme-toggle của Django, và
     dark_mode.css đặt sẵn cho lớp đó:

         margin-inline-start: 5px;
         margin-top: -1px;

     Luật trên (.app-dong) chỉ khai margin-bottom nên hai lề kia sống sót:
     riêng dòng "Đổi nền sáng / tối" bị đẩy sang phải 5px và lên trên 1px,
     trong khi mọi dòng khác thẳng hàng - đo ra đúng +5 / -1. Mấy thứ khác
     của .theme-toggle (padding: 0, background: transparent) thì không sao vì
     app-nav.css nạp sau, cùng độ ưu tiên nên thắng.

     Khai lại bằng margin rút gọn để sau này Django có thêm lề nào nữa cũng
     bị quét sạch, khỏi phải đuổi theo từng thuộc tính. */
  .app-dong.theme-toggle { margin: 0 0 8px; }
  .app-dong-icon { font-size: 19px; line-height: 1; flex: none; }
  .app-dong-ten { flex: 1; }
  /* line-height: 1 BẮT BUỘC. Chữ 20px mà để giãn dòng mặc định thì hộp chữ
     cao ~23px, kéo cả dòng cao thêm 7px so với những dòng không có mũi tên -
     nhìn ra ngay là một ô lệch khỏi hàng. */
  .app-dong-mui {
    font-size: 20px; line-height: 1; flex: none;
    color: var(--nm-ink-soft, #64748b);
  }

  .app-dong-thoat { color: var(--nm-red, #dc2626) !important; }
}

/* --- Cách chuyển cảnh giữa hai trang ------------------------------------
   Hai thanh: TẮT HẲN hoạt ảnh. Ảnh cũ ẩn ngay, ảnh mới hiện ngay - không
   mờ dần, không trượt. Mắt đọc ra là "thanh không hề đổi".

   Để mặc định thì chúng mờ chồng lên nhau một nhịp, ra đúng cái chớp đang
   phải bỏ. */
::view-transition-old(pl-thanh-tren),
::view-transition-old(pl-thanh-day) {
  animation: none;
  opacity: 0;
}
::view-transition-new(pl-thanh-tren),
::view-transition-new(pl-thanh-day) {
  animation: none;
  opacity: 1;
}
::view-transition-group(pl-thanh-tren),
::view-transition-group(pl-thanh-day) {
  animation: none;
}

/* Phần nội dung: hoà mềm thật nhanh. Dài hơn là thành hiệu ứng để ngắm,
   mà người dùng đang chờ trang chứ không chờ hoạt ảnh. */
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 0.18s;
}

/* Máy đã bật "giảm chuyển động": bỏ hẳn hoà mềm, đổi phắt sang trang mới.
   Chuyển cảnh vẫn chạy nên hai thanh vẫn đứng yên - đó là thứ giúp đỡ chóng
   mặt, không phải thứ gây ra. */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation: none;
  }
}

/* --- Vạch báo đang chuyển trang -----------------------------------------
   spa.js gắn lớp .dang-chuyen-trang lên <html> trong lúc tải trang mới.

   HOÃN 0,3 GIÂY rồi mới hiện. Trang trong mạng nội bộ thường về trong vài
   chục mili giây; hiện vạch ngay là người dùng thấy một tia loé lên ở mọi
   cú bấm - lại đúng thứ "nháy" đang đi chữa, chỉ đổi chỗ. Hoãn một nhịp thì
   lần chuyển nhanh không hiện gì cả, còn lần nào chậm thật mới có vạch để
   biết máy đang làm việc chứ không phải treo.

   Đặt trên <html> chứ không chèn thẻ mới vào trang: thêm bớt thẻ thật là
   đụng vào bố cục, mà ::before thì không.

   Không đặt view-transition-name: vạch này chỉ sống trong lúc chờ, để nó
   tham gia chuyển cảnh chỉ tổ chớp thêm một cái nữa. */
.dang-chuyen-trang::before {
  content: "";
  position: fixed;
  top: 0;
  left: 0;
  height: 2px;
  width: 0;
  z-index: 100;
  background: var(--nm-accent, #2563eb);
  pointer-events: none;
  /* Chạy nhanh lúc đầu rồi chậm dần và KHÔNG bao giờ tới 100%: chưa tải
     xong mà vạch đã đầy thì người dùng tưởng máy treo. Tải xong là lớp bị
     gỡ, vạch biến mất luôn. */
  animation: plc-vach-tai 8s cubic-bezier(0.15, 0.85, 0.25, 1) 0.3s forwards;
}
@keyframes plc-vach-tai {
  from { width: 0; }
  to   { width: 92%; }
}

/* --- Banner thông báo đẩy khi đang mở ứng dụng --------------------------- */
/* Dựng bởi static/js/bao-trong-app.js. Dính đầu màn hình, né tai thỏ, nằm
   trên mọi thứ kể cả thanh trên. */
.app-bao-day {
  position: fixed; z-index: 10000;
  top: calc(env(safe-area-inset-top, 0px) + 8px);
  left: 50%; transform: translateX(-50%);
  width: min(560px, calc(100% - 20px));
  display: flex; align-items: center; gap: 10px;
  padding: 11px 10px 11px 14px;
  border-radius: 16px;
  background: var(--nm-bg, #e9edf2);
  box-shadow: 0 10px 30px rgba(15, 23, 42, .28);
  border-left: 4px solid var(--nm-accent, #2563eb);
  color: var(--nm-ink, #1f2a3a);
  font-size: 13px; line-height: 1.35;
  animation: app-bao-day-vao .25s ease-out;
}
.app-bao-day[hidden] { display: none; }
@keyframes app-bao-day-vao {
  from { opacity: 0; transform: translate(-50%, -12px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}
.app-bao-day-chu { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.app-bao-day-tieu-de { font-weight: 700; }
.app-bao-day-noi-dung {
  color: var(--nm-ink-soft, #64748b);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.app-bao-day-xem {
  flex: none; padding: 6px 12px; border-radius: 999px;
  background: var(--nm-accent, #2563eb); color: #fff !important;
  font-size: 12px; font-weight: 600; text-decoration: none !important;
}
.app-bao-day-dong {
  flex: none; border: 0; background: none; cursor: pointer;
  font-family: inherit; font-size: 18px; line-height: 1;
  color: var(--nm-ink-soft, #64748b);
}

/* ===== VUỐT LÊN ẨN HAI THANH, VUỐT XUỐNG HIỆN LẠI =========================
   Như Safari trên iPhone: cuộn nội dung lên (đọc tiếp xuống dưới) thì thanh
   trên trượt lên khỏi màn hình, thanh đáy trượt xuống - nhường trọn màn hình
   cho nội dung; cuộn ngược lại là cả hai trượt về. Lớp .an-thanh trên <html>
   do script "VUỐT ẨN / HIỆN HAI THANH" cuối base_site.html bật tắt.

   transform CHỈ đặt lúc ĐANG ẨN (lúc hiện là none): transform biến thanh
   thành khung chứa của các thẻ position: fixed bên trong nó (nền chắn của
   bảng chuông nằm trong thanh trên) - để transform thường trực là bảng chuông
   bị giam trong thanh. Script không bao giờ ẩn khi bảng chuông đang mở.

   Thanh đáy trượt thêm 40px: nút Hỏi AI nhô lên trên mép thanh ~37px, trượt
   đúng 100% thì cái đĩa còn lơ lửng ở đáy màn hình. */
@media (max-width: 860px) {
  .la-webapp body:not(.login) .app-tren,
  .la-webapp .app-nav {
    transition: transform 0.28s cubic-bezier(0.2, 0.8, 0.2, 1);
  }
  .la-webapp.an-thanh body:not(.login) .app-tren {
    transform: translateY(-100%);
  }
  /* Thanh NỔI cách đáy một khoảng (`bottom` của .app-nav) - trượt thêm đúng
     khoảng ấy, không thì đỉnh nút EVN còn ló lên ở đáy màn hình (đã gặp). */
  .la-webapp.an-thanh .app-nav {
    transform: translateY(calc(100% + 48px
      + max(8px, calc(env(safe-area-inset-bottom, 0px) - 12px))));
  }
}
@media (prefers-reduced-motion: reduce) {
  .la-webapp body:not(.login) .app-tren,
  .la-webapp .app-nav { transition: none; }
}

/* Ô trống giữ chỗ cho mục thanh đáy bị ẩn vì không có quyền (base_site.html). */
.app-nav-trong { pointer-events: none; visibility: hidden; }

/* Không phóng to khi chạm đúp (người dùng yêu cầu trang luôn vừa màn điện
   thoại) - `manipulation` vẫn cho cuộn bình thường. Chụm hai ngón chặn ở
   script cuối base_site.html. */
html { touch-action: manipulation; }
