/* Minification failed. Returning unminified contents.
(2,5): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(8,15): run-time error CSS1039: Token not allowed after unary operator: '-web-space-2'
(18,33): run-time error CSS1039: Token not allowed after unary operator: '-web-ease'
(18,56): run-time error CSS1039: Token not allowed after unary operator: '-web-ease'
(18,86): run-time error CSS1039: Token not allowed after unary operator: '-web-ease'
(28,77): run-time error CSS1039: Token not allowed after unary operator: '-btn-shine'
(85,22): run-time error CSS1039: Token not allowed after unary operator: '-web-primary'
(86,17): run-time error CSS1039: Token not allowed after unary operator: '-web-white'
(87,41): run-time error CSS1039: Token not allowed after unary operator: '-web-btn-shadow'
(91,43): run-time error CSS1039: Token not allowed after unary operator: '-web-btn-shadow'
(96,43): run-time error CSS1039: Token not allowed after unary operator: '-web-btn-shadow'
(102,22): run-time error CSS1039: Token not allowed after unary operator: '-web-white'
(103,17): run-time error CSS1039: Token not allowed after unary operator: '-web-primary'
(104,24): run-time error CSS1039: Token not allowed after unary operator: '-web-primary'
(105,22): run-time error CSS1039: Token not allowed after unary operator: '-web-shadow-lg'
(113,66): run-time error CSS1039: Token not allowed after unary operator: '-web-shadow-lg'
(118,66): run-time error CSS1039: Token not allowed after unary operator: '-web-shadow-lg'
(126,21): run-time error CSS1039: Token not allowed after unary operator: '-web-text-sm'
(127,23): run-time error CSS1039: Token not allowed after unary operator: '-web-text-md-lh'
(129,25): run-time error CSS1039: Token not allowed after unary operator: '-web-radius-sm'
(130,22): run-time error CSS1039: Token not allowed after unary operator: '-web-shadow-xs'
(134,66): run-time error CSS1039: Token not allowed after unary operator: '-web-shadow-xs'
(139,66): run-time error CSS1039: Token not allowed after unary operator: '-web-shadow-xs'
(160,9): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(161,22): run-time error CSS1039: Token not allowed after unary operator: '-glint'
(208,5): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(209,22): run-time error CSS1039: Token not allowed after unary operator: '-web-white'
(210,17): run-time error CSS1039: Token not allowed after unary operator: '-web-primary'
(211,24): run-time error CSS1039: Token not allowed after unary operator: '-web-white'
(212,22): run-time error CSS1039: Token not allowed after unary operator: '-web-shadow-md'
(216,66): run-time error CSS1039: Token not allowed after unary operator: '-web-shadow-md'
(221,66): run-time error CSS1039: Token not allowed after unary operator: '-web-shadow-md'
(241,15): run-time error CSS1039: Token not allowed after unary operator: '-web-space-4'
(242,16): run-time error CSS1039: Token not allowed after unary operator: '-btn-row-zoom'
(243,34): run-time error CSS1039: Token not allowed after unary operator: '-btn-row-zoom'
(247,5): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(255,25): run-time error CSS1039: Token not allowed after unary operator: '-web-space-4'
(257,22): run-time error CSS1039: Token not allowed after unary operator: '-web-accent-50'
(258,17): run-time error CSS1039: Token not allowed after unary operator: '-web-accent-dark'
(259,21): run-time error CSS1039: Token not allowed after unary operator: '-web-text-sm'
(260,23): run-time error CSS1039: Token not allowed after unary operator: '-web-text-sm-lh'
(269,21): run-time error CSS1039: Token not allowed after unary operator: '-web-section-title'
(270,23): run-time error CSS1039: Token not allowed after unary operator: '-web-section-title-lh'
(273,17): run-time error CSS1039: Token not allowed after unary operator: '-web-gray-900'
(279,17): run-time error CSS1039: Token not allowed after unary operator: '-web-primary'
(300,21): run-time error CSS1039: Token not allowed after unary operator: '-section-copy-max'
(302,22): run-time error CSS1039: Token not allowed after unary operator: '-web-space-3'
(303,21): run-time error CSS1039: Token not allowed after unary operator: '-web-text-xl'
(304,23): run-time error CSS1039: Token not allowed after unary operator: '-web-text-xl-lh'
(305,17): run-time error CSS1039: Token not allowed after unary operator: '-web-gray-700'
(337,45): run-time error CSS1039: Token not allowed after unary operator: '-hm-f'
(365,70): run-time error CSS1039: Token not allowed after unary operator: '-stat-in'
(369,9): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(373,9): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(387,24): run-time error CSS1039: Token not allowed after unary operator: '-news-media-ratio'
(389,22): run-time error CSS1039: Token not allowed after unary operator: '-web-gray-50'
(407,32): run-time error CSS1039: Token not allowed after unary operator: '-web-ease'
(418,28): run-time error CSS1039: Token not allowed after unary operator: '-web-ease'
(424,21): run-time error CSS1039: Token not allowed after unary operator: '-web-primary'
(443,55): run-time error CSS1039: Token not allowed after unary operator: '-web-gray-50'
(443,82): run-time error CSS1039: Token not allowed after unary operator: '-web-gray-100'
(444,29): run-time error CSS1039: Token not allowed after unary operator: '-web-gray-300'
(445,17): run-time error CSS1039: Token not allowed after unary operator: '-web-gray-600'
(454,15): run-time error CSS1039: Token not allowed after unary operator: '-web-space-2'
(455,23): run-time error CSS1039: Token not allowed after unary operator: '-web-space-3'
(467,27): run-time error CSS1039: Token not allowed after unary operator: '-web-text-md-lh'
(468,27): run-time error CSS1039: Token not allowed after unary operator: '-web-text-md-lh'
(469,21): run-time error CSS1039: Token not allowed after unary operator: '-web-text-md'
(470,23): run-time error CSS1039: Token not allowed after unary operator: '-web-text-md-lh'
(472,17): run-time error CSS1039: Token not allowed after unary operator: '-web-news-title'
(481,37): run-time error CSS1039: Token not allowed after unary operator: '-web-primary'
(499,21): run-time error CSS1039: Token not allowed after unary operator: '-web-text-sm'
(500,23): run-time error CSS1039: Token not allowed after unary operator: '-web-text-sm-lh'
(502,17): run-time error CSS1039: Token not allowed after unary operator: '-web-news-meta'
(511,25): run-time error CSS1039: Token not allowed after unary operator: '-web-news-title'
(517,21): run-time error CSS1039: Token not allowed after unary operator: '-web-news-title'
(523,21): run-time error CSS1039: Token not allowed after unary operator: '-web-text-md'
(524,23): run-time error CSS1039: Token not allowed after unary operator: '-web-text-md-lh'
(525,17): run-time error CSS1039: Token not allowed after unary operator: '-web-news-body'
(539,21): run-time error CSS1039: Token not allowed after unary operator: '-web-primary'
(547,15): run-time error CSS1039: Token not allowed after unary operator: '-web-space-3'
(551,21): run-time error CSS1039: Token not allowed after unary operator: '-web-ecosystem-content'
(560,54): run-time error CSS1039: Token not allowed after unary operator: '-web-primary-900'
(560,84): run-time error CSS1039: Token not allowed after unary operator: '-web-primary'
(570,17): run-time error CSS1039: Token not allowed after unary operator: '-web-yellow'
(574,22): run-time error CSS1039: Token not allowed after unary operator: '-web-space-3'
(575,21): run-time error CSS1039: Token not allowed after unary operator: '-web-text-lg'
(576,23): run-time error CSS1039: Token not allowed after unary operator: '-web-text-lg-lh'
(581,22): run-time error CSS1039: Token not allowed after unary operator: '-web-yellow'
(582,17): run-time error CSS1039: Token not allowed after unary operator: '-web-gray-900'
(583,41): run-time error CSS1039: Token not allowed after unary operator: '-web-btn-shadow'
(587,16): run-time error CSS1039: Token not allowed after unary operator: '-btn-row-zoom'
(591,39): run-time error CSS1039: Token not allowed after unary operator: '-web-btn-shadow'
(596,43): run-time error CSS1039: Token not allowed after unary operator: '-web-btn-shadow'
(601,5): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(602,5): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(603,5): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(604,5): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(605,5): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(623,21): run-time error CSS1039: Token not allowed after unary operator: '-link-pad-x'
(624,17): run-time error CSS1039: Token not allowed after unary operator: '-link-color'
(625,21): run-time error CSS1039: Token not allowed after unary operator: '-link-size'
(626,23): run-time error CSS1039: Token not allowed after unary operator: '-link-lh'
(635,20): run-time error CSS1039: Token not allowed after unary operator: '-link-pad-x'
(636,21): run-time error CSS1039: Token not allowed after unary operator: '-link-pad-x'
(646,21): run-time error CSS1039: Token not allowed after unary operator: '-link-color-hover'
(651,21): run-time error CSS1039: Token not allowed after unary operator: '-link-color-hover'
(701,5): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(702,5): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(703,5): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(714,25): run-time error CSS1039: Token not allowed after unary operator: '-web-radius-card'
(717,34): run-time error CSS1039: Token not allowed after unary operator: '-web-ease'
(738,28): run-time error CSS1039: Token not allowed after unary operator: '-web-accent-50'
(740,22): run-time error CSS1039: Token not allowed after unary operator: '-web-accent-100'
(754,21): run-time error CSS1039: Token not allowed after unary operator: '-web-text-xl'
(755,23): run-time error CSS1039: Token not allowed after unary operator: '-web-text-xl-lh'
(756,17): run-time error CSS1039: Token not allowed after unary operator: '-web-gray-900'
(760,21): run-time error CSS1039: Token not allowed after unary operator: '-web-text-md'
(761,23): run-time error CSS1039: Token not allowed after unary operator: '-web-text-md-lh'
(762,17): run-time error CSS1039: Token not allowed after unary operator: '-web-gray-600'
(766,21): run-time error CSS1039: Token not allowed after unary operator: '-web-text-sm'
(767,23): run-time error CSS1039: Token not allowed after unary operator: '-web-text-sm-lh'
(769,17): run-time error CSS1039: Token not allowed after unary operator: '-web-accent-dark'
(775,15): run-time error CSS1039: Token not allowed after unary operator: '-news-side-top'
(775,41): run-time error CSS1039: Token not allowed after unary operator: '-web-header-h'
(775,63): run-time error CSS1039: Token not allowed after unary operator: '-web-space-6'
(778,15): run-time error CSS1039: Token not allowed after unary operator: '-web-space-8'
(809,15): run-time error CSS1039: Token not allowed after unary operator: '-web-space-2'
(810,19): run-time error CSS1039: Token not allowed after unary operator: '-web-space-2'
(811,21): run-time error CSS1039: Token not allowed after unary operator: '-web-text-sm'
(812,23): run-time error CSS1039: Token not allowed after unary operator: '-web-text-sm-lh'
(815,17): run-time error CSS1039: Token not allowed after unary operator: '-web-primary-900'
(832,28): run-time error CSS1039: Token not allowed after unary operator: '-web-primary'
(838,35): run-time error CSS1039: Token not allowed after unary operator: '-web-rule'
(848,15): run-time error CSS1039: Token not allowed after unary operator: '-web-space-3'
(850,19): run-time error CSS1039: Token not allowed after unary operator: '-web-space-3'
(857,22): run-time error CSS1039: Token not allowed after unary operator: '-web-gray-50'
(867,36): run-time error CSS1039: Token not allowed after unary operator: '-web-ease'
(893,21): run-time error CSS1039: Token not allowed after unary operator: '-web-text-sm'
(894,23): run-time error CSS1039: Token not allowed after unary operator: '-web-text-sm-lh'
(896,17): run-time error CSS1039: Token not allowed after unary operator: '-web-news-title'
(897,28): run-time error CSS1039: Token not allowed after unary operator: '-web-ease'
(901,17): run-time error CSS1039: Token not allowed after unary operator: '-web-primary'
(906,21): run-time error CSS1039: Token not allowed after unary operator: '-web-primary'
(914,21): run-time error CSS1039: Token not allowed after unary operator: '-web-text-xs'
(916,17): run-time error CSS1039: Token not allowed after unary operator: '-web-news-meta'
(937,5): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(938,5): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(939,5): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(940,5): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(944,19): run-time error CSS1039: Token not allowed after unary operator: '-web-z-fab'
(968,22): run-time error CSS1039: Token not allowed after unary operator: '-fab-bg'
(969,17): run-time error CSS1039: Token not allowed after unary operator: '-web-white'
(970,22): run-time error CSS1039: Token not allowed after unary operator: '-web-shadow-lg'
(972,32): run-time error CSS1039: Token not allowed after unary operator: '-web-ease'
(987,32): run-time error CSS1039: Token not allowed after unary operator: '-web-white'
(987,60): run-time error CSS1039: Token not allowed after unary operator: '-web-gray-700'
(1002,22): run-time error CSS1039: Token not allowed after unary operator: '-web-white'
(1022,5): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(1026,5): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(1030,5): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(1069,25): run-time error CSS1039: Token not allowed after unary operator: '-web-radius-sm'
(1070,22): run-time error CSS1039: Token not allowed after unary operator: '-web-gray-900'
(1071,17): run-time error CSS1039: Token not allowed after unary operator: '-web-white'
(1077,30): run-time error CSS1039: Token not allowed after unary operator: '-web-ease'
(1092,24): run-time error CSS1039: Token not allowed after unary operator: '-fab-mascot-shift'
(1101,17): run-time error CSS1039: Token not allowed after unary operator: '-fab-mascot-w'
(1102,18): run-time error CSS1039: Token not allowed after unary operator: '-fab-mascot-h'
(1112,32): run-time error CSS1039: Token not allowed after unary operator: '-web-ease'
(1123,32): run-time error CSS1039: Token not allowed after unary operator: '-web-white'
(1123,60): run-time error CSS1039: Token not allowed after unary operator: '-web-gray-700'
(1131,17): run-time error CSS1039: Token not allowed after unary operator: '-fab-mascot-w'
(1132,18): run-time error CSS1039: Token not allowed after unary operator: '-fab-mascot-h'
(1159,28): run-time error CSS1039: Token not allowed after unary operator: '-web-accent'
(1182,30): run-time error CSS1030: Expected identifier, found ':'
(1182,44): run-time error CSS1031: Expected selector, found ')'
(1182,44): run-time error CSS1025: Expected comma or open brace, found ')'
(1216,32): run-time error CSS1039: Token not allowed after unary operator: '-fab-avatar-d'
(1216,63): run-time error CSS1039: Token not allowed after unary operator: '-anim-frames'
(1216,88): run-time error CSS1039: Token not allowed after unary operator: '-fab-avatar-d'
(1251,22): run-time error CSS1039: Token not allowed after unary operator: '-fab-mascot-w'
(1251,44): run-time error CSS1039: Token not allowed after unary operator: '-fab-mascot-shift'
(1260,18): run-time error CSS1039: Token not allowed after unary operator: '-fab-mascot-h'
(1269,30): run-time error CSS1039: Token not allowed after unary operator: '-web-ease'
(1269,57): run-time error CSS1039: Token not allowed after unary operator: '-web-ease'
(1280,28): run-time error CSS1039: Token not allowed after unary operator: '-web-white'
(1286,17): run-time error CSS1039: Token not allowed after unary operator: '-web-gray-900'
(1301,10): run-time error CSS1030: Expected identifier, found '.'
(1301,45): run-time error CSS1031: Expected selector, found ')'
(1301,45): run-time error CSS1025: Expected comma or open brace, found ')'
(1307,9): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(1308,9): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(1309,9): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(1331,36): run-time error CSS1039: Token not allowed after unary operator: '-fab-mascot-w'
(1331,58): run-time error CSS1039: Token not allowed after unary operator: '-anim-frames'
(1392,25): run-time error CSS1039: Token not allowed after unary operator: '-rv-x'
(1392,40): run-time error CSS1039: Token not allowed after unary operator: '-rv-y'
(1393,21): run-time error CSS1039: Token not allowed after unary operator: '-rv-s'
(1419,65): run-time error CSS1039: Token not allowed after unary operator: '-rv-d'
(1423,9): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(1424,9): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(1425,9): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(1426,73): run-time error CSS1039: Token not allowed after unary operator: '-rv-d'
(1429,33): run-time error CSS1030: Expected identifier, found '.'
(1429,64): run-time error CSS1031: Expected selector, found ')'
(1429,64): run-time error CSS1025: Expected comma or open brace, found ')'
(1468,25): run-time error CSS1039: Token not allowed after unary operator: '-web-text-sm'
(1563,15): run-time error CSS1039: Token not allowed after unary operator: '-web-space-4'
(1569,15): run-time error CSS1039: Token not allowed after unary operator: '-web-space-4'
(1579,15): run-time error CSS1039: Token not allowed after unary operator: '-web-space-2'
(1585,21): run-time error CSS1039: Token not allowed after unary operator: '-web-text-sm'
(1586,23): run-time error CSS1039: Token not allowed after unary operator: '-web-text-sm-lh'
(1588,17): run-time error CSS1039: Token not allowed after unary operator: '-web-gray-700'
(1592,17): run-time error CSS1039: Token not allowed after unary operator: '-web-accent'
(1602,21): run-time error CSS1039: Token not allowed after unary operator: '-web-text-md'
(1603,23): run-time error CSS1039: Token not allowed after unary operator: '-web-text-md-lh'
(1604,17): run-time error CSS1039: Token not allowed after unary operator: '-web-gray-900'
(1607,22): run-time error CSS1039: Token not allowed after unary operator: '-web-white'
(1608,28): run-time error CSS1039: Token not allowed after unary operator: '-web-gray-300'
(1609,25): run-time error CSS1039: Token not allowed after unary operator: '-web-radius-sm'
(1610,35): run-time error CSS1039: Token not allowed after unary operator: '-web-ease'
(1610,63): run-time error CSS1039: Token not allowed after unary operator: '-web-ease'
(1615,21): run-time error CSS1039: Token not allowed after unary operator: '-web-gray-500'
(1626,28): run-time error CSS1039: Token not allowed after unary operator: '-web-primary'
(1633,36): run-time error CSS1039: Token not allowed after unary operator: '-web-primary-200'
(1638,28): run-time error CSS1039: Token not allowed after unary operator: '-web-yellow-800'
(1642,21): run-time error CSS1039: Token not allowed after unary operator: '-web-text-xs'
(1645,17): run-time error CSS1039: Token not allowed after unary operator: '-web-yellow-800'
(1653,21): run-time error CSS1039: Token not allowed after unary operator: '-web-text-sm'
(1654,23): run-time error CSS1039: Token not allowed after unary operator: '-web-text-sm-lh'
(1657,25): run-time error CSS1039: Token not allowed after unary operator: '-web-radius-sm'
(1665,21): run-time error CSS1039: Token not allowed after unary operator: '-web-accent-dark'
(1666,26): run-time error CSS1039: Token not allowed after unary operator: '-web-accent-50'
(1670,21): run-time error CSS1039: Token not allowed after unary operator: '-web-text-xs'
(1672,17): run-time error CSS1039: Token not allowed after unary operator: '-web-gray-600'
 */
.web-btn {
    --btn-shine: rgba(255, 255, 255, .75);
    position: relative;
    overflow: hidden;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--web-space-2);
    padding: 14px 24px;
    border: 1.5px solid transparent;
    border-radius: 16px;
    font-family: inherit;
    font-size: 18px;
    line-height: 28px;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
    transition: background var(--web-ease), color var(--web-ease), border-color var(--web-ease), transform .3s ease, box-shadow .3s ease;
}

    .web-btn::after {
        content: "";
        position: absolute;
        top: 0;
        left: -20%;
        width: 45%;
        height: 100%;
        background: linear-gradient(100deg, rgba(255, 255, 255, 0) 0%, var(--btn-shine) 50%, rgba(255, 255, 255, 0) 100%);
        transform: translateX(-150%) skewX(-20deg);
        pointer-events: none;
        z-index: 2;
    }

    .web-btn:focus-visible::after {
        transform: translateX(280%) skewX(-20deg);
        transition: transform .75s cubic-bezier(.4, 0, .2, 1);
    }

@media (hover: hover) and (pointer: fine) and (min-width: 1025px) {
    .web-btn:hover::after {
        transform: translateX(280%) skewX(-20deg);
        transition: transform .75s cubic-bezier(.4, 0, .2, 1);
    }
}

/* --- HOVER: NHẤC LÊN 4px --------------------------------------- 08/08/2026 --
      Yêu cầu: "nút chạy lên giống ở phần thông tin liên hệ". Lấy đúng 2 con số của
      `.contact-col:hover` — `translateY(-4px)` + `.3s ease` (bản thân 2 số đó chép
      từ BẢN LIVE `.contact-card:hover`, xem ghi chú nội bộ của Designer).
   
      📌 BÓNG thì CỐ Ý khác thẻ Liên hệ. Thẻ Liên hệ lúc nghỉ KHÔNG có bóng nên bóng
      xanh lá 12% là bóng DUY NHẤT của nó; nút thì đã có bóng riêng theo variant, và
      nút primary nền xanh DƯƠNG — dán bóng xanh lá vào là lệch hệ màu. Nên hover chỉ
      làm ĐẬM/XA thêm bóng sẵn có, khai riêng cho từng variant bên dưới.
   
      ⚠ SPECIFICITY CÓ CHỦ ĐÍCH — `.web-btn:hover` = (0,2,0), CAO HƠN
      `.web-btn-primary` (0,1,0). Nếu đặt `box-shadow` ở rule chung này thì nó đè
      bóng lúc nghỉ của cả 3 variant. Vì vậy: `transform` ở rule chung, `box-shadow`
      ở rule variant. Bài học cascade ghi chú nội bộ của Designer — thắng bằng specificity,
      đừng dựa vào thứ tự dòng.
   
      ⚠ GHI CHO LÚC PORT: `transform` này nằm TRONG phần tử có `zoom` (`.hero` dùng
      `--hero-zoom`, `.web-btn-row` dùng `--btn-row-zoom`) nên 4px bị co theo — đo ở
      1536 nhấc thật ~3.1px. Trên trang KHÔNG có hero thì `--btn-row-zoom` = 1 nên
      nhấc đủ 4px; đó là đúng, không phải lệch.
      Đây là đúng tinh thần "chữ + ảnh + khoảng cách co cùng lúc" ở mục 3.1, KHÔNG
      phải lỗi. Bỏ `zoom` khi port thì 4px tự về đúng 4px, không phải sửa gì thêm. */
.web-btn:focus-visible {
    transform: translateY(-4px);
}

@media (hover: hover) and (pointer: fine) and (min-width: 1025px) {
    .web-btn:hover {
        transform: translateY(-4px);
    }
}

@media (hover: hover) and (pointer: fine) and (min-width: 1025px) {
    .web-btn:active {
        transform: translateY(-1px);
    }
}

.web-btn-primary {
    background: var(--web-primary);
    color: var(--web-white);
    box-shadow: 0 12px 21.6px -4px var(--web-btn-shadow), 0 4px 6px -2px rgba(118, 146, 235, 0.03);
}

    .web-btn-primary:focus-visible {
        box-shadow: 0 18px 28px -6px var(--web-btn-shadow), 0 6px 8px -2px rgba(118, 146, 235, 0.06);
    }

@media (hover: hover) and (pointer: fine) and (min-width: 1025px) {
    .web-btn-primary:hover {
        box-shadow: 0 18px 28px -6px var(--web-btn-shadow), 0 6px 8px -2px rgba(118, 146, 235, 0.06);
    }
}

.web-btn-secondary {
    overflow: visible;
    background: var(--web-white);
    color: var(--web-primary);
    border-color: var(--web-primary);
    box-shadow: var(--web-shadow-lg);
}

    .web-btn-secondary::after {
        display: none;
    }

    .web-btn-secondary:focus-visible {
        box-shadow: 0 8px 18px -4px rgba(44, 71, 158, .18), var(--web-shadow-lg);
    }

@media (hover: hover) and (pointer: fine) and (min-width: 1025px) {
    .web-btn-secondary:hover {
        box-shadow: 0 8px 18px -4px rgba(44, 71, 158, .18), var(--web-shadow-lg);
    }
}


.web-btn.header-cta {
    flex: 0 0 auto;
    padding: 10px 16px;
    font-size: var(--web-text-sm);
    line-height: var(--web-text-md-lh);
    border-width: 0;
    border-radius: var(--web-radius-sm);
    box-shadow: var(--web-shadow-xs);
}

    .web-btn.header-cta:focus-visible {
        box-shadow: 0 6px 14px -4px rgba(44, 71, 158, .35), var(--web-shadow-xs);
    }

@media (hover: hover) and (pointer: fine) and (min-width: 1025px) {
    .web-btn.header-cta:hover {
        box-shadow: 0 6px 14px -4px rgba(44, 71, 158, .35), var(--web-shadow-xs);
    }
}

.web-btn-glint {
    position: absolute;
    inset: -1.5px;
    width: calc(100% + 3px);
    height: calc(100% + 3px);
    overflow: visible;
    pointer-events: none;
    z-index: 1;
}

    .web-btn-glint rect {
        x: .75px;
        y: .75px;
        width: calc(100% - 1.5px);
        height: calc(100% - 1.5px);
        rx: 16px;
        fill: none;
        --glint: #6E9BFF;
        stroke: var(--glint);
        stroke-width: 1.5px;
        stroke-linecap: round;
        filter: drop-shadow(0 0 3px rgba(110, 155, 255, .85));
        stroke-dasharray: 31.8 101.7;
        stroke-dashoffset: 31.8;
        opacity: 0;
    }

@keyframes web-btn-glint-run {
    0% {
        stroke-dashoffset: 31.8;
        opacity: 0;
    }

    12% {
        opacity: 1;
    }

    76% {
        opacity: 1;
    }

    100% {
        stroke-dashoffset: -101.7;
        opacity: 0;
    }
}

.web-btn-secondary:focus-visible .web-btn-glint rect {
    animation: web-btn-glint-run 1s ease-in-out;
}

@media (hover: hover) and (pointer: fine) and (min-width: 1025px) {
    .web-btn-secondary:hover .web-btn-glint rect {
        animation: web-btn-glint-run 1s ease-in-out;
    }
}

@media (prefers-reduced-motion: reduce) {
    .web-btn-secondary:hover .web-btn-glint rect,
    .web-btn-secondary:focus-visible .web-btn-glint rect {
        animation: none;
    }
}

.web-btn-tertiary {
    --btn-shine: rgba(44, 71, 158, .32);
    background: var(--web-white);
    color: var(--web-primary);
    border-color: var(--web-white);
    box-shadow: var(--web-shadow-md);
}

    .web-btn-tertiary:focus-visible {
        box-shadow: 0 8px 18px -4px rgba(44, 71, 158, .18), var(--web-shadow-md);
    }

@media (hover: hover) and (pointer: fine) and (min-width: 1025px) {
    .web-btn-tertiary:hover {
        box-shadow: 0 8px 18px -4px rgba(44, 71, 158, .18), var(--web-shadow-md);
    }
}

@media (prefers-reduced-motion: reduce) {
    .web-btn:hover,
    .web-btn:focus-visible,
    .web-btn:active {
        transform: none;
    }

    .web-btn::after {
        display: none;
    }
}

.web-btn-row {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--web-space-4);
    zoom: var(--btn-row-zoom);
    margin-top: calc(56px / var(--btn-row-zoom));
}

.section-heading {
    --section-copy-max: 768px;
    text-align: center;
    margin: 0 auto 40px;
}

.section-badge {
    display: inline-block;
    padding: 4px 12px;
    margin-bottom: var(--web-space-4);
    border-radius: 16px;
    background: var(--web-accent-50);
    color: var(--web-accent-dark);
    font-size: var(--web-text-sm);
    line-height: var(--web-text-sm-lh);
    font-weight: 500;
    mix-blend-mode: multiply;
}

.section-title {
    display: flex;
    flex-direction: column;
    gap: 6px;
    font-size: var(--web-section-title);
    line-height: var(--web-section-title-lh);
    letter-spacing: -0.72px;
    font-weight: 600;
    color: var(--web-gray-900);
    text-wrap: balance;
}

.section-title-accent {
    display: block;
    color: var(--web-primary);
}

@supports ((-webkit-background-clip: text) or (background-clip: text)) {
    .section-title-accent {
        background-image: linear-gradient(101.92deg, var(--web-primary-900) 0.62%, var(--web-primary) 112.33%);
        -webkit-background-clip: text;
        background-clip: text;
        -webkit-text-fill-color: transparent;
        color: transparent;
    }
}

@keyframes hm-float {
    50% {
        translate: 0 -6px;
    }
}

.section-subtitle {
    text-align: center;
    max-width: var(--section-copy-max, 768px);
    margin-inline: auto;
    margin-top: var(--web-space-3);
    font-size: var(--web-text-xl);
    line-height: var(--web-text-xl-lh);
    color: var(--web-gray-700);
}

.stat-badge-row {
    position: relative;
    z-index: 3;
    max-width: 858px;
    margin-inline: auto;
    display: flex;
    justify-content: center;
    gap: 67.2px;
    padding: 36.96px;
    border-radius: 20.16px;
    background: rgba(255, 255, 255, .7);
    backdrop-filter: blur(6.2px);
    -webkit-backdrop-filter: blur(6.2px);
    filter: drop-shadow(-13px 11px 14.75px rgba(69, 66, 140, .08));
}

.stat-badge {
    display: flex;
    gap: 15.12px;
    align-items: flex-start;
}

.stat-badge-icon {
    width: 48px;
    height: 48px;
    flex-shrink: 0;
}

.stat-badge img {
    animation: hm-float 5s ease-in-out var(--hm-f, 0s) infinite;
}


.stat-badge-count {
    font-size: 40.32px;
    line-height: 50.4px;
    letter-spacing: -0.8064px;
    font-weight: 600;
    color: #000;
}

.stat-badge-desc {
    font-size: 13.44px;
    line-height: 20.16px;
    font-weight: 500;
    color: #000;
}

@keyframes web-stat-in {
    from {
        opacity: 0;
        translate: 0 12px;
    }
}

@media (prefers-reduced-motion: no-preference) {
    .stat-badge-count {
        animation: web-stat-in .6s cubic-bezier(.22, 1, .36, 1) var(--stat-in, 300ms) both;
    }

    .stat-badge:nth-child(2) {
        --stat-in: 420ms;
    }

    .stat-badge:nth-child(3) {
        --stat-in: 540ms;
    }

    .stat-badge-count.is-stat-wait {
        animation-play-state: paused;
    }
}

.news-card {
    background: none;
    box-shadow: none;
}

.news-media {
    aspect-ratio: var(--news-media-ratio, 25 / 12);
    overflow: hidden;
    background: var(--web-gray-50);
}

    .news-media .news-thumb,
    .news-media .news-thumb--empty {
        width: 100%;
        height: 100%;
        display: block;
        object-fit: cover;
        border-radius: 0;
    }

.news-thumb-all {
    height: 250px !important
}

.news-media .news-thumb,
.news-media .news-thumb--empty {
    transition: transform var(--web-ease);
}

@media (hover: hover) and (pointer: fine) and (min-width: 1025px) {
    .news-card:hover .news-thumb,
    .news-card:hover .news-thumb--empty {
        transform: scale(1.04);
    }
}

.news-title {
    transition: color var(--web-ease);
}

@media (hover: hover) and (pointer: fine) and (min-width: 1025px) {
    .news-card:hover .news-title,
    .news-card:hover .news-title a {
        color: var(--web-primary);
    }
}

@media (prefers-reduced-motion: reduce) {
    .news-media .news-thumb,
    .news-media .news-thumb--empty {
        transition: none;
    }

    .news-card:hover .news-thumb,
    .news-card:hover .news-thumb--empty {
        transform: none;
    }
}

.news-thumb--empty {
    display: grid;
    place-items: center;
    background: repeating-linear-gradient(45deg, var(--web-gray-50) 0 12px, var(--web-gray-100) 12px 24px);
    border: 1px dashed var(--web-gray-300);
    color: var(--web-gray-600);
    font-size: 11px;
    text-align: center;
    padding: 8px;
}

.news-body {
    display: flex;
    flex-direction: column;
    gap: var(--web-space-2);
    padding-top: var(--web-space-3);
    min-width: 0;
}

.news-title {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
    /* Giữ khung đúng 2 dòng kể cả khi tiêu đề chỉ có 1 dòng -> các card đều nhau.
     max-height là fallback khi trình duyệt không hỗ trợ -webkit-line-clamp:
     khung vẫn chốt 2 dòng, meta + foot bên dưới luôn thẳng hàng. */
    min-height: calc(var(--web-text-md-lh) * 2);
    max-height: calc(var(--web-text-md-lh) * 2);
    font-size: var(--web-text-md);
    line-height: var(--web-text-md-lh);
    font-weight: 600;
    color: var(--web-news-title);
}

    .news-title a {
        color: inherit;
        text-decoration: none;
    }

        .news-title a:focus-visible {
            outline: 2px solid var(--web-primary);
            outline-offset: 2px;
        }

/* Cả card bấm được (stretched-link thuần CSS): link tiêu đề phủ kín card
       nên hover/click bất kỳ đâu trên card đều tới trang chi tiết. Link
       "Xem bài viết" cùng đích nên nằm dưới lớp phủ vẫn đúng điều hướng. */
.news-card {
    position: relative;
}

    .news-card .news-title > a::after {
        content: "";
        position: absolute;
        inset: 0;
    }

.news-meta {
    font-size: var(--web-text-sm);
    line-height: var(--web-text-sm-lh);
    font-weight: 400;
    color: var(--web-news-meta);
}

    .news-meta a {
        color: inherit;
        text-decoration: none;
    }

        .news-meta a:focus-visible {
            color: var(--web-news-title);
            text-decoration: underline;
        }

@media (hover: hover) and (pointer: fine) and (min-width: 1025px) {
    .news-meta a:hover {
        color: var(--web-news-title);
        text-decoration: underline;
    }
}

.news-excerpt {
    font-size: var(--web-text-md);
    line-height: var(--web-text-md-lh);
    color: var(--web-news-body);
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
}

    .news-excerpt a {
        color: inherit;
        text-decoration: underline;
    }

@media (hover: hover) and (pointer: fine) and (min-width: 1025px) {
    .news-excerpt a:hover {
        color: var(--web-primary);
    }
}

.news-foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--web-space-3);
}

.cta-band {
    max-width: var(--web-ecosystem-content);
    margin-inline: auto;
    min-height: 300px;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 32px;
    padding: 70px 54px;
    border-radius: 34px;
    background-image: linear-gradient(93.12deg, var(--web-primary-900) 0.62%, var(--web-primary) 112.33%);
}

.cta-band-text {
    flex: 1 1 460px;
    min-width: 0;
}

.cta-band-title {
    font-weight: 600;
    color: var(--web-yellow);
}

.cta-band-desc {
    margin-top: var(--web-space-3);
    font-size: var(--web-text-lg);
    line-height: var(--web-text-lg-lh);
    color: #FCFCFD;
}

.web-btn-yellow {
    background: var(--web-yellow);
    color: var(--web-gray-900);
    box-shadow: 0 12px 21.6px -4px var(--web-btn-shadow), 0 4px 6px -2px rgba(118, 146, 235, 0.03);
}

.cta-band .web-btn {
    zoom: var(--btn-row-zoom);
}

.web-btn-yellow:focus-visible {
    box-shadow: 0 18px 28px -6px var(--web-btn-shadow), 0 6px 8px -2px rgba(118, 146, 235, 0.06);
}

@media (hover: hover) and (pointer: fine) and (min-width: 1025px) {
    .web-btn-yellow:hover {
        box-shadow: 0 18px 28px -6px var(--web-btn-shadow), 0 6px 8px -2px rgba(118, 146, 235, 0.06);
    }
}

.web-link-arrow {
    --link-color: var(--web-primary);
    --link-color-hover: var(--web-primary-dark);
    --link-size: var(--web-text-sm);
    --link-lh: var(--web-text-md-lh);
    --link-pad-x: 0px;
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    /* 🪤 `width: fit-content` KHÔNG PHẢI thừa — nó chặn một bẫy đã dính thật
          03/09/2026. Component này hay được đặt làm CON TRỰC TIẾP của một flex
          column (`.module-card`), mà flex column mặc định `align-items: stretch`
          -> hộp của link bị KÉO RỘNG HẾT thẻ dù `display: inline-flex`. Chữ và mũi
          tên vẫn nằm trái nên nhìn không ra; nhưng gạch chân `::after` neo theo HỘP
          (left/right) nên nó chạy dài hết thẻ — đúng triệu chứng Designer báo.
          `.module-more` bản cũ cũng bị kéo y hệt, chỉ là nó không có gạch chân nên
          lỗi nằm im.
          ⚠ Vì sao KHÔNG dùng `align-self: start`: `align-self` tác động lên trục
          PHỤ, mà trục phụ đổi nghĩa theo hướng của cha — trong `.web-btn-row` và
          `.news-foot` (flex ROW) nó sẽ thành canh dọc, đá link lên đỉnh hàng thay vì
          canh giữa. `width` thì đúng một nghĩa ở mọi hướng. */
    width: fit-content;
    padding: 0 var(--link-pad-x);
    color: var(--link-color);
    font-size: var(--link-size);
    line-height: var(--link-lh);
    font-weight: 600;
    text-decoration: none;
    transition: color .3s cubic-bezier(.165, .84, .44, 1);
}

    .web-link-arrow::after {
        content: "";
        position: absolute;
        left: var(--link-pad-x);
        right: var(--link-pad-x);
        bottom: -6px;
        height: 2px;
        background: currentColor;
        transform: scaleX(0);
        transform-origin: right;
        transition: transform .3s cubic-bezier(.165, .84, .44, 1);
    }

    .web-link-arrow:focus-visible {
        color: var(--link-color-hover);
    }

@media (hover: hover) and (pointer: fine) and (min-width: 1025px) {
    .web-link-arrow:hover {
        color: var(--link-color-hover);
    }
}

.web-link-arrow:focus-visible::after {
    transform: scaleX(1);
    transform-origin: left;
}

@media (hover: hover) and (pointer: fine) and (min-width: 1025px) {
    .web-link-arrow:hover::after {
        transform: scaleX(1);
        transform-origin: left;
    }
}

.web-link-arrow-ico {
    flex: 0 0 auto;
    width: 12px;
    height: 12px;
    background-color: currentColor;
    -webkit-mask: url("../../Public/vietasoft/assets/icons/ui/arrow-up-right.svg") center / 12px 12px no-repeat;
    mask: url("../../Public/vietasoft/assets/icons/ui/arrow-up-right.svg") center / 12px 12px no-repeat;
    transition: transform .3s cubic-bezier(.165, .84, .44, 1);
}

.web-link-arrow:focus-visible .web-link-arrow-ico {
    transform: translateX(4px) rotate(45deg);
}

@media (hover: hover) and (pointer: fine) and (min-width: 1025px) {
    .web-link-arrow:hover .web-link-arrow-ico {
        transform: translateX(4px) rotate(45deg);
    }
}

@media (prefers-reduced-motion: reduce) {
    .web-link-arrow,
    .web-link-arrow::after,
    .web-link-arrow-ico {
        transition: none;
    }

        .web-link-arrow:hover .web-link-arrow-ico,
        .web-link-arrow:focus-visible .web-link-arrow-ico {
            transform: none;
        }
}

.web-btn-row .web-link-arrow {
    --link-size: var(--web-text-md);
    --link-lh: var(--web-text-lg-lh);
    --link-pad-x: 16px;
}


.contact-col {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 20px;
    padding: 24px 20px;
    margin: -24px -20px;
    border-radius: var(--web-radius-card);
    opacity: 0;
    transform: translateY(16px);
    transition: opacity .5s var(--web-ease), transform .3s ease, box-shadow .3s ease;
}

    .contact-col.is-visible {
        opacity: 1;
        transform: translateY(0);
    }

@media (hover: hover) and (pointer: fine) and (min-width: 1025px) {
    .contact-col:hover {
        transform: translateY(-4px);
        box-shadow: 0 4px 16px rgba(13, 156, 74, .12);
        transition-delay: 0s;
    }
}

.contact-icon {
    width: 48px;
    height: 48px;
    display: grid;
    place-items: center;
    border: 8px solid var(--web-accent-50);
    border-radius: 28px;
    background: var(--web-accent-100);
}

    .contact-icon img {
        display: block;
    }

.contact-text {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.contact-title {
    font-size: var(--web-text-xl);
    line-height: var(--web-text-xl-lh);
    color: var(--web-gray-900);
}

.contact-desc {
    font-size: var(--web-text-md);
    line-height: var(--web-text-md-lh);
    color: var(--web-gray-600);
}

.contact-value {
    font-size: var(--web-text-sm);
    line-height: var(--web-text-sm-lh);
    font-weight: 600;
    color: var(--web-accent-dark);
}


.news-side {
    position: sticky;
    top: var(--news-side-top, calc(var(--web-header-h) + var(--web-space-6)));
    display: flex;
    flex-direction: column;
    gap: var(--web-space-8);
}

.news-side-box[hidden] {
    display: none;
}

.news-side-banner {
    display: block;
}

    .news-side-banner img {
        width: 100%;
        height: auto;
        aspect-ratio: 344 / 180;
        object-fit: cover;
    }

    .news-side-banner:focus-visible img {
        opacity: .92;
    }

@media (hover: hover) and (pointer: fine) and (min-width: 1025px) {
    .news-side-banner:hover img {
        opacity: .92;
    }
}

.news-side-title {
    display: flex;
    align-items: center;
    gap: var(--web-space-2);
    padding: var(--web-space-2) 0;
    font-size: var(--web-text-sm);
    line-height: var(--web-text-sm-lh);
    font-weight: 600;
    text-transform: uppercase;
    color: var(--web-primary-900);
}

@supports ((-webkit-background-clip: text) or (background-clip: text)) {
    .news-side-title-text {
        background-image: linear-gradient(95deg, var(--web-primary-900) 0%, var(--web-primary) 15%);
        -webkit-background-clip: text;
        background-clip: text;
        -webkit-text-fill-color: transparent;
        color: transparent;
    }
}

.news-side-icon {
    flex: 0 0 auto;
    width: 24px;
    height: 24px;
    background-color: var(--web-primary);
    -webkit-mask: url("../../Public/vietasoft/assets/icons/ui/news-01.svg") center / 24px 24px no-repeat;
    mask: url("../../Public/vietasoft/assets/icons/ui/news-01.svg") center / 24px 24px no-repeat;
}

.news-side-list li {
    border-bottom: 1px solid var(--web-rule);
}

    .news-side-list li:last-child {
        border-bottom: 0;
    }

.news-side-item {
    display: grid;
    grid-template-columns: 110px minmax(0, 1fr);
    gap: var(--web-space-3);
    align-items: start;
    padding: var(--web-space-3) 0;
    text-decoration: none;
}

.news-side-thumb {
    aspect-ratio: 5 / 3;
    overflow: hidden;
    background: var(--web-gray-50);
    border-radius: 0; /* 🔴 0 bo góc — nhất quán với cả hệ */
}

    .news-side-thumb img {
        display: block;
        width: 100%;
        height: 100%;
        object-fit: cover;
        border-radius: 0;
        transition: transform var(--web-ease);
    }

.news-side-item:focus-visible .news-side-thumb img {
    transform: scale(1.06);
}

@media (hover: hover) and (pointer: fine) and (min-width: 1025px) {
    .news-side-item:hover .news-side-thumb img {
        transform: scale(1.06);
    }
}

.news-side-text {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0; /* 🪤 grid item mặc định không co nhỏ hơn nội
                                            dung -> tiêu đề dài đẩy vỡ cột 344 */
}

.news-side-name {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
    font-size: var(--web-text-sm);
    line-height: var(--web-text-sm-lh);
    font-weight: 600;
    color: var(--web-news-title);
    transition: color var(--web-ease);
}

.news-side-item:focus-visible .news-side-name {
    color: var(--web-primary);
}

@media (hover: hover) and (pointer: fine) and (min-width: 1025px) {
    .news-side-item:hover .news-side-name {
        color: var(--web-primary);
    }
}

.news-side-date {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: var(--web-text-xs);
    line-height: 18px;
    color: var(--web-news-meta);
}

    .news-side-date .bi {
        font-size: 13px;
        line-height: 1;
    }

@media (prefers-reduced-motion: reduce) {
    .news-side-thumb img {
        transition: none;
    }

    .news-side-item:hover .news-side-thumb img,
    .news-side-item:focus-visible .news-side-thumb img {
        transform: none;
    }
}


.contact-fab {
    --fab-avatar-d: 64px;
    --fab-mascot-w: var(--fab-avatar-d);
    --fab-mascot-h: var(--fab-avatar-d);
    --fab-mascot-shift: 0px;
    position: fixed;
    right: 12px;
    bottom: 28px;
    z-index: var(--web-z-fab);
    display: flex;
    flex-direction: column;
    align-items: flex-end;
}

.contact-fab-list {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin: 0 0 24px;
    padding: 0;
    list-style: none;
}

.contact-fab-item {
    position: relative;
    display: grid;
    place-items: center;
    width: 52px;
    height: 52px;
    border: 0;
    padding: 0;
    border-radius: 50%;
    background: var(--fab-bg);
    color: var(--web-white);
    box-shadow: var(--web-shadow-lg);
    cursor: pointer;
    transition: transform var(--web-ease);
}

    .contact-fab-item:focus-visible {
        transform: translateX(-6px);
    }

@media (hover: hover) and (pointer: fine) and (min-width: 1025px) {
    .contact-fab-item:hover {
        transform: translateX(-6px);
    }
}

.contact-fab-item:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--web-white), 0 0 0 6px var(--web-gray-700);
}

.contact-fab-glint {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    overflow: visible;
    pointer-events: none;
    z-index: 1;
}

    .contact-fab-glint circle {
        fill: none;
        stroke: var(--web-white);
        stroke-width: 1.5;
        stroke-linecap: round;
        filter: drop-shadow(0 0 3px rgba(255, 255, 255, .9));
        stroke-dasharray: 31.8 101.7;
        stroke-dashoffset: 31.8;
        opacity: 0;
    }

.contact-fab-item:focus-visible .contact-fab-glint circle {
    animation: web-btn-glint-run 1s ease-in-out;
}

@media (hover: hover) and (pointer: fine) and (min-width: 1025px) {
    .contact-fab-item:hover .contact-fab-glint circle {
        animation: web-btn-glint-run 1s ease-in-out;
    }
}

.contact-fab-item[data-fab="phone"] {
    --fab-bg: var(--web-accent);
}

.contact-fab-item[data-fab="zalo"] {
    --fab-bg: #0068FF;
}

.contact-fab-item[data-fab="messenger"] {
    --fab-bg: #0084FF;
}

.contact-fab-ico {
    display: grid;
    place-items: center;
    width: 100%;
    height: 100%;
    pointer-events: none;
}

    .contact-fab-ico .bi {
        font-size: 22px;
        line-height: 1;
    }

.contact-fab-item[data-fab="zalo"] .contact-fab-ico::before,
.contact-fab-item[data-fab="messenger"] .contact-fab-ico::before {
    content: "";
    display: block;
    width: 100%;
    height: 100%;
    background-color: currentColor;
}

.contact-fab-item[data-fab="zalo"] .contact-fab-ico::before {
    -webkit-mask: url("../../Public/vietasoft/assets/icons/social/zalo.svg") center / 69.64px 69.64px no-repeat;
    mask: url("../../Public/vietasoft/assets/icons/social/zalo.svg") center / 69.64px 69.64px no-repeat;
}

.contact-fab-item[data-fab="messenger"] .contact-fab-ico::before {
    -webkit-mask: url("../../Public/vietasoft/assets/icons/social/messenger.svg") center / 51.59px 51.59px no-repeat;
    mask: url("../../Public/vietasoft/assets/icons/social/messenger.svg") center / 51.59px 51.59px no-repeat;
}

.contact-fab-tip {
    position: absolute;
    right: calc(100% + 10px);
    padding: 6px 12px;
    border-radius: var(--web-radius-sm);
    background: var(--web-gray-900);
    color: var(--web-white);
    font-size: 13px;
    line-height: 18px;
    white-space: nowrap;
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--web-ease);
}

@media (hover: hover) and (pointer: fine) and (min-width: 1025px) {
    .contact-fab-item:hover .contact-fab-tip {
        opacity: 1;
    }
}

.contact-fab-item:focus-visible .contact-fab-tip {
    opacity: 1;
}

.contact-fab-mascot-slot {
    position: relative;
    margin-right: var(--fab-mascot-shift);
    line-height: 0;
    animation: gihy-idle 4s ease-in-out infinite;
    transform-origin: 50% 100%;
}

.contact-fab-mascot {
    position: relative;
    display: block;
    width: var(--fab-mascot-w);
    height: var(--fab-mascot-h);
    padding: 0;
    border: 0;
    border-radius: 50%;
    cursor: pointer;
    /* 🔴 BỎ `background` gradient CSS ngày 07/09/2026 (B81) — `gihy-avatar.png`
          đã bake sẵn gradient + viền trắng, vẽ thêm ở đây là THỪA (ảnh phủ kín nên
          không lộ ra, nhưng vẫn tốn một layer nền vô ích). */
    box-shadow: 0 8px 20px -4px rgba(16, 24, 40, .20), 0 3px 8px -2px rgba(16, 24, 40, .12);
    transform-origin: 50% 50%;
    transition: transform var(--web-ease);
}

@media (hover: hover) and (pointer: fine) and (min-width: 1025px) {
    .contact-fab-mascot:hover {
        transform: scale(1.06);
    }
}

.contact-fab-mascot:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--web-white), 0 0 0 6px var(--web-gray-700);
}

.contact-fab-mascot-img,
.contact-fab-mascot-anim {
    position: absolute;
    left: 0;
    top: 0;
    width: var(--fab-mascot-w);
    height: var(--fab-mascot-h);
}

.contact-fab-mascot-img {
    display: block;
    transition: opacity 120ms ease;
}

.contact-fab[data-anim] .contact-fab-mascot-slot {
    animation-play-state: paused;
}

@keyframes gihy-idle {
    0%, 100% {
        transform: translateY(0);
    }

    50% {
        transform: translateY(-4px);
    }
}

.contact-fab-mascot-slot::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: 50%;
    border: 2px solid var(--web-accent);
    opacity: 0;
    pointer-events: none;
    animation: gihy-ping 4.5s ease-out infinite;
}

@keyframes gihy-ping {
    0% {
        transform: scale(1);
        opacity: .5;
    }

    16% {
        transform: scale(1.42);
        opacity: 0;
    }

    100% {
        transform: scale(1.42);
        opacity: 0;
    }
}

.contact-fab-mascot-slot:has(:focus-visible)::after {
    animation: none;
    opacity: 0;
}

@media (hover: hover) and (pointer: fine) and (min-width: 1025px) {
    .contact-fab-mascot-slot:hover::after {
        animation: none;
        opacity: 0;
    }
}

.contact-fab-mascot-anim {
    /* 🪤 `background-image` do JS gán THẲNG vào style của phần tử — CỐ Ý không đi
          qua biến CSS. `url()` tương đối trong một custom property được phân giải theo
          base URL của STYLESHEET tiêu thụ nó (file này ở `css/`), nên `assets/...`
          thành `css/assets/...` -> 404 và sprite không vẽ gì, IM LẶNG hoàn toàn.
          Đã dính thật 04/09/2026. Xem comment trong initMascot(), js/app.js. */
    background-repeat: no-repeat;
    /* 🔴 SỬA 05/09/2026 (B78) — 2 bẫy CHỒNG NHAU từng nằm ở đây:
          (1) `.9322` là hệ số CŨ (trước B77 đổi thành `1.0306`), lệch với `width`
          thật của chính phần tử này -> JS bước từng khung bằng bề rộng phần tử ĐO
          ĐƯỢC (1.0306×D) trong khi mỗi khung trong ảnh nền chỉ rộng .9322×D -> mỗi
          bước trượt LỆCH 0.1×D, nhìn như hoạt ảnh LƯỚT NGANG qua các khung thay vì
          đổi khung SẠCH. Bắt buộc dùng ĐÚNG MỘT số `1.0306` ở cả `width` (rule
          chung) lẫn `background-size` — lệch nhau dù chỉ một hệ số là hỏng.
          (2) chiều cao viết `100%` tức LUÔN khớp chiều cao phần tử — nay phần tử đã
          hạ xuống 1.0028×D (cửa sổ crop, xem rule chung), viết `100%` sẽ BÓP MÉO
          sprite theo chiều cao mới thay vì giữ tỉ lệ khung gốc 280/196. Phải khai
          TƯỜNG MINH chiều cao THẬT của 1 khung (tính từ bề rộng THẬT của nó, không
          phải từ chiều cao cửa sổ) rồi để phần dư bị cắt bởi chính bề cao ngắn hơn
          của phần tử — giống hệt cách `.contact-fab-mascot-img` dùng `object-fit:
          cover` để cắt, chỉ khác đây là background nên "cắt" tự động xảy ra ở mép
          phần tử (background-clip mặc định border-box), không cần khai thêm gì. */
    background-size: calc(var(--fab-avatar-d) * 1.0306 * var(--anim-frames)) calc(var(--fab-avatar-d) * 1.0306 * 280 / 196);
    background-position: 0 0;
    opacity: 0;
    pointer-events: none;
    transition: opacity 120ms ease;
}
/* 🔴 PHẦN CHẠY KHUNG NẰM Ở JS, KHÔNG Ở ĐÂY — cố ý, và đây là lý do:
      yêu cầu 04/09/2026 là rời chuột thì hoạt ảnh **TUA NGƯỢC** về tư thế nghỉ, tua
      từ ĐÚNG KHUNG ĐANG ĐỨNG (rời giữa chừng thì lùi từ giữa chừng). CSS `animation`
      không diễn đạt được: `animation-direction: reverse` luôn khởi động lại từ khung
      cuối, còn muốn lùi từ vị trí hiện tại thì phải BIẾT thời điểm hiện tại — CSS
      không cho đọc số đó. Web Animations API có `playbackRate = -1` làm đúng việc
      này, và nó lùi từ chính chỗ đang đứng.
      -> Xem initMascot() trong js/app.js. Ở đây chỉ còn phần TĨNH của sprite.
      ⚠ ĐỪNG thêm lại `@keyframes` + `.is-running`: 2 nguồn cùng điều khiển
      `background-position` sẽ tranh nhau, và lỗi kiểu đó rất khó truy. */
.contact-fab[data-anim] .contact-fab-mascot-anim {
    opacity: 1;
}

.contact-fab[data-anim] .contact-fab-mascot-img {
    opacity: 0;
}

.contact-fab-bubbles {
    position: absolute;
    /* 🔴 SỬA 05/09/2026 (lỗi mới phát hiện) — PHẢI đọc `--fab-mascot-w`, KHÔNG đọc
          `--fab-avatar-d`. Bản trước dùng thẳng `--fab-avatar-d` (luôn 64px), đúng ở
          dạng avatar (--fab-mascot-w cũng = 64 lúc đó) nhưng SAI ở dạng toàn thân
          (>1560): `--fab-mascot-w` phình lên 98px trong khi `--fab-avatar-d` đứng yên
          64px, nên khe tính hụt mất 34px — bong bóng ăn lấn 24px vào mascot và bị
          mascot (vẽ SAU trong DOM, không z-index) đè lên góc phải. Đo được ở 1920:
          bubbles.right=1823 > mascotSlot.left=1799 trước khi sửa.
          Đọc `--fab-mascot-w` thì công thức TỰ ĐÚNG cả 2 dạng vì `--fab-mascot-w`
          vốn đã bằng `--fab-avatar-d` ở dạng avatar (khai ở đầu `.contact-fab`). */
    right: calc(var(--fab-mascot-w) + var(--fab-mascot-shift) + 10px);
    bottom: 0;
    /* 🔴 SỬA 05/09/2026 (B76) — PHẢI đọc `--fab-mascot-h`, KHÔNG `--fab-avatar-d`.
          Cùng họ lỗi với `right` ở trên: `--fab-avatar-d` cố định 64px, nên ở dạng
          toàn thân (mascot cao thật 140px) khối bong bóng chỉ cao 64 rồi CĂN GIỮA
          TRONG ĐÚNG 64px ĐÁY của mascot — nhìn ra như dán sát chân mascot thay vì nằm
          giữa thân. Đọc `--fab-mascot-h` thì khối cao ĐÚNG BẰNG mascot (64 ở avatar,
          140 ở toàn thân) nên `justify-content: center` mới thật sự căn giữa TOÀN
          THÂN mascot, không chỉ căn giữa một lát cắt đáy của nó. */
    height: var(--fab-mascot-h);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: flex-end;
    gap: 6px;
    opacity: 0;
    transform: translateY(6px);
    pointer-events: none;
    transition: opacity var(--web-ease), transform var(--web-ease);
}

.contact-fab[data-bubbles] .contact-fab-bubbles {
    opacity: 1;
    transform: none;
}

.contact-fab-bubble {
    margin: 0;
    padding: 12px;
    border: 1px solid var(--web-white);
    border-radius: 999px;
    background: rgba(255, 255, 255, .92);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    box-shadow: -2px 3px 14px rgba(37, 37, 37, .08);
    color: var(--web-gray-900);
    font-size: 12px;
    line-height: 16.86px;
    font-weight: 500;
    white-space: nowrap;
}

/* Menu mobile mở thì giấu hẳn cụm nút.
      z-index 900 đã lo phần TRÙNG với panel (panel nằm trong .header-fixed z-1000
      nên được vẽ cả khối ở tầng đó); dòng này lo phần THÒ RA dưới đáy panel trên màn
      cao — panel chỉ cao 741 tới 765px chứ không phủ hết viewport.
      Thắng bằng SPECIFICITY (0,2,1) > .contact-fab (0,1,0), KHÔNG nhờ thứ tự dòng —
      đúng bài học T1 đã dính 4 lần ở.header-cta.
      ⚠ KHI PORT: data-nav-open là cơ chế nav riêng của prototype (js/app.js);
      repo thật dùng Bootstrap 5 Offcanvas -> đổi móc nối sang state của nó. */
body:has(.header-fixed[data-nav-open="true"]) .contact-fab {
    display: none;
}

@media (min-width: 1561px) {
    .contact-fab {
        --fab-mascot-w: 98px;
        --fab-mascot-h: 140px;
        --fab-mascot-shift: -4px;
        /* 🔴 TRẢ VỀ 20px — B76 nhích `bottom` mặc định lên 28px CHỈ CHO DẠNG AVATAR,
              khai ở đây để TOÀN THÂN giữ nguyên vị trí gốc (đã đo/duyệt ở B73/B74b). */
        bottom: 20px;
    }

    .contact-fab-list {
        margin-bottom: 16px;
    }

    .contact-fab-mascot {
        border-radius: 12px;
        overflow: visible;
        background: none;
        box-shadow: none;
    }

    .contact-fab-mascot-slot::after {
        display: none;
    }

    .contact-fab-mascot-anim {
        background-size: calc(var(--fab-mascot-w) * var(--anim-frames)) 100%;
    }
}

@media (prefers-reduced-motion: reduce) {
    .contact-fab-item {
        transition: none;
    }

        .contact-fab-item:hover,
        .contact-fab-item:focus-visible {
            transform: none;
        }

    .contact-fab-tip {
        transition: none;
    }

    .contact-fab-item:hover .contact-fab-glint circle,
    .contact-fab-item:focus-visible .contact-fab-glint circle {
        animation: none;
        stroke-dasharray: none;
        opacity: 1;
    }

    .contact-fab-mascot-slot {
        animation: none;
    }

    .contact-fab-mascot-img {
        transition: none;
    }

    .contact-fab-mascot {
        transition: none;
    }

        .contact-fab-mascot:hover {
            transform: none;
        }

    .contact-fab-bubbles {
        transition: none;
    }

    .contact-fab-mascot-slot::after {
        animation: none;
        opacity: 0;
    }

    .contact-fab-mascot-anim {
        animation: none;
        opacity: 0;
        transition: none;
    }
}


@keyframes web-in {
    from {
        opacity: 0;
        translate: var(--rv-x, 0) var(--rv-y, 32px);
        scale: var(--rv-s, 1);
    }
}

@keyframes web-glint {
    from {
        background-position: 100% 0, 0 0;
    }

    to {
        background-position: 0% 0, 0 0;
    }
}

@keyframes web-settle {
    from {
        scale: 1.12;
    }
}

@media screen and (prefers-reduced-motion: no-preference) {
    .web-rv:not(.is-in) {
        opacity: 0;
    }

    .web-rv.is-in {
        animation: web-in .8s cubic-bezier(.22, 1, .36, 1) var(--rv-d, 0ms) both;
    }

    .cta-band.web-rv.is-in .web-btn-yellow {
        --rv-x: 0;
        --rv-y: 0;
        --rv-s: .8;
        animation: web-in .5s cubic-bezier(.34, 1.56, .64, 1) calc(var(--rv-d, 0ms) + 300ms) both;
    }

    .news-card.web-rv.is-in :is(.news-thumb, .news-thumb--empty) {
        animation: web-settle 1.4s cubic-bezier(.22, 1, .36, 1) var(--rv-d, 0ms) both;
    }
}


@media (max-width: 1200px) {
    .stat-badge-row {
        gap: 40px;
    }

    .cta-band {
        padding: 56px 40px;
    }
}

@media (max-width: 1099px) {
    .stat-badge-row {
        flex-direction: column;
        align-items: flex-start;
        padding: 24px;
        gap: 24px;
    }

    .stat-badge-count {
        font-size: 36px;
        line-height: 44px;
    }
}

@media (max-width: 768px) {
    .section-title {
        font-size: 28px;
        line-height: 36px;
    }

    .web-btn.header-cta {
        order: 2;
        padding: 10px 16px;
        font-size: var(--web-text-sm);
        line-height: 20px;
        border-radius: 12px;
    }

    .web-btn-row {
        flex-direction: column;
        align-items: stretch;
    }

    .cta-band {
        min-height: 0;
        padding: 40px 24px;
        border-radius: 24px;
    }

    .contact-col {
        padding: 20px 16px;
        margin: -20px -16px;
    }

    .contact-fab {
        right: 16px;
        bottom: 24px;
    }
    /* 🔴 SỬA 05/09/2026 (lỗi mới phát hiện, B75) — BỎ `margin-bottom: 0`, để khe
          kế thừa từ rule gốc phía trên (khi đó là 16px, nay B76 nâng gốc lên 24px —
          giá trị kế thừa ở đây ĐỔI THEO, không cần sửa dòng này lần nữa). Số 0 này
          ĐÚNG lúc B73 viết ra (mascot còn ẨN ở ≤768 nên dưới list không có gì, 0 tốn
          chỗ cũng hợp lý), nhưng B74b cho mascot HIỆN LẠI ở ≤768 (đổi sang avatar
          64px) mà quên trả khe lại — 0 khe cộng nhịp thở `gihy-idle` (trôi tới −4px)
          làm avatar lấn lên tới 4px vào nút Messenger. Đo được ở 768px TRƯỚC khi sửa:
          mascotSlot.top=941.4 < nút thứ 3.bottom=944. */
    .contact-fab-list {
        gap: 10px;
    }

    .contact-fab-item {
        width: 48px;
        height: 48px;
    }

    .contact-fab-ico .bi {
        font-size: 20px;
    }

    .contact-fab-bubbles {
        display: none;
    }

    .contact-fab-item[data-fab="zalo"] .contact-fab-ico::before {
        -webkit-mask-size: 64.3px 64.3px;
        mask-size: 64.3px 64.3px;
    }

    .contact-fab-item[data-fab="messenger"] .contact-fab-ico::before {
        -webkit-mask-size: 47.6px 47.6px;
        mask-size: 47.6px 47.6px;
    }
}


/* ==========================================================================
      FORM LIEN HE — .web-form*                          THEM 07/09/2026 (B82)
      ==========================================================================
      🔴 DAY LA HO CLASS DAU TIEN CUA PROJECT CHO PHAN TU NHAP LIEU. Truoc vong nay
      `grep -n "input|textarea" css/base.css css/components.css` tra ve 0 dong —
      tuc 15 trang chua tung co mot o nhap nao. Vi vay:
        · KHONG co "kieu cu" de bam theo -> moi so duoi day deu suy tu THANG CO SAN
          (--web-space-*, --web-text-*, --web-radius-*), 0 token moi, 0 mau moi.
        · Dat o components.css chu khong o pages/lien-he.css vi trang Home (section
          7 "Lien he") va cac trang chi tiet SP deu la ung vien dung lai (W6). Neu
          sau 1 thang van chi 1 trang dung thi ha xuong pages/ — nhung ha xuong re
          hon nhieu so voi go 5 ban sao ra.
   
      🔴 VI SAO CO FORM NAY (ghi de quyet dinh cu — R8):
      lien-he.html tung ghi "Nguoi dung chot 22/08/2026: KHONG co form dang ky tu
      van, bam ban live". Quyet dinh do BI DAO NGUOC ngay 07/09/2026, nguoi dung xac
      nhan tuong minh, sau khi do 3 doi thu (MISA · KiotViet · ezCloud): CA BA deu
      co form <= 4 truong tren trang Lien he. Ban live vietasoft.com.vn — can cu cua
      quyet dinh cu — la ban BO CUC CU ma Figma da thiet ke lai toan bo (ghi chú nội bộ của Designer
      muc 2), nen no khong con la can cu manh nua.
   
      ⚠ FORM NAY KHONG GUI DI DAU. Prototype la HTML tinh (W3) — khong co endpoint,
      va CO Y khong tro toi endpoint nao: mot form tinh tro ra dich vu ngoai la vua
      gui du lieu that cua khach vao mot ben thu ba khong ai duyet. `onsubmit` bi
      chan trong js/pages/lien-he.js, chi hien thong bao thanh cong gia lap.
      KHI PORT: xem docs/HANDOFF.md — dev noi vao Controller + chong CSRF + captcha.
   
      ⚠ KHONG dat `:focus { outline: none }` o bat ky dau trong ho nay. Do la cach
      nhanh nhat de mot form dep tren anh chup thanh khong dung duoc bang ban phim. */

.web-form {
    display: flex;
    flex-direction: column;
    gap: var(--web-space-4);
}

.web-form-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--web-space-4);
}

    .web-form-row > .web-field {
        flex: 1 1 220px;
    }

.web-field {
    display: flex;
    flex-direction: column;
    gap: var(--web-space-2);
    min-width: 0; /* 🪤 BAT BUOC trong luoi: thieu la o nhap khong chiu co duoi
                          be rong noi tai cua no -> tran ngang o mobile. */
}

.web-label {
    font-size: var(--web-text-sm);
    line-height: var(--web-text-sm-lh);
    font-weight: 600;
    color: var(--web-gray-700);
}

.web-label-req {
    color: var(--web-accent);
}

/* 🔴 `font: inherit` LA DONG QUAN TRONG NHAT O DAY, khong phai mau hay bo goc.
      Trinh duyet KHONG ke thua font cho input/textarea/select — chung dung font he
      thong mac dinh. Thieu dong nay thi o nhap ra font khac han 15 trang con lai
      (thuong la Arial/Times), va loi do KHONG lo tren anh chup o co nho. */
.web-input,
.web-textarea {
    font: inherit;
    font-size: var(--web-text-md);
    line-height: var(--web-text-md-lh);
    color: var(--web-gray-900);
    width: 100%;
    padding: 12px 16px;
    background: var(--web-white);
    border: 1px solid var(--web-gray-300);
    border-radius: var(--web-radius-sm);
    transition: border-color var(--web-ease), box-shadow var(--web-ease);
}

    .web-input::placeholder,
    .web-textarea::placeholder {
        color: var(--web-gray-500);
    }

.web-textarea {
    min-height: 120px;
    resize: vertical;
}

    .web-input:focus,
    .web-textarea:focus {
        outline: none;
        border-color: var(--web-primary);
        /* 🪤 BAC 200 (#C3CBE4) CHU KHONG PHAI BAC 50. `--web-primary-50` la #F2F4FA —
          do lai thi thay no gan nhu trang; mot quang 3px mau do dat tren the form nen
          `--web-gray-50` la VO HINH, tuc dong box-shadow nay ton mot dong CSS ma
          khong ve ra gi. Bac 200 nhin thay duoc tren ca nen trang lan nen gray-50.
          📌 Dau hieu dat WCAG 2.4.11 nam o VIEN doi tu #D0D5DD sang #2C479E (chenh
          rat lon); quang chi la lop bo tro cho de thay o duoi anh sang manh. */
        box-shadow: 0 0 0 3px var(--web-primary-200);
    }

    .web-input[aria-invalid="true"],
    .web-textarea[aria-invalid="true"] {
        border-color: var(--web-yellow-800);
    }

.web-field-error {
    font-size: var(--web-text-xs);
    line-height: 1.5;
    font-weight: 500;
    color: var(--web-yellow-800);
}

    .web-field-error:empty {
        display: none;
    }

.web-form-status {
    font-size: var(--web-text-sm);
    line-height: var(--web-text-sm-lh);
    font-weight: 600;
    padding: 12px 16px;
    border-radius: var(--web-radius-sm);
}

    .web-form-status:empty {
        display: none;
    }

    .web-form-status[data-state="ok"] {
        color: var(--web-accent-dark);
        background: var(--web-accent-50);
    }

.web-form-note {
    font-size: var(--web-text-xs);
    line-height: 1.5;
    color: var(--web-gray-600);
}

