@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+Display:wght@300;400;500;600;700&family=Noto+Sans+Thai:wght@300;400;600;700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Noto+Color+Emoji&display=swap');
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+Thai:wght@400;500;600;700&display=swap');
/* handwriting pair for the landing-page headline only — the woff2 is fetched lazily,
   so pages that never use the family pay nothing beyond this stylesheet line */
@import url('https://fonts.googleapis.com/css2?family=Sriracha&family=Caveat:wght@500;600&display=swap');
/* mono is the instrument voice on the landing page — tick labels, phase markers,
   step numerals. Declared in --fp-mono since the 2a body but never actually loaded. */
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500&display=swap');

html {
    font-family: 'Noto Sans Thai', 'Noto Color Emoji', 'Noto Sans Display', sans-serif !important;
    --rz-text-font-family: 'Noto Sans Thai', 'Noto Color Emoji', 'Noto Sans Display', sans-serif !important;
    --bs-body-font-family: 'Noto Sans Thai', 'Noto Color Emoji', 'Noto Sans Display', sans-serif !important;
    --rz-text-button-font-weight: 400 !important;
    --rz-root-font-size: 14px !important;
    --bs-body-font-size: clamp(0.875rem, 0.875rem + 0.175vw, 1.075rem);
}

/* Side navigation mini-rail: desktop-only width override.
   Radzen sets sidebar width from --rz-sidebar-width (:root = 250px); we shrink
   that variable on the rail element. Global (not isolated) CSS because ::deep
   cannot pierce RadzenSidebar's own root element. */
/* Radzen ตั้ง .rz-sidebar { overflow: auto } ไว้ — ปิดทิ้งเพราะ .side-nav__scroll ข้างในเป็นตัวสกอลล์แทน
   ปล่อยไว้จะได้สกอลล์บาร์ซ้อนกันสองชั้น และปุ่มพับ/กางจะเลื่อนหลุดจอไปพร้อมรายการเมนู */
.rz-sidebar.app-sidebar {
    overflow: hidden;
}

@media (min-width: 769px) {
    .rz-sidebar.app-sidebar {
        transition: width .15s ease;
    }
    .rz-sidebar.app-sidebar--rail {
        --rz-sidebar-width: 64px;
        overflow: visible;
        z-index: 5;
    }
}

tspan, .apexcharts-title-text, .apexcharts-tooltip > *, .apexcharts-legend-series > * {
    font-family: 'Noto Sans Thai', 'Noto Color Emoji', 'Noto Sans Display', sans-serif !important;
    color: var(--rz-text-body1-color) !important;
    fill: var(--rz-text-body1-color) !important;
}

.apexcharts-datalabels > text, .apexcharts-datalabels {
    color: #ffffff !important;
    fill: #ffffff !important;
}

[id^="apexcharts"] > svg {
    background-color: transparent !important;
}

/*path {
    fill: rgb(78, 197, 255) !important;
}*/

.apexcharts-tooltip, .apexcharts-tooltip-title {
    background-color: var(--rz-card-background-color) !important;
}

body {
    margin: 0;
    overflow: hidden;
}

h1:focus {
    outline: none;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid #e50000;
}

.validation-message {
    color: #e50000;
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

.darker-border-checkbox.form-check-input {
    border-color: #929292;
}

#components-reconnect-modal h5 {
    color: #232323 !important;
    font-weight: 500 !important;
}

p[class^="rz-text"], span[class^="rz-text"] {
    margin-block: 0;
    margin-bottom: 0;
}

.rz-body {
    padding: 0 !important;
}

.rz-label {
    font-size: 0.9rem;
    font-weight: 500;
}

.rz-layout {
    height: auto !important;
    min-height: 100vh !important;
}

.rz-notification {
    top: 16px !important;
}

.rz-navigation-item-text {
    font-size: 0.85rem;
}

.rz-text-display-h1, .rz-text-display-h2, .rz-text-display-h3, .rz-text-display-h4, .rz-text-display-h5, .rz-text-display-h6,
.rz-text-h1, .rz-text-h2, .rz-text-h3, .rz-text-h4, .rz-text-h5, .rz-text-h6,
.rz-text-body1, .rz-text-body2, .rz-button-box, p {
    font-family: 'Noto Sans Thai', 'Noto Color Emoji', 'Noto Sans Display', sans-serif !important;
}

.statCardButton .rz-button-box {
    width: 100%;
}

.frontPageImage {
    filter: drop-shadow(0px 0px 10px rgb(90 120 255 / 27%));
}

.bgTopImage {
    z-index: -1;
    position: absolute;
    top: -280px;
    opacity: 0.35;
}

.bgBottomImage {
    z-index: -1;
    position: absolute;
    bottom: 0px;
    opacity: 0.35;
}

.siteFooter {
    background: #ffffff;
    width: 100%;
    box-shadow: 0 -32px 24px 0 rgb(88 185 253 / 6%), 0px 2px 4px rgb(144 228 255 / 37%), 0px 4px 16px rgb(95 165 255 / 40%);
}

.rz-multiselect-header {
    font-size: var(--rz-dropdown-item-font-size);
}

.rz-card {
	border-radius: 0.5rem !important;
}

.rz-density-compact span, .rz-density-compact p {
	font-size: 0.85rem;
}

.home-star-image-bg {
    position: absolute;
    width: 24vw;
    right: 8vw;
    top: 5vh;
    z-index: -1;
}

.CourseCardButton {
    padding: 0 !important;
    display: flex;
    width: 100%;
}

    .CourseCardButton:hover {
        background-color: rgba(132, 215, 255, 0.13) !important;
    }

    .CourseCardButton span.rz-button-box {
        width: 100%;
        align-items: start;
        justify-content: start;
        display: flex;
    }

.CourseCardButton p {
    text-align: left;
}

.CourseStatusBadge {
	display: flex !important;
	flex-direction: row;
	align-items: center;
	padding-inline: 0.5rem;
}

	.CourseStatusBadge.disabled {
		-ms-opacity: 0.7;
		opacity: 0.7;
	}

.RateComponent {
    transition: all 100ms ease-in-out;
    max-width: 100%;
    flex-wrap: wrap;
}

/* ข้อความความหมายของคะแนนที่เลือก — สีต้องสลับตามธีม (เดิม hardcode #4858d4 อ่านไม่ออกบนพื้นมืด) */
.rate-meaning {
    color: #4858d4 !important;
}

:root[data-theme="dark"] .rate-meaning {
    color: #aab6ff !important;
}

/* อิโมจิกับตัวเลขต้องชิดกันเป็นก้อนเดียว — margin เดิมของ h3/p ทำให้ปุ่มยืดเป็นแท่งสูง */
.RateComponent .rz-button .rz-text-h3,
.RateComponent .rz-button .rz-text-body1 {
    margin: 0;
    line-height: 1.2;
}

/* จอแคบ: ตัวเลือกคะแนนต้องหดให้พอดีแถวเดียว ไม่งั้นการ์ดล้นจอจนหน้าเลื่อนแนวนอนได้
   ค่า min-width/gap เดิมเป็น inline style จึงต้องใช้ !important ทับ */
@media (max-width: 640px) {
    .RateComponent {
        width: 100%;
        gap: 0.4rem !important;
    }

    .RateComponent .rz-button {
        min-width: 0 !important;
        padding: 10px 2px 8px 2px !important;
        flex: 1 1 0;
    }

    .RateComponent .rz-button .rz-text-h3 {
        font-size: 1.5rem;
    }
}

.RateComponent .rz-button.rz-state-active {
	border: 3px solid !important;
}

.CourseEvalTab > .rz-tabview-nav {
	display: none !important;
}

.CourseEvalTab > .rz-tabview-panels {
	background: none !important;
	border: none !important;
}

.CourseEvalTab > .rz-tabview-panels > .rz-tabview-panel {
	padding: 0 !important;
}

.rz-notification-message {
    width: 100% !important;
    max-width: 420px !important;
}

.rz-growl-item {
    background-color: #323232 !important;
    color: #fff !important;
    padding: 16px 24px;
    border-radius: 0.5rem !important;
    box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.16), 0px 3px 6px rgba(0, 0, 0, 0.23) !important;
    text-align: center;
    pointer-events: all;
    transition: opacity 0.5s, transform 0.5s;
}

.rz-growl-message-success .rz-growl-item {
    border-bottom: 6px solid #19bd19;
}

.rz-growl-image {
    display: none !important;
}

.ces-hide {
    opacity: 0;
}

.ces-show {
    opacity: 1;
}

.sideImage-dark{
    filter: brightness(0.6) contrast(1.2);
}

.primary-text-color {
    color: var(--rz-text-body1-color) !important;
}

.resultMatrixGroupTable .rz-group-header .rz-group-header-items{
    display: none !important;
}

.resultMatrixGroupTable .rz-custom-header {
    width: 100%;
}

.resultMatrixGroupTable colgroup {
    width: 100%;
}

.w-fill {
    width: 100% !important;
}

/* Sidebar toggle (hamburger) is redundant on desktop — the nav footer rail
   chevron controls collapse there. Keep it for the mobile drawer. */
@media (min-width: 769px) {
    .rz-sidebar-toggle {
        display: none;
    }
}
/* ---- Shared load/entrance animations (compositor-friendly: opacity/transform only) ---- */

/* Skeleton bar on card/list surfaces */
.course-skel {
    border-radius: 8px;
    background: color-mix(in srgb, var(--rz-text-secondary-color) 16%, transparent);
    animation: course-skel-pulse 1.4s ease-in-out infinite;
}

@keyframes course-skel-pulse {
    0%, 100% { opacity: .5; }
    50% { opacity: .95; }
}

/* Page-level blocks rising in, staggered via -d1..-d3 */
.rise-in {
    animation: rise-in .4s cubic-bezier(.22, .61, .36, 1) backwards;
}

.rise-in-d1 { animation-delay: .07s; }
.rise-in-d2 { animation-delay: .14s; }
.rise-in-d3 { animation-delay: .21s; }

@keyframes rise-in {
    from { opacity: 0; transform: translateY(12px); }
    to { opacity: 1; transform: none; }
}

/* Content replacing a skeleton; stagger per item with inline animation-delay */
.card-rise {
    animation: card-rise .35s cubic-bezier(.22, .61, .36, 1) backwards;
}

@keyframes card-rise {
    from { opacity: 0; transform: translateY(10px); }
    to { opacity: 1; transform: none; }
}

/* Dashed "nothing here" surface shared by list pages */
.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    padding: 28px 20px;
    border-radius: 12px;
    background: var(--rz-card-background-color, #fff);
    border: 1px dashed var(--rz-border-color, #C9D3E0);
    text-align: center;
}

.empty-state-title {
    font-weight: 700;
    color: var(--rz-text-color);
}

.empty-state-text {
    font-size: .88rem;
    color: var(--rz-text-secondary-color);
    max-width: 44ch;
}

@media (prefers-reduced-motion: reduce) {
    .course-skel, .rise-in, .card-rise {
        animation: none;
    }
}

/* Circular initials avatar shown when a user has no profile photo */
.avatar-fallback {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    border-radius: 50%;
    background: color-mix(in srgb, var(--rz-primary) 14%, var(--rz-card-background-color, #fff));
    color: var(--rz-primary);
    font-weight: 700;
    letter-spacing: .02em;
    user-select: none;
}

.score-value {
    color: #009B51;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

/* ============================================================
   Filter cards on management pages (.filter-*)
   ป้ายกำกับวางเหนือช่องกรอก ไม่ใช่ข้างช่อง — ป้ายภาษาไทยยาวไม่เท่ากัน
   การวางข้างทำให้ช่องกรอกเริ่มไม่ตรงกันทุกแถว
   ใช้ flex ไม่ใช่ grid track: จำนวนตัวกรองต่างกันทุกหน้า (3–5 ช่อง และบางหน้า
   ซ่อน/แสดงตามเงื่อนไข) grid ที่ตรึงจำนวนคอลัมน์จะเหลือช่องว่างเปล่าท้ายแถว
   ============================================================ */
.filter-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px 20px;
}

.filter-heading {
    margin: 0;
    font-weight: 600;
}

.filter-head-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
}

.filter-grid {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 16px 20px;
}

.filter-field {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
    /* ยืดเต็มแถวเสมอ ไม่เหลือช่องว่าง แต่ไม่ยืดจนช่องเดียวกินทั้งจอ */
    flex: 1 1 220px;
    max-width: 420px;
}

.filter-label {
    font-weight: 600;
    font-size: 0.9rem;
    color: var(--rz-text-color, #1e293b);
}

/* แถวคำค้น + ปุ่มค้นหา แยกจากแถวตัวกรอง เส้นสายตาไปทางเดียวกับการพิมพ์แล้วกดค้นหา */
.filter-search-row {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 12px 16px;
}

.filter-search-row .filter-field {
    flex: 1 1 320px;
    max-width: none;
}

.filter-search-row .rz-button {
    flex: 0 0 auto;
    min-width: 140px;
}

@media (max-width: 640px) {
    .filter-field {
        flex-basis: 100%;
        max-width: none;
    }

    .filter-search-row .rz-button {
        flex: 1 1 100%;
    }

    .filter-head {
        align-items: flex-start;
    }
}

/* ============================================================
   Management data grids (.mgmt-grid)
   ใช้ร่วมกับ Responsive="true" ของ Radzen ซึ่ง reflow ที่ <= 768px
   ============================================================ */

/* Density.Compact ของธีมบีบจนหัวตารางเล็กและอึดอัด — คืนระยะห่างกลับมาครึ่งทางระหว่าง compact กับ default
   ต้องใช้ 3 คลาสเพื่อชนะ .rz-data-grid.rz-density-compact ของธีม (app.css โหลดก่อน CSS ธีม) */
.rz-data-grid.mgmt-grid.rz-density-compact {
    --rz-grid-cell-padding: 0.55rem 0.75rem;
    --rz-grid-cell-line-height: 1.4;
    --rz-grid-header-cell-padding: 0.55rem 0;
    --rz-grid-header-padding: 0.55rem 1rem;
    --rz-grid-header-font-size: 0.9375rem;
    --rz-grid-header-line-height: 1.35;
    --rz-grid-filter-padding: 0.5rem;
}

/* table-layout: fixed ของ Radzen จะบีบคอลัมน์ที่ไม่ระบุความกว้างจนเนื้อหาโดนตัดทิ้ง
   แทนที่จะดันตารางให้เลื่อนแนวนอน — ตั้งความกว้างขั้นต่ำไว้ให้ตัวสกอลล์ (.rz-data-grid-data
   ซึ่งเป็น overflow: auto อยู่แล้ว) ได้ทำงานจริง
   เฉพาะจอ >768px เพราะต่ำกว่านั้น Responsive reflow เปลี่ยนตารางเป็น block ไปแล้ว */
@media (min-width: 769px) {
    .mgmt-grid .rz-grid-table,
    .mgmt-grid .rz-data-grid-data > table,
    .mgmt-grid .rz-datatable-tablewrapper > table {
        min-width: 900px;
    }
}

/* หัวคอลัมน์ภาษาไทยยาวกว่าอังกฤษมาก ปล่อยให้ตัดบรรทัดแทนโดนตัดท้าย
   (ธีมตั้ง nowrap + ellipsis ไว้ทั้งสองชั้น จึงต้อง override ทั้งคู่) */
.mgmt-grid thead .rz-column-title,
.mgmt-grid thead .rz-column-title-content {
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
    line-height: 1.3;
}

.mgmt-grid .rz-data-row > td {
    vertical-align: middle;
    /* ตัวเลขในตารางอ่านง่ายขึ้นเมื่อความกว้างตัวเลขเท่ากัน */
    font-variant-numeric: tabular-nums;
}

/* ปุ่มในคอลัมน์ action ไม่ควรถูกบีบจนตัวหนังสือหาย */
.mgmt-grid .rz-data-row > td .rz-button {
    white-space: nowrap;
}

@media (max-width: 768px) {
    /* reflow ของ Radzen ตัด border ของ td ทิ้ง ทำให้แต่ละแถวกลืนกัน — วาดเส้นคั่นระดับแถวคืน */
    .mgmt-grid .rz-data-row {
        border: 1px solid var(--rz-border-color, #C9D3E0);
        border-radius: 10px;
        padding: 8px 4px;
        margin-bottom: 10px;
        background: var(--rz-card-background-color, #fff);
    }

    /* reflow แสดง .rz-column-title ในเซลล์ — ทำให้เป็นป้ายกำกับเล็ก ๆ แทนตัวหนังสือขนาดเท่าข้อมูล */
    .mgmt-grid .rz-data-row > td .rz-column-title {
        font-size: .72rem;
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: .03em;
        color: var(--rz-text-secondary-color);
        margin-bottom: 2px;
    }

    .mgmt-grid .rz-data-row > td {
        padding-block: 4px;
    }

    /* แถบ action เต็มความกว้าง กดง่ายบนมือถือ */
    .mgmt-grid .rz-data-row > td .rz-button {
        white-space: normal;
    }
}

