/*
 * MWKConnect on AdminLTE 4: shell styles and shared helpers.
 * Loaded only when $mwk_layout_v4, after mwk-ui.css.
 */

.fs-7 { font-size: .8125rem !important; }

/* Full-width horizontal Turnstile on every screen. JS fits the complete 300px minimum
   proportionally in narrower forms; zoom keeps its layout height correct without clipping. */
.mwk-turnstile {
  box-sizing: border-box;
  width: 100%; min-width: 0; padding: .5rem;
}
.mwk-turnstile__viewport { width: 100%; min-width: 0; }
.mwk-turnstile__viewport > .cf-turnstile {
  width: var(--mwk-turnstile-width, 100%); min-width: 0; min-height: 65px;
  zoom: var(--mwk-turnstile-zoom, 1);
}
@media (min-width: 576px) { .mwk-turnstile { padding: 1rem; } }

/* "พื้นหลังใหม่" (user, 2026-10-21): graph-paper lines, white page in light mode, rounder cards with a soft shadow.
   Only when body has .paper-grid (display setting paperBackground = grid, set by theme-init.php and mwk-display.js).
   Without the class the page keeps the old look. Colours come from --mwk-grid-line / --mwk-card-shadow (mwk-theme.css). */
body.mwk-v4.paper-grid {
  --mwk-grid-size: 3rem;
  background-image:
    linear-gradient(to right, var(--mwk-grid-line) 1px, transparent 1px),
    linear-gradient(to bottom, var(--mwk-grid-line) 1px, transparent 1px);
  background-size: var(--mwk-grid-size) var(--mwk-grid-size);
}
@media (min-width: 768px) { body.mwk-v4.paper-grid { --mwk-grid-size: 3.5rem; } }
/* Light mode: white page. Beats Bootstrap's bg-body-tertiary !important. Dark mode keeps its tertiary surface. */
html[data-bs-theme="light"] body.mwk-v4.paper-grid { background-color: var(--bs-body-bg) !important; }
/* Rounder cards: this build sets border-radius directly on .card, so set it here too. */
body.mwk-v4.paper-grid .card { --bs-card-border-radius: 1rem; border-radius: 1rem; box-shadow: var(--mwk-card-shadow) !important; }
body.mwk-v4.paper-grid .card > .card-header:first-child { border-radius: 1rem 1rem 0 0; }

/* "คุณชอบพื้นหลังแบบไหน?" popup (paper-prompt.php): two choices, each with a small sample of the look.
   .mwk-paper-sample = old look (tertiary page, plain card); .is-grid = new look. Colours from the shared tokens. */
.mwk-paper-choice {
  display: block; width: 100%; min-height: 44px; padding: 1rem; text-align: start;
  color: var(--bs-body-color); background: var(--bs-body-bg);
  border: 1px solid var(--bs-border-color); border-radius: .75rem;
}
.mwk-paper-choice.active { border-color: var(--bs-primary); box-shadow: 0 0 0 1px var(--bs-primary); }
.mwk-paper-choice:focus-visible { outline: 2px solid var(--bs-primary); outline-offset: 2px; }
.mwk-paper-sample {
  height: 7.5rem; overflow: hidden;
  background: var(--bs-tertiary-bg); border: 1px solid var(--bs-border-color); border-radius: .5rem;
}
.mwk-paper-sample.is-grid {
  background-color: var(--bs-body-bg);
  background-image:
    linear-gradient(to right, var(--mwk-grid-line) 1px, transparent 1px),
    linear-gradient(to bottom, var(--mwk-grid-line) 1px, transparent 1px);
  background-size: 1.25rem 1.25rem;
}
/* Mini page: top bar, side menu, one card with text lines and a button. */
.mwk-paper-sample-nav { height: 1.5rem; flex: none; background: var(--bs-body-bg); border-bottom: 1px solid var(--bs-border-color); }
.mwk-paper-sample-body { min-height: 0; }
.mwk-paper-sample-side { width: 22%; flex: none; background: var(--bs-secondary-bg); border-inline-end: 1px solid var(--bs-border-color); }
.mwk-paper-sample-main { padding: .5rem; min-width: 0; }
.mwk-paper-sample-card {
  height: 100%; gap: .3rem; padding: .5rem; min-width: 0;
  background: var(--bs-body-bg); border: 1px solid var(--bs-border-color); border-radius: .25rem;
}
.mwk-paper-sample.is-grid .mwk-paper-sample-card { border-color: transparent; border-radius: .75rem; box-shadow: var(--mwk-card-shadow); }
.mwk-paper-sample-line { height: .3rem; width: 80%; border-radius: .15rem; background: var(--bs-secondary-bg); }
.mwk-paper-sample-line.short { width: 50%; }
.mwk-paper-sample-btn { margin-top: auto; align-self: flex-end; width: 2.5rem; height: .9rem; border-radius: .25rem; background: var(--bs-primary); }

/* Sidebar menu states (user 2026-10-23). Red marks only the page you are on, on any level.
   An open group and a hover are soft tints, never red or white. AdminLTE paints :focus, which
   left a stuck colour after a click, so hover and keyboard focus use :hover / :focus-visible. */
.mwk-v4-sidebar .sidebar-wrapper .sidebar-menu .nav-link:hover,
.mwk-v4-sidebar .sidebar-wrapper .sidebar-menu .nav-link:focus-visible {
  background-color: rgba(255, 255, 255, .08);
  color: #fff;
}

.mwk-v4-sidebar .sidebar-wrapper .sidebar-menu .nav-link.active,
.mwk-v4-sidebar .sidebar-wrapper .sidebar-menu .nav-link.active:hover,
.mwk-v4-sidebar .sidebar-wrapper .sidebar-menu .nav-link.active:focus,
.mwk-v4-sidebar .sidebar-wrapper .sidebar-menu .nav-link.active:focus-visible {
  background-color: var(--mwk-nav-active-bg);
  color: #fff;
  font-weight: 600;
}

.mwk-v4-sidebar .sidebar-wrapper .sidebar-menu > .nav-item.menu-open > .nav-link:not(.active) {
  background-color: rgba(255, 255, 255, .05);
  color: #fff;
  font-weight: 600;
}

/* Submenus sit under their group: indented, with a guide line and room above, smaller text. */
.mwk-v4-sidebar .sidebar-wrapper .sidebar-menu .nav-treeview {
  margin: .375rem 0 .625rem 1.25rem;
  padding: .25rem 0 .25rem .625rem;
  border-left: 1px solid rgba(255, 255, 255, .15);
}

.mwk-v4-sidebar .sidebar-wrapper .sidebar-menu .nav-treeview .nav-link {
  min-height: 2.375rem;
  margin-bottom: .125rem;
  font-size: .9375rem;
}

.mwk-v4-sidebar .sidebar-wrapper .sidebar-menu .nav-treeview .nav-link .nav-icon {
  font-size: .75rem;
}

.mwk-v4-sidebar .nav-header {
  font-size: .75rem;
  letter-spacing: .04em;
  text-transform: uppercase;
  opacity: .6;
}

/* "ใหม่" chip in the sidebar: light chip with dark text (colours from mwk-theme.css), a little smaller than the default badge. */
.mwk-v4-sidebar .sidebar-menu .nav-link > p > .nav-badge.badge {
  font-size: .6875rem;
  padding: .2em .5em;
  line-height: 1.25;
  font-weight: 400;
  background-color: var(--mwk-nav-badge-bg);
  color: var(--mwk-nav-badge-fg);
  border: 1px solid var(--mwk-nav-badge-border);
}

/* Group headers get room above them, so each group reads as its own block. */
.mwk-v4-sidebar .sidebar-menu > .nav-header {
  margin-top: .75rem;
}

.mwk-v4-profile {
  color: var(--bs-body-color); /* re-resolve inside the dark sidebar scope */
  padding: .75rem .75rem .875rem;
  border-bottom: 1px solid rgba(255, 255, 255, .1);
}

.mwk-v4-profile__link {
  display: flex;
  align-items: center;
  gap: .75rem;
  color: inherit;
  text-decoration: none;
}

.mwk-v4-profile__link:hover { opacity: .85; }

.mwk-v4-profile__avatar { width: 3rem; height: 3rem; }
.mwk-v4-profile__clock { background: rgba(0, 0, 0, .15); border-color: rgba(255, 255, 255, .15) !important; }

/* Student portraits are ID-style photos; show the whole image. */
.mwk-v4-profile__photo {
  width: 2.6rem;
  height: 3.3rem;
  object-fit: contain;
  border-radius: .4rem;
}

.mwk-v4-profile__text { min-width: 0; }
.mwk-v4-profile__text small { display: block; opacity: .6; font-size: .75rem; }
.mwk-v4-profile__text strong {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mwk-v4-profile__meta {
  margin-top: .625rem;
  padding-top: .625rem;
  border-top: 1px solid rgba(255, 255, 255, .1);
  font-size: .8125rem;
  line-height: 1.5;
}

/* Hide the profile block when the sidebar is collapsed to icons. */
.sidebar-mini.sidebar-collapse .app-sidebar:not(:hover) .mwk-v4-profile { display: none; }

/* Navbar */
.app-header .user-image { object-fit: cover; }

.mwk-v4-notifications {
  width: min(24rem, calc(100vw - 1rem));
  max-width: none;
}
/* Phones: the bell sits near the screen edge, so Popper would push the card off the left side.
   Pin the card to the screen width under the header instead (overrides Popper's inline transform). */
@media (max-width: 767.98px) {
  .mwk-v4-notifications {
    position: fixed !important;
    top: 4.5rem !important;
    right: .5rem !important;
    left: .5rem !important;
    width: auto;
    transform: none !important;
  }
}
/* Account menu under the header avatar: narrow card, never wider than the phone screen */
.mwk-account-menu {
  width: min(18rem, calc(100vw - 1rem));
  max-width: none;
}

.mwk-v4-notifications__scroll {
  max-height: min(60vh, 28rem);
  overflow-y: auto;
}

.mwk-v4-notifications__icon {
  display: inline-flex;
  flex: 0 0 2.25rem;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
}

/* Display settings (offcanvas #mwk-display-settings): body classes set by assets/js/v4/mwk-display.js.
   They reach every part: page, sidebar, navbar, popups and toasts. */
body.mwk-v4.underline-links a:not(.btn),
body.mwk-v4.underline-links .nav-link { text-decoration: underline !important; }
html:has(body.mwk-v4.grayscale-mode) { filter: grayscale(100%); } /* on <html> so fixed/sticky parts keep working */
/* Top Nav layout (display setting topNav, body.top-nav set by theme-init.php / mwk-display.js). Desktop only:
   no sidebar column, the header spans the page and the content is centred at 1280px. The sidebar (same menu, same
   markup) opens as a drawer from the ≡ button, body.mwk-topnav-open (mwk-display.js). Phones keep the drawer as before. */
.mwk-topnav-only { display: none !important; }
@media (min-width: 992px) {
  body.mwk-v4.top-nav .mwk-topnav-only { display: flex !important; align-items: center; gap: .5rem; margin-inline-end: 1rem; }
  body.mwk-v4.top-nav .app-wrapper { grid-template-areas: "lte-app-header" "lte-app-main" "lte-app-footer"; grid-template-columns: minmax(0, 1fr); }
  body.mwk-v4.top-nav .app-sidebar {
    position: fixed; top: 0; bottom: 0; left: 0; z-index: 1060; width: 250px; max-height: none;
    transform: translate3d(-102%, 0, 0); visibility: hidden;
    box-shadow: 8px 0 24px rgba(0, 0, 0, .24);
    transition: transform .15s ease-out, visibility 0s linear .15s;
  }
  body.mwk-v4.top-nav.mwk-topnav-open .app-sidebar { transform: none; visibility: visible; transition-delay: 0s; }
  /* Left edge strip: a mouse moving here opens the drawer (mwk-display.js topNavDrawer). */
  /* Left edge: a thin strip (hot zone) with a small handle in the middle, so the menu is discoverable. */
  .mwk-sidebar-hot-edge { position: fixed; z-index: 1059; top: 0; bottom: 0; left: 0; width: 8px; display: none; }
  .mwk-sidebar-hot-edge::after {
    content: ''; position: absolute; top: 50%; left: 0; width: 6px; height: 3.5rem; margin-top: -1.75rem;
    border-radius: 0 .5rem .5rem 0; background: var(--bs-secondary-bg); border: 1px solid var(--bs-border-color); border-left: 0;
    opacity: .75;
  }
  @media (hover: hover) and (pointer: fine) {
    body.mwk-v4.top-nav .mwk-sidebar-hot-edge { display: block; }
    body.mwk-v4.top-nav.mwk-topnav-open .mwk-sidebar-hot-edge { display: none; }
  }
  /* Current page name beside ≡ (desktop top nav only) */
  body.mwk-v4.top-nav .mwk-topnav-title { display: flex !important; min-width: 0; max-width: 40vw; }
  body.mwk-v4.top-nav .mwk-topnav-title .nav-link { padding-inline: .25rem; cursor: default; }
  /* The drawer always shows full labels, even when "ย่อเมนูด้านข้าง" is on */
  body.mwk-v4.top-nav.sidebar-collapse .app-sidebar { width: 250px; }
  body.mwk-v4.top-nav.sidebar-collapse .app-sidebar .sidebar-brand .brand-text,
  body.mwk-v4.top-nav.sidebar-collapse .app-sidebar .sidebar-menu .nav-link p,
  body.mwk-v4.top-nav.sidebar-collapse .app-sidebar .sidebar-menu .nav-header { display: inline; opacity: 1; visibility: visible; }
  body.mwk-v4.top-nav.sidebar-collapse .app-sidebar .mwk-v4-profile,
  body.mwk-v4.top-nav.sidebar-collapse .app-sidebar .mwk-menu-search-box { display: block; }
  body.mwk-v4.top-nav .app-header > .container-fluid,
  body.mwk-v4.top-nav .app-main .app-content-header > .container-fluid,
  body.mwk-v4.top-nav .app-main .app-content > .container-fluid { max-width: 1280px; margin-inline: auto; }
}
/* One brand lockup everywhere (sidebar, top nav, launch page): logo + bold name, fixed .5rem gap. */
.mwk-brand { display: flex; align-items: center; gap: .5rem; }
.mwk-brand .brand-image { float: none; flex: none; opacity: 1; box-shadow: none; }
body.mwk-v4 .mwk-brand .brand-text { margin-left: 0; font-weight: 700; }
/* Phones: the sidebar is a drawer. AdminLTE animates margin-left, which relayouts the menu on every frame and stutters.
   Slide it with transform instead (GPU), and keep the closed drawer out of taps and screen readers with visibility. */
@media (max-width: 991.98px) {
  body.mwk-v4.sidebar-expand-lg .app-sidebar {
    --lte-sidebar-width: 250px; min-width: 250px; max-width: 250px; margin-left: 0;
    transform: translate3d(-102%, 0, 0); visibility: hidden;
    transition: transform .2s ease-out, visibility 0s linear .2s;
  }
  body.mwk-v4.sidebar-expand-lg.sidebar-open .app-sidebar { transform: none; visibility: visible; transition-delay: 0s; }
  /* The drawer always shows full labels, even when the desktop "ย่อเมนูด้านข้าง" setting left body.sidebar-collapse on */
  body.mwk-v4.sidebar-expand-lg.sidebar-collapse .app-sidebar .sidebar-brand .brand-text,
  body.mwk-v4.sidebar-expand-lg.sidebar-collapse .app-sidebar .sidebar-menu .nav-link p,
  body.mwk-v4.sidebar-expand-lg.sidebar-collapse .app-sidebar .sidebar-menu .nav-header { display: inline; opacity: 1; visibility: visible; }
  body.mwk-v4.sidebar-expand-lg.sidebar-collapse .app-sidebar .mwk-v4-profile,
  body.mwk-v4.sidebar-expand-lg.sidebar-collapse .app-sidebar .mwk-menu-search-box { display: block; }
  /* Menu items stay still: no label, badge or arrow animation (AdminLTE fades and widens them on open). */
  body.mwk-v4.sidebar-expand-lg .app-sidebar .sidebar-menu .nav-link,
  body.mwk-v4.sidebar-expand-lg .app-sidebar .sidebar-menu .nav-link p,
  body.mwk-v4.sidebar-expand-lg .app-sidebar .sidebar-menu .nav-header,
  body.mwk-v4.sidebar-expand-lg .app-sidebar .brand-text,
  body.mwk-v4.sidebar-expand-lg .app-sidebar .nav-badge,
  body.mwk-v4.sidebar-expand-lg .app-sidebar .nav-arrow {
    animation: none; transition: none; width: auto; margin-left: 0; opacity: 1; visibility: visible;
  }
  body.mwk-v4.sidebar-expand-lg.sidebar-open .sidebar-overlay { animation-duration: .15s; }
  @media (prefers-reduced-motion: reduce) {
    body.mwk-v4.sidebar-expand-lg .app-sidebar { transition: none; }
  }
}
/* Bottom nav (mwk_ui_bottom_nav, staff and students), iOS tab-bar feel. It starts compact (.is-compact: icons only, a small floating bar);
   a tap expands it (labels, a little taller), and it folds back while the reader scrolls down or after a few idle seconds and expands on a clear scroll back up (mwk-nav.js bottomNav).
   One tinted pill glides to the tapped item with a little spring while the tapped icon turns into a spinner until the page opens (.is-loading);
   tapping the open page scrolls to the top. The pill's place comes from data-active and data-count on the bar, so there is no inline style.
   Devices: notch-safe sides, narrower bar on tablets, icon-only in landscape phones, hover and keyboard focus. Play: every icon arrives its own way (hop, toss, glow, flip), the pill
   stretches like liquid while it glides, a soft glow follows the finger, labels pop in one by one, the badge pops in and pulses while there is news. The page keeps room below it, sticky bars and back-to-top follow its height, and it hides while a
   field is focused for the keyboard. Sizes are the tokens on .mwk-bottom-nav. */
@keyframes mwk-nav-pop { 0% { transform: scale(.55); } 60% { transform: scale(1.2); } 100% { transform: scale(1); } }
@keyframes mwk-nav-ring { 0%, 100% { transform: rotate(0); } 20% { transform: rotate(16deg); } 40% { transform: rotate(-14deg); } 60% { transform: rotate(8deg); } 80% { transform: rotate(-4deg); } }
@keyframes mwk-nav-pulse { 0% { box-shadow: 0 0 0 0 rgba(var(--bs-danger-rgb), .55); } 70%, 100% { box-shadow: 0 0 0 .5rem rgba(var(--bs-danger-rgb), 0); } }
@keyframes mwk-nav-spin { to { transform: rotate(360deg); } }
@keyframes mwk-fx-hop { 0% { transform: translateY(0) scale(.7); } 45% { transform: translateY(-.35rem) scale(1.15); } 70% { transform: translateY(.05rem) scale(.95); } 100% { transform: none; } }
@keyframes mwk-fx-toss { 0% { transform: scale(.7); } 40% { transform: translateY(-.5rem) rotate(-24deg) scale(1.15); } 75% { transform: translateY(.05rem) rotate(8deg); } 100% { transform: none; } }
@keyframes mwk-fx-shield { 0% { transform: scale(.6); filter: drop-shadow(0 0 0 rgba(var(--bs-primary-rgb), 0)); } 50% { transform: scale(1.2); filter: drop-shadow(0 0 .4rem rgba(var(--bs-primary-rgb), .7)); } 100% { transform: none; filter: none; } }
@keyframes mwk-fx-flip { 0% { transform: perspective(200px) rotateY(-180deg) scale(.8); } 100% { transform: none; } }
@keyframes mwk-nav-breathe { 50% { opacity: .55; } }
@keyframes mwk-nav-bounce { 40% { transform: translateY(-.375rem); } 70% { transform: translateY(.0625rem); } }
@media (max-width: 991.98px) {
  body.mwk-has-bottom-nav { --mwk-bottom-nav-h: calc(4.5rem + env(safe-area-inset-bottom, 0px)); --mwk-nav-ease: cubic-bezier(.32, .72, 0, 1); --mwk-nav-spring: cubic-bezier(.34, 1.45, .64, 1); }
  /* One reserved height for both sizes: folding or expanding the bar never moves the page or the sticky bars (user, 2026-10-25). */
  .mwk-bottom-nav { --mwk-nav-pad: .1875rem; --mwk-nav-icon: 1.25rem; --mwk-nav-icon-box: 1.5rem; --mwk-nav-label: .65rem; --n: 4; --i: 0; }
  .mwk-bottom-nav[data-count="3"] { --n: 3; } .mwk-bottom-nav[data-count="5"] { --n: 5; } .mwk-bottom-nav[data-count="6"] { --n: 6; }
  .mwk-bottom-nav[data-active="1"] { --i: 1; } .mwk-bottom-nav[data-active="2"] { --i: 2; } .mwk-bottom-nav[data-active="3"] { --i: 3; } .mwk-bottom-nav[data-active="4"] { --i: 4; }
  .mwk-bottom-nav {
    left: max(.75rem, env(safe-area-inset-left, 0px)); right: max(.75rem, env(safe-area-inset-right, 0px));
    bottom: calc(.5rem + env(safe-area-inset-bottom, 0px)); max-width: 22rem; margin-inline: auto; padding: var(--mwk-nav-pad);
    background: rgba(var(--bs-body-bg-rgb), .82); -webkit-backdrop-filter: saturate(180%) blur(16px); backdrop-filter: saturate(180%) blur(16px);
    border: 1px solid var(--bs-border-color); border-radius: 1.25rem;
    box-shadow: 0 1px 6px rgba(var(--bs-body-color-rgb), .12); /* small on purpose: a big shadow is cut off by the screen edge below the bar */
    transition: max-width .3s var(--mwk-nav-ease), padding .3s var(--mwk-nav-ease); will-change: max-width;
  }
  .mwk-bottom-nav__pill {
    /* Positioned from the bar's own width, so it follows a resizing bar with no transition of its own (no ghost pill).
       The slide to a new item is a FLIP animation in mwk-nav.js. */
    position: absolute; z-index: 0; pointer-events: none; top: var(--mwk-nav-pad); bottom: var(--mwk-nav-pad);
    left: calc(var(--mwk-nav-pad) + var(--i) * (100% - 2 * var(--mwk-nav-pad)) / var(--n));
    width: calc((100% - 2 * var(--mwk-nav-pad)) / var(--n)); border-radius: 1.25rem; background: var(--bs-primary-bg-subtle);
    transition: opacity .2s;
    box-shadow: inset 0 0 0 1px rgba(var(--bs-primary-rgb), .16);
  }
  .mwk-bottom-nav:has(.is-loading) .mwk-bottom-nav__pill { animation: mwk-nav-breathe 1s ease-in-out infinite; }
  .mwk-bottom-nav[data-active="-1"] .mwk-bottom-nav__pill { opacity: 0; }
  .mwk-bottom-nav__item {
    position: relative; z-index: 1; flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: .125rem; padding: .1875rem 0;
    font-size: var(--mwk-nav-label); line-height: 1.2; text-decoration: none; color: var(--bs-secondary-color); border-radius: 1rem;
    transition: transform .15s var(--mwk-nav-spring), color .2s; -webkit-tap-highlight-color: transparent;
  }
  .mwk-bottom-nav__item::after {
    content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; opacity: 0; transform: scale(.6);
    background: radial-gradient(circle at 50% 40%, rgba(var(--bs-primary-rgb), .26), transparent 65%); transition: opacity .25s, transform .25s var(--mwk-nav-spring);
  }
  .mwk-bottom-nav__item:active::after { opacity: 1; transform: scale(1); transition-duration: .08s; }
  .mwk-bottom-nav__item:active { transform: scale(.9); }
  .mwk-bottom-nav__item:focus-visible { outline: 2px solid var(--bs-primary); outline-offset: -2px; }
  .mwk-bottom-nav__icon { position: relative; display: flex; align-items: center; justify-content: center; width: 3.25rem; height: var(--mwk-nav-icon-box); transition: height .3s var(--mwk-nav-ease), width .3s var(--mwk-nav-ease); }
  .mwk-bottom-nav__icon > .bi { font-size: var(--mwk-nav-icon); line-height: 1; transition: transform .15s var(--mwk-nav-spring), opacity .15s; }
  .mwk-bottom-nav__item:active .mwk-bottom-nav__icon > .bi { transform: scale(.82); }
  .mwk-bottom-nav__icon > .badge { position: absolute; transform: translateY(-50%); } /* not .translate-middle-y: its !important would block the pop-in animation */
  .mwk-bottom-nav__label { max-height: 1.2rem; overflow: hidden; white-space: nowrap; transition: max-height .3s var(--mwk-nav-ease), opacity .2s ease-out; }
  /* Labels pop in one after another when the bar expands. */
  .mwk-bottom-nav__item:nth-child(3) { --k: 1; } .mwk-bottom-nav__item:nth-child(4) { --k: 2; } .mwk-bottom-nav__item:nth-child(5) { --k: 3; } .mwk-bottom-nav__item:nth-child(6) { --k: 4; }
  /* Expanding: the box grows first, then the text fades in, so it is never cut off mid-growth (the clipped "SBT" of 2026-10-25). */
  body.mwk-has-bottom-nav:not(.mwk-bottom-nav-compact) .mwk-bottom-nav__label { transition: max-height .3s var(--mwk-nav-ease), opacity .2s ease-out calc(140ms + var(--k, 0) * 35ms); }
  .mwk-bottom-nav__item.is-active { color: var(--bs-primary); font-weight: 600; }
  /* The icon effect plays only for the item the reader just tapped (.is-fresh, set in mwk-nav.js). A page that arrives shows its icons still. */
  .mwk-bottom-nav__item.is-active.is-fresh .mwk-bottom-nav__icon > .bi { animation: mwk-nav-pop .4s ease-out both; }
  /* Each icon arrives its own way: house hops, cap is tossed, shield glows, the rest flip. */
  .mwk-bottom-nav__item.is-active.is-fresh[data-icon="bi-house"] .mwk-bottom-nav__icon > .bi { animation: mwk-fx-hop .5s var(--mwk-nav-spring) both; }
  .mwk-bottom-nav__item.is-active.is-fresh[data-icon="bi-mortarboard"] .mwk-bottom-nav__icon > .bi { animation: mwk-fx-toss .55s var(--mwk-nav-spring) both; }
  .mwk-bottom-nav__item.is-active.is-fresh[data-icon="bi-shield-check"] .mwk-bottom-nav__icon > .bi { animation: mwk-fx-shield .6s ease-out both; }
  .mwk-bottom-nav__item.is-active.is-fresh[data-icon="bi-clipboard-data"] .mwk-bottom-nav__icon > .bi,
  .mwk-bottom-nav__item.is-active.is-fresh[data-icon="bi-people"] .mwk-bottom-nav__icon > .bi { animation: mwk-fx-flip .5s var(--mwk-nav-spring) both; }
  .mwk-bottom-nav__item.is-active.is-fresh[data-icon="bi-bell"] .mwk-bottom-nav__icon > .bi { transform-origin: 50% 0; animation: mwk-nav-ring .9s ease-in-out both; }
  .mwk-bottom-nav__item.is-bounce .mwk-bottom-nav__icon > .bi { animation: mwk-nav-bounce .4s ease-out; }
  .mwk-bottom-nav .badge { animation: mwk-nav-pulse 2.2s .6s ease-out infinite; }
  /* Loading: the icon turns into a spinner until the next page opens. */
  .mwk-bottom-nav__item.is-loading .mwk-bottom-nav__icon > .bi { opacity: 0; animation: none; }
  .mwk-bottom-nav__item.is-loading .mwk-bottom-nav__icon::after {
    content: ""; position: absolute; top: 50%; left: 50%; width: 1.25rem; height: 1.25rem; margin: -.625rem 0 0 -.625rem;
    border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%; animation: mwk-nav-spin .7s linear infinite;
  }
  /* Compact: icons only, a slimmer and narrower bar. */
  body.mwk-bottom-nav-compact .mwk-bottom-nav { --mwk-nav-pad: .125rem; max-width: 15rem; }
  body.mwk-bottom-nav-compact .mwk-bottom-nav .mwk-bottom-nav__label { max-height: 0; opacity: 0; }
  body.mwk-bottom-nav-compact .mwk-bottom-nav .mwk-bottom-nav__item { gap: 0; padding: 0; }
  body.mwk-bottom-nav-compact .mwk-bottom-nav .mwk-bottom-nav__icon { height: 2.625rem; width: 100%; }
  @media (hover: hover) { .mwk-bottom-nav__item:hover { color: var(--bs-primary); } }
  body.mwk-has-bottom-nav .app-footer { padding-bottom: calc(var(--mwk-bottom-nav-h) + .75rem); }
  body.mwk-has-bottom-nav .sticky-bottom, body.mwk-has-bottom-nav .mwk-step-bar { bottom: var(--mwk-bottom-nav-h); }
  body.mwk-has-bottom-nav #mwk-back-to-top { bottom: calc(var(--mwk-bottom-nav-h) + .5rem); }
  body.mwk-has-bottom-nav:has(input:focus, select:focus, textarea:focus) .mwk-bottom-nav { display: none !important; }
  @media (min-width: 768px) { .mwk-bottom-nav { max-width: 24rem; } body.mwk-bottom-nav-compact .mwk-bottom-nav { max-width: 16rem; } }
  @media (max-width: 359.98px) { .mwk-bottom-nav { --mwk-nav-label: .5938rem; --mwk-nav-icon: 1.125rem; } }
  /* Landscape phones are short: icons only, a slim bar, no shrinking needed. */
  @media (max-height: 479.98px) and (orientation: landscape) {
    body.mwk-has-bottom-nav { --mwk-bottom-nav-h: calc(3.75rem + env(safe-area-inset-bottom, 0px)); }
    .mwk-bottom-nav__label { max-height: 0; opacity: 0; }
    .mwk-bottom-nav__item { gap: 0; padding: 0; }
    .mwk-bottom-nav__icon { height: 2.25rem; }
  }
  /* No slide or fade on the page itself when it changes: the skeleton is the only transition (user, 2026-10-25: stability).
     Switched off in display settings (ตั้งค่าการแสดงผล > แถบเมนูล่าง): no bar and no room kept for it. */
  body.bottom-nav-off .mwk-bottom-nav { display: none !important; }
  body.mwk-has-bottom-nav.bottom-nav-off { --mwk-bottom-nav-h: 0px; }
  @media (prefers-reduced-motion: reduce) {
    .mwk-bottom-nav, .mwk-bottom-nav *, body.mwk-has-bottom-nav .sticky-bottom, body.mwk-has-bottom-nav .mwk-step-bar, body.mwk-has-bottom-nav #mwk-back-to-top { animation: none !important; transition: none !important; }
    .mwk-bottom-nav__item.is-loading .mwk-bottom-nav__icon::after { animation: mwk-nav-spin 1.4s linear infinite !important; } /* progress must stay visible */
  }
}
@media print { .mwk-bottom-nav { display: none !important; } }
/* A page with .mwk-print-area prints only that block (e.g. Club teacher document). */
@media print {
  @page { size: A4 portrait; margin: 15mm; }
  body.mwk-v4:has(.mwk-print-area) * { visibility: hidden !important; }
  body.mwk-v4:has(.mwk-print-area) .mwk-print-area,
  body.mwk-v4:has(.mwk-print-area) .mwk-print-area * { visibility: visible !important; }
  body.mwk-v4:has(.mwk-print-area) .mwk-print-area { position: absolute; inset: 0; width: 100%; margin: 0 !important; border: 0 !important; box-shadow: none !important; color: #000 !important; background: #fff !important; }
}
body.mwk-v4.disable-animations,
body.mwk-v4.disable-animations *,
body.mwk-v4.disable-animations *::before,
body.mwk-v4.disable-animations *::after { transition: none !important; animation: none !important; scroll-behavior: auto !important; }
body.mwk-v4.reading-spacing-compact { line-height: 1.35; }
body.mwk-v4.reading-spacing-compact .card-body,
body.mwk-v4.reading-spacing-compact .modal-body { padding: .75rem; }
body.mwk-v4.reading-spacing-compact .table > :not(caption) > * > * { padding: .25rem .5rem; }
body.mwk-v4.reading-spacing-relaxed { line-height: 1.85; }
body.mwk-v4.reading-spacing-relaxed .card-body,
body.mwk-v4.reading-spacing-relaxed .modal-body { padding: 1.5rem; }
body.mwk-v4.reading-spacing-relaxed .table > :not(caption) > * > * { padding: .9rem .75rem; }
body.mwk-v4.reading-spacing-relaxed .nav-link { padding-top: .75rem; padding-bottom: .75rem; }
/* High contrast: black on white (white on black in dark mode), strong borders, obvious links and focus. */
body.mwk-v4.high-contrast { --bs-body-color: #000; --bs-body-bg: #fff; --bs-secondary-color: #1a1a1a; --bs-border-color: #000; --bs-link-color-rgb: 0, 55, 140; }
[data-bs-theme="dark"] body.mwk-v4.high-contrast { --bs-body-color: #fff; --bs-body-bg: #000; --bs-secondary-color: #f0f0f0; --bs-border-color: #fff; --bs-link-color-rgb: 255, 214, 0; }
body.mwk-v4.high-contrast { --bs-card-border-color: var(--bs-border-color); --bs-card-bg: var(--bs-body-bg); --bs-card-color: var(--bs-body-color); }
body.mwk-v4.high-contrast .card,
body.mwk-v4.high-contrast .form-control,
body.mwk-v4.high-contrast .form-select,
body.mwk-v4.high-contrast .modal-content,
body.mwk-v4.high-contrast .offcanvas { border: 1px solid var(--bs-border-color); background-color: var(--bs-body-bg); color: var(--bs-body-color); }
body.mwk-v4.high-contrast .text-body-secondary { color: var(--bs-secondary-color) !important; }
body.mwk-v4.high-contrast a:not(.btn):not(.nav-link) { text-decoration: underline; }
body.mwk-v4.high-contrast :focus-visible { outline: 3px solid #ff9800 !important; outline-offset: 2px; }
/* Table density (display setting tableDensity): cell padding only. */
body.mwk-v4.table-density-compact .table > :not(caption) > * > * { padding: .2rem .4rem; }
body.mwk-v4.table-density-relaxed .table > :not(caption) > * > * { padding: .9rem .75rem; }
/* Large touch targets (display setting largeTouch): 44px minimum for buttons and fields. */
body.mwk-v4.large-touch .btn { min-height: 2.75rem; }
body.mwk-v4.large-touch .btn-sm { min-height: 2.5rem; }
body.mwk-v4.large-touch .form-control,
body.mwk-v4.large-touch .form-select { min-height: 2.75rem; }
body.mwk-v4.large-touch .form-check-input { width: 1.5em; height: 1.5em; }
/* Roomy lines (display setting roomyLines): longer reading text only, headings keep their own leading. */
body.mwk-v4.room-lines p, body.mwk-v4.room-lines li, body.mwk-v4.room-lines td, body.mwk-v4.room-lines .card-body { line-height: 1.85; }
/* Strong focus ring (display setting strongFocus). */
body.mwk-v4.strong-focus :focus-visible { outline: 3px solid var(--bs-primary) !important; outline-offset: 2px; }
/* Privacy blur (display setting privacyBlur): photos blur until tapped (.mwk-revealed set by mwk-display.js). */
body.mwk-v4.privacy-blur :is(.mwk-avatar, .mwk-avatar-cover, .mwk-profile-photo, .mwk-detail-photo):not(.mwk-revealed) {
  filter: blur(4px);
  transition: filter .15s ease;
  cursor: pointer;
}
/* Boxed content width (display setting boxedLayout): keeps lines readable on wide screens. */
body.mwk-v4.boxed-layout .app-main .app-content-header > .container-fluid,
body.mwk-v4.boxed-layout .app-main .app-content > .container-fluid { max-width: 1280px; margin-inline: auto; }
/* Reset button: only the icon is red; it turns once on hover (display panel footer). */
#mwk-display-reset .bi { display: inline-block; transition: transform .4s ease; }
#mwk-display-reset:hover .bi, #mwk-display-reset:focus-visible .bi { transform: rotate(-360deg); }
/* Compact display panel: small buttons still get a 2.5rem touch height (user, 2026-10-22: panel took too much room). */
#mwk-display-settings .btn-sm { min-height: 2.5rem; }
/* Back-to-top button (display setting backToTop); quickHelpers() in mwk-display.js toggles .show. */
#mwk-back-to-top { display: none; position: fixed; right: 1rem; bottom: 1rem; z-index: 1030; width: 2.75rem; height: 2.75rem; align-items: center; justify-content: center; }
body.mwk-v4.back-to-top #mwk-back-to-top.show { display: inline-flex; }
/* Only the bold red arrow-circle shows (no button fill); it nudges up on hover or focus (off with disableAnimations). */
#mwk-back-to-top { padding: 0; }
/* The arrow glyph sits 2px left of the box centre in the icon font, so nudge it back */
#mwk-back-to-top .bi { display: flex; font-size: 1.5rem; line-height: 1; transform: translateX(2px); }
#mwk-back-to-top:hover .bi, #mwk-back-to-top:focus-visible .bi { animation: mwk-nudge-up .9s ease-in-out infinite; }
/* Keep the 2px centring offset inside the keyframes, or hover snaps the arrow off-centre */
@keyframes mwk-nudge-up { 0%, 100% { transform: translate(2px, 0); } 50% { transform: translate(2px, -3px); } }

/* Shared components (App/Helpers/UiHelper.php). Everything else uses AdminLTE 4 /
   Bootstrap 5 classes directly; add a rule here only when no utility exists. */
.mwk-avatar { width: 2.25rem; height: 2.25rem; flex: none; font-size: .8125rem; }
.mwk-avatar-lg { width: 3.25rem; height: 3.25rem; font-size: 1.0625rem; }
@media (min-width: 992px) { .mwk-avatar-lg { width: 4rem; height: 4rem; font-size: 1.25rem; } }
/* Portrait ratio for student ID photos, alongside Bootstrap's .ratio-* helpers. */
.ratio-3x4 { --bs-aspect-ratio: 133.3333%; }
/* Drag handle for sortable lists (SortableJS). */
.mwk-drag-handle { cursor: grab; touch-action: none; }
/* Card headers (mwk_ui_card_open): quiet and consistent. Icon, then title with the description under it. */
.mwk-card-header { padding: 1rem 1.25rem; background: var(--bs-card-bg); border-bottom: 1px solid var(--bs-border-color); }
.mwk-card-heading { min-width: 0; }
.mwk-card-title { float: none; font-size: 1rem; font-weight: 600; line-height: 1.35; margin: 0; color: var(--bs-emphasis-color); }
.mwk-card-icon { display: inline-flex; font-size: 1.25rem; line-height: 1; }
.mwk-card-desc { font-size: .8125rem; line-height: 1.45; margin: .125rem 0 0; max-width: 64ch; }
/* Rounder cards: one value for every card (step bar and header follow it). */
:root { --mwk-radius-card: 1rem; }
.card { --bs-card-border-radius: var(--mwk-radius-card); --bs-card-inner-border-radius: calc(var(--mwk-radius-card) - 1px); }
/* Collapsible cards: the chevron turns when the card is folded. The icon is an inline <i>, which ignores transform, so it needs display:inline-block. */
.mwk-card-header-toggle { cursor: pointer; }
.mwk-card-collapse-icon { display: inline-block; transition: transform .25s ease; }
.card.collapsed-card .mwk-card-collapse-icon { transform: rotate(180deg); }
.card.collapsed-card .card-header { border-bottom: 0; }
/* A folded card is only its header, so the header takes all four rounded corners. */
body.mwk-v4 .card.collapsed-card > .card-header:first-child,
body.mwk-v4.paper-grid .card.collapsed-card > .card-header:first-child { border-radius: var(--mwk-radius-card); }
/* "แสดงทั้งหมด" disclosure: the summary is a button, so hide the native triangle. */
.mwk-more > summary { list-style: none; }
.mwk-more > summary::-webkit-details-marker { display: none; }
/* Segmented pills (status filters, tabs): compact. */
.mwk-seg { padding: 4px; gap: 4px; }
.mwk-seg .nav-link { padding: .4375rem 1rem; font-size: .875rem; line-height: 1.5; border-radius: .5rem; min-height: 2.25rem; }
.mwk-seg .badge { font-size: .6875rem; font-weight: 600; padding: .15em .5em; margin-left: .25rem; }
@media (max-width: 575.98px) {
  /* Every segmented pill group (tabs, filters) on phones: one row of equal tabs that scrolls sideways,
     icon above a short label. The right edge fades while more tabs are hidden (mwk-seg-more, set in mwk-ui.js). */
  .mwk-seg { display: grid !important; grid-auto-flow: column; grid-auto-columns: minmax(max-content, 1fr); width: 100%; overflow-x: auto; scrollbar-width: none; scroll-snap-type: x proximity; overscroll-behavior-x: contain; padding: .25rem; }
  .mwk-seg::-webkit-scrollbar { display: none; }
  .mwk-seg.mwk-seg-more { mask-image: linear-gradient(to right, #000 calc(100% - 2.5rem), transparent); -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 2.5rem), transparent); }
  .mwk-seg .nav-item { min-width: 0; scroll-snap-align: start; }
  .mwk-seg .nav-link { width: 100%; min-height: 3.25rem; display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: .8125rem; line-height: 1.25; padding: .5rem .75rem; text-align: center; white-space: nowrap; }
  .mwk-seg .nav-link .bi { display: block; margin: 0 0 .125rem; font-size: 1.25rem; }
  /* A tab without an icon keeps its count beside the label; stacking it dropped the count below. */
  .mwk-seg .nav-link:not(:has(> .bi)) { flex-direction: row; }
}
/* Detail modal (mwk_ui_detail_modal): photo, quiet labels, readable values, copy on hover. */
/* Full photo (not cropped), sized per screen: phone small enough to leave the data on the first screen,
   desktop beside the tabs. Never one size for both. */
.mwk-detail-photo { display: block; margin: 0 auto; width: auto; height: auto; max-width: 100%; max-height: 10.5rem; }
@media (min-width: 576px) { .mwk-detail-photo { max-width: 9rem; max-height: none; } }
@media (min-width: 992px) { .mwk-detail-photo { max-width: 10rem; } }
/* Photo deposit (ระบบฝากรูป): previews show the whole image; 6rem phone, 7.5rem from tablet up. */
.mwk-upload-thumb { display: block; width: 100%; height: 6rem; object-fit: contain; background: var(--bs-tertiary-bg); }
@media (min-width: 768px) { .mwk-upload-thumb { height: 7.5rem; } }
.mwk-upload-result-thumb { width: 4.5rem; height: 4.5rem; flex-shrink: 0; object-fit: contain; }
@media (min-width: 992px) { .mwk-upload-result-thumb { width: 5.5rem; height: 5.5rem; } }
.mwk-upload-result-body { min-width: 0; }
/* mwk-ui.css still shrinks .btn-lg on v4 pages (body keeps the mwk-ui class): restore a 44px main button. */
body.mwk-v4.mwk-ui .btn-lg { font-size: 1.0625rem; min-height: 2.75rem; padding: .625rem 1.25rem; }
/* 44px touch target for a secondary button that sits next to a main action. */
.mwk-touch { min-height: 3rem; }
/* Search result photo: smaller than the detail popups so the code stays in view beside it. */
.mwk-result-photo { display: block; width: auto; height: auto; max-width: 100%; max-height: 7rem; }
@media (min-width: 576px) { .mwk-result-photo { max-height: 7.5rem; } }
.mwk-dl .mwk-field { padding: .625rem 0; border-bottom: 1px solid var(--bs-border-color-translucent); }
.mwk-dl .mwk-field:nth-last-child(-n+2) { border-bottom: 0; }
.mwk-dl dt { font-size: .75rem; font-weight: 500; color: var(--bs-secondary-color); margin-bottom: .125rem; }
.mwk-dl dd { font-size: .9375rem; font-weight: 500; margin: 0; word-break: break-word; }
.mwk-dl .mwk-field:nth-child(odd) { padding-right: 1rem; }
.mwk-copy { opacity: 0; transition: opacity .15s; }
.mwk-field:hover .mwk-copy, .mwk-copy:focus-visible { opacity: 1; }
.mwk-detail .modal-body { min-height: 14rem; }
/* SweetAlert2 dialogs (MWK.confirm / MWK.alert): compact, calm, readable. */
.mwk-swal { padding: 1.5rem 1.5rem 1.25rem; border-radius: .75rem; }
/* SweetAlert2 draws every icon (success, error, warning, info, question) in em of its own font-size.
   Scale the font-size, not width/height alone, or the ring and marks move off-centre. */
.mwk-swal .swal2-icon { font-size: .65rem; margin: .25rem auto .875rem; }
.mwk-swal-title { padding: 0; margin: 0; font-size: 1.125rem; font-weight: 600; line-height: 1.45; }
.mwk-swal-text { margin: .5rem 0 0; padding: 0; font-size: .9375rem; line-height: 1.55; color: var(--bs-secondary-color); }
.mwk-swal-actions { margin-top: 1.25rem; gap: .25rem; }
.mwk-swal-actions .btn { min-width: 6.5rem; }
/* Toasts (MWK.toast, SweetAlert2 toast): the bell menu's look, placed under the header like the bell menu. */
.swal2-container.swal2-top-end { padding: 4.5rem 1rem 0 0; }
.swal2-popup.swal2-toast {
  width: min(24rem, calc(100vw - 2rem));
  margin: 0;
  padding: 1rem;
  align-items: flex-start;
  background: var(--bs-body-bg);
  color: var(--bs-body-color);
  border: 1px solid var(--bs-border-color-translucent);
  border-radius: var(--bs-border-radius);
  box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .15);
}
/* Title only (no body text): centre the icon and title vertically. */
.swal2-popup.swal2-toast:not(:has(.swal2-html-container:not(:empty))) { align-items: center; }
.swal2-popup.swal2-toast .swal2-title { margin: 0; padding: 0; font-size: .875rem; font-weight: 600; line-height: 1.4; text-align: start; color: var(--bs-body-color); }
.swal2-popup.swal2-toast .swal2-html-container { margin: .125rem 0 0; padding: 0; font-size: .875rem; line-height: 1.5; text-align: start; color: var(--bs-secondary-color); }
/* Toast icon: keep SweetAlert2's own 2em toast geometry (ring, check, error marks) so they line up; only the gap changes. */
.swal2-popup.swal2-toast .swal2-icon { margin: 0 .75rem 0 0; }
/* Form stepper (mwk-ui.js initStepper). */
.mwk-step { border: 0; padding: 0; margin: 0; min-width: 0; }
.mwk-steps { display: flex; list-style: none; margin: 0 0 1.5rem; padding: 0; counter-reset: step; }
.mwk-steps-item { position: relative; flex: 1 1 0; min-width: 0; }
.mwk-steps-item:not(:last-child)::after { content: ""; position: absolute; top: 1.125rem; left: calc(50% + 1.5rem); right: calc(-50% + 1.5rem); height: 2px; background: var(--bs-border-color); }
.mwk-steps-item.is-done:not(:last-child)::after { background: var(--bs-success); }
.mwk-step-btn { display: flex; flex-direction: column; align-items: center; gap: .375rem; width: 100%; padding: 0 .25rem; border: 0; background: none; color: var(--bs-secondary-color); text-align: center; }
.mwk-step-btn:disabled { cursor: not-allowed; }
.mwk-step-dot { display: inline-flex; align-items: center; justify-content: center; width: 2.25rem; height: 2.25rem; border-radius: 50%; border: 2px solid var(--bs-border-color); background: var(--bs-body-bg); font-size: .875rem; font-weight: 600; }
.mwk-step-text { display: flex; flex-direction: column; min-width: 0; }
.mwk-step-label { font-size: .875rem; font-weight: 600; }
.mwk-step-desc { font-size: .75rem; line-height: 1.3; }
.mwk-steps-item.is-current .mwk-step-btn { color: var(--bs-emphasis-color); }
.mwk-steps-item.is-current .mwk-step-dot { border-color: var(--bs-primary); background: var(--bs-primary); color: #fff; box-shadow: 0 0 0 .25rem var(--bs-primary-bg-subtle); }
.mwk-steps-item.is-done .mwk-step-dot { border-color: var(--bs-success); background: var(--bs-success); color: #fff; }
.mwk-steps-item.is-error .mwk-step-dot { border-color: var(--bs-danger); background: var(--bs-danger); color: #fff; }
.mwk-steps-item.is-error .mwk-step-label { color: var(--bs-danger); }
.mwk-step-head { margin-bottom: 1.25rem; padding-bottom: .75rem; border-bottom: 1px solid var(--bs-border-color-translucent); }
.mwk-step-title { font-size: 1.0625rem; font-weight: 600; margin: 0; }
.mwk-step-sub { margin: .125rem 0 0; font-size: .8125rem; color: var(--bs-secondary-color); }
.mwk-step-summary { margin-bottom: 1.25rem; }
.mwk-step-bar { position: sticky; bottom: 0; z-index: 5; display: flex; align-items: center; gap: .75rem; margin: 1.5rem -1.25rem -1.25rem; padding: .75rem 1.25rem; background: var(--bs-card-bg); border-top: 1px solid var(--bs-border-color); border-radius: 0 0 var(--bs-card-border-radius) var(--bs-card-border-radius); }
@media (max-width: 575.98px) {
  .mwk-step-text .mwk-step-desc, .mwk-steps-item:not(.is-current) .mwk-step-label { display: none; }
  .mwk-steps-item:not(:last-child)::after { left: calc(50% + 1.25rem); right: calc(-50% + 1.25rem); }
}
/* Popups (mwk_ui_modal_open): one header/footer pattern. */
.modal-header { padding: 1rem 1.25rem; }
.modal-body { padding: 1.25rem; }
.modal-footer { padding: .75rem 1.25rem; gap: .5rem; }
.mwk-modal-icon {
  display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 2.5rem; height: 2.5rem; border-radius: var(--bs-border-radius);
  background: var(--bs-secondary-bg); font-size: 1.25rem;
}
.mwk-modal-icon.text-danger { background: var(--bs-danger-bg-subtle); }
.modal-header .modal-title { font-weight: 600; }
.modal-header .mwk-card-desc { margin: .25rem 0 0; font-size: .875rem; }

/* ---- Phones first: popups and dialogs -------------------------------------------
   Popups fill the screen, the footer stays visible with big touch targets, the main
   action is on top (thumb reach), and confirms become full-width bottom sheets. */
@media (max-width: 575.98px) {
  /* mwk-ui.css gives every dialog a .75rem margin on phones; a full-screen one must not be pushed off screen. */
  body.mwk-v4 .modal-dialog.modal-fullscreen-sm-down { margin: 0; }
  .modal-fullscreen-sm-down .modal-content { border-radius: 0; }
  .modal-fullscreen-sm-down .modal-header { position: sticky; top: 0; z-index: 2; background: var(--bs-modal-bg); padding: .75rem 1rem; }
  .modal-fullscreen-sm-down .modal-body { padding: 1rem; }
  .modal-fullscreen-sm-down .modal-footer {
    position: sticky; bottom: 0; z-index: 2; background: var(--bs-modal-bg);
    flex-direction: column-reverse; align-items: stretch; gap: .5rem; padding: .75rem 1rem calc(.75rem + env(safe-area-inset-bottom, 0px));
    box-shadow: 0 -4px 12px rgba(0, 0, 0, .06);
  }
  .modal-fullscreen-sm-down .modal-footer > *,
  .modal-fullscreen-sm-down .modal-footer .btn { width: 100%; margin: 0; }
  .modal-fullscreen-sm-down .modal-footer .btn { min-height: 2.75rem; }
  .mwk-detail .modal-footer { flex-direction: column; }
  .mwk-detail .modal-footer [data-slot="actions"] { flex-direction: column; width: 100%; }
  .mwk-detail .modal-footer [data-slot="actions"] .btn { min-height: 2.75rem; }
  .mwk-detail .modal-header .btn-group .btn { min-width: 2.75rem; min-height: 2.75rem; }
  .mwk-detail .modal-header .btn-close { padding: .75rem; }
  /* The ← → pager takes only its buttons' width; otherwise it grows to the whole header and the title shrinks to 0px (one word per line). */
  .mwk-detail .modal-header [data-detail-pager] { flex: 0 0 auto; max-width: max-content; }
  .mwk-dl .mwk-field { padding-right: 0 !important; }
  .mwk-copy { opacity: 1; }
  .mwk-dl dd { font-size: 1rem; }

  /* SweetAlert2 confirms: floating bottom card with a gap to every screen edge, stacked full-width buttons, main action first. */
  .swal2-container.swal2-center { align-items: flex-end; padding: .75rem .75rem calc(.75rem + env(safe-area-inset-bottom, 0px)); }
  .mwk-swal { width: 100% !important; max-width: none; margin: 0; border-radius: 1rem; padding: 1.25rem 1rem 1rem; }
  .mwk-swal-actions { flex-direction: column-reverse; width: 100%; gap: .5rem; }
  .mwk-swal-actions .btn { width: 100%; min-height: 2.75rem; margin: 0 !important; }
  .swal2-container.swal2-top-end { padding: 4.5rem .5rem 0; }
}
@media (max-width: 575.98px) {
  .mwk-step-bar .btn { min-height: 2.75rem; }
  .mwk-step-bar { padding-bottom: calc(.75rem + env(safe-area-inset-bottom, 0px)); }
  .mwk-step-count { display: none; }
}
.mwk-detail[data-single] [data-detail-pager], .mwk-detail[data-single] [data-detail-pager-sm] { display: none !important; }
@media (max-width: 575.98px) {
  .mwk-detail .modal-title { font-size: 1.0625rem; }
  .mwk-detail .modal-footer { flex-direction: column; align-items: stretch; gap: .75rem; }
  .mwk-detail .modal-footer [data-slot="actions"] { display: grid !important; grid-template-columns: 1fr 1fr; gap: .5rem; width: 100%; }
  .mwk-detail .modal-footer [data-slot="actions"] .btn { width: 100%; }
  .mwk-detail .modal-footer [data-slot="actions"] .btn:first-child { grid-column: 1 / -1; }
  /* Previous/next live in the header on phones (icon buttons), so the footer is only the actions. */
  .mwk-detail [data-detail-pager-sm] { display: none !important; }
}
/* Phone buttons that have a 44px height centre their label (inline-block would stick the text to the top). */
@media (max-width: 575.98px) {
  .modal-fullscreen-sm-down .modal-footer .btn, .mwk-swal-actions .btn, .mwk-step-bar .btn, .mwk-form-actions .btn,
  .mwk-detail .modal-header .btn-group .btn { display: inline-flex; align-items: center; justify-content: center; gap: .375rem; }
  .modal-fullscreen-sm-down .modal-footer .btn > .bi, .mwk-form-actions .btn > .bi { margin: 0 !important; }
}
/* Alerts (mwk_ui_alert and the stepper summary): soft tint, strong icon, readable text. */
.mwk-alert { display: flex; align-items: flex-start; gap: .75rem; padding: .875rem 1rem; margin-bottom: 1rem; border: 1px solid; border-radius: .625rem; }
.mwk-alert-icon { font-size: 1.25rem; line-height: 1.3; flex-shrink: 0; }
.mwk-alert-body { min-width: 0; flex: 1; }
.mwk-alert-title { font-weight: 600; line-height: 1.4; }
.mwk-alert-text { font-size: .9375rem; line-height: 1.5; margin-top: .125rem; opacity: .9; }
.mwk-alert-actions { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: .625rem; }
.mwk-alert a { font-weight: 600; text-decoration: underline; }
.mwk-alert ul { margin: .375rem 0 0; }
/* Scrolling announcement ticker: two identical groups, track slides by half its width; duration is set by mwk-ui.js. */
.mwk-marquee { overflow: hidden; min-width: 0; }
.mwk-marquee-track { display: flex; width: max-content; animation: mwk-marquee 30s linear infinite; }
.mwk-marquee-group { display: inline-flex; align-items: center; white-space: nowrap; padding-right: .5rem; }
.mwk-marquee-sep { margin-right: .5rem; opacity: .5; }
.mwk-marquee:hover .mwk-marquee-track, .mwk-marquee:focus-within .mwk-marquee-track, .mwk-marquee.is-paused .mwk-marquee-track { animation-play-state: paused; }
@keyframes mwk-marquee { to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) {
  .mwk-marquee-track { animation: none; width: auto; }
  .mwk-marquee-group { white-space: normal; flex-wrap: wrap; }
  .mwk-marquee-group[aria-hidden="true"], .mwk-marquee-toggle { display: none; }
}
.mwk-alert .btn-close { position: static; padding: .25rem; flex-shrink: 0; }
.mwk-alert-info    { background: var(--bs-info-bg-subtle);    border-color: var(--bs-info-border-subtle);    color: var(--bs-info-text-emphasis); }
.mwk-alert-success { background: var(--bs-success-bg-subtle); border-color: var(--bs-success-border-subtle); color: var(--bs-success-text-emphasis); }
.mwk-alert-warning { background: var(--bs-warning-bg-subtle); border-color: var(--bs-warning-border-subtle); color: var(--bs-warning-text-emphasis); }
.mwk-alert-danger  { background: var(--bs-danger-bg-subtle);  border-color: var(--bs-danger-border-subtle);  color: var(--bs-danger-text-emphasis); }
.mwk-alert-info .mwk-alert-icon { color: var(--bs-info); }
.mwk-alert-success .mwk-alert-icon { color: var(--bs-success); }
.mwk-alert-warning .mwk-alert-icon { color: var(--bs-warning-text-emphasis); }
.mwk-alert-danger .mwk-alert-icon { color: var(--bs-danger); }
/* Dropdown menus with icons and a hint line (toolbar groups, row menus). */
.mwk-menu { min-width: 16rem; padding: .375rem; }
.mwk-menu-item { display: flex; align-items: flex-start; gap: .625rem; padding: .5rem .625rem; border-radius: .375rem; white-space: normal; }
.mwk-menu-icon { font-size: 1.05rem; margin-top: .125rem; color: var(--bs-secondary-color); }
.mwk-menu-item.text-danger .mwk-menu-icon { color: var(--bs-danger); }
.mwk-menu-text { font-size: .9375rem; line-height: 1.35; }
.mwk-menu-text small { font-size: .78rem; margin-top: .125rem; }
@media (max-width: 575.98px) {
  .mwk-menu { min-width: min(20rem, calc(100vw - 2rem)); }
  .mwk-menu-item { padding: .75rem .75rem; min-height: 2.75rem; }
}
.mwk-tap-row { cursor: pointer; }
.mwk-tap-row:hover > td { background-color: var(--bs-tertiary-bg); }
.mwk-profile-photo { width: 4.5rem; height: 6rem; flex-shrink: 0; }
@media (min-width: 576px) { .mwk-profile-photo { width: 7rem; height: 9.333rem; } }
@media (min-width: 992px) { .mwk-profile-photo { width: 8rem; height: 10.667rem; } }
@media (max-width: 575.98px) { .mwk-form-actions .btn { min-height: 2.75rem; } }
/* A button row placed after a field in a card body needs air ("ติด", user 2026-10-26); in a card or modal footer the footer padding already gives it. */
.mwk-form-actions { margin-top: 1rem; }
.card-footer .mwk-form-actions, .modal-footer .mwk-form-actions { margin-top: 0; }

/* AdminLTE sets overflow:auto on .app-main, which stops position:sticky (.sticky-lg-top side panels). */
@media (min-width: 992px) { body.mwk-v4.layout-fixed.sidebar-expand-lg .app-main { overflow: visible; } }
/* Responsive font size utility used by empty states (Bootstrap has none): fs-2 on phones, fs-1 from md. */
@media (min-width: 768px) { .fs-md-1 { font-size: 2.5rem !important; } }

/* Filter box controls: search, select and pill switch share one height (2.5rem) and one font size,
   on phones too. Compact, but still easy to hit. */
[role="search"] .form-control, [role="search"] .form-select, [role="search"] .input-group .btn,
[role="search"] .select2-container--bootstrap-5 .select2-selection {
  min-height: 2.5rem; height: 2.5rem; padding-block: .375rem; font-size: .9375rem; line-height: 1.5;
  display: flex; align-items: center;
}
[role="search"] .input-group .btn { padding-inline: .875rem; }
[role="search"] .input-group-text { height: 2.5rem; padding-block: 0; }
[role="search"] .select2-container--bootstrap-5 .select2-selection__rendered { line-height: 1.5; padding: 0; }
[role="search"] .mwk-seg { padding: .1875rem; }
[role="search"] .mwk-seg .nav-link { min-height: 2rem; height: 2rem; padding-block: 0; font-size: .875rem; display: flex; align-items: center; justify-content: center; }
/* Table search box and page-size select match the filter controls (2.5rem). */
.dataTables_filter .form-control, .dataTables_length .form-select, .dataTables_filter .input-group .btn,
.dataTables_filter .input-group-text, .dataTables_length .input-group-text { min-height: 2.5rem; height: 2.5rem; padding-block: .375rem; font-size: .9375rem; display: flex; align-items: center; }

/* Timeline (mwk_ui_timeline): date pill, round icon on a line, one card per event. Theme tokens only. */
.mwk-timeline { position: relative; padding-top: .25rem; }
.mwk-timeline::before { content: ""; position: absolute; top: 1rem; bottom: 1rem; left: 1rem; width: 2px; margin-left: -1px; background: var(--bs-border-color); }
.mwk-tl-date { position: relative; margin: 0 0 .75rem; }
.mwk-tl-date > span { display: inline-flex; align-items: center; min-height: 1.875rem; padding: .25rem .75rem; border: 1px solid var(--bs-border-color); border-radius: 999px; background: var(--bs-tertiary-bg); color: var(--bs-secondary-color); font-size: .8125rem; font-weight: 600; }
.mwk-tl-item { position: relative; margin: 0 0 .75rem; padding-left: 3rem; }
.mwk-tl-marker { position: absolute; top: .875rem; left: 0; width: 2rem; height: 2rem; display: inline-flex; align-items: center; justify-content: center; border-radius: 50%; border: 3px solid var(--bs-body-bg); box-shadow: 0 0 0 1px var(--bs-border-color); font-size: .8125rem; }
.mwk-tl-card { padding: .875rem 1rem; border: 1px solid var(--bs-border-color); border-radius: .5rem; background: var(--bs-body-bg); }
.mwk-tl-title { margin: 0; font-size: 1rem; font-weight: 600; line-height: 1.4; overflow-wrap: anywhere; }
.mwk-tl-sub { margin: .125rem 0 0; font-size: .8125rem; color: var(--bs-secondary-color); line-height: 1.45; overflow-wrap: anywhere; }
.mwk-tl-facts { display: flex; flex-wrap: wrap; gap: .375rem; margin-top: .625rem; }
.mwk-tl-chip { display: inline-flex; align-items: center; gap: .3125rem; padding: .1875rem .5rem; border: 1px solid var(--bs-border-color); border-radius: .3125rem; background: var(--bs-tertiary-bg); color: var(--bs-body-color); font-size: .75rem; line-height: 1.4; }
.mwk-tl-body { margin-top: .75rem; }
.mwk-tl-footer { margin-top: .75rem; padding-top: .5rem; border-top: 1px solid var(--bs-border-color-translucent); font-size: .75rem; color: var(--bs-secondary-color); }
@media (max-width: 575.98px) {
  .mwk-timeline::before { left: .8125rem; }
  .mwk-tl-item { padding-left: 2.25rem; }
  .mwk-tl-marker { top: .75rem; width: 1.625rem; height: 1.625rem; font-size: .6875rem; border-width: 2px; }
  .mwk-tl-card { padding: .75rem; }
  .mwk-tl-title { font-size: .9375rem; }
}
/* from -> to boxes inside a timeline card: two equal boxes with an arrow, also on phones. */
.mwk-tl-move { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: .5rem; max-width: 28rem; }

/* Info grid (mwk_ui_info_grid): spec-sheet look. 1px gap over a border-coloured box makes the dividers. */
.mwk-info { display: grid; grid-template-columns: 1fr; border: 1px solid var(--bs-border-color); border-radius: .5rem; overflow: hidden; background: var(--bs-body-bg); }
/* Half-pixel shadows of neighbours add up to one hairline; an empty slot never shows a grey block. */
.mwk-info-cell { padding: .625rem .875rem; min-width: 0; box-shadow: 0 0 0 .5px var(--bs-border-color); }
.mwk-info dt { font-size: .75rem; font-weight: 500; color: var(--bs-secondary-color); margin-bottom: .125rem; }
.mwk-info dd { margin: 0; font-size: .9375rem; font-weight: 500; line-height: 1.45; overflow-wrap: anywhere; }
@media (min-width: 576px) {
  .mwk-info { grid-template-columns: 1fr 1fr; }
  .mwk-info-wide { grid-column: 1 / -1; }
}
/* A person/level block: small header (icon, name, role) above an info grid. */
.mwk-person-head { display: flex; align-items: center; gap: .75rem; margin-bottom: .625rem; }
.mwk-person-icon { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 2.25rem; height: 2.25rem; border-radius: 50%; background: var(--bs-tertiary-bg); color: var(--bs-secondary-color); font-size: 1.0625rem; }
.mwk-person-name { font-size: 1rem; font-weight: 600; line-height: 1.35; margin: 0; }
.mwk-person-block + .mwk-person-block { margin-top: 1.25rem; }
.mwk-info + .mwk-person-block { margin-top: 1.25rem; }

/* Phones: 44px touch targets for navbar icons and sidebar links. */
@media (max-width: 991.98px) {
  .mwk-v4-sidebar .sidebar-menu .nav-link { min-height: 2.75rem; }
  .mwk-v4-sidebar .sidebar-menu .nav-link > p { white-space: normal; }
}

/* Display settings offcanvas: wide enough on desktop, full screen on phones (phones first); selected option = primary.
   Phones: every button and switch row is at least 44px tall, the close button is 44px, and the reset footer stays at the bottom. */
#mwk-display-settings { --bs-offcanvas-width: 24rem; max-width: 100vw; }
#mwk-display-settings [aria-pressed="true"] { background-color: var(--bs-primary); border-color: var(--bs-primary); color: #fff; }
/* px, not rem: phones set the root font to 15px, so 2.75rem would be 41px */
#mwk-display-settings .btn-group .btn,
#mwk-display-settings .btn { min-height: 44px; }
#mwk-display-settings .list-group-item { min-height: 44px; }
#mwk-display-settings .btn-close { width: 44px; height: 44px; padding: .75rem; }
@media (max-width: 575.98px) {
  #mwk-display-settings { --bs-offcanvas-width: 100vw; width: 100vw; border: 0; }
  #mwk-display-settings .offcanvas-header,
  #mwk-display-settings .offcanvas-footer { padding-inline: 1rem; padding-bottom: calc(1rem + env(safe-area-inset-bottom)); }
  #mwk-display-settings .offcanvas-body { padding-inline: .75rem; }
  #mwk-display-settings .list-group-item { padding-block: .625rem; }
}

/* Required-step popups: message text keeps its line breaks; dashed drop zones; photo preview size per screen. */
.mwk-prewrap { white-space: pre-line; }
/* Round guidance images stay whole and can be opened at full size. */
.mwk-image-example { display: block; max-height: 12rem; }
/* Enlarged guidance stays whole and leaves room for its title and close controls. */
.mwk-image-viewer .mwk-image-viewer-image { max-width: 100%; max-height: calc(100dvh - 15rem); object-fit: contain; margin: 1rem auto 0; }
.mwk-image-viewer .swal2-close { min-width: 2.75rem; min-height: 2.75rem; }
@media (min-width: 576px) { .mwk-image-example { max-height: 18rem; } }
@media (min-width: 992px) { .mwk-image-example { max-height: 20rem; } }
.mwk-dashed { border-style: dashed !important; }
.mwk-forced-photo { width: 7.5rem; height: 7.5rem; }
@media (min-width: 576px) { .mwk-forced-photo { width: 9rem; height: 9rem; } }

/* Menu search is hidden while the sidebar is collapsed to icons. */
.sidebar-mini.sidebar-collapse .app-sidebar:not(:hover) .mwk-menu-search-box { display: none; }

/* Count on the navbar bell: a red pill on the icon's top-right corner, ringed in the header colour so it reads in light and dark. */
.mwk-bell-count { min-width: 1.25rem; height: 1.25rem; padding: 0 .3125rem; display: inline-flex; align-items: center; justify-content: center; font-size: .6875rem; line-height: 1; border: 2px solid var(--bs-body-bg); }

/* Navbar icon buttons: fixed px boxes so text-size changes never shift icons or the bell count. */
.app-header .navbar-nav.ms-auto > .nav-item > a.nav-link:not(.dropdown-toggle),
.app-header .navbar-nav.ms-auto > .nav-item > button.nav-link,
.app-header .navbar-nav > .mwk-sidebar-toggle > .nav-link { width: 40px; height: 40px; min-width: 40px; padding: 0; display: inline-flex; align-items: center; justify-content: center; position: relative; }
.app-header .navbar-nav.ms-auto > .nav-item > a.nav-link:not(.dropdown-toggle) > .bi,
.app-header .navbar-nav.ms-auto > .nav-item > button.nav-link > .bi,
.app-header .navbar-nav > .mwk-sidebar-toggle > .nav-link > .bi,
.app-header .navbar-nav .nav-link .position-relative > .bi { font-size: 17px; line-height: 1; }
.app-header .navbar-nav .position-relative.d-inline-block { display: inline-flex !important; width: 22px; height: 22px; align-items: center; justify-content: center; }
.app-header .mwk-bell-count { top: -5px !important; left: auto !important; right: -9px; transform: none !important; min-width: 17px; height: 17px; padding: 0 4px; font-size: 10px; border-width: 1.5px; }
.app-header .navbar-nav > .user-menu > .nav-link { height: 40px; min-width: 40px; padding: 0 8px; font-size: 16px; }

@media (max-width: 991.98px) {
  .app-header .navbar-nav.ms-auto > .nav-item > a.nav-link:not(.dropdown-toggle),
  .app-header .navbar-nav.ms-auto > .nav-item > button.nav-link,
  .app-header .navbar-nav > .mwk-sidebar-toggle > .nav-link,
  .app-header .navbar-nav > .user-menu > .nav-link { height: 44px; min-width: 44px; }
  .app-header .navbar-nav.ms-auto > .nav-item > a.nav-link:not(.dropdown-toggle),
  .app-header .navbar-nav.ms-auto > .nav-item > button.nav-link,
  .app-header .navbar-nav > .mwk-sidebar-toggle > .nav-link { width: 44px; }
}

/* Colour-mode dropdown in the navbar: icon-only button that looks like the other nav links. */
.app-header .dropdown-toggle-no-caret::after { display: none; }
.app-header button.nav-link { border: 0; background: none; color: inherit; }

/* Dark mode for pages that are not migrated yet: their own CSS hard-codes light colours, so the legacy
   content area is rendered light (data-bs-theme="light" in shell.php) and inverted as a whole; media keep
   their colours. Migrated views use Bootstrap variables and are not touched. Disappears with the last legacy page. */
[data-bs-theme="dark"] .mwk-legacy-content { filter: invert(.92) hue-rotate(180deg); }
[data-bs-theme="dark"] .mwk-legacy-content img,
[data-bs-theme="dark"] .mwk-legacy-content video,
[data-bs-theme="dark"] .mwk-legacy-content canvas,
[data-bs-theme="dark"] .mwk-legacy-content iframe { filter: invert(1) hue-rotate(180deg); }
.mwk-legacy-content { color: var(--bs-body-color); } /* re-resolve inside the light scope */

/* Select2 follows the colour mode (its Bootstrap 5 theme is light only). */
[data-bs-theme="dark"] .select2-container--bootstrap-5 .select2-selection,
[data-bs-theme="dark"] .select2-container--bootstrap-5 .select2-dropdown,
[data-bs-theme="dark"] .select2-container--bootstrap-5 .select2-search__field {
  background-color: var(--bs-body-bg); color: var(--bs-body-color); border-color: var(--bs-border-color);
}
[data-bs-theme="dark"] .select2-container--bootstrap-5 .select2-selection__rendered,
[data-bs-theme="dark"] .select2-container--bootstrap-5 .select2-results__option { color: var(--bs-body-color); }
[data-bs-theme="dark"] .select2-container--bootstrap-5 .select2-results__option--highlighted { background-color: var(--bs-primary); color: #fff; }
[data-bs-theme="dark"] .select2-container--bootstrap-5 .select2-results__option[aria-selected="true"] { background-color: var(--bs-secondary-bg); }

/* Push prompt is a <dialog>, not a .modal: give its content the modal surface itself. */
.mwk-push-prompt .modal-content {
  --bs-modal-bg: var(--bs-body-bg); --bs-modal-color: var(--bs-body-color); --bs-modal-border-color: var(--bs-border-color);
  --bs-modal-header-border-color: var(--bs-border-color); --bs-modal-footer-border-color: var(--bs-border-color);
  --bs-modal-padding: 1rem; --bs-modal-header-padding: 1rem; --bs-modal-footer-gap: .5rem;
  background: var(--bs-body-bg); color: var(--bs-body-color); border: 1px solid var(--bs-border-color); border-radius: var(--bs-border-radius-lg);
}
.mwk-push-prompt .modal-header, .mwk-push-prompt .modal-body, .mwk-push-prompt .modal-footer { padding: 1rem; }
.mwk-push-prompt .modal-header { border-bottom: 1px solid var(--bs-border-color); }
.mwk-push-prompt .modal-footer { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: .5rem; border-top: 1px solid var(--bs-border-color); }

/* Home: tiles flow into as many columns as fit the card (no fixed breakpoints, so a narrow card does not stack one tile per row). */
.mwk-autogrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr)); gap: .5rem; }
/* Tablet and desktop: wider tiles so the name and the "ใหม่" badge do not break words. */
@media (min-width: 768px) { .mwk-autogrid { grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr)); gap: .75rem; } }
/* Home: shortcut tiles and row icons (no Bootstrap utility sets a fixed square size). */
.mwk-shortcut { min-height: 2.75rem; transition: background-color .15s; }
.mwk-shortcut:hover { background-color: var(--bs-tertiary-bg) !important; color: var(--bs-body-color); }
.mwk-shortcut-icon { width: 2rem; height: 2rem; font-size: 1rem; }
.mwk-row-icon { width: 2.5rem; height: 2.5rem; font-size: 1.125rem; }
.min-w-0 { min-width: 0; }
/* Home banner popup: dialog sits at the top, centred, 1rem from the edges; image fits under the close row and indicators. .mwk-icon-btn = 2.5rem square icon button (banner close, QR at the photo corner). */
.mwk-banner-dialog { margin: 1rem auto; max-width: min(71.25rem, calc(100% - 2rem)); }
.mwk-banner-img { max-height: calc(100dvh - 7rem); width: auto; }
.mwk-icon-btn { width: 2.5rem; height: 2.5rem; padding: 0; }

/* Sidebar profile: compact clock box on phones, a little roomier from tablet up. */
.mwk-v4-profile__clock .fs-4 { font-size: 1.375rem !important; }
@media (min-width: 992px) { .mwk-v4-profile__clock .fs-4 { font-size: 1.5rem !important; } }
.mwk-rank { width: 1.5rem; flex: none; }
.mwk-home-logo { width: 3.5rem; height: 3.5rem; } @media (min-width: 992px) { .mwk-home-logo { width: 4rem; height: 4rem; } }
.mwk-row-body { flex: 1 1 12rem; min-width: 0; }
/* List rows with several buttons (MWKGo): a full-width bar of equal thumb-size buttons on phones, compact at the row end from 576px. */
.mwk-row-actions { width: 100%; }
.mwk-row-actions > .d-flex > .btn, .mwk-row-actions > .d-flex > .dropdown > .btn { flex: 1 1 0; min-height: 2.75rem; display: inline-flex; align-items: center; justify-content: center; white-space: nowrap; padding-inline: .375rem; }
.mwk-row-actions > .d-flex > .dropdown { display: flex; flex: 1 1 0; }
@media (min-width: 576px) {
  .mwk-row-actions { width: auto; flex-shrink: 0; margin-left: auto; }
  .mwk-row-actions > .d-flex > .btn, .mwk-row-actions > .d-flex > .dropdown > .btn { flex: none; min-height: 0; padding-inline: .5rem; }
  .mwk-row-actions > .d-flex > .dropdown { flex: none; }
}
/* Phones: every menu item (row ⋯ menus, toolbar dropdowns) is a 44px thumb target. */
@media (max-width: 575.98px) { .dropdown-menu .dropdown-item { min-height: 2.75rem; display: flex; align-items: center; } }
/* MWKGo people picker: the result list floats over the next fields and scrolls when long. */
.mwk-people-list { z-index: 1000; max-height: 18rem; overflow-y: auto; }
/* Hero: round logo and avatar sizes per screen (phone / desktop). */
.mwk-welcome-logo { width: 4rem; height: 4rem; padding: .25rem; }
@media (min-width: 992px) { .mwk-welcome-logo { width: 5rem; height: 5rem; } .mwk-welcome .mwk-avatar-lg { width: 5rem; height: 5rem; font-size: 1.5rem; } }

/* Sign-in pages (mwk_ui_auth_open): school logo emblem and its icon badge, sized per screen. */
.mwk-auth-emblem { width: 4.5rem; height: 4.5rem; }
.mwk-auth-badge { width: 1.75rem; height: 1.75rem; font-size: .875rem; }
@media (min-width: 992px) { .mwk-auth-emblem { width: 5.5rem; height: 5.5rem; } .mwk-auth-badge { width: 2rem; height: 2rem; font-size: 1rem; } }
/* Provider buttons sit beside Google's own personalised button (40px tall, max 400px wide, logo left, label centred): same size, border and radius so the three read as one set. Pixels, not rem: Google does not scale with the text-size setting. */
.mwk-auth-provider { position: relative; max-width: 400px; margin-inline: auto; }
.mwk-auth-slot { min-height: 40px; }
body.mwk-v4 .btn.mwk-auth-provider { height: 40px; min-height: 40px; padding: 0 40px; font-size: 14px; font-weight: 500; border-radius: 4px; color: var(--bs-body-color); background: var(--bs-body-bg); border: 1px solid var(--bs-border-color); }
body.mwk-v4 .btn.mwk-auth-provider:hover, body.mwk-v4 .btn.mwk-auth-provider:focus-visible { background: var(--bs-tertiary-bg); border-color: var(--bs-secondary-border-subtle); color: var(--bs-body-color); }
body.mwk-v4 .btn.mwk-auth-provider:focus-visible { box-shadow: 0 0 0 .2rem var(--bs-primary-border-subtle); }
/* "ใช้ล่าสุด" tag: vertically centred inside the button, right edge; the button reserves room so the label never runs under it. */
.mwk-auth-last { font-size: 11px; font-weight: 600; line-height: 1; padding: .3rem .55rem; border-radius: 999px; white-space: nowrap; background: var(--bs-primary-bg-subtle); color: var(--bs-primary-text-emphasis); }
.mwk-auth-provider > .mwk-auth-last { position: absolute; right: 10px; top: 50%; transform: translateY(-50%); }
body.mwk-v4 .btn.mwk-auth-provider.has-last { padding-right: 76px; }
.mwk-auth-last-inline { display: inline-block; margin-left: .5rem; vertical-align: middle; }
.mwk-auth-provider-logo { position: absolute; left: 12px; top: 50%; width: 20px; height: 20px; transform: translateY(-50%); }
.mwk-fact { font-size: .875rem; } @media (min-width: 768px) { .mwk-fact { font-size: 1rem; } }
.mwk-qr { max-width: 12rem; } @media (min-width: 768px) { .mwk-qr { max-width: 14rem; } }
/* Passkey recovery script marks a bad field with aria-invalid and writes its message into [data-recovery-status]. */
.form-control[aria-invalid="true"] { border-color: var(--bs-danger); }
[data-recovery-status]:empty { display: none; }
[data-recovery-status][data-state="error"] { color: var(--bs-danger-text-emphasis) !important; }
.mwk-progress-thin { height: .5rem; }
.border-dashed { border-style: dashed !important; }
.mwk-fact-icon { width: 2rem; height: 2rem; font-size: .9375rem; } @media (min-width: 768px) { .mwk-fact-icon { width: 2.25rem; height: 2.25rem; font-size: 1rem; } }
/* Old home look: only the top edge of the tasks card is yellow. */
.mwk-edge-warning { border-top: 3px solid var(--bs-warning); }
/* Welcome card: ID photo is smaller than on the profile page (phone 4.5x6rem, md+ 6x8rem); side column holds stat tiles and the account button. */


/* Welcome card = student ID: red side panel (full width header on phones, 17rem column from md), photo 6x8rem phone / 9.4x12.5rem md+, QR button on its corner. */
/* Brand gradient surface with two soft overlapping circles on the right (user chose the soft look over a hard ring).
   Use .mwk-brand-surface on any red gradient panel; circles are smaller on phones. */
.mwk-hero-panel, .mwk-brand-surface { position: relative; overflow: hidden; background: var(--mwk-brand-gradient); }
.mwk-hero-panel::before, .mwk-hero-panel::after, .mwk-brand-surface::before, .mwk-brand-surface::after {
  content: ""; position: absolute; border-radius: 50%; pointer-events: none; background: rgba(255, 255, 255, .14);
  right: -2.5rem; top: -3rem; width: 9.5rem; height: 9.5rem;
}
.mwk-hero-panel::after, .mwk-brand-surface::after { background: rgba(255, 255, 255, .08); right: 3rem; top: auto; bottom: -4rem; width: 7.5rem; height: 7.5rem; }
.mwk-hero-panel > *, .mwk-brand-surface > * { position: relative; z-index: 1; }
@media (min-width: 768px) {
  .mwk-hero-panel::before, .mwk-brand-surface::before { right: -3rem; top: -4rem; width: 12rem; height: 12rem; }
  .mwk-hero-panel::after, .mwk-brand-surface::after { right: 4rem; bottom: -5rem; width: 9rem; height: 9rem; }
}
.mwk-hero-label { letter-spacing: .08em; opacity: .9; }
.mwk-hero-code { letter-spacing: .12em; }
.mwk-welcome .mwk-profile-photo { width: 6rem; height: 8rem; }
@media (min-width: 768px) { .mwk-welcome .mwk-profile-photo { width: 9.375rem; height: 12.5rem; } }
.mwk-welcome .mwk-icon-btn { width: 2.5rem; height: 2.5rem; }
.mwk-stat-tile { min-width: 8rem; }
/* Hero facts: label/value one step smaller so the grid stays compact */
.mwk-fact-label { font-size: .75rem; }
.mwk-fact { font-size: .875rem; }
.mwk-qr-corner { transform: translate(25%, 25%); }

/* Sign-in role cards: border darkens on hover so they read as tappable. */

/* Announcement body: author HTML (editor output) must fit the page and keep readable line spacing. */
.mwk-prose { line-height: 1.85; overflow-wrap: anywhere; }
.mwk-prose img, .mwk-prose video, .mwk-prose iframe { max-width: 100%; height: auto; }
.mwk-prose table { display: block; max-width: 100%; overflow-x: auto; border-collapse: collapse; }
.mwk-prose th, .mwk-prose td { border: 1px solid var(--bs-border-color); padding: .4rem .6rem; }
.mwk-prose blockquote { border-left: .25rem solid var(--bs-border-color); padding-left: 1rem; color: var(--bs-secondary-color); }
.mwk-prose hr { opacity: .25; }
.mwk-prose > :last-child { margin-bottom: 0; }

/* Row just saved (?saved=...&sid=...): the same tint on every cell, so the row is found after the toast. */
.table > tbody > tr.mwk-saved-row > * {
  background-color: var(--mwk-row-highlight);
}

/* Table head: sort icon sits right after the title (vendor puts two arrows at the cell edge). */
table.dataTable > thead > tr > th { padding: 1rem .75rem; font-size: .875rem; font-weight: 600; white-space: nowrap; vertical-align: middle; background: var(--bs-secondary-bg); color: var(--bs-body-color); border-bottom: 1px solid var(--bs-border-color); }
table.dataTable > thead > tr > th:not(.sorting_disabled) { padding-right: .75rem; }
table.dataTable > thead .sorting:before, table.dataTable > thead .sorting_asc:before, table.dataTable > thead .sorting_desc:before { display: none; }
table.dataTable > thead .sorting:after, table.dataTable > thead .sorting_asc:after, table.dataTable > thead .sorting_desc:after {
  position: static; display: inline-block; margin-left: .25rem; vertical-align: middle; font-family: bootstrap-icons; font-size: .875rem; line-height: 1; opacity: .4; content: "\f283";
}
table.dataTable > thead .sorting_asc:after { content: "\f145"; opacity: 1; color: var(--bs-primary); }
table.dataTable > thead .sorting_desc:after { content: "\f124"; opacity: 1; color: var(--bs-primary); }
table.dataTable > thead .sorting:hover:after { opacity: .8; }
/* Page changes: short cross-fade, navbar and sidebar stay put (Chrome/Edge/Safari; others ignore it).
   Desktop only: on phones the drawer is closed on the new page, so its old snapshot would linger and fade out over it. */
@media (prefers-reduced-motion: no-preference) and (min-width: 992px) {
  @view-transition { navigation: auto; }
  .app-header { view-transition-name: mwk-header; }
  .app-sidebar { view-transition-name: mwk-sidebar; }
  ::view-transition-old(root), ::view-transition-new(root) { animation-duration: .14s; }
}

/* Page loading: thin bar under the navbar while a link or form is loading (mwk-nav.js beginNav).
   It only grows when .is-on is added, and it disappears at once when that class is removed. */
.mwk-nav-progress { position: fixed; top: 0; left: 0; height: 3px; width: 0; opacity: 0; background: var(--bs-primary); z-index: 1200; pointer-events: none; }
.mwk-nav-progress.is-on { opacity: 1; width: 85%; transition: width 8s cubic-bezier(.1, .6, .3, 1); }

/* Loading skeleton: a native v4 page starts with body.mwk-is-loading (shell.php). The skeleton (mwk_ui_page_skeleton) shows, and the
   real content and sidebar stay hidden in place, so their space is kept and nothing moves when they appear. mwk-nav.js removes the
   class once the DOM is ready and its fonts are ready (settleSkeleton; not window load). Blocks use the --mwk-skel tokens from mwk-theme.css. */
body.mwk-v4 .app-main { position: relative; }
.mwk-page-skeleton { display: none; position: absolute; top: 0; left: 0; right: 0; }
/* The skeleton waits 150 ms before it shows, so a page that is ready sooner never flashes it (UX: no flicker). */
body.mwk-is-loading .mwk-page-skeleton { display: block; animation: mwk-skel-in .2s ease-out .15s both; }
/* Hidden while loading: transparent and not tappable, but still in place (no movement). They fade in when the class goes. */
body.mwk-is-loading .app-main > :not(.mwk-page-skeleton),
body.mwk-is-loading .app-footer,
body.mwk-is-loading .app-sidebar .sidebar-wrapper { opacity: 0; pointer-events: none; }
body.mwk-v4 .app-main > :not(.mwk-page-skeleton),
body.mwk-v4 .app-footer,
body.mwk-v4 .app-sidebar .sidebar-wrapper { transition: opacity .24s ease-out; }
@keyframes mwk-skel-in { from { opacity: 0; } to { opacity: 1; } }
.mwk-skel { display: block; position: relative; overflow: hidden; background: var(--mwk-skel); border-radius: .375rem; }
.mwk-skel::after { content: ''; position: absolute; inset: 0; background: linear-gradient(90deg, transparent, var(--mwk-skel-shine), transparent); transform: translateX(-100%); animation: mwk-shimmer 1.3s ease-in-out infinite; }
@keyframes mwk-shimmer { to { transform: translateX(100%); } }
.mwk-skel-title { width: 40%; height: 1.75rem; }
.mwk-skel-line { height: .875rem; margin-top: .5rem; }
.mwk-skel-line:first-child { margin-top: 0; }
.mwk-skel-avatar { width: 2.5rem; height: 2.5rem; border-radius: 50%; }
.mwk-skel-box { height: 2.5rem; border-radius: .5rem; }
.mwk-skel-pill { width: 6.5rem; height: 2.25rem; border-radius: 2rem; }
.mwk-skel-box.mt-3 { height: 9rem; }
.mwk-page-skeleton .app-content-header { padding-bottom: .5rem; }
.mwk-page-skeleton .app-content { padding-top: .5rem; }
@media (max-width: 575.98px) { .mwk-skel-title { width: 65%; } .mwk-skel-box.mt-3 { height: 6rem; } }
/* Reveal (settleSkeleton): the skeleton fades out while the page, sidebar and footer fade in, in the same place. No movement. */
body.mwk-is-revealing .mwk-page-skeleton { display: block; animation: mwk-skel-out .24s ease-out both; }
@keyframes mwk-skel-out { to { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .mwk-skel::after { animation: none; }
  body.mwk-is-loading .mwk-page-skeleton, body.mwk-is-revealing .mwk-page-skeleton { animation: none; }
  body.mwk-v4 .app-main > :not(.mwk-page-skeleton), body.mwk-v4 .app-footer, body.mwk-v4 .app-sidebar .sidebar-wrapper { transition: none; }
}
@media (prefers-reduced-motion: reduce) { .mwk-nav-progress.is-on { transition: none; width: 85%; } }

/* Permissions page: the system chevron turns when its <details> is open. */
.perm-system[open] > summary .perm-chevron { transform: rotate(90deg); }
.perm-system > summary { list-style: none; }
.perm-system > summary::-webkit-details-marker { display: none; }
.perm-chevron { transition: transform .15s ease; }

/* Home (visitor and signed-in). Below xl the two columns dissolve so the blocks sit directly in .row (order-* on the blocks);
   from xl the columns return. display:contents drops the column's gutter padding, so each block takes the same gutter as .row > *. */
@media (max-width: 1199.98px) { .mwk-contents-lt-xl { display: contents; } .mwk-contents-lt-xl > * { padding-inline: calc(var(--bs-gutter-x) * .5); } }
/* Role buttons "ฉันคือ…": lift on hover/focus, chevron slides, gentle staggered entrance. */
.mwk-role-link { transition: transform .15s ease, box-shadow .15s ease; }
.mwk-role-link:hover, .mwk-role-link:focus-visible { transform: translateY(-2px); box-shadow: var(--bs-box-shadow-sm); }
.mwk-role-link .mwk-row-icon { transition: transform .2s ease; }
.mwk-role-link:hover .mwk-row-icon, .mwk-role-link:focus-visible .mwk-row-icon { transform: scale(1.12) rotate(-6deg); }
.mwk-role-link .bi-chevron-right { transition: transform .15s ease; }
.mwk-role-link:hover .bi-chevron-right, .mwk-role-link:focus-visible .bi-chevron-right { transform: translateX(.25rem); }
@media (prefers-reduced-motion: no-preference) {
  .mwk-rise { animation: mwk-rise .45s ease both; }
  .mwk-rise:nth-child(2) { animation-delay: .07s; }
  .mwk-rise:nth-child(3) { animation-delay: .14s; }
  @keyframes mwk-rise { from { opacity: 0; transform: translateY(.5rem); } }
  /* Logo floats slowly; cards below the fold fade up when scrolled into view (home-guest.js adds .mwk-reveal, then .is-in). */
  .mwk-float { animation: mwk-float 4s ease-in-out infinite; }
  @keyframes mwk-float { 50% { transform: translateY(-.25rem); } }
  .mwk-reveal { opacity: 0; transform: translateY(1rem); transition: opacity .5s ease, transform .5s ease; }
  .mwk-reveal.is-in { opacity: 1; transform: none; }
}

/* Visitor home banner: a soft placeholder keeps the card from looking empty while the large image is still decoding.
   The natural height takes over once the image is drawn. */
#guestHomeBannerCarousel img { min-height: 8rem; background-color: var(--bs-tertiary-bg); }

/* Live clock in the visitor status bar: digits keep the same width so the text does not jitter every second. */
#guest-status .tabular-nums { font-variant-numeric: tabular-nums; }

/* Visitor home on phones: the content sits 16px from the screen edge (8px app-content + 8px container). The migrate guide asks for 16px,
   so the container gives back 4px here only. The row keeps its default negative margin; the blocks' gutter padding cancels it.
   Scoped with :has() so the other pages keep their spacing. */
@media (max-width: 575.98px) {
  .app-content > .container-fluid:has(#guest-welcome) { padding-inline: .5rem; }
}

/* Account page: square profile picture (personnel photos are cropped 1:1): phone 5rem, tablet 8rem, desktop 9rem. */
.mwk-profile-square { width: 5rem; height: 5rem; flex-shrink: 0; }
/* Square photo editor: direct touch manipulation, with a larger desktop preview. */
.mwk-photo-upload.is-dragover .mwk-photo-drop-zone { border-color: var(--bs-primary) !important; background: var(--bs-primary-bg-subtle) !important; }
.mwk-photo-current-panel { border-bottom: 1px solid var(--bs-border-color); }
.mwk-photo-current-image { width: min(100%, 12rem); height: auto; aspect-ratio: 1; }
.mwk-photo-choose, .mwk-photo-file-actions .btn { min-height: 2.75rem; }
.mwk-photo-file-info { min-width: 0; }
@media (max-width: 575.98px) {
  .mwk-photo-choose { width: 100%; }
  .mwk-photo-file-actions .btn { flex: 1 1 auto; }
}
.mwk-photo-crop { position: relative; width: min(100%, 20rem); aspect-ratio: 1; }
.mwk-photo-crop canvas { display: block; width: 100%; height: 100%; touch-action: none; cursor: grab; }
.mwk-photo-crop canvas.is-dragging { cursor: grabbing; }
.mwk-photo-crop canvas:focus-visible { outline: 3px solid var(--bs-primary); outline-offset: -3px; }
.mwk-photo-crop-frame { position: absolute; inset: 9%; border: 2px solid var(--bs-white); outline: 1px solid color-mix(in srgb, var(--bs-secondary-color) 70%, transparent); box-shadow: 0 0 0 30rem color-mix(in srgb, var(--bs-secondary-color) 48%, transparent); pointer-events: none; }
.mwk-photo-crop-frame::after { content: ''; position: absolute; inset: 0; opacity: 0; background: linear-gradient(to right, transparent calc(100% / 3 - .5px), var(--bs-white) calc(100% / 3), transparent calc(100% / 3 + .5px), transparent calc(200% / 3 - .5px), var(--bs-white) calc(200% / 3), transparent calc(200% / 3 + .5px)), linear-gradient(to bottom, transparent calc(100% / 3 - .5px), var(--bs-white) calc(100% / 3), transparent calc(100% / 3 + .5px), transparent calc(200% / 3 - .5px), var(--bs-white) calc(200% / 3), transparent calc(200% / 3 + .5px)); }
.mwk-photo-crop canvas.is-dragging + .mwk-photo-crop-frame::after { opacity: .55; }
.mwk-photo-crop-hint { position: absolute; top: .75rem; left: 50%; transform: translateX(-50%); white-space: nowrap; pointer-events: none; }
.mwk-photo-crop-zoom { min-width: 0; min-height: 2.75rem; margin: 0; }
.mwk-photo-crop-tools .btn { min-width: 2.75rem; min-height: 2.75rem; }
.mwk-photo-crop-result { display: block; width: 4rem; height: 4rem; }
@media (min-width: 768px) {
  .mwk-photo-crop { width: min(100%, 24rem); }
  .mwk-photo-crop-result { width: min(100%, 8rem); height: auto; aspect-ratio: 1; margin-inline: auto; }
}
@media (min-width: 992px) {
  .mwk-photo-current-panel { border-bottom: 0; border-inline-end: 1px solid var(--bs-border-color); }
  .mwk-photo-current-image { width: min(100%, 18rem); }
}
/* Mandatory entry keeps the upload action above a compact current-photo row. */
#editProfilePictureModal .modal-footer:has(.mwk-modal-logout) > .btn {
  min-height: 2.75rem; display: inline-flex; align-items: center; justify-content: center;
}
@media (min-width: 576px) {
  #editProfilePictureModal .modal-footer:has(.mwk-modal-logout) > .btn { width: 13rem; }
}
.mwk-photo-upload-required .mwk-photo-current-panel { border: 0; border-top: 1px solid var(--bs-border-color); }
.mwk-photo-upload-required .mwk-photo-current-image { width: 4rem; height: 4rem; }
@media (min-width: 768px) {
  .mwk-photo-upload-required .mwk-photo-current-image { width: 5rem; height: 5rem; }
}
@media (min-width: 576px) { .mwk-profile-square { width: 8rem; height: 8rem; } }
@media (min-width: 992px) { .mwk-profile-square { width: 9rem; height: 9rem; } }

/* Passkey enrolment (passkey.js sets .pk-step-complete, aria-current and data-state). */
.passkey-account summary { list-style: none; cursor: pointer; }
.passkey-account summary::-webkit-details-marker { display: none; }
.passkey-account details[open] > summary > .pk-toggle { transform: rotate(180deg); }
.pk-steps { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .5rem; list-style: none; padding: 0; margin: 0 0 1rem; }
.pk-steps li { display: flex; align-items: center; gap: .375rem; font-size: .8125rem; color: var(--bs-secondary-color); }
.pk-steps li > span { display: inline-flex; align-items: center; justify-content: center; width: 1.5rem; height: 1.5rem; border-radius: 50%; border: 1px solid var(--bs-border-color); background: var(--bs-tertiary-bg); font-size: .75rem; }
.pk-steps [aria-current="step"] { color: var(--bs-primary); font-weight: 600; }
.pk-steps [aria-current="step"] > span { background: var(--bs-primary); border-color: var(--bs-primary); color: var(--bs-white); }
.pk-steps .pk-step-complete > span { background: var(--bs-success-bg-subtle); border-color: var(--bs-success-border-subtle); color: var(--bs-success-text-emphasis); }
.pk-message:empty { display: none; }
.pk-message { padding: .75rem 1rem; margin-bottom: 1rem; border-radius: .5rem; border-left: 3px solid var(--bs-primary); background: var(--bs-tertiary-bg); font-size: .875rem; overflow-wrap: anywhere; }
.pk-message[data-state="error"] { border-left-color: var(--bs-danger); }
.pk-message[data-state="success"] { border-left-color: var(--bs-success); }

/* List rows that sit flush inside a card body (p-0) must follow the card's rounded bottom corners,
   otherwise the square last row pokes out past the card edge (user, 2026-10-22). */
.card > .card-body.p-0 > .list-group:last-child > .list-group-item:last-child {
  border-bottom-left-radius: var(--bs-card-inner-border-radius, calc(var(--bs-card-border-radius, .375rem) - var(--bs-card-border-width, 1px)));
  border-bottom-right-radius: var(--bs-card-inner-border-radius, calc(var(--bs-card-border-radius, .375rem) - var(--bs-card-border-width, 1px)));
}

/* Notification settings cards: anchor jumps (#device, #email) stop below the sticky navbar. */
#device, #email { scroll-margin-top: 4.5rem; }
/* API docs: cards reached from the "ไปที่หัวข้อ" menu stop below the sticky navbar */
.mwk-anchor { scroll-margin-top: 4.5rem; }

/* Roster export (mwk_ui_roster_export) ------------------------------------------------------ */
/* Choice tile: a radio drawn as a bordered box; the chosen one turns action blue. */
.mwk-choice { display: flex; gap: .75rem; align-items: flex-start; padding: .75rem 1rem; min-height: 4rem; cursor: pointer; border: 1px solid var(--bs-border-color); border-radius: var(--bs-border-radius-lg); background: var(--bs-body-bg); }
.mwk-choice:hover { border-color: var(--bs-primary-border-subtle); }
.btn-check:checked + .mwk-choice { border-color: var(--bs-primary); background: var(--bs-primary-bg-subtle); box-shadow: 0 0 0 1px var(--bs-primary); }
.btn-check:checked + .mwk-choice .bi { color: var(--bs-primary) !important; }
.btn-check:focus-visible + .mwk-choice { outline: 2px solid var(--bs-primary); outline-offset: 2px; }
/* Ordered column rows: big grip (44px) so a thumb can drag; the row lifts while dragging. */
.mwk-col-row { min-height: 3.25rem; }
.mwk-col-handle, .mwk-col-remove { width: 2.75rem; height: 2.75rem; display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; text-decoration: none; }
.mwk-col-row { transition: transform .15s ease; }
.mwk-col-step { width: 2.75rem; height: 1.5rem; display: inline-flex; align-items: center; justify-content: center; text-decoration: none; line-height: 1; }
.mwk-col-step:disabled { opacity: .3; }
.mwk-sorting { user-select: none; }
.mwk-col-row.mwk-dragging { transition: none; touch-action: none; background: var(--bs-body-bg) !important; border-color: var(--bs-primary) !important; box-shadow: var(--bs-box-shadow); position: relative; z-index: 2; }
.mwk-col-row.mwk-dragging .mwk-col-handle { cursor: grabbing; }
.mwk-pick-row { min-height: 2.75rem; cursor: pointer; }
.mwk-summary-row { cursor: pointer; }
.mwk-roster-bar { z-index: 1030; }
/* The printed document uses TH Sarabun New; the preview must look the same. */
@font-face { font-family: 'TH Sarabun New'; src: url('../../fonts/THSarabunNew.ttf') format('truetype'); font-weight: normal; font-style: normal; font-display: swap; }
@font-face { font-family: 'TH Sarabun New'; src: url('../../fonts/THSarabunNew_Bold.ttf') format('truetype'); font-weight: bold; font-style: normal; font-display: swap; }
/* Scale paper typography with its own container, independently of UI font preferences. */
.mwk-paper-stage { width: 100%; max-width: 11rem; margin-inline: auto; container-type: inline-size; }
@media (min-width: 992px) { .mwk-roster-preview { max-height: calc(100dvh - 5.5rem); overflow-y: auto; } }
.mwk-paper-stage:has([data-orientation="landscape"]) { max-width: 16rem; }
.mwk-paper-stage--expanded { max-width: 50rem; }
.mwk-paper-stage--expanded:has([data-orientation="landscape"]) { max-width: 62rem; }
.mwk-paper { --mwk-font-family: 'TH Sarabun New', sans-serif; box-sizing: border-box; width: 100%; aspect-ratio: 210 / 297; padding: 5.714cqw; overflow: hidden; background: var(--bs-white); color: var(--bs-black); border: 1px solid var(--bs-border-color); border-radius: .25rem; box-shadow: var(--bs-box-shadow-sm); font-family: var(--mwk-font-family); font-size: 2.688cqw; line-height: 1.3; }
.mwk-paper[data-orientation="landscape"] { aspect-ratio: 297 / 210; padding: 4.04cqw; font-size: 1.9cqw; }
.mwk-paper * { font-family: var(--mwk-font-family); }
.mwk-paper-title { text-align: center; font-weight: 700; font-size: 1.125em; overflow-wrap: break-word; }
.mwk-paper-sub { text-align: center; }
.mwk-paper-term { margin-bottom: .5em; }
.mwk-paper-table { width: 100%; table-layout: fixed; border-collapse: collapse; font-size: .75em; line-height: 1.3; }
.mwk-paper[data-density="compact"] .mwk-paper-table { font-size: .6875em; }
.mwk-paper[data-density="dense"] .mwk-paper-table { font-size: .625em; }
.mwk-paper-table th, .mwk-paper-table td { border: .5px solid var(--bs-gray-600); padding: .2em .35em; overflow-wrap: anywhere; vertical-align: middle; height: 1.9em; }
.mwk-paper-table th { text-align: center; font-weight: 700; }
.mwk-paper-img { display: block; margin: 0 auto; width: 1.4em; height: 1.7em; background: var(--bs-gray-400); border-radius: .1em; }
.mwk-paper-signatures { display: flex; justify-content: space-around; gap: 1em; margin-top: 2em; font-size: .75em; }
.mwk-col-edit { width: 1.75rem; height: 1.75rem; display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; text-decoration: none; }
/* Chart.js canvas box (usage page): the chart needs a fixed-height parent; sized per screen (phone / desktop). */
.mwk-chart { position: relative; width: 100%; height: 14rem; }
.mwk-chart-lg { height: 16rem; }
@media (min-width: 992px) { .mwk-chart { height: 15rem; } .mwk-chart-lg { height: 21rem; } }

/* App feel: no 300ms tap delay or grey tap flash, no rubber-band chaining, soft cross-fade between pages. */
/* scrollbar-gutter: the page never shifts sideways when a scrollbar appears or goes between two pages (desktop). */
html { -webkit-tap-highlight-color: transparent; -webkit-text-size-adjust: 100%; scrollbar-gutter: stable; }
a, button, [role="button"], .btn, .nav-link, label, summary, select, input[type="checkbox"], input[type="radio"] { touch-action: manipulation; }
body.mwk-v4 { overscroll-behavior-y: none; }
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
  ::view-transition-old(root), ::view-transition-new(root) { animation-duration: .12s; }
}
@media (max-width: 575.98px) {
  /* Phone sizing: base text comes from html (15px, set in mwk-display.js); keep the main tap targets at 44px even though rem shrank. */
  .btn:not(.btn-sm):not(.btn-lg), .modal-footer .btn, .mwk-form-actions .btn, .mwk-step-bar .btn, .mwk-seg .nav-link { min-height: 44px; }
}

/* Pre-launch page (App/Modules/Main/Views/Launch/prepare.php): system look, light and neutral; the countdown digits stay put while they change. */
.mwk-launch-num { font-size: 1.75rem; font-variant-numeric: tabular-nums; }
.mwk-launch-unit { position: relative; overflow: hidden; transition: opacity .3s, box-shadow .5s; background: linear-gradient(180deg, var(--bs-body-bg), var(--bs-primary-bg-subtle)); }
.mwk-launch-unit::after { content: ''; position: absolute; inset: 0; background: linear-gradient(105deg, transparent 35%, rgba(255, 255, 255, .55) 50%, transparent 65%); transform: translateX(-120%); pointer-events: none; }
.mwk-launch-unit.mwk-shine::after { animation: mwk-shine .9s ease-out; }
@keyframes mwk-shine { to { transform: translateX(120%); } }
.mwk-launch-beat { box-shadow: 0 0 0 .3rem var(--bs-primary-bg-subtle); }
/* The soon badge breathes so the last hour feels close. */
.mwk-launch-soon { animation: mwk-breathe 1.6s ease-in-out infinite; }
@keyframes mwk-breathe { 50% { transform: scale(1.04); } }
/* Veil over the video while the sound is blocked; the button inside is the call to action. */
.mwk-launch-veil { background: rgba(0, 0, 0, .35); cursor: pointer; z-index: 2; }
/* A changed digit rolls in from above; reduced-motion readers see it change without movement. */
.mwk-tick { animation: mwk-tick .35s ease-out; }
@keyframes mwk-tick { from { transform: translateY(-.35em); opacity: .2; } to { transform: none; opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .mwk-tick, .mwk-launch-unit.mwk-shine::after, .mwk-launch-soon { animation: none; } }
@media (min-width: 768px) { .mwk-launch-num { font-size: 2.5rem; } }

/* MWK Mail Alert admin: email preview frame stays white (emails are designed on white); diagnostics scroll */
.mwk-email-preview { height: 37.5rem; background: var(--bs-white); }
.mwk-pre-scroll { max-height: 20rem; overflow: auto; }

/* Parent child page: a subject row opens its score breakdown; the chevron turns when open */
.parent-subject > summary { list-style: none; cursor: pointer; }
.parent-subject > summary::-webkit-details-marker { display: none; }
.parent-subject > summary .parent-subject-chevron { transition: transform .15s ease; }
.parent-subject[open] > summary .parent-subject-chevron { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) { .parent-subject > summary .parent-subject-chevron { transition: none; } }

/* Goodnotes support chat: a scrolling column of message bubbles (bubble colours are utilities in the view) */
.mwk-chat { display: flex; flex-direction: column; gap: .75rem; max-height: min(60vh, 28rem); overflow-y: auto; }
.mwk-chat > * { max-width: 85%; }
.mwk-chat a { overflow-wrap: anywhere; }

/* Outline actions follow the readable secondary token in both colour modes. */
body.mwk-v4 .btn-outline-secondary {
  --bs-btn-color: var(--bs-secondary-color);
  --bs-btn-border-color: var(--bs-secondary-color);
  --bs-btn-hover-color: var(--bs-body-bg);
  --bs-btn-hover-bg: var(--bs-secondary-color);
  --bs-btn-hover-border-color: var(--bs-secondary-color);
  --bs-btn-active-color: var(--bs-body-bg);
  --bs-btn-active-bg: var(--bs-secondary-color);
  --bs-btn-active-border-color: var(--bs-secondary-color);
  --bs-btn-disabled-color: var(--bs-secondary-color);
  --bs-btn-disabled-border-color: var(--bs-secondary-color);
}

/* MWKGo statistics chart: columns are at most 1.5rem wide (the slot is the hover target), 4px-ish rounded data end, 2px air between slots. */
.mwk-bars-plot { height: 10rem; gap: 2px; position: relative; z-index: 1; }
.mwk-bar { flex: 1 1 0; min-width: 0; height: 100%; display: flex; align-items: flex-end; justify-content: center; border-radius: .25rem .25rem 0 0; cursor: default; }
.mwk-bar svg { width: 100%; max-width: 1.5rem; height: 100%; display: block; fill: var(--bs-primary); }
.mwk-bar:hover, .mwk-bar.is-active { background: var(--bs-secondary-bg); }
.mwk-bar:hover svg, .mwk-bar.is-active svg { opacity: .8; }
.mwk-bars:focus-visible { outline: 2px solid var(--bs-primary); outline-offset: 2px; border-radius: .25rem; }
.mwk-bars-tip { z-index: 3; white-space: nowrap; transform: translateX(-50%); }

/* REG curriculum picker (card 3) follows the scroll on large screens: it never gets taller than the screen, only its list scrolls and the filter box stays pinned */
@media (min-width: 992px) {
  .mwk-sticky-picker { position: sticky; top: 4.5rem; max-height: calc(100vh - 5.5rem); display: flex; flex-direction: column; }
  .mwk-sticky-picker > form { display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto; }
  .mwk-sticky-picker .card { display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto; }
  .mwk-sticky-picker .card-body { overflow-y: auto; min-height: 0; flex: 1 1 auto; }
}

/* REG curriculum board: one column per room at a comfortable width (21rem), scroll sideways when they do not fit */
/* Board: scrolls freely (no snapping, it stops where the finger stops); a fade on the right says more columns are there */
.mwk-board { position: relative; }
.mwk-board::after { content: ""; position: absolute; top: 0; right: 0; bottom: 0; width: 2.5rem; pointer-events: none; opacity: 0; transition: opacity .2s; background: linear-gradient(to right, transparent, var(--bs-body-bg)); }
.mwk-board.has-more::after { opacity: 1; }
.mwk-kanban { display: flex; gap: 1rem; overflow-x: auto; -webkit-overflow-scrolling: touch; padding: 1rem; }
.mwk-kanban > * { flex: 0 0 calc(50% - .5rem); min-width: 16rem; }

/* Popups stay centred between 576px and 767px: the legacy phone rule (mwk-ui.css, margin .75rem) replaced Bootstrap's auto side margins and its vertical margin. */
@media (min-width: 576px) and (max-width: 767.98px) {
  body.mwk-ui .modal-dialog { margin: var(--bs-modal-margin) auto; }
}
