/**/
/* default side padding for items (mainmenu, blocks etc.) */
html {
  -ms-overflow-style: scrollbar;
}
/* Hide Alpine-cloaked elements until Alpine initialises them (no Focus plugin bundled). */
[x-cloak] {
  display: none !important;
}
body {
  margin: 0;
  padding: 0;
  width: 100%;
  font-family: Arial, "Arial", "Helvetica", sans-serif;
  font-size: 14px;
  word-wrap: break-word;
  position: relative;
  overflow: auto !important;
}
#body-wrapper {
  width: 100%;
  float: left;
  box-sizing: border-box;
  padding: 0 15px 0 15px;
}
#body-wrapper #main-col {
  float: left;
}
.default-white-block {
  border-radius: 4px;
}
/* Rounded-corner helper for blocks sitting bare on the page background: adds the dashboard-card
   radius + shadow (shadow lives in user-lightmode-color / user-darkmode-color) WITHOUT touching the
   block's own background — so it works on white blocks and on brand-colored bars (captions, back
   bars) alike. No overflow:hidden here (unlike .dashboard-blockbg): it would clip escaping form
   popups (sumoselect / datepicker). Blocks whose content reaches the corners (calendar, tiles) add
   overflow:hidden themselves. */
.rounded-shadow-block {
  border-radius: 4px;
}
/* Rounded-corner helper for tables sitting bare on the page background. .default-list-table is
   border-collapse:collapse, which prevents the radius from clipping the cell corners; switching to
   separate + spacing:0 + overflow:hidden makes the rounding visible (same trick as .support-table).
   The `table.` prefix wins specificity over `.default-list-table` so the collapse is overridden. */
table.rounded-table {
  border-collapse: separate;
  border-spacing: 0;
  overflow: hidden;
  border-radius: 4px;
}
/* The myTrainingEvents mini-calendar fills its wrapper edge to edge, so it needs overflow:hidden
   (in addition to .rounded-shadow-block's radius) to clip fullcalendar's square corners. Safe here —
   this compact month widget has no escaping popovers. */
.my-training-events-calendar {
  overflow: hidden;
}
/* Variant of .rounded-table for placeholder tables that can hold MULTIPLE rows meant to read as
   separate cards (e.g. the myTrainingEvents no-records row + the injected "show older terms" row).
   Instead of clipping the whole table into one card, round each cell and keep an 8px gap between
   rows (matching the userEntityList card spacing). Shadow lives in user-lightmode / user-darkmode. */
table.rounded-cards-table {
  border-collapse: separate;
  border-spacing: 0 8px;
}
table.rounded-cards-table td {
  border-radius: 4px;
}
div.ramec {
  position: relative;
}
div.max-edu-width {
  max-width: 1600px;
  margin: 0 auto 0 auto;
}
/**
 Styles for font styles - italic, bold, underline...
 */
.italic {
  font-style: italic;
}
.bold {
  font-weight: bold !important;
}
.nobold {
  font-weight: normal !important;
}
a,
a:visited,
.hyperlink {
  text-decoration: none;
  outline: none;
}
a:hover,
.hyperlink:hover {
  text-decoration: underline;
}
a.no-underline,
a.no-underline:visited,
a.no-underline:hover,
a.no-underline:focus {
  text-decoration: none;
}
a:focus,
.hyperlink:focus {
  text-decoration: underline;
}
h1 {
  font-size: 20px;
  font-weight: normal;
  margin-bottom: 8px;
}
.cursorPointer,
.hyperlink {
  cursor: pointer;
}
.cursorDefault {
  cursor: default !important;
}
.cursorNResize {
  cursor: n-resize;
}
.positionRelative {
  position: relative;
}
.positionAbsolute {
  position: absolute;
}
.borderBox {
  box-sizing: border-box !important;
}
.borderSpacing0 {
  border-spacing: 0 !important;
}
.contentBox {
  box-sizing: content-box !important;
}
.floatLeft {
  float: left !important;
}
.showOnlyTextMultiline {
  white-space: pre-line;
  line-height: normal;
}
.floatRight {
  float: right !important;
}
.floatNone {
  float: none !important;
}
.left {
  text-align: left;
}
.leftImportant {
  text-align: left !important;
}
.right {
  text-align: right;
}
.alignLeftTable tr th,
.alignLeftTable tr td {
  text-align: left;
}
.center {
  text-align: center !important;
}
.outlineNone:focus {
  outline: none;
}
.displayNone {
  display: none;
}
.displayNoneImportant {
  display: none !important;
}
.displayBlock {
  display: block !important;
}
.displayInline {
  display: inline;
}
.displayInlineBlock {
  display: inline-block;
}
.displayTable {
  display: table;
}
.displayTableCell {
  display: table-cell;
}
.noListStyle,
.noListStyle li {
  list-style-type: none;
}
.borderNone {
  border: none !important;
}
.fontSmall {
  font-size: 11px;
}
.fontLarge {
  font-size: 30px;
}
.fontSize10 {
  font-size: 10px !important;
}
.fontSize11 {
  font-size: 11px !important;
}
.fontSize12 {
  font-size: 12px !important;
}
.fontSize16 {
  font-size: 16px !important;
}
.fontSize17 {
  font-size: 17px !important;
}
.fontSize18 {
  font-size: 18px !important;
}
.fontSize20 {
  font-size: 20px !important;
}
.fontSize24 {
  font-size: 24px !important;
}
.fontSize30 {
  font-size: 30px !important;
}
.fontSize60 {
  font-size: 60px !important;
}
.verticalMiddle {
  vertical-align: middle !important;
}
.verticalTop {
  vertical-align: top !important;
}
/* Background-color for buttons */
.red-button {
  background-color: #DD0000 !important;
  border: 1px solid #DD0000 !important;
}
.orange-button {
  background-color: #FF9900 !important;
  border: 1px solid #FF9900 !important;
}
.green-button {
  background-color: #00b050 !important;
  border: 1px solid #00b050 !important;
}
.red-button,
.orange-button,
.green-button {
  color: #FFF !important;
}
/* Font colors */
.red-text {
  color: #DD0000 !important;
}
.orange-text {
  color: #FF9900 !important;
}
.green-text {
  color: #008f41 !important;
}
.light-green-text {
  color: #58b50d !important;
}
.yellow-text {
  color: #ffcf37 !important;
}
.gray-text {
  color: #888888 !important;
}
.blue-text {
  color: #3d8af7 !important;
}
.dark-blue-text {
  color: #0754a6 !important;
}
.pink-text {
  color: #ff8a84 !important;
}
.purple-text {
  color: #A805BB !important;
}
.black-text {
  color: #000 !important;
}
.white-text {
  color: #FFF !important;
}
/** border colors */
.red-checkbox .checkbox-image {
  border-color: #DD0000 !important;
}
.red-checkbox input:checked ~ .checkbox-image {
  background-color: #DD0000 !important;
}
.red-background {
  background-color: #DD0000 !important;
}
.green-background {
  background-color: #008f41 !important;
}
.backgroundNone {
  background: none !important;
}
/**
  Automatic generate position styles
 */
.top0 {
  top: 0px !important;
}
.top40 {
  top: 40px !important;
}
/**
  Automatic generate Margin styles
 */
.noMargin,
.margin0 {
  margin: 0 !important;
}
/**
  Automatic generate Margin for all sides
 */
.margin0 {
  margin: 0px !important;
}
.margin10 {
  margin: 10px !important;
}
.margin15 {
  margin: 15px !important;
}
.marginTop0 {
  margin-top: 0px !important;
}
.marginTop1 {
  margin-top: 1px !important;
}
.marginTop2 {
  margin-top: 2px !important;
}
.marginTop3 {
  margin-top: 3px !important;
}
.marginTop5 {
  margin-top: 5px !important;
}
.marginTop6 {
  margin-top: 6px !important;
}
.marginTop7 {
  margin-top: 7px !important;
}
.marginTop8 {
  margin-top: 8px !important;
}
.marginTop9 {
  margin-top: 9px !important;
}
.marginTop10 {
  margin-top: 10px !important;
}
.marginTop12 {
  margin-top: 12px !important;
}
.marginTop13 {
  margin-top: 13px !important;
}
.marginTop15 {
  margin-top: 15px !important;
}
.marginTop20 {
  margin-top: 20px !important;
}
.marginTop28 {
  margin-top: 28px !important;
}
.marginTop40 {
  margin-top: 40px !important;
}
.marginBottom0 {
  margin-bottom: 0px !important;
}
.marginBottom5 {
  margin-bottom: 5px !important;
}
.marginBottom6 {
  margin-bottom: 6px !important;
}
.marginBottom7 {
  margin-bottom: 7px !important;
}
.marginBottom8 {
  margin-bottom: 8px !important;
}
.marginBottom10 {
  margin-bottom: 10px !important;
}
.marginBottom15 {
  margin-bottom: 15px !important;
}
.marginBottom20 {
  margin-bottom: 20px !important;
}
.marginBottom28 {
  margin-bottom: 28px !important;
}
.marginBottom30 {
  margin-bottom: 30px !important;
}
.marginBottom60 {
  margin-bottom: 60px !important;
}
.marginRight0 {
  margin-right: 0px !important;
}
.marginRight2 {
  margin-right: 2px !important;
}
.marginRight3 {
  margin-right: 3px !important;
}
.marginRight4 {
  margin-right: 4px !important;
}
.marginRight5 {
  margin-right: 5px !important;
}
.marginRight7 {
  margin-right: 7px !important;
}
.marginRight10 {
  margin-right: 10px !important;
}
.marginRight15 {
  margin-right: 15px !important;
}
.marginLeft0 {
  margin-left: 0px !important;
}
.marginLeft5 {
  margin-left: 5px !important;
}
.marginLeft8 {
  margin-left: 8px !important;
}
.marginLeft10 {
  margin-left: 10px !important;
}
.marginLeft12 {
  margin-left: 12px !important;
}
.marginLeft15 {
  margin-left: 15px !important;
}
.marginLeft20 {
  margin-left: 20px !important;
}
.marginLeft28 {
  margin-left: 28px !important;
}
/**
  Automatic generate Padding styles
 */
.noPadding {
  padding: 0 !important;
}
/**
  Automatic generate Padding for all sides
 */
.padding0 {
  padding: 0px !important;
}
.padding10 {
  padding: 10px !important;
}
.padding15 {
  padding: 15px !important;
}
.paddingTop0 {
  padding-top: 0px !important;
}
.paddingTop3 {
  padding-top: 3px !important;
}
.paddingTop5 {
  padding-top: 5px !important;
}
.paddingTop6 {
  padding-top: 6px !important;
}
.paddingTop7 {
  padding-top: 7px !important;
}
.paddingTop10 {
  padding-top: 10px !important;
}
.paddingTop15 {
  padding-top: 15px !important;
}
.paddingTop17 {
  padding-top: 17px !important;
}
.paddingTop20 {
  padding-top: 20px !important;
}
.paddingBottom0 {
  padding-bottom: 0px !important;
}
.paddingBottom3 {
  padding-bottom: 3px !important;
}
.paddingBottom5 {
  padding-bottom: 5px !important;
}
.paddingBottom10 {
  padding-bottom: 10px !important;
}
.paddingBottom15 {
  padding-bottom: 15px !important;
}
.paddingBottom17 {
  padding-bottom: 17px !important;
}
.paddingBottom20 {
  padding-bottom: 20px !important;
}
.paddingRight0 {
  padding-right: 0px !important;
}
.paddingRight7 {
  padding-right: 7px !important;
}
.paddingRight15 {
  padding-right: 15px !important;
}
.paddingLeft0 {
  padding-left: 0px !important;
}
.paddingLeft8 {
  padding-left: 8px !important;
}
.paddingLeft10 {
  padding-left: 10px !important;
}
.paddingLeft15 {
  padding-left: 15px !important;
}
.paddingLeft20 {
  padding-left: 20px !important;
}
.paddingLeft25 {
  padding-left: 25px !important;
}
.paddingLeft30 {
  padding-left: 30px !important;
}
.paddingLeft60 {
  padding-left: 60px !important;
}
/**
  Automatic generate Padding both sides
 */
.paddingSide0 {
  padding-left: 0px !important;
  padding-right: 0px !important;
}
.paddingSide5 {
  padding-left: 5px !important;
  padding-right: 5px !important;
}
.paddingSide10 {
  padding-left: 10px !important;
  padding-right: 10px !important;
}
.paddingSide15 {
  padding-left: 15px !important;
  padding-right: 15px !important;
}
/**
  Automatic generate Width style in percentage
 */
.width25 {
  width: 25% !important;
  box-sizing: border-box;
}
.width33 {
  width: 33% !important;
  box-sizing: border-box;
}
.width40 {
  width: 40% !important;
  box-sizing: border-box;
}
.width50 {
  width: 50% !important;
  box-sizing: border-box;
}
.width60 {
  width: 60% !important;
  box-sizing: border-box;
}
.width75 {
  width: 75% !important;
  box-sizing: border-box;
}
.width80 {
  width: 80% !important;
  box-sizing: border-box;
}
.width90 {
  width: 90% !important;
  box-sizing: border-box;
}
.width100 {
  width: 100% !important;
  box-sizing: border-box;
}
/**
  Automatic generate Width style in pixels
 */
.width12p {
  width: 12px !important;
  box-sizing: border-box;
}
.width16p {
  width: 16px !important;
  box-sizing: border-box;
}
.width20p {
  width: 20px !important;
  box-sizing: border-box;
}
.width22p {
  width: 22px !important;
  box-sizing: border-box;
}
.width24p {
  width: 24px !important;
  box-sizing: border-box;
}
.width25p {
  width: 25px !important;
  box-sizing: border-box;
}
.width30p {
  width: 30px !important;
  box-sizing: border-box;
}
.width36p {
  width: 36px !important;
  box-sizing: border-box;
}
.width40p {
  width: 40px !important;
  box-sizing: border-box;
}
.width50p {
  width: 50px !important;
  box-sizing: border-box;
}
.width52p {
  width: 52px !important;
  box-sizing: border-box;
}
.width55p {
  width: 55px !important;
  box-sizing: border-box;
}
.width60p {
  width: 60px !important;
  box-sizing: border-box;
}
.width66p {
  width: 66px !important;
  box-sizing: border-box;
}
.width70p {
  width: 70px !important;
  box-sizing: border-box;
}
.width80p {
  width: 80px !important;
  box-sizing: border-box;
}
.width90p {
  width: 90px !important;
  box-sizing: border-box;
}
.width95p {
  width: 95px !important;
  box-sizing: border-box;
}
.width100p {
  width: 100px !important;
  box-sizing: border-box;
}
.width105p {
  width: 105px !important;
  box-sizing: border-box;
}
.width110p {
  width: 110px !important;
  box-sizing: border-box;
}
.width120p {
  width: 120px !important;
  box-sizing: border-box;
}
.width130p {
  width: 130px !important;
  box-sizing: border-box;
}
.width135p {
  width: 135px !important;
  box-sizing: border-box;
}
.width140p {
  width: 140px !important;
  box-sizing: border-box;
}
.width150p {
  width: 150px !important;
  box-sizing: border-box;
}
.width155p {
  width: 155px !important;
  box-sizing: border-box;
}
.width160p {
  width: 160px !important;
  box-sizing: border-box;
}
.width170p {
  width: 170px !important;
  box-sizing: border-box;
}
.width180p {
  width: 180px !important;
  box-sizing: border-box;
}
.width190p {
  width: 190px !important;
  box-sizing: border-box;
}
.width200p {
  width: 200px !important;
  box-sizing: border-box;
}
.width210p {
  width: 210px !important;
  box-sizing: border-box;
}
.width250p {
  width: 250px !important;
  box-sizing: border-box;
}
.width260p {
  width: 260px !important;
  box-sizing: border-box;
}
.width300p {
  width: 300px !important;
  box-sizing: border-box;
}
.width340p {
  width: 340px !important;
  box-sizing: border-box;
}
.width350p {
  width: 350px !important;
  box-sizing: border-box;
}
.width400p {
  width: 400px !important;
  box-sizing: border-box;
}
.width450p {
  width: 450px !important;
  box-sizing: border-box;
}
.width500p {
  width: 500px !important;
  box-sizing: border-box;
}
.width620p {
  width: 620px !important;
  box-sizing: border-box;
}
.width980p {
  width: 980px !important;
  box-sizing: border-box;
}
/**
  Automatic generate Width style in pixels
 */
.minWidth50 {
  min-width: 50% !important;
  box-sizing: border-box;
}
.minWidth51 {
  min-width: 51% !important;
  box-sizing: border-box;
}
/**
  Automatic generate Width style in pixels
 */
.maxWidth50 {
  max-width: 50% !important;
  box-sizing: border-box;
}
.maxWidth100 {
  max-width: 100% !important;
  box-sizing: border-box;
}
/**
  Automatic generate min-width style in pixels
 */
.minWidth24p {
  min-width: 24px !important;
  box-sizing: border-box;
}
.minWidth50p {
  min-width: 50px !important;
  box-sizing: border-box;
}
.minWidth100p {
  min-width: 100px !important;
  box-sizing: border-box;
}
.minWidth160p {
  min-width: 160px !important;
  box-sizing: border-box;
}
/**
  Automatic generate max-width style in pixels
 */
.maxWidth18p {
  max-width: 18px !important;
  box-sizing: border-box;
}
.maxWidth20p {
  max-width: 20px !important;
  box-sizing: border-box;
}
.maxWidth24p {
  max-width: 24px !important;
  box-sizing: border-box;
}
.maxWidth50p {
  max-width: 50px !important;
  box-sizing: border-box;
}
.maxWidth150p {
  max-width: 150px !important;
  box-sizing: border-box;
}
.maxWidth200p {
  max-width: 200px !important;
  box-sizing: border-box;
}
.maxWidth250p {
  max-width: 250px !important;
  box-sizing: border-box;
}
.maxWidth300p {
  max-width: 300px !important;
  box-sizing: border-box;
}
.maxWidth400p {
  max-width: 400px !important;
  box-sizing: border-box;
}
/**
  Automatic generate Height style in pixels
 */
.height15p {
  height: 15px !important;
  box-sizing: border-box;
}
.height20p {
  height: 20px !important;
  box-sizing: border-box;
}
.height22p {
  height: 22px !important;
  box-sizing: border-box;
}
.height28p {
  height: 28px !important;
  box-sizing: border-box;
}
.height30p {
  height: 30px !important;
  box-sizing: border-box;
}
.height36p {
  height: 36px !important;
  box-sizing: border-box;
}
.height37p {
  height: 37px !important;
  box-sizing: border-box;
}
.height40p {
  height: 40px !important;
  box-sizing: border-box;
}
.height42p {
  height: 42px !important;
  box-sizing: border-box;
}
.height50p {
  height: 50px !important;
  box-sizing: border-box;
}
.height60p {
  height: 60px !important;
  box-sizing: border-box;
}
.height80p {
  height: 80px !important;
  box-sizing: border-box;
}
.height100p {
  height: 100px !important;
  box-sizing: border-box;
}
.height120p {
  height: 120px !important;
  box-sizing: border-box;
}
.height150p {
  height: 150px !important;
  box-sizing: border-box;
}
.height200p {
  height: 200px !important;
  box-sizing: border-box;
}
.height240p {
  height: 240px !important;
  box-sizing: border-box;
}
.height300p {
  height: 300px !important;
  box-sizing: border-box;
}
.height400p {
  height: 400px !important;
  box-sizing: border-box;
}
.height500p {
  height: 500px !important;
  box-sizing: border-box;
}
/**
  Automatic generate max-height style in pixels
 */
.maxHeight18p {
  max-height: 18px !important;
  box-sizing: border-box;
}
.maxHeight20p {
  max-height: 20px !important;
  box-sizing: border-box;
}
.maxHeight24p {
  max-height: 24px !important;
  box-sizing: border-box;
}
.maxHeight50p {
  max-height: 50px !important;
  box-sizing: border-box;
}
.maxHeight100p {
  max-height: 100px !important;
  box-sizing: border-box;
}
.maxHeight150p {
  max-height: 150px !important;
  box-sizing: border-box;
}
.maxHeight400p {
  max-height: 400px !important;
  box-sizing: border-box;
}
/**
  Automatic generate Line-Height style in pixels
 */
.lineHeight20 {
  line-height: 20px !important;
}
.lineHeight22 {
  line-height: 22px !important;
}
.lineHeight24 {
  line-height: 24px !important;
}
.lineHeight28 {
  line-height: 28px !important;
}
.lineHeight30 {
  line-height: 30px !important;
}
.lineHeight32 {
  line-height: 32px !important;
}
.lineHeight36 {
  line-height: 36px !important;
}
.lineHeight50 {
  line-height: 50px !important;
}
.lineHeight60 {
  line-height: 60px !important;
}
/**
  Hidden wrapper for default values in forms.
 */
.forms-wrapper {
  display: none;
}
/**
  Mainmenu cascade styles
  MainMenu
 */
div#mainmenu-panel {
  min-width: 100%;
  margin: 0;
  padding: 0 15px 0 15px;
  box-sizing: border-box;
  float: left;
  height: 60px;
}
/* Desktop: the nav is a flex row — the left navigation group, then the optional "More…" overflow button,
   then the right action group pinned to the far edge. align-items centres the 46px items vertically in the
   60px bar (this replaces the old 7px top margin on the lists). Below 768px the @media block re-stacks the
   whole thing into the hamburger panel (it resets #mainmenu-nav back to a block). */
#mainmenu-nav {
  display: flex;
  align-items: center;
  height: 60px;
}
#mainmenu-left,
#mainmenu-right {
  padding: 0;
  margin: 0;
  display: flex;
  align-items: center;
  font-family: Arial, "Arial", "Helvetica", sans-serif;
  width: auto;
}
/* Keep the action icons pinned to the right edge of the bar. */
#mainmenu-right {
  margin-left: auto;
}
#mainmenu-left li,
#mainmenu-right li {
  flex: 0 0 auto;
  height: 46px;
  line-height: 46px;
  border-radius: 4px;
  font-size: 14px;
  list-style-type: none;
  padding: 0 15px 0 15px;
  margin-right: 5px;
}
/* The logo renders at 60px — taller than the 46px menu row — so as an inline, baseline-aligned image it
   sits ~7px too low and reads as not vertically centered in the 60px bar (Martin's report). Flex-center it
   inside the row so its centre matches the bar's centre. Mirrors the flex-centering the mobile bar (@media,
   #mainmenu-right li:has(img.edunio-logo)) and the admin sidebar already apply to this same item. */
#mainmenu-right li:has(img.edunio-logo) {
  display: flex;
  align-items: center;
}
/* Menu reload in flight — stamped on each item by MainMenuFacadeComponent.setItemsHidden(). The items on
   screen still belong to the PREVIOUS session, which during an admin -> user switch means the admin's own
   menu showing inside the user's environment, so they are hidden until the fetch answers. `visibility` and
   not `display`: the bar keeps its geometry, so revealing the new items does not reflow the page under them.

   Deliberately a marker on the item itself rather than a `body.<state> #mainmenu-right > li` rule — see the
   comment on setItemsHidden() for the one item that a body-class cascade never reached. */
.mainmenu-item-hidden {
  visibility: hidden;
  /* Hide instantly. The language item is pinned to the bottom of the admin sidebar card by a rule carrying
     `transition: all 0.18s ease` (see body.admin-sidebar-mode #mainmenu-right li:has(.SumoSelect) below),
     and `all` swept up `visibility` as well: the marker applied, but the discrete visible -> hidden flip
     only landed at the END of the transition, so that one item kept showing the admin's languages while
     every other item had already gone. Nothing here is worth animating — it exists to not be seen.
     `!important` because that sidebar rule is both more specific and later in the sheet. */
  transition: none !important;
}
/* Desktop overflow ("priority+") — the "More…" button and its dropdown. Hidden until the reflow
   (mainMenuHamburger.reflowOverflow) actually moves items into it, and always hidden below the mobile
   breakpoint (the hamburger owns every item there — see @media). The trigger looks like a normal menu item;
   the dropdown reuses the tableMenu kebab look and the panel's themed background (.custom-background). */
#mainmenu-more {
  display: none;
  position: relative;
  flex: 0 0 auto;
  margin-right: 5px;
}
#mainmenu-more.mainmenu-more-visible {
  display: flex;
  align-items: center;
}
/* Class-only selector on purpose: the themed hover (.custom-background .customHoverBg:hover) and selected
   (.custom-background .menu-selected) rules are 3-class specificity, so keeping this at 1 class lets them win
   — the "More…" button then hovers and highlights exactly like a normal menu item (an #id-scoped rule here
   would out-specify the theme and leave the selected button greyed with no background). */
.mainmenu-more-toggle {
  height: 46px;
  line-height: 46px;
  padding: 0 15px;
  border: 0;
  border-radius: 4px;
  background: transparent;
  color: inherit;
  font-family: inherit;
  font-size: 14px;
  cursor: pointer;
}
#mainmenu-more .mainmenu-more-list {
  display: none;
  position: absolute;
  top: 52px;
  left: 0;
  z-index: 1000;
  min-width: 180px;
  max-width: calc(100vw - 24px);
  margin: 0;
  padding: 6px 0;
  border-radius: 4px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
}
#mainmenu-more .mainmenu-more-list.open {
  display: block;
}
/* Items relocated into the dropdown always show icon + text (like the hamburger) — even onlyIco items whose
   text is hidden in the horizontal bar — laid out as full-width rows instead of the horizontal chips. */
#mainmenu-more .mainmenu-more-list li {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  /* Include the horizontal padding in the 100% width, otherwise the row (and its hover highlight) overflows
     the dropdown by ~28px to the right. */
  box-sizing: border-box;
  height: auto;
  line-height: normal;
  margin: 0;
  padding: 10px 14px;
  float: none;
  border-radius: 0;
  white-space: nowrap;
}
#mainmenu-more .mainmenu-more-list li .menu-ico {
  display: inline-block;
  width: 20px;
  text-align: center;
}
#mainmenu-more .mainmenu-more-list li .menu-text {
  display: inline;
}
/* The nested submenu of a has-submenu item stays hidden inside the dropdown too (desktop keeps its separate
   submenu bar) — in the overflow it is just a plain navigating row. */
#mainmenu-more .mainmenu-more-list li .mainmenu-submenu,
#mainmenu-more .mainmenu-more-list li .submenu-arrow {
  display: none;
}
/* Hamburger toggle — present in the DOM on every page but hidden above the mobile breakpoint.
   Rendered as a rounded 40x40 tile (radius matches other buttons); the rest + hover tile colours are
   solid shades of the bar colour, set per-theme in *mode-color.php.less (menuIconTileBgRest/Hover). */
#mainmenu-toggle {
  display: none;
  height: 40px;
  width: 40px;
  padding: 0;
  border: 0;
  border-radius: 4px;
  /* Only clear the native button background; the tile colours come from the theme #id rules. */
  background-color: transparent;
  color: inherit;
  cursor: pointer;
  font-size: 14px;
}
/* Admin docked-sidebar collapse toggle — present in the DOM on every page but hidden by default (exactly like
   the hamburger toggle above). Only the desktop admin sidebar block (@media min-width:769px, body.admin-sidebar-mode)
   turns it on; this base rule keeps it OFF everywhere else — mobile (any environment) and the user desktop —
   so it never stacks over the hamburger or shows a stray icon on user pages. */
#sidebar-collapse-toggle {
  display: none;
  height: 60px;
  width: 46px;
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;
  cursor: pointer;
  font-size: 14px;
}
/* Player-mode bar icons: a close cross + a 3-dots overlay toggle that replace the hamburger on learner
   player pages. Present in the DOM on every page (the bar is global) but hidden above the mobile breakpoint,
   like the hamburger; Alpine x-show="playerMode" adds the player-mode gating on top (see mainMenu.hbs).
   Rendered as rounded 40x40 tiles (radius matches other buttons), like the hamburger; the 6px gap
   between them comes from #player-overlay-toggle's left offset (40 tile + 6 < 46 offset). The rest +
   hover tile colours come from the per-theme #id rules in *mode-color.php.less. */
#player-close-btn,
#player-overlay-toggle {
  display: none;
  height: 40px;
  width: 40px;
  padding: 0;
  border: 0;
  border-radius: 4px;
  /* Only clear the native button background; the tile colours come from the theme #id rules. */
  background-color: transparent;
  color: inherit;
  cursor: pointer;
  font-size: 14px;
}
/* Menu items carry both an icon (.menu-ico) and a text label (.menu-text). The original
   (desktop) menu shows only one of them, reproducing the legacy look: onlyIco items show the
   icon, all other items show the text. The hamburger menu (mobile) shows both — see @media. */
#mainmenu-left li.menu-onlyico .menu-text,
#mainmenu-right li.menu-onlyico .menu-text {
  display: none;
}
#mainmenu-left li:not(.menu-onlyico) .menu-ico,
#mainmenu-right li:not(.menu-onlyico) .menu-ico {
  display: none;
}
/* The eager nested submenu (responsive submenu, variant 2) is consumed only by the mobile hamburger.
   On desktop the horizontal main menu must never show the nested list or its chevron — desktop keeps
   its separate submenu bar. Hidden by default at every width; revealed only inside the open hamburger
   (see the @media block below). */
.mainmenu-submenu,
.submenu-arrow,
.submenu-dots {
  display: none;
}
/*
  Admin docked sidebar (desktop admin main menu, >= 769px) — detached "floating cards" layout.

  In the admin environment the main menu becomes a set of separate rounded cards, detached from the screen
  edges with gaps between them (per the mockups admin-menu-full.png / admin-menu-short.png):
    - a LOGO card (top-left, themed/brand colour) holding the wordmark + the collapse toggle,
    - a MENU card (below the logo, LIGHT surface) holding the vertical nav list + language selector,
    - a TOP-BAR card (top, right of the logo, LIGHT surface) holding the right-hand action icons.
  It reuses the SAME #mainmenu-left list + eager nested submenu + Alpine accordion the mobile hamburger uses,
  so the sidebar and hamburger share one visual language (only the scheme colours differ). Card surface
  colours live in admin-*mode-color.php.less; layout/rounding/gaps are here. Collapsed (body.admin-sidebar-
  collapsed) shrinks the cards to an icon rail with an "E" logomark, a toggle box, active-section dots and
  hover flyouts. Gated to admin AND desktop width; below 768px the mobile hamburger @media block takes over.
  Spec: .claude/specs/spec-admin-sidebar-menu-2026-07-04.md.
 */
@media (min-width: 769px) {
  /* ---- "Logged in as user X" band (#sa-wrapper): the strip a superadmin sees while impersonating someone.
       It is ONE global element (index.php), first in the document flow, statically positioned — so in the
       user environment it simply pushes the page down, and its `z-index` never applies. The admin sidebar
       chrome is all `position: fixed` and used to paint straight over its y0..50 strip, which made the band
       vanish the moment you switched to administration (Martin's report). Here it joins the fixed chrome
       instead: pinned to the viewport top above the cards (z1010 > logo/top-bar/menu 1000..1006), but below
       modals (1050), the full loader (1060) and the notify panel (1100), so an open modal still covers it —
       exactly as in the user environment. --sa-band (declared with the base `div#sa-wrapper` rule) then
       shifts the whole chrome down by its height. ---- */
  body.admin-sidebar-mode #sa-wrapper {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 1010;
  }
  /* ---- MENU card: the panel becomes a detached rounded card below the logo card. Light surface + text
       come from the scheme (override the .custom-background purple). ---- */
  body.admin-sidebar-mode #mainmenu-panel {
    position: fixed;
    top: calc(72px + var(--sa-band, 0px));
    /* 8 gap + 56 logo card + 8 gap, below the "logged as" band */
    left: 8px;
    bottom: 8px;
    width: 280px;
    height: auto;
    min-width: 0;
    margin: 0;
    padding: 0;
    float: none;
    border-radius: 4px;
    /* No border — the mockup cards are borderless, separated purely by the gaps + a faint shadow. */
    overflow: hidden;
    /* clip the card to its rounded corners; #mainmenu-nav scrolls inside */
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
    z-index: 1001;
    transition: width 0.18s ease;
  }
  body.admin-sidebar-mode.admin-sidebar-collapsed #mainmenu-panel {
    width: 70px;
  }
  /* Collapsed: let hover flyouts escape the narrow rail (a scroll container would clip them). */
  body.admin-sidebar-mode.admin-sidebar-collapsed #mainmenu-panel {
    overflow: visible;
  }
  /* Nav fills the menu card and scrolls vertically; never horizontally (long titles are clipped, below). */
  body.admin-sidebar-mode #mainmenu-nav {
    display: block;
    height: 100%;
    padding: 8px 0 64px 0;
    /* leave room at the bottom for the language selector */
    box-sizing: border-box;
    overflow-y: auto;
    overflow-x: hidden;
  }
  body.admin-sidebar-mode.admin-sidebar-collapsed #mainmenu-nav {
    overflow: visible;
  }
  /* ---- LOGO card: top-left brand-coloured rounded card (bg from scheme). Holds the wordmark. ---- */
  body.admin-sidebar-mode #mainmenu-right li:has(img.edunio-logo) {
    position: fixed;
    top: calc(8px + var(--sa-band, 0px));
    left: 8px;
    width: 280px;
    height: 56px;
    display: flex;
    align-items: center;
    margin: 0;
    padding: 0 16px;
    box-sizing: border-box;
    border-radius: 4px;
    overflow: hidden;
    z-index: 1002;
    transition: width 0.18s ease;
  }
  /* The wordmark fills the card vertically like the mockup (the default menu logo renders small). */
  body.admin-sidebar-mode #mainmenu-right li:has(img.edunio-logo) img.edunio-logo {
    width: auto;
    margin: 0;
  }
  /* Collapsed: the logo becomes ONE brand "E" card (matching the 70px rail) with the "E" glyph on
     the left; the circular toggle overhangs its right edge (see the toggle rule). NOT two separate boxes. */
  body.admin-sidebar-mode.admin-sidebar-collapsed #mainmenu-right li:has(img.edunio-logo) {
    /* Same 70px width as the icon rail below it (Martin: the "E" card must match the menu). */
    width: 70px;
    padding: 0;
    justify-content: center;
  }
  body.admin-sidebar-mode.admin-sidebar-collapsed #mainmenu-right li:has(img.edunio-logo) img.edunio-logo {
    display: none;
  }
  body.admin-sidebar-mode.admin-sidebar-collapsed #mainmenu-right li:has(img.edunio-logo)::after {
    content: "";
    width: 26px;
    height: 26px;
    background: url("../img/logo-e.svg") center / contain no-repeat;
  }
  /* ---- Collapse toggle. Expanded: a bare icon at the right end of the logo card (NO circle — Martin: full
       width shows just the glyph, tinted light-blue by the scheme). Collapsed: the icon sits in a brand-blue
       CIRCLE next to the "E" square, ringed by a page-background border (surface colours from the scheme). ---- */
  body.admin-sidebar-mode #sidebar-collapse-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    position: fixed;
    top: calc(20px + var(--sa-band, 0px));
    /* vertically centred in the 56px logo card: 8 + (56-32)/2 */
    left: 244px;
    /* right end of the logo card (288) minus a 12px inset and the 32px hit area */
    width: 32px;
    height: 32px;
    padding: 0;
    border: 0;
    /* Expanded: no chip — just the icon on the brand card (background/border stay clear; scheme sets the tint). */
    background: transparent;
    color: inherit;
    cursor: pointer;
    z-index: 1004;
    transition: left 0.18s ease, top 0.18s ease, width 0.18s ease, height 0.18s ease;
  }
  /* Icon size fixed at 15px in BOTH states (no fa-lg on the glyph). */
  body.admin-sidebar-mode #sidebar-collapse-toggle i {
    font-size: 15px;
  }
  /* Collapsed: a brand-blue CIRCLE overhanging the RIGHT EDGE of the single "E" card (one card + circle, NOT two
     separate boxes) — centred at ~x67 so it sits half on the "E" card, half in the gap, exactly per mockup. The
     border sits inside the 38px box (border-box); its colour matches the page background (from the scheme). */
  body.admin-sidebar-mode.admin-sidebar-collapsed #sidebar-collapse-toggle {
    top: calc(17px + var(--sa-band, 0px));
    /* centred in the 56px header band: 8 + (56-38)/2 */
    left: 59px;
    /* circle x59..x97, centred ~x78 — overhangs the 70px "E" card right edge (x78) */
    width: 38px;
    height: 38px;
    border-radius: 50%;
    box-sizing: border-box;
    /* keep the 38px outer size once the scheme adds its border */
    background: transparent;
    /* the scheme paints the collapsed circle surface + border */
  }
  /* ---- MENU list: vertical rows (icon + text), full width, long titles clipped (no horizontal scroll). ---- */
  body.admin-sidebar-mode #mainmenu-left {
    display: block;
    float: none;
    width: 100%;
    margin: 0;
    padding: 4px 0 0 0;
    overflow: hidden;
  }
  body.admin-sidebar-mode #mainmenu-left li {
    display: block;
    position: relative;
    float: none;
    width: 100%;
    height: auto;
    line-height: normal;
    margin: 0;
    /* Denser vertical rhythm + roomier left padding + icon->text gap to match the mockup (row pitch ~45px,
       icon left ~x28, text left ~x74). */
    padding: 13px 16px 13px 20px;
    border-radius: 0;
    box-sizing: border-box;
    white-space: nowrap;
    overflow: hidden;
  }
  /* Both icon and text show — including onlyIco items (the dashboard home). */
  body.admin-sidebar-mode #mainmenu-left li.menu-onlyico .menu-text {
    display: inline-block;
  }
  body.admin-sidebar-mode #mainmenu-left li .menu-ico {
    display: inline-block;
    width: 20px;
    margin-right: 26px;
    text-align: center;
    vertical-align: middle;
  }
  /* The label. Clipped to the row so a long title never forces a horizontal scrollbar; it marquee-slides on
     hover (left->right and back, like the modal title) to reveal the rest. */
  body.admin-sidebar-mode #mainmenu-left li .menu-text {
    display: inline-block;
    max-width: calc(100% - 40px);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: middle;
  }
  /* Marquee ONLY when the label actually overflows: JS (class.js updateMenuOverflow) adds .is-overflowing and
     sets --marquee-x = -(overflow px) on those texts. Short labels that fit get no class → never animate. */
  body.admin-sidebar-mode #mainmenu-left li:hover .menu-text.is-overflowing {
    text-overflow: clip;
    animation: admin-sidebar-marquee 4.5s linear infinite alternate;
  }
  /* has-submenu chevron: a thin Font Awesome angle sitting in a small rounded badge on the right (per the
     mockup), flips up when open. The badge surface colour comes from the scheme. All badges share ONE
     visual column — the one defined by a badge inside the inset open-section card (10px card margin +
     14px badge offset = 24px from the menu edge). Card rows (.menu-selected or .expanded) keep the
     card-relative 14px; full-width rows compensate the missing 10px inset with right: 24px below. */
  body.admin-sidebar-mode #mainmenu-left .has-submenu > .submenu-arrow {
    display: flex;
    align-items: center;
    justify-content: center;
    position: absolute;
    top: 12px;
    right: 14px;
    width: 22px;
    height: 22px;
    border-radius: 4px;
    font-size: 12px;
    transition: transform 0.18s ease;
  }
  /* Full-width (non-card) rows only — a collapsed-but-active section (.menu-selected without .expanded)
     is still an inset card and must NOT take this offset, or its badge would double-shift. */
  body.admin-sidebar-mode #mainmenu-left .has-submenu:not(.menu-selected):not(.expanded) > .submenu-arrow {
    right: 24px;
  }
  body.admin-sidebar-mode #mainmenu-left .has-submenu.expanded > .submenu-arrow {
    transform: rotate(180deg);
  }
  /* Open-section card: a rounded card INSET within the menu (margin on both sides), wrapping the section
     header AND — when expanded — its submenu, exactly like the mockup. ONE selector group covers both the
     active section (.menu-selected — a card even while collapsed) and ANY expanded section, active or not:
     the two open states must look identical, only the active-state accents differ (brand header colour from
     the scheme; sub-items stay neutral, their own active sub-item goes brand + bold). */
  body.admin-sidebar-mode #mainmenu-left .menu-selected,
  body.admin-sidebar-mode #mainmenu-left .has-submenu.expanded {
    width: auto;
    margin: 2px 10px;
    /* The 10px side margins inset the card; compensate the left padding (base 20px → 10px) so the
       icon, text and nested sub-arrows stay in the SAME column as the non-selected rows instead of being
       shoved 10px to the right (Martin's alignment fix). */
    padding-left: 10px;
    border-radius: 4px;
  }
  /* Chevron badge inside the card loses its own fill (sits on the card surface). */
  body.admin-sidebar-mode #mainmenu-left .menu-selected > .submenu-arrow,
  body.admin-sidebar-mode #mainmenu-left .has-submenu.expanded > .submenu-arrow {
    background: transparent;
  }
  /* Nested submenu (accordion) — clamped to zero height until the section is .expanded, and SLID open/shut
     instead of snapped. A display flip cannot be animated, and since the section now auto-collapses whenever
     the user navigates to a page that owns no submenu, that snap read as an aggressive blink (Martin's
     report). The list keeps its box at every width and only its max-height moves, so the same easing runs in
     both directions. The height cannot be eased towards `auto`, so class.js (openSection) stamps the measured
     content height into --submenu-h before adding .expanded; the literal fallback only ever applies if that
     JS never ran. Duration matches the chevron rotation below, so badge and list settle together.
     Sub-items align with the parent rows (no extra indent): the Font Awesome corner arrow sits where the
     parent icon is, the text where the parent text is. */
  body.admin-sidebar-mode #mainmenu-left .has-submenu > .mainmenu-submenu {
    display: block;
    overflow: hidden;
    max-height: 0;
    opacity: 0;
    margin: 0;
    padding: 0;
    transition: max-height 0.18s ease, opacity 0.18s ease, margin-top 0.18s ease;
  }
  body.admin-sidebar-mode #mainmenu-left .has-submenu.expanded > .mainmenu-submenu {
    max-height: var(--submenu-h, 400px);
    opacity: 1;
    /* A clear breathing gap between the section title and its first sub-item — the design wants more air here
       than the flush layout gave (Martin's report). */
    margin: 10px 0 0 0;
  }
  /* Roomier bottom padding on the open card so the sub-items are not cramped against its lower edge. Eased on
     the same curve as the list itself — otherwise the card's lower edge jumps a step ahead of the slide. */
  body.admin-sidebar-mode #mainmenu-left .has-submenu {
    transition: padding-bottom 0.18s ease;
  }
  body.admin-sidebar-mode #mainmenu-left .has-submenu.expanded {
    padding-bottom: 12px;
  }
  body.admin-sidebar-mode #mainmenu-left .mainmenu-submenu-item {
    display: block;
    position: relative;
    width: 100%;
    box-sizing: border-box;
    /* No left padding: the nested <ul> already sits inside the parent row's 16px left padding, so the corner
       arrow (.submenu-item-ico) lands in the SAME column as the parent icons and the text under the parent
       text — sub-items start at the left with no extra indent (F1 / Martin's requirement). */
    padding: 10px 16px 10px 0;
    margin: 0;
    line-height: normal;
    white-space: nowrap;
    overflow: hidden;
  }
  body.admin-sidebar-mode #mainmenu-left .mainmenu-submenu-item .submenu-item-ico {
    display: inline-block;
    width: 22px;
    margin-right: 14px;
    text-align: center;
    font-size: 13px;
    opacity: 0.6;
    vertical-align: middle;
  }
  body.admin-sidebar-mode #mainmenu-left .mainmenu-submenu-item .menu-text {
    display: inline-block;
    max-width: calc(100% - 40px);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: middle;
  }
  body.admin-sidebar-mode #mainmenu-left .mainmenu-submenu-item.submenu-active {
    font-weight: bold;
  }
  /* Hover: the shared .customHoverBg paints a brand IMAGE gradient (reads as a left-to-right shading on the
     light menu card). Replace it with a plain neutral tint on top-level rows. An EXPANDED section is a card —
     its own background never reacts to hover (:not(.expanded)); hover feedback inside the open card belongs
     to the individual sub-item rows, which take the same neutral tint. */
  body.admin-sidebar-mode #mainmenu-left > li.customHoverBg:not(.expanded):hover {
    background-image: none;
    background-color: rgba(128, 128, 128, 0.1);
  }
  /* The theme files still paint the brand overlayImg via `.custom-background .customHoverBg:hover`; the
     expanded card must stay image-free on hover too (its surface colour keeps coming from the scheme rule). */
  body.admin-sidebar-mode #mainmenu-left > li.customHoverBg.expanded:hover {
    background-image: none;
  }
  body.admin-sidebar-mode #mainmenu-left .mainmenu-submenu-item:hover {
    background-image: none;
    background-color: rgba(128, 128, 128, 0.1);
  }
  /* ---- COLLAPSED rail: icon-only, centered; text/chevron hidden; scoped to top-level (> li) so the rules
       don't leak into nested submenu items. ---- */
  /* Let the hover flyouts escape the rail: the list and rows clip their content when expanded (long-title
     marquee), but in the collapsed rail the flyout is an absolutely-positioned child that must overflow to
     the right, so drop the clipping here. */
  body.admin-sidebar-mode.admin-sidebar-collapsed #mainmenu-left,
  body.admin-sidebar-mode.admin-sidebar-collapsed #mainmenu-left > li {
    overflow: visible;
  }
  body.admin-sidebar-mode.admin-sidebar-collapsed #mainmenu-left > li {
    padding: 12px 0;
    text-align: center;
  }
  /* In the icon rail the active row must fill the full rail width: the inset card margin (only meaningful for
     the expanded card) otherwise narrows the row and pushes its right edge away from the hover flyout, leaving
     a dead gap where the cursor drops :hover and the flyout vanishes (Martin's report). The centred icon and
     its rounded highlight are unaffected — only the horizontal margin is reset. */
  body.admin-sidebar-mode.admin-sidebar-collapsed #mainmenu-left > li.menu-selected {
    margin-left: 0;
    margin-right: 0;
  }
  /* Collapsed: the selected highlight is a centered ~45px rounded chip wrapping the icon AND the dots stack,
     NOT a full-width band. The <li> stays full-width so the hover hit-area still reaches the flyout (above);
     only the visible highlight narrows. The chip is a ::before spanning the row height behind the content —
     the icon and dots are lifted above it via z-index. Its surface colour comes from the scheme. */
  body.admin-sidebar-mode.admin-sidebar-collapsed #mainmenu-left > li.menu-selected::before {
    content: "";
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    /* The chip extends higher above the icon than the plain 6px bottom inset: the icon glyph sits low in its
       box and the last dot carries its own 8px bottom padding, so an equal top/bottom inset reads as cramped
       at the top. top:0 lifts the chip to match the ~14px visible gap below the last dot (Martin's symmetry
       request). */
    top: 0;
    bottom: 6px;
    width: 45px;
    border-radius: 10px;
    z-index: 0;
  }
  body.admin-sidebar-mode.admin-sidebar-collapsed #mainmenu-left > li.menu-selected > .menu-ico,
  body.admin-sidebar-mode.admin-sidebar-collapsed #mainmenu-left > li.menu-selected > .submenu-dots {
    position: relative;
    z-index: 1;
  }
  body.admin-sidebar-mode.admin-sidebar-collapsed #mainmenu-left > li .menu-ico {
    margin-right: 0;
  }
  body.admin-sidebar-mode.admin-sidebar-collapsed #mainmenu-left > li > .menu-text,
  body.admin-sidebar-mode.admin-sidebar-collapsed #mainmenu-left .has-submenu > .submenu-arrow {
    display: none;
  }
  /* Active collapsed section shows its children as a small stack of dots under the icon (per the mockup). The
     dots are their OWN in-flow element (.submenu-dots) — NOT the nested <ul>, which turns into the right-hand
     flyout on hover. Because they are a separate element, the hover flyout never touches them, so they stay put
     under the icon instead of vanishing (Martin's report), and being in-flow they size the row to exactly fit
     the dots whatever their count (no fixed reserved strip, no clipping). */
  body.admin-sidebar-mode.admin-sidebar-collapsed #mainmenu-left > li.has-submenu.menu-selected > .submenu-dots {
    display: flex;
    flex-direction: column;
    align-items: center;
    /* No padding on the container — the vertical rhythm comes from each dot's own padding (Martin's request).
       margin-top gives the icon→dots gap. The cluster is in-flow, so this only grows the TOP gap; the bottom
       gap stays driven by the row's padding — set so the top gap matches the bottom (~14px, Martin's request). */
    margin: 18px 0 0 0;
    padding: 0;
  }
  /* Each dot: an 8px top+bottom padding box around a 6px circle (Martin's request). box-sizing:content-box keeps
     width/height as the circle size; background-clip:content-box paints the fill only in that 6x6 content box so
     the padding stays transparent — the dots read as evenly spaced circles, not padded pills. flex-shrink:0 keeps
     each dot at its full size so the stack never compresses.
     KEEP border-radius at 50% (NOT a fixed px): background-clip:content-box shrinks each corner radius by that
     side's padding, so the vertical radius resolves to 11-8=3px (= half the 6px dot) → a true circle. A fixed
     `border-radius:3px` would instead be reduced to 0 vertically by the 8px padding and square off the top/bottom.
     At 50% the shape self-adjusts if the dot size or padding ever changes. */
  body.admin-sidebar-mode.admin-sidebar-collapsed #mainmenu-left > li.has-submenu.menu-selected > .submenu-dots .submenu-dot {
    display: block;
    box-sizing: content-box;
    flex-shrink: 0;
    width: 6px;
    height: 6px;
    padding: 8px 0;
    border-radius: 50%;
    /* Inactive dots are grey; only the active sub-page's dot is brand-coloured (Martin's request). The exact
       grey and the active brand fill are set per scheme in admin-{light,dark}mode-color.php.less — this is the
       neutral fallback. */
    background-color: #c0c4cc;
    background-clip: content-box;
  }
  /* Active sub-page's dot — brand-coloured (fill set per scheme). Only this one is highlighted. */
  body.admin-sidebar-mode.admin-sidebar-collapsed #mainmenu-left > li.has-submenu.menu-selected > .submenu-dots .submenu-dot.submenu-dot-active {
    background-color: currentColor;
  }
  /* Hover flyout (pure CSS): reveals the nested list (has-submenu) or the label (plain item) as a themed
     panel to the right of the rail. Overrides the inline-dots styling on hover. Surface colour = neutral dark
     (readable over both light and dark admin backgrounds). */
  body.admin-sidebar-mode.admin-sidebar-collapsed #mainmenu-left .has-submenu:hover > .mainmenu-submenu {
    display: block;
    /* Undo the expanded-sidebar accordion clamp: the flyout is a full-height panel that appears on hover, not
       a slide-open list, so it must not inherit the max-height/opacity/overflow the accordion animates. */
    max-height: none;
    opacity: 1;
    overflow: visible;
    transition: none;
    position: absolute;
    left: 70px;
    top: 0;
    min-width: 220px;
    margin: 0;
    padding: 8px 0;
    border-radius: 4px;
    text-align: left;
    z-index: 1005;
    background-color: #606060;
    color: #fff;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.28);
  }
  body.admin-sidebar-mode.admin-sidebar-collapsed #mainmenu-left .has-submenu:hover > .mainmenu-submenu .mainmenu-submenu-item {
    padding: 9px 16px;
    text-align: left;
    color: #fff;
  }
  body.admin-sidebar-mode.admin-sidebar-collapsed #mainmenu-left .has-submenu:hover > .mainmenu-submenu .mainmenu-submenu-item .submenu-item-ico,
  body.admin-sidebar-mode.admin-sidebar-collapsed #mainmenu-left .has-submenu:hover > .mainmenu-submenu .mainmenu-submenu-item .menu-text {
    display: inline-block;
  }
  /* Hovering a row INSIDE the flyout darkens it — the neutral #606060 panel gets a translucent-white tint (works
     over both themes; the flyout surface is always this dark grey). Needs higher specificity than the general
     `.mainmenu-submenu-item:hover` rule (the grey tint the expanded-card sub-items take) so the flyout keeps its
     own translucent-white feedback instead (Martin's report). */
  body.admin-sidebar-mode.admin-sidebar-collapsed #mainmenu-left .has-submenu:hover > .mainmenu-submenu .mainmenu-submenu-item:hover {
    background-image: none;
    background-color: rgba(255, 255, 255, 0.12);
  }
  body.admin-sidebar-mode.admin-sidebar-collapsed #mainmenu-left > li:not(.has-submenu):hover .menu-text {
    display: block;
    position: absolute;
    left: 70px;
    top: 50%;
    transform: translateY(-50%);
    max-width: none;
    min-width: 150px;
    padding: 11px 16px;
    border-radius: 4px;
    text-align: left;
    white-space: nowrap;
    overflow: visible;
    z-index: 1005;
    background-color: #606060;
    color: #fff;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.28);
    animation: none;
  }
  /* ---- TOP-BAR card: right-hand action icons on a light rounded card, top, right of the logo card. ---- */
  body.admin-sidebar-mode #mainmenu-right {
    position: fixed;
    top: calc(8px + var(--sa-band, 0px));
    left: 296px;
    /* 8 + 280 + 8: right of the logo card */
    right: 8px;
    height: 56px;
    margin: 0;
    padding: 0 3px;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    border-radius: 4px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
    z-index: 1000;
    transition: left 0.18s ease;
  }
  body.admin-sidebar-mode.admin-sidebar-collapsed #mainmenu-right {
    left: 86px;
    /* 8px past the "E" card right edge (x78) — the same 8px gap the "E" card has to
                                  the menu rail below it (Martin: keep both gaps equally small). The toggle circle
                                  floats over this left edge (higher z-index), like it sits on the logo card. */
  }
  /* Tighter icon spacing so the action icons sit close to the right edge like the mockup. */
  body.admin-sidebar-mode #mainmenu-right li {
    flex: 0 0 auto;
    height: 44px;
    line-height: 44px;
    padding: 0 7px;
  }
  /* The action icons are square tiles, flush against each other. The inherited horizontal-bar metrics
     (padding: 0 7px + a 5px gutter) shrink-wrapped each box around its glyph, so the icons came out
     narrow and unequal (25 / 29 / 32px) with a gap between them; the mockup wants one contiguous row of
     equally sized tiles, each big enough for its hover highlight. Scoped to .menu-onlyico so the logo and
     the language selectbox — both relocated to cards of their own — keep their layout. */
  body.admin-sidebar-mode #mainmenu-right > li.menu-onlyico {
    width: 44px;
    padding: 0;
    margin: 0;
    text-align: center;
  }
  /* Hover: same neutral tint as the sidebar rows above. Without this the icons fall through to the shared
     .customHoverBg rule, which paints the dark brand overlay image — far too heavy on the light top-bar card. */
  body.admin-sidebar-mode #mainmenu-right > li.customHoverBg:hover {
    background-image: none;
    background-color: rgba(128, 128, 128, 0.1);
  }
  /* ---- Language selector -> pinned to the bottom of the MENU card. ---- */
  body.admin-sidebar-mode #mainmenu-right li:has(.SumoSelect) {
    position: fixed;
    bottom: 16px;
    left: 20px;
    width: 256px;
    height: 40px;
    display: flex;
    align-items: center;
    margin: 0;
    padding: 0;
    z-index: 1002;
    transition: all 0.18s ease;
  }
  body.admin-sidebar-mode.admin-sidebar-collapsed #mainmenu-right li:has(.SumoSelect) {
    left: 8px;
    /* Match the collapsed rail width (70px) so the flag sits centered on the rail — the previous 60px
       was a leftover from the era when the rail itself was 60px wide. */
    width: 70px;
    justify-content: center;
  }
  /* The SumoSelect options list is a fixed div appended to <body> (data-sumo-parent) with the library's own
     z-index 1000 — below the docked menu card (1001), so in the sidebar the flag list opened BEHIND the panel
     and looked dead (Martin's report). Lift just this menu's list above the card, toggle and logo. */
  body.admin-sidebar-mode div[data-sumo-parent='mainmenuLang'] {
    z-index: 1006 !important;
  }
  /* "More…" overflow never applies in the vertical sidebar. */
  body.admin-sidebar-mode #mainmenu-more {
    display: none !important;
  }
  /* ---- Page layout: reserve the top-bar band and shift content clear of the sidebar (with the gap). ---- */
  /* The wrapper becomes a fixed, opaque masking band across the whole top header zone (viewport top down to the
     top-bar card's bottom edge, y72 = 8 gap + 56 bar + 8 gap). It is painted in the page-background colour by the
     colour schemes, so the floating logo / top-bar / menu cards still read as detached cards on the page. Its job:
     hide page content that scrolls up INTO the 8px gaps around those cards — without it, content bleeds through
     above the top bar's bottom border on scroll (Martin's report). z-index sits above the scrolling content but
     below the cards (top bar 1000, menu card 1001), which are descendants and paint on top of the band. */
  body.admin-sidebar-mode #mainmenu-wrapper {
    position: fixed;
    top: var(--sa-band, 0px);
    /* starts under the "logged in as user X" band, when that one is showing */
    left: 0;
    right: 0;
    height: 72px;
    z-index: 999;
  }
  body.admin-sidebar-mode #submenu-wrapper,
  body.admin-sidebar-mode #body-wrapper {
    width: auto;
    float: none;
    margin-left: 296px;
    /* 8 + 280 + 8 */
    /* No left padding: the content's left edge then lines up with the top-bar card's left edge (both x296),
       as in the mockup. Top = 72px puts the content top edge 8px below the top-bar card (bottom y64) —
       the same 8px card gap the menu card uses, so the content top aligns with the menu card top.
       The two wrappers are in-flow siblings, so the --sa-band reservation would be counted twice if an admin
       sidebar-mode page ever rendered the horizontal submenu bar. Today none does (a pure-list submenu is
       hidden further down, and only user-environment components fill #submenu-left-filter), so this stays
       inert — but split the padding per wrapper the moment that changes. */
    padding: calc(72px + var(--sa-band, 0px)) 8px 0 0;
    transition: margin-left 0.18s ease;
  }
  body.admin-sidebar-mode.admin-sidebar-collapsed #submenu-wrapper,
  body.admin-sidebar-mode.admin-sidebar-collapsed #body-wrapper {
    margin-left: 86px;
    /* 8 + 70 rail + 8 — aligned with the collapsed top-bar left edge (x86) so the
                                  header and content share one left margin and keep the 8px card gap. */
  }
  /* The admin band is NOT capped/centered at 1600px like the user environment: content, submenu bar and
     footer all run edge-to-edge between the sidebar gap and the 8px right margin (spec
     admin-main-col-full-width). Also nominally hits #mainmenu-nav, which stays constrained by the menu
     card, so that is harmless. */
  body.admin-sidebar-mode div.max-edu-width {
    max-width: none;
  }
  /* The framework's `.marginTop15` inter-block rhythm must not leak ABOVE the first rendered block: the
     band padding already provides the full 8px card gap (y72), so with the extra 15px the visible gap read
     as ~3x the menu gap (Martin's QA, 2026-07-07). Zero it on the first block of each column; blocks
     further down keep their 15px rhythm. Pages whose custom template already drops `marginTop15` ("disable
     margin15 from top") are unaffected. */
  /* (!important everywhere below only because the `.marginTop15` utility itself is !important.) */
  body.admin-sidebar-mode #main-col > #body-content-wrapper.marginTop15 {
    margin-top: 0 !important;
  }
  /* Same for facades that render their own root into #main-col (no `#body-content-wrapper` at all —
     Profile, GDPR, the detail pages): only the FIRST block must lose its margin; later siblings keep the
     8px inter-block rhythm from the "Main-column block spacing" rule below. */
  body.admin-sidebar-mode #main-col > .marginTop15:first-child {
    margin-top: 0 !important;
  }
  /* Admin dashboard: its wrapper has no margin, the 15px sits on the first row inside it. */
  body.admin-sidebar-mode #main-col > #body-content-wrapper > #admin-dashboard-quicklinks:first-child,
  body.admin-sidebar-mode #main-col > #body-content-wrapper > #admin-dashboard-top:first-child {
    margin-top: 0 !important;
  }
  /* Right panel: the first block lives inside the first NON-EMPTY panel wrapper (the wrappers are always
     present, most are empty). Zero every block's top margin, then restore the 8px rhythm for blocks whose
     wrapper follows another non-empty wrapper (the restore selector out-specifies the zero one). The 8px is
     the app-wide inter-block gap, carried to the user environment by the un-scoped rule further down
     ("Right-panel block spacing"); that rule is out-specified by the zero rule above, so the admin restore
     has to repeat the value here. */
  body.admin-sidebar-mode #rightPanel-main-div > div > .marginTop15 {
    margin-top: 0 !important;
  }
  body.admin-sidebar-mode #rightPanel-main-div > div:has(> *) ~ div > .marginTop15 {
    margin-top: 8px !important;
  }
  /* Footer follows the same content band as #body-wrapper (its inner .max-edu-width is uncapped above);
     hidden on mobile by the @media (max-width: 768px) block, so this only ever renders on the admin
     desktop. */
  body.admin-sidebar-mode #footer-wrapper {
    margin-left: 296px;
    padding-right: 8px;
    transition: margin-left 0.18s ease;
  }
  body.admin-sidebar-mode.admin-sidebar-collapsed #footer-wrapper {
    margin-left: 86px;
  }
  /* A pure list-type submenu (no filter) is carried by the sidebar accordion, so hide its redundant
     horizontal bar on the admin desktop — exactly as the mobile @media folds it into the hamburger. */
  body.admin-sidebar-mode #submenu-wrapper:has(.submenu-left-menu):not(:has(#submenu-left-filter > *)) {
    display: none !important;
  }
}
/* Marquee for long menu labels (hovered) — slides left to reveal the clipped tail, then back. Mirrors the
   modal-header title behaviour (App/Assets/less/modals.css.less). */
@keyframes admin-sidebar-marquee {
  0%,
  15% {
    transform: translateX(0);
  }
  85%,
  100% {
    transform: translateX(var(--marquee-x, 0));
  }
}
/*
  Responsive main menu (etapa 1). Below 768px the navigation collapses into a hamburger:
  the bar shows only the hamburger toggle (left) and the Edunio logo (right); everything else
  folds into a full-screen, scrollable panel. Desktop (>= 768px) is untouched.
 */
@media (max-width: 768px) {
  /* Fix the bar (with its themed background) to the top so it stays put on scroll — like the
     hamburger/logo pinned on it. The wrapper reserves the 60px the now-fixed bar vacated, so the
     page content below doesn't slide up underneath the bar. */
  /* ---- "Logged in as user X" band (#sa-wrapper). The bar below is fixed and the band is not, so the bar
       painted straight over it and the band was invisible on every narrow window — in the user environment
       just as much as in the admin one. Pin the band into the fixed chrome (z1010: over the bar at 1001 and
       its pinned hamburger/logo at 1002, under modals at 1050 and the notify panel at 1100) and let
       --sa-band push the bar, its spacer, and every other pinned mobile surface below it. ---- */
  #sa-wrapper {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 1010;
  }
  #mainmenu-wrapper {
    /* Reserves the space both fixed strips vacated: the band on top of the bar. */
    height: calc(60px + var(--sa-band, 0px));
  }
  div#mainmenu-panel {
    position: fixed;
    top: var(--sa-band, 0px);
    left: 0;
    right: 0;
    height: 60px;
    z-index: 1001;
  }
  /* Show the hamburger and pin it to the left of the bar. top:10px vertically centers the 40px tile
     in the 60px bar. */
  #mainmenu-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    position: fixed;
    top: calc(10px + var(--sa-band, 0px));
    left: 15px;
    z-index: 1002;
  }
  /* Player mode: the close cross + 3-dots sit where the hamburger did — as a pair on the left of the bar
     (the logo stays pinned right). x-show hides them off the player pages; here they only get positioned.
     Reveal them at mobile width (base is display:none, like the hamburger); x-show adds the player gating. */
  #player-close-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    position: fixed;
    top: calc(10px + var(--sa-band, 0px));
    left: 15px;
    z-index: 1002;
  }
  #player-overlay-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    position: fixed;
    top: calc(10px + var(--sa-band, 0px));
    left: 61px;
    z-index: 1002;
  }
  /* Player mode: keep the overlay player-only (AC10). #mainmenu-left and "More…" are x-show-hidden; the
     right list is NOT x-show-gated (it carries the logo, which stays pinned right), so hide only its
     non-logo global items here. The logo is the single right item that survives. */
  #mainmenu-panel.player-menu-mode #mainmenu-right li:not(:has(img.edunio-logo)) {
    display: none;
  }
  /* Login / empty menu: the left list has no items (MAINMENU_EMPTY). There is nothing to
     collapse, so drop the hamburger and surface the language selector directly in the bar
     (where the hamburger would sit); the logo, if any, stays pinned on the right. `:has()`
     is live, so once the user logs in and the left menu fills, the hamburger returns. */
  #mainmenu-panel:has(#mainmenu-left:empty) #mainmenu-toggle {
    display: none;
  }
  #mainmenu-panel:has(#mainmenu-left:empty) #mainmenu-right li:has(.SumoSelect) {
    display: flex;
    align-items: center;
    position: fixed;
    top: var(--sa-band, 0px);
    left: 15px;
    height: 60px;
    margin: 0;
    padding: 0;
    float: none;
    z-index: 1002;
  }
  /* Hide the left navigation when the panel is closed. */
  #mainmenu-left {
    display: none;
  }
  /* The desktop overflow ("More…") never applies below the breakpoint — the hamburger owns every item.
     Keep it hidden in both the closed bar and the open panel (the reflow also empties it back into
     #mainmenu-left when the viewport drops under the breakpoint). */
  #mainmenu-more {
    display: none !important;
  }
  /* Right list keeps only the logo visible in the bar; all other icons fold into the panel. */
  #mainmenu-right {
    float: none;
    margin: 0;
  }
  #mainmenu-right li {
    display: none;
  }
  /* The logo (img.edunio-logo) always stays pinned to the right of the bar. */
  #mainmenu-right li:has(img.edunio-logo) {
    display: flex;
    align-items: center;
    position: fixed;
    top: var(--sa-band, 0px);
    right: 15px;
    height: 60px;
    float: none;
    margin: 0;
    padding: 0;
    z-index: 1002;
  }
  /* OPEN state: the themed panel expands to a full-screen, scrollable overlay.
     z-index stays below the sumoselect options wrapper (fixed, z-index 1000, appended to body)
     so the language flag list renders ABOVE the panel; the fixed bar (hamburger + logo, 1002)
     stays above both. */
  #mainmenu-panel.menu-open {
    position: fixed;
    /* Not `inset: 0` — the overlay starts under the "logged in as user X" band, so the band (z1010) stays
       readable and its "Ukončit" link clickable while the hamburger is open. */
    top: var(--sa-band, 0px);
    left: 0;
    right: 0;
    bottom: 0;
    height: auto;
    overflow-y: auto;
    z-index: 999;
  }
  #mainmenu-panel.menu-open #mainmenu-nav {
    /* Leave room for the fixed bar (hamburger + logo) and fade the panel in. The desktop nav is a 60px flex
       row; in the open hamburger it must be a full-height stacked block again (the desktop overflow does not
       apply on mobile). */
    display: block;
    height: auto;
    padding-top: 60px;
    animation: edu-menu-fade 0.18s ease-out;
  }
  #mainmenu-panel.menu-open #mainmenu-left,
  #mainmenu-panel.menu-open #mainmenu-right,
  #mainmenu-panel.menu-open #mainmenu-player-list {
    display: block;
    float: none;
    width: 100%;
    margin: 0;
    /* Reset the default <ul> padding-left: #mainmenu-left/right get it from their base rule, but
       #mainmenu-player-list (class noListStyle, which only clears the bullet) otherwise keeps the browser's
       ~40px indent, pushing the player items under the 3-dots instead of aligning them under the cross. */
    padding: 0;
  }
  #mainmenu-panel.menu-open #mainmenu-left li,
  #mainmenu-panel.menu-open #mainmenu-right li,
  #mainmenu-panel.menu-open #mainmenu-player-list li {
    display: block;
    float: none;
    width: 100%;
    height: auto;
    line-height: normal;
    margin: 0 0 4px 0;
    padding: 14px 15px;
    box-sizing: border-box;
  }
  /* The close affordance (✕) STAYS pinned LEFT in the open panel. The hamburger toggle is a single button
     (fa-bars when closed, fa-times when open) and is NOT relocated on open, so the ✕ sits exactly where the
     closed-state hamburger sat (left, from the #mainmenu-toggle rule above). The open panel's header thus
     mirrors the closed bar — ✕ left, logo right — and the close icon does not jump across the bar. */
  /* Keep the logo pinned to the RIGHT of the bar while the panel is open — the same spot as in the closed
     bar (it does not move to the left). The display/width/height/padding overrides cancel the generic
     open-state row rule above (#mainmenu-panel.menu-open #mainmenu-right li), which would otherwise stretch
     the logo into a full-width block. */
  #mainmenu-panel.menu-open #mainmenu-right li:has(img.edunio-logo) {
    display: flex;
    width: auto;
    height: 60px;
    padding: 0;
    right: 15px;
    left: auto;
  }
  /* Hamburger items show BOTH icon (left) and text (right). */
  #mainmenu-panel.menu-open #mainmenu-left li .menu-ico,
  #mainmenu-panel.menu-open #mainmenu-right li .menu-ico,
  #mainmenu-panel.menu-open #mainmenu-player-list li .menu-ico {
    display: inline-block;
    width: 24px;
    margin-right: 12px;
    text-align: center;
    vertical-align: middle;
  }
  #mainmenu-panel.menu-open #mainmenu-left li .menu-text,
  #mainmenu-panel.menu-open #mainmenu-right li .menu-text,
  #mainmenu-panel.menu-open #mainmenu-player-list li .menu-text {
    display: inline;
    vertical-align: middle;
  }
  /* Bigger gap between the left-menu group and the right-menu group. */
  #mainmenu-panel.menu-open #mainmenu-right {
    margin-top: 30px;
  }
  /* Variant 2 — eager nested submenu inside the open hamburger. Selectors include #mainmenu-left so
     they out-specify the generic `#mainmenu-panel.menu-open #mainmenu-left li` row rule above. The
     nested list shows only when its section carries the `expanded` class (toggled by the accordion). */
  #mainmenu-panel.menu-open #mainmenu-left .has-submenu {
    position: relative;
  }
  /* Open-section card — rounded corners + the scheme surface / flipped text colour from the theme files
     (`.custom-background .customHoverBg.has-submenu.expanded` in the card colour groups). NO side margins:
     unlike the admin sidebar card, the overlay rows are flush with the panel edge, and an inset card would
     sit 10px right of the other menu items (Martin's report). */
  #mainmenu-panel.menu-open #mainmenu-left .has-submenu.expanded {
    margin: 2px 0 6px;
    border-radius: 4px;
  }
  /* The theme files paint the brand overlayImg on `.customHoverBg:hover`; the open card must stay
     image-free whatever is hovered inside it — hover feedback belongs to the individual sub-items,
     which take the neutral tint (the 2-id selectors below out-specify the 0-id theme rules). */
  #mainmenu-panel.menu-open #mainmenu-left .has-submenu.expanded:hover {
    background-image: none;
  }
  #mainmenu-panel.menu-open #mainmenu-left .has-submenu.expanded .mainmenu-submenu-item:hover {
    background-image: none;
    background-color: rgba(128, 128, 128, 0.1);
  }
  #mainmenu-panel.menu-open #mainmenu-left .has-submenu > .submenu-arrow {
    display: block;
    position: absolute;
    top: 18px;
    right: 15px;
    transition: transform 0.18s ease;
  }
  #mainmenu-panel.menu-open #mainmenu-left .has-submenu.expanded > .submenu-arrow {
    transform: rotate(180deg);
  }
  #mainmenu-panel.menu-open #mainmenu-left .has-submenu > .mainmenu-submenu {
    display: none;
    margin: 0;
    padding: 0;
  }
  #mainmenu-panel.menu-open #mainmenu-left .has-submenu.expanded > .mainmenu-submenu {
    display: block;
    /* Keep the section header at its own full row height — push the nested list clearly below it so the
       header reads as a row of its own (like the collapsed items), not crammed against the first sub-item. */
    margin-top: 14px;
  }
  #mainmenu-panel.menu-open #mainmenu-left .mainmenu-submenu-item {
    display: block;
    width: 100%;
    box-sizing: border-box;
    /* No own left padding: the nested <ul> already sits inside the parent row's side padding, so the corner
       arrow (.submenu-item-ico) lands in the SAME column as the parent icon and the text under the parent
       text — exactly like the admin docked sidebar. */
    padding: 12px 15px 12px 0;
    margin: 0;
    line-height: normal;
  }
  /* Font Awesome corner-arrow indicator (.submenu-item-ico) before each nested item — shared markup with the
     admin docked sidebar, so the hamburger and the sidebar submenu read identically. */
  #mainmenu-panel.menu-open #mainmenu-left .mainmenu-submenu-item .submenu-item-ico {
    display: inline-block;
    width: 24px;
    margin-right: 12px;
    text-align: center;
    opacity: 0.6;
    vertical-align: middle;
  }
  /* Active sub-item (the current page) — marked with bold only. The section's selected background stays on
     the header; the sub-item itself gets no background, just the bold weight. */
  #mainmenu-panel.menu-open #mainmenu-left .mainmenu-submenu-item.submenu-active {
    font-weight: bold;
  }
  /* Responsive footer (etapa 4). Hide the page footer on mobile — but ONLY when a hamburger exists (the left
     menu has items). On login / empty menu there is no hamburger to host the footer, so it stays in the body
     (FT9). `:has(#mainmenu-left li)` keys off real <li> presence (the skeleton's empty <ul> carries only
     whitespace, so :empty would be unreliable). */
  body:has(#mainmenu-left li) #footer-wrapper {
    display: none;
  }
  /* Show the relocated footer at the very bottom of the OPEN hamburger, under the navigation. It inherits the
     panel's themed background (#mainmenu-panel.custom-background); margin-top separates it from the menu. */
  #mainmenu-panel.menu-open #mainmenu-footer {
    display: block;
    width: 100%;
    box-sizing: border-box;
    margin-top: 30px;
    padding: 14px 15px;
    font-size: 12px;
    opacity: 0.7;
    text-align: center;
  }
  /* Footer hyperlinks (the GDPR .hyperlink span + any <a>, e.g. the Zentiva prevent.cz link) sit on the
     themed panel background where the default link color blends in. Render them in the surrounding text
     color, but keep a permanent underline so they still read as links (per Martin's request). */
  #mainmenu-footer a,
  #mainmenu-footer .hyperlink {
    color: inherit;
    text-decoration: underline;
  }
  /*
    Responsive login (etapa 5). Below 768px the fixed-width auth blocks (#login-block 460px,
    #sign-in-block 500px) overflow narrow viewports. Keep each block at its natural width and let the
    desktop `margin: 0 auto` keep centring it — only CAP the width with max-width so that once the
    viewport gets narrower than the block, it shrinks instead of overflowing, always leaving
    @defaultSidePadding (15px) clear on both sides. Do NOT set `width: auto` here — that would stretch
    the block to fill the row and it would stop reading as a centred box on mid-size screens (e.g. 700px).
    The inner horizontal padding is reduced to @defaultSidePadding so the form fields have room on a
    phone. Vertical centring is untouched — it stays driven by LoginFacadeComponent.updateCSS().
    #sign-in-block lives on the public event/quiz sign-in pages (not the login page) but shares the
    same fixed-width pattern, so it gets the same treatment for consistency. The SignUp and
    LostPassword screens are modals, handled by the modal responsive CSS, not here. SSO buttons are
    content-width inline-blocks centred in .center, so they do not overflow and need no rule.
  */
  #login-block,
  #sign-in-block {
    max-width: calc(100% - (15px * 2));
    padding-left: 15px;
    padding-right: 15px;
  }
}
@keyframes edu-menu-fade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
/*
  Shared responsive filter overlay (variant 4). SINGLE definition reused by BOTH the app submenu bar
  (#submenu-panel, x-data="filterOverlay()") and the admin list toolbar (.list-toolbar,
  x-data="filterOverlay('.list-toolbar-filters')"). All selectors below are class-based so a change here
  applies to both consumers (the submenu markup carries .filter-panel/.filter-toggle/.filter-overlay/
  .filter-source/.filter-overlay-* alongside its ids; the list toolbar carries the same classes). On filter
  pages the bar stays on mobile: the inline (desktop) filter controls (.filter-source) are hidden and a
  fa-filter button (.filter-toggle) opens a full-screen overlay (.filter-overlay) that HOSTS those controls
  plus an Apply button. Everything here is hidden/untouched on desktop (>= 768px) — desktop keeps the filters
  inline. The submenu-only bar geometry (position:fixed, top:60px) stays in submenu.css.less.
 */
.filter-toggle {
  display: none;
  height: 22px;
  width: 22px;
  margin: 19px 0 0 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;
  font-size: 14px;
  line-height: 22px;
  text-align: center;
  cursor: pointer;
}
/* When a filter is active the rich-toggle pages mark their (desktop) collapse arrow icon with `.red-text`
   (ListItemsComponent). Mirror that on the mobile funnel: if the panel holds a red-text arrow, the fa-filter
   funnel goes red too — same active-filter cue as the non-responsive design. */
.list-toolbar:has(#toggle-filter-list i.red-text) .filter-toggle {
  color: #DD0000;
}
/* Overlay is desktop-hidden; only the @media block below reveals it (x-cloak hides it until Alpine inits). */
.filter-overlay {
  display: none;
}
/* Mobile action slot (per-page secondary control left of the funnel) is desktop-hidden too; the page's
   relocate-mode control lives in its desktop home ≥769px and the overlay-mode toggle only exists on
   mobile. Revealed in the @media block below. */
#submenu-action-slot {
  display: none;
}
/* TrainingEvents terms list: the "Status" dropdown and the optional training-events filter share one
   .filter-source so the mobile overlay relocates them together. display:contents lets the group's children
   flow directly in the desktop toolbar (Status floats inline; the TE block is the collapsible 2nd row),
   while the shared @media rules below still hide (.filter-panel .filter-source) and re-lay-out
   (.filter-overlay .filter-source) the whole group below 768px — both outrank this rule by specificity. */
.training-events-terms-filter-source {
  display: contents;
}
/* TrainingEvents terms tables (main terms page, CM terms page, trainingEventForm terms tab — all share
   this id). Their fixed columns (icon 52 + group 180 + occupancy 120 + merged date&time 180 + expiration
   150 + options 190 ≈ 872px) left the width-less "name" column nothing to grow into once the content area
   dropped below ~900px, collapsing "name" to a single character per line (worst around 850px). A min-width
   keeps the table at its natural size so it overflows into the surrounding .list-table-scroll-wrap and
   scrolls horizontally there (the sanctioned 768–1000px behaviour) instead of squeezing "name"; below 768px
   the `table.mobile-cards { min-width: 0 !important }` rule resets this so the cards stack full-width. */
#training-events-terms-table {
  min-width: 1040px;
}
@media (max-width: 768px) {
  /* Hide the inline filter controls WHILE they sit in the panel/bar; the fa-filter button replaces them.
     Scoped to .filter-panel so that once the controls are relocated INTO .filter-overlay (no longer a
     descendant of .filter-panel) they show again. */
  .filter-panel .filter-source {
    display: none;
  }
  /* Show the fa-filter button only on pages that actually have filter controls. */
  .filter-panel:has(.filter-source > *) .filter-toggle {
    display: block;
    float: right;
  }
  /* Submenu bar controls as full-height 46×60 tap targets — parity with the player bar pair
     (#player-close-btn / #player-overlay-toggle: 46px-wide adjacent boxes over the full 60px bar), so
     the action icon and the funnel are comfortably tappable without mis-taps. Scoped to the submenu
     bar; the admin list-toolbar funnel keeps its compact 22px box. */
  #submenu-panel .filter-toggle {
    height: 60px;
    width: 46px;
    margin: 0;
    align-items: center;
    justify-content: center;
  }
  #submenu-panel:has(.filter-source > *) .filter-toggle {
    display: flex;
  }
  /* Mobile action slot: rendered only on pages that declare a panelAction, so a flat reveal is enough.
     The slot floats right AFTER the funnel in source order, i.e. it renders to the funnel's LEFT. */
  #submenu-action-slot {
    display: flex;
    align-items: center;
    justify-content: center;
    float: right;
    height: 60px;
    width: 46px;
  }
  /* The overlay-mode toggle fills the slot (the .filter-toggle base is display:none and the :has()
     rule above only covers the funnel, so display is granted here). */
  #submenu-action-slot .submenu-action-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    width: 100%;
    margin: 0;
  }
  /* A relocate-mode control adopted by the slot drops its desktop input chrome (border/background/
     padding from inputs.css.less + colour-theme files) and renders exactly like the funnel: a bare
     glyph in the bar text colour, filling the whole tap target. */
  #submenu-action-slot > *:not(.submenu-action-toggle) {
    display: flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    height: 100%;
    width: 100%;
    margin: 0;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    /* also kills the theme :hover/:focus chrome (accent border + box-shadow glow) — the id selector
       outranks the themed pseudo-class rules for the same properties, so the control stays a bare
       glyph like the funnel in every state */
    box-shadow: none;
    color: inherit;
    line-height: normal;
    cursor: pointer;
  }
  #submenu-action-slot > *:not(.submenu-action-toggle) i {
    color: inherit;
  }
  /* User Library submenu: its only filter is the fulltext input, which fits the bar — show it
     inline instead of hiding it behind the fa-filter overlay (Martin's QA, 2026-07-11). Scoped via
     the input id INSIDE the submenu panel, so the admin list toolbar (same input id, different
     panel) keeps the standard funnel behaviour. */
  #submenu-panel:has(#library-table-fulltext) .filter-source {
    display: block;
  }
  #submenu-panel:has(#library-table-fulltext) .filter-toggle {
    display: none;
  }
  /* Full-screen themed overlay hosting the relocated filters. The overlay is a SIBLING of the panel (so it
     escapes the bar's fixed stacking context); .filter-overlay only exists in the overlay markup, so a flat
     class selector reveals it for both consumers. */
  .filter-overlay {
    display: block;
    position: fixed;
    /* Not `inset: 0` — like the open hamburger, the overlay starts under the "logged in as user X" band.
       It replaces the top bar with a header of its own, so it must sit where the bar sits, not over the
       band (z1010); a real modal still covers the band, exactly as on the desktop. */
    top: var(--sa-band, 0px);
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1003;
    overflow-y: auto;
    padding: 60px 15px 76px 15px;
    box-sizing: border-box;
    animation: edu-menu-fade 0.18s ease-out;
  }
  /* Lay the relocated filter controls out as a left-aligned column: every control on its own row, with its
     label on its own line ABOVE the input. Targets the filter structure wrappers (.filter-source plus up to
     two nested div levels — covers the single-level pages and the MyCourses grouped wrapper). The SumoSelect
     internals are deeper and untouched; selects keep their own width, just left-aligned. */
  .filter-overlay .filter-source,
  .filter-overlay .filter-source > div,
  .filter-overlay .filter-source > div > div {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    float: none;
    width: 100%;
    margin: 0;
    line-height: normal;
    text-align: left;
  }
  /* Vertical gap between the stacked controls. */
  .filter-overlay .filter-source > div > div,
  .filter-overlay .filter-source > div:only-child {
    margin-bottom: 20px;
  }
  /* Each input/select sits just below its label. */
  .filter-overlay .filter-source .SumoSelect,
  .filter-overlay .filter-source input,
  .filter-overlay .filter-source select {
    margin-top: 6px;
    float: none;
  }
  /* Full-width, left-aligned selectboxes/inputs in the overlay column (the desktop SumoSelect keeps a fixed
     px width + float that otherwise leaves e.g. the language row's control hanging on the right). */
  .filter-overlay .filter-source .SumoSelect,
  .filter-overlay .filter-source select,
  .filter-overlay .filter-source input[type="text"] {
    width: 100% !important;
    float: none !important;
    margin-left: 0 !important;
  }
  .filter-overlay .filter-source .filter-table > tbody > tr > th,
  .filter-overlay .filter-source .filter-table > tbody > tr > td {
    text-align: left !important;
    float: none !important;
    /* Clear preceding floats (e.g. the org-structure picker in the row above) so each stacked label/control
       starts on its own line instead of flowing to the right of a float. */
    clear: both;
  }
  /* Rich-toggle admin pages relocate their collapsible filter block into the overlay; that block carries
     `admin-list-filter-hidden` (height:0 + opacity:0) when the page's own desktop toggle is closed. Inside
     the overlay it must always be fully expanded regardless of that toggle state. */
  .filter-overlay .admin-list-filter-hidden {
    opacity: 1;
    transform: none;
    pointer-events: auto;
    height: auto !important;
  }
  /* Rich-toggle filter blocks are desktop multi-column `filter-table` grids (fixed `width160p`/`width210p`
     columns). In the narrow overlay reflow them to a single vertical column: each label (th) on its own row
     above its controls (td), full width. Empty spacer cells are dropped. */
  .filter-overlay .filter-source .filter-table,
  .filter-overlay .filter-source .filter-table > tbody,
  .filter-overlay .filter-source .filter-table > tbody > tr,
  .filter-overlay .filter-source .filter-table > tbody > tr > th,
  .filter-overlay .filter-source .filter-table > tbody > tr > td {
    display: block;
    width: 100% !important;
    max-width: 100%;
    text-align: left;
    box-sizing: border-box;
  }
  .filter-overlay .filter-source .filter-table > tbody > tr > th:empty,
  .filter-overlay .filter-source .filter-table > tbody > tr > td:empty {
    display: none;
  }
  .filter-overlay .filter-source .filter-table > tbody > tr > th {
    margin-top: 14px;
    font-weight: bold;
  }
  .filter-overlay .filter-source .filter-table > tbody > tr > td {
    padding: 4px 0 !important;
  }
  /* The clickable option cells (filter-table-items) stay a contiguous segmented control exactly like
     desktop — a single full-width fixed-layout table row, cells adjacent with shared 1px borders and NO
     gaps between them. The desktop base rules (`table-layout:fixed; width:100%` + `border-right-width:0`
     on non-last cells) already produce this, so we must NOT reflow them into spaced inline-block pills;
     just ensure the table fills the (now stacked) row width. */
  .filter-overlay .filter-source .filter-table-items {
    width: 100% !important;
  }
  /* Chip colours on the (blue) overlay: inactive = transparent fill so the blue shows through, with a white
     border + white text; only ACTIVE (`.selected`) chips get a solid white fill with dark text. */
  .filter-overlay .filter-source .filter-table table.filter-table-items td {
    background-color: transparent;
    border-color: #FFF;
    color: #FFF;
  }
  .filter-overlay .filter-source .filter-table table.filter-table-items td.selected {
    background-color: #FFF !important;
    border-color: #FFF !important;
  }
  /* Header of the filter overlay mirrors the closed top panel: a decorative filter icon pinned top-LEFT
     (a visual echo of the funnel that opened the overlay, like ☰ in the bar) and the Edunio logo pinned
     top-RIGHT (where the logo sits in the top panel). There is no close (✕) affordance here — the overlay
     closes via the bottom Apply/"Zavřít" button, Esc, or a resize back to desktop. */
  .filter-overlay-ico {
    position: fixed;
    top: var(--sa-band, 0px);
    left: 15px;
    display: flex;
    align-items: center;
    justify-content: center;
    height: 60px;
    width: 46px;
    color: inherit;
    z-index: 1004;
  }
  .filter-overlay-logo {
    position: fixed;
    top: var(--sa-band, 0px);
    right: 15px;
    display: flex;
    align-items: center;
    height: 60px;
    z-index: 1004;
  }
  /* Apply button pinned full-width to the bottom. */
  .filter-overlay-apply {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100%;
    height: 56px;
    padding: 0;
    border: 0;
    border-top: 1px solid rgba(127, 127, 127, 0.25);
    background: transparent;
    /* A <button> does not inherit color by default (UA sets it black); inherit the overlay's themed
       `.custom-background` text colour (fontColorOnCustomColor — white in this admin) so the Apply label
       matches the instance's colour scheme instead of rendering black. */
    color: inherit;
    font-size: 14px;
    font-weight: bold;
    cursor: pointer;
    z-index: 1004;
  }
  /* --- MTE mobile restack (story S2) --- */
  /* Hide the calendar column only while it sits in the page — once relocated into the action overlay
     it escapes this descendant scope (same trick as `.filter-panel .filter-source` above). The id
     selector + !important outranks the static `.width25 { width: … !important }` utility. */
  #body-content-wrapper #my-training-events-calendar-div {
    display: none;
  }
  #my-training-events-list-div {
    width: 100% !important;
  }
  /* The action-overlay body spans the overlay's padding box so the page JS can measure the available
     height for FullCalendar (setCalendarOverlayMode), and the relocated column fills it. */
  #submenu-action-overlay .filter-overlay-body {
    height: 100%;
  }
  #submenu-action-overlay #my-training-events-calendar-div {
    width: 100% !important;
    padding-left: 0 !important;
    margin-top: 0 !important;
  }
  /* --- myCourses slot icon (story S3) --- */
}
/**
  Logo in submenu.
 */
#submenuLogoDiv {
  width: 350px;
  height: 60px;
  display: flex;
  align-items: center;
  justify-content: right;
  align-content: center;
}
#submenuLogoDiv img {
  flex-grow: 0;
  flex-shrink: 0;
}
/**
  Footer cascade styles
 */
div#footer-panel {
  float: left;
  width: 100%;
  height: 40px;
  font-size: 12px;
  margin-top: 40px;
  opacity: 0.7;
  text-align: center;
}
/* Responsive footer (etapa 4) — the footer copy embedded at the bottom of the hamburger (mainMenu.hbs) is
   hidden by default; it is revealed only inside the open panel below 768px (see the @media block above). */
#mainmenu-footer {
  display: none;
}
/**
  Login form.
 */
#login-panel,
#sign-in-panel {
  min-height: 280px;
  width: 100%;
  text-align: center;
}
#sign-in-block {
  width: 500px;
  padding: 26px 15px 0 15px;
  min-height: 280px;
  box-sizing: border-box;
  margin: 0 auto;
  text-align: center;
  -webkit-border-radius: 4px;
  -moz-border-radius: 4px;
  border-radius: 4px;
}
#login-block {
  width: 460px;
  padding: 26px 58px 0 58px;
  min-height: 280px;
  box-sizing: border-box;
  margin: 0 auto;
  text-align: center;
  -webkit-border-radius: 4px;
  -moz-border-radius: 4px;
  border-radius: 4px;
}
#login-block div,
#sign-in-block div {
  padding: 6px 0 0 0;
}
#login-block .login-caption {
  font-family: Arial, "Arial", "Helvetica", sans-serif;
  font-size: 20px;
  text-align: left;
  padding: 6px 0 0 0;
}
#sign-in-block div.input,
#login-block div.input,
#login-block div.links {
  padding: 2px 0 0 0;
}
#login-block div.input i {
  position: absolute;
  left: 5px;
  top: 10px;
  width: 28px;
  height: 20px;
  line-height: 20px;
  z-index: 1;
}
/*
  Style of default table in modal.
*/
.default-table,
.default-table tr td,
.default-table th {
  border-spacing: 0;
  border: 0;
  border-collapse: collapse;
  line-height: 36px;
  padding: 3px 0;
  vertical-align: top;
}
/*
  Style for error (403, 404) page.
 */
#page-error {
  padding: 50px 15px 100px 15px;
  text-align: center;
  float: left;
}
#page-error .center-wrapper {
  margin: 0 auto 0 auto;
  text-align: left;
  max-width: 1000px;
}
#page-error .ico-wrapper {
  float: left;
  font-size: 120px;
  margin-right: 30px;
}
#page-error .text-wrapper {
  mrgin-top: 20px;
  float: left;
}
/*
  Style for admin dashboard.
 */
#adminDashboardTable tr td,
.verticalTop {
  vertical-align: top;
}
#adminDashboardTable h3 {
  margin: 0;
  font-size: 14px;
}
#adminDashboardTiles div.infoBox {
  width: 50%;
  float: left;
  margin-bottom: 12px;
  box-sizing: border-box;
  transition: all 0.2s linear;
  cursor: pointer;
}
#adminDashboardTiles div.infoBox h4 {
  font-size: 18px;
  margin: 58px auto 32px 10px;
}
#adminDashboardTiles div.infoBox span,
#adminDashboardTiles div.infoBox a,
#adminDashboardTiles div.infoBox a:visited {
  margin: auto auto 10px 10px;
  float: left;
}
#adminDashboardTiles div.infoBox div {
  float: left;
  max-width: 344px;
}
#adminDashboardTiles div.infoBox div.num {
  background-color: #666;
  width: 80px;
  float: right;
  height: 140px;
  line-height: 140px;
  color: #FFF;
  font-size: 40px;
  text-align: center;
}
#adminDashboardTiles div.infoBox div.percentage {
  margin-top: -140px;
  width: 80px;
  text-align: center;
  height: 140px;
  line-height: 140px;
}
#adminDashboardTiles .statusbar {
  margin: 0;
  padding: 0;
  float: left;
  width: 80px;
  background-color: #06b025;
}
#adminDashboardTiles .statusbarRed {
  margin: 0;
  padding: 0;
  float: left;
  width: 80px;
  background-color: #CC0000;
}
/**
  Style for rotating information in admin submenu.
 */
#information-list {
  position: relative;
}
#information-list li {
  position: absolute;
  text-align: right;
  width: 335px;
  top: 0;
  right: 0;
  color: #999;
}
/**
  Default table in main body
 */
.default-table-body,
.default-table-list {
  margin-bottom: 20px;
  border-spacing: 0;
  table-layout: fixed;
}
.default-table-body > tbody > tr,
.default-table-list > tbody > tr {
  padding: 0;
}
.default-table-body > tbody > tr > td,
.default-table-body > tbody > tr > th {
  line-height: 36px;
  vertical-align: top;
  padding: 0 0 7px 0;
}
.default-table-body > tbody > tr > th,
.default-table-body > tr > th {
  font-weight: normal;
  line-height: 20px;
  padding-top: 8px;
  padding-bottom: 15px;
  text-align: left;
  padding-right: 15px;
}
.default-table-list > tbody > tr > td,
.default-table-list > tbody > tr > th {
  line-height: 22px;
  vertical-align: top;
  padding: 0;
  text-align: left;
}
/**
  Page with default table with list of item.
*/
.default-list-table {
  border-collapse: collapse;
  table-layout: fixed;
}
.default-list-table > tbody > tr > th,
.default-list-table > tbody > tr > td {
  padding: 10px 15px 10px 0;
  text-align: left;
  font-weight: normal;
  line-height: 22px;
  vertical-align: top;
}
.default-list-table > tbody > tr > th:first-child,
.default-list-table > tbody > tr > td:first-child,
.default-list-table > tbody > tr > td:first-child .td-link {
  padding: 10px 15px 10px 15px;
}
.default-list-table > tbody > tr > td .td-link {
  line-height: 22px;
  padding: 10px 15px 10px 0;
}
/* List-table header auto-fit (listHeaderFit.js). A header label wider than its own declared column
   used to wrap, because .default-list-table is `table-layout: fixed` and the numbered .widthNNNp
   utility is the column's only width input. The pass grows such a column instead.

   ADR-001 forbids overriding a numbered utility, so a grown column has .widthNNNp REMOVED from its
   <th> and carries this distinctly-named class instead - the escape the ADR prescribes. The
   `box-sizing: border-box` is NOT decorative: .widthNNNp supplied it, and without it every fitted
   column would silently gain the cell's 15px right padding. */
.default-list-table > tbody > tr > th.list-col-fitted {
  width: var(--list-col-w);
  box-sizing: border-box;
}
/* Transient measuring state, added and removed within a single synchronous block by
   measureListHeaderNaturalWidths(). Under fixed layout the browser never measures content, so the
   table is flipped to auto layout with a nowrap header row to expose each label's natural width.
   `table.` outranks .default-list-table's own `table-layout: fixed` without needing !important. */
table.list-table-measuring {
  table-layout: auto;
  /* A width floor or cap left in place defeats the whole point: auto layout stretches the table to
     satisfy it and then spreads the leftover across the columns, so every column measures wider than
     its own label (#training-events-terms-table's 1040px floor grew its Czech columns by up to
     104px). This is NOT an ADR-001 violation: the numbered width utilities are removed from the
     element by listHeaderFit.js before this state is entered, so no numbered class is overridden -
     this only neutralises id- and class-level rules that carry no number in their name. */
  min-width: 0 !important;
  max-width: none !important;
}
table.list-table-measuring > tbody > tr > th {
  white-space: nowrap;
}
/* Header labels never break mid-word: the body-level `word-wrap: break-word` otherwise splits a
   single-word label that is a hair wider than its fixed-width column (WebKit's wider font metrics
   break "Možnosti" in the 80px options column into "Možnost / i" and double the header row height
   on tablets). Multi-word titles still wrap at word boundaries; a lone word too wide for its
   column now paints into the cell's own 15px right padding instead of wrapping. */
.default-list-table > tbody > tr > th {
  overflow-wrap: normal;
  word-wrap: normal;
}
/* Card-like rounded tables (CatalogCrossroad rozcestník) center each cell's content vertically.
   The shared .default-list-table rule above top-aligns cells; on a multi-line row that leaves the
   leading folder icon and the count clinging to the top instead of sitting centered against the
   wrapped name. `table.` out-specifies `.default-list-table`, so this wins without !important. */
table.rounded-table > tbody > tr > td {
  vertical-align: middle;
}
.wrapTdContent {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tableAuto {
  table-layout: auto !important;
}
.tableFixed {
  table-layout: fixed !important;
}
/**
 ul/li in table style
 */
.tableList {
  list-style-type: none;
  margin: 0;
  padding: 0;
  width: 100%;
  float: left;
}
.tableList li {
  width: 100%;
  float: left;
  padding: 0;
  margin: 0;
}
.tableList li > div > div {
  padding: 10px 15px 10px 0;
  line-height: 22px;
}
.tableList li > div > div:first-child {
  padding: 10px 15px;
}
/**
  Menu v tabulce, většinou vpravo
 */
.table-menu {
  margin: 0;
  padding: 0;
  height: 22px;
  line-height: 22px;
}
.table-menu li,
.button-right-help {
  margin: 0 2px 0 0;
  text-align: center;
  width: 22px !important;
  height: 22px !important;
  box-sizing: border-box;
  float: left;
  padding: 0;
  cursor: pointer;
  list-style-type: none;
  line-height: 21px;
  -webkit-border-radius: 2px;
  -moz-border-radius: 2px;
  border-radius: 2px;
}
.table-menu li.fa .tooltip-temp {
  font-family: Arial, "Arial", "Helvetica", sans-serif;
  font-weight: normal;
}
.table-menu li.fa {
  line-height: 17px;
}
.table-menu li i,
.button-right-help i {
  color: #C0C0C0;
  font-size: 14px;
  line-height: 20px;
  width: 100%;
}
/*
  Responsive list tables (etapa 6). Below 768px a list table opts into a card layout by carrying the
  `mobile-cards` class on the <table>. Opt-in (not a blanket `.default-list-table` rule) keeps in-modal
  and in-form tables — which do NOT add the class — untouched, and makes desktop regression impossible
  unless the class is present. Each data <tr> becomes a card: a leading slot (checkbox|icon, absolute
  top-left), a bold title, label:value meta rows (label from `data-label`), and the right-column actions
  fold into a 3-dot dropdown (absolute top-right). The column-header <tr> is hidden (cards carry their own
  labels). Desktop (>= 769px) is untouched. The `.table-menu-kebab` trigger and `.table-menu-mobile-label`
  text live here too — both are display:none on desktop so the inline icon row is unchanged above 768px.
 */
.table-menu-kebab {
  display: none;
}
.table-menu-mobile-label {
  display: none;
}
/* Mobile-card-only inline fragment (e.g. firstname appended into the lastname title cell) — hidden on
   desktop, where the firstname keeps its own column. */
.mobile-only-inline {
  display: none;
}
/* The wrapper around the action <ul> generates no box on desktop, so the inline icon row (and every
   non-card usage of the tableMenu partial — modals, in-form lists) is byte-for-byte unchanged. */
.table-menu-wrap {
  display: contents;
}
/*
  Tooltip modal (#tooltip-modal-wrapper, index.php + TooltipModalModel). Mobile counterpart of the
  hover tooltip for `detailsModal` table-menu buttons: the rich HTML tooltip (course/event info table)
  opens as a centered overlay because touch layouts have no hover. The panel reuses `.tooltip-content`
  for its theme colors (background/font come from the *-color.php.less files); position/size overrides
  below beat it via the id-scoped selector. z-index sits above every page modal (~1006) and below the
  hover tooltip (10001), which is force-hidden on open anyway (showTooltipModal → hideTooltip).
 */
#tooltip-modal-wrapper {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  background: rgba(0, 0, 0, 0.5);
  box-sizing: border-box;
}
#tooltip-modal-wrapper .tooltip-modal-panel {
  position: relative;
  min-width: 0;
  width: auto;
  max-width: min(480px, 100%);
  max-height: 80vh;
  overflow: auto;
  padding: 16px;
  text-align: left;
}
#tooltip-modal-wrapper .tooltip-modal-close {
  position: absolute;
  top: 2px;
  right: 2px;
  width: 36px;
  height: 36px;
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;
  font-size: 16px;
  cursor: pointer;
}
#tooltip-modal-wrapper .tooltip-modal-content {
  /* keep the first tooltip-table row clear of the absolute close button */
  padding-right: 30px;
}
/*
  Responsive content, 768-1000px band (2026-07-02 stage). A desktop list table (baseListTable.hbs) that
  doesn't fit the available width no longer forces <body> wider (the app-wide 1000px floor was removed) —
  it scrolls inside its own wrapper instead. Below 768px the table already switches to the mobile-cards
  layout (see below) and this is a no-op; at >= 1000px the table already fits, so this is also a no-op
  there (overflow-x: auto shows a scrollbar only when content actually overflows).
 */
.list-table-scroll-wrap {
  width: 100%;
  overflow-x: auto;
  box-sizing: border-box;
}
/* Library breadcrumb row (library.hbs): the left padding is owned by this class instead of the
   paddingLeft15 utility, because below 768px it shrinks to 12px to line the home glyph up with the
   strip's back arrow — a utility must always realize its number (ADR-001). */
.library-breadcrumb {
  padding-left: 15px;
}
/* Back-navigation bar (catalogRecords / catalogCategories). A brand-coloured pill on desktop that
   becomes a list-item-like card with only the arrow on mobile (geometry + label hide in the @media
   block below; surface + arrow colour in user-*mode-color). It owns its 15px padding — replacing the
   .padding15 utility on the element — so the mobile card can raise it to 16px without an
   !important tug-of-war with that (also-!important) utility. */
.list-back-card {
  padding: 15px;
}
/* On desktop the Library go-up control is a narrow (~50px) table column header, so it stays
   icon-only there — hide the "Zpět" label to avoid widening that column and misaligning the rows.
   The mobile strip card (below 768px) shows the label. Catalog back bars use a different id and are
   unaffected — they keep "← Zpět" on desktop as before. */
@media (min-width: 769px) {
  #library-go-up-th .list-back-card-label {
    display: none;
  }
}
@media (max-width: 768px) {
  /* Table, its tbodies and rows collapse to blocks; drop the fixed layout and any desktop min-width. */
  table.mobile-cards,
  table.mobile-cards > tbody {
    display: block;
    width: 100%;
    min-width: 0 !important;
    table-layout: auto !important;
  }
  /* Hide the column-header row (the bare <tr> of <th>); cards label their own fields. !important beats
     the equal-specificity `> tbody > tr { display: block }` card rule below regardless of source order. */
  table.mobile-cards tr:has(> th) {
    display: none !important;
  }
  /* Each data row becomes a card. Right padding reserves space for the kebab; left padding is added
     only when a leading slot is present (see :has rule below). */
  table.mobile-cards > tbody > tr {
    /* A flex column lets the title/subtitle be hoisted to the top via `order` regardless of their
       source column position (some lists put a date/owner column before the name), and — being a flex
       container — it is also its own block formatting context, isolated from uncleared page floats
       above the table (e.g. the Users paging bar) that otherwise pushed the first card's content down. */
    display: flex;
    flex-direction: column;
    position: relative;
    margin: 0 0 10px 0;
    padding: 12px 44px 12px 12px;
    border: 1px solid rgba(127, 127, 127, 0.14);
    border-radius: 4px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
    box-sizing: border-box;
  }
  /* Back-nav bar (catalogRecords / catalogCategories) reads as a list-item card on mobile — same
     border/radius/shadow as the folder cards, with a larger 16px padding and the "← Zpět" arrow +
     label. `font-size: 20px` sets the arrow (its original strip size); the "Zpět" label is pinned to
     16px below so the text is a touch smaller than the icon. Surface + arrow colour are
     theme-specific and live in user-*mode-color; here: geometry + padding. Padding wins over the
     base .list-back-card rule by later source order. */
  .list-back-card {
    padding: 16px;
    border: 1px solid rgba(127, 127, 127, 0.14);
    border-radius: 4px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
    font-size: 20px;
  }
  /* The "Zpět" label sits at 16px on both back bars (catalog cards + Library go-up strip), while the
     arrow keeps its 20px icon size. */
  .list-back-card-label {
    font-size: 16px;
  }
  /* Co-centre the 20px arrow and the 16px label: with both on `vertical-align: middle` their centres
     align to the same line, so the differently-sized glyph and text read as one vertically-centred
     row (baseline alignment would otherwise drop the smaller label below the arrow). */
  .list-back-card > i,
  .list-back-card-label,
  .library-go-up-inner > i {
    vertical-align: middle;
  }
  /* Make room on the left for the leading slot only when the card actually has one. The
     leading tile is 64px tall (12px top inset + 64 + 12px breathing room), so reserve that
     both horizontally (padding-left) and vertically (min-height) — otherwise the enlarged
     tile overlaps the title or spills past the bottom border on a short single-line card. */
  table.mobile-cards > tbody > tr:has(.mobile-lead) {
    padding-left: 88px;
    min-height: 88px;
    /* Center the (usually short) title/subtitle block vertically so it lines up with the
       vertically-centered leading tile instead of clinging to the top and leaving a gap
       below that reads like a missing row. No-op once the content is taller than the tile. */
    justify-content: center;
  }
  /* Cells become block; strip table padding/width, allow wrapping so nothing forces horizontal scroll.
     `!important` on the border beats the higher-specificity theme rule
     (`.admin-lightmode-color table.default-list-table > tbody > tr > td { border-top/bottom }`) that
     would otherwise draw stray horizontal lines inside each card. */
  table.mobile-cards > tbody > tr > td {
    display: block;
    width: auto !important;
    min-width: 0 !important;
    padding: 1px 0 !important;
    border: 0 !important;
    line-height: 1.4;
    white-space: normal;
    overflow-wrap: anywhere;
    vertical-align: baseline;
  }
  /* label:value — the label comes from data-label (injected from the matching <th>, XSS-safe). Title,
     subtitle and the leading slot are excluded (they render label-less). */
  table.mobile-cards > tbody > tr > td[data-label]:not(:empty):not(.mobile-title):not(.mobile-subtitle):not(.mobile-lead)::before {
    content: attr(data-label) ": ";
    opacity: 0.6;
  }
  /* A leading-slot cell (icon/checkbox/type tile) never shows a "label:" prefix. */
  table.mobile-cards .mobile-lead[data-label]::before {
    content: none !important;
  }
  /* Inner desktop wrappers (the `width100 floatLeft` <a>/<div>/<span.td-link> tap targets inside many
     cells) must not float or span the full row in card mode, or the title words would stack and meta
     would mis-wrap. The 10px vertical `.td-link` padding (a desktop row tap target) must also be
     dropped here — otherwise a one-line title/subtitle renders in a 42px box and the text clings to
     the top, reading like a stray empty line below each row (seen on the Library list). */
  table.mobile-cards > tbody > tr > td a,
  table.mobile-cards > tbody > tr > td > div,
  table.mobile-cards > tbody > tr > td span.td-link {
    float: none !important;
    width: auto !important;
    padding-top: 0 !important;
    padding-bottom: 0 !important;
    line-height: 1.4;
    /* some desktop cells center their value (e.g. the Test/Certifikát check icon via `.center`); in a
       card the value must sit right after its label, left-aligned. */
    text-align: left !important;
  }
  /* Role classes the templates (or the JS injector) apply. Title is inline-block so multi-column titles
     (e.g. Users lastname + firstname) sit on one line separated by the markup whitespace. The inner <a>
     (invisibleHyperlink) must inherit the bold weight and size or the title reads like body text. */
  /* Title is hoisted to the very top of the card via order (works no matter where the name column sits
     in the source). The inner <a> renders inline and wrapping so a combined name (Users lastname +
     firstname in one cell) reads as one heading and a long name wraps instead of forcing scroll. */
  table.mobile-cards .mobile-title {
    order: -2;
    font-weight: 700 !important;
    font-size: 16px;
    line-height: 1.3;
  }
  table.mobile-cards .mobile-title a,
  table.mobile-cards .mobile-title .mobile-only-inline {
    display: inline;
    font-weight: 700 !important;
    font-size: 16px;
    white-space: normal !important;
    overflow: visible !important;
    text-overflow: clip !important;
    overflow-wrap: anywhere;
  }
  /* Hand-written list titles use a bare span (`td-link wrapTdContent`) instead of an <a>
     (e.g. training-event terms lists), so the rule above never reaches them and the desktop
     `.wrapTdContent` nowrap/ellipsis survived into card mode — a long name rendered as one
     clipped line running under the 3-dot kebab. Release it for ANY card cell: stacked card
     lines have no column width to protect, so ellipsised desktop cells wrap by words here. */
  table.mobile-cards > tbody > tr > td .wrapTdContent {
    white-space: normal !important;
    overflow: visible !important;
    text-overflow: clip !important;
  }
  /* Whole-card tap target: a list row's click affordance normally covers only the cell (or the
     inner link) that carries it, leaving dead zones on a card — the icon-reserve gap between the
     leading tile and the title, the card padding, and the empty flex space (reported: Library and
     CatalogCategories). Stretch that affordance over the entire card via a positioned `::after` on
     the title cell: a tap anywhere on the card hit-tests to the pseudo-element and dispatches the
     click to its host, so the whole block acts on the row event. `inset:0` resolves against the card
     `<tr>` (position:relative). z-index:1 keeps it BELOW the kebab (z-index:2) and its open dropdown
     (z-index:5), so the 3-dot menu stays independently tappable and is never covered/triggered.
     Two anchors for the two list templates:
       - generic lists (baseListItemsTable): `onclick` + `cursorPointer` sit on the <td> itself;
       - hand-written lists (Library libraryItems.hbs): the click lives on an inner `span.td-link`. */
  table.mobile-cards > tbody > tr > td.mobile-title.cursorPointer::after,
  table.mobile-cards .mobile-title > .td-link.cursorPointer::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
  }
  /* Subtitle sits right under the title, above the label:value meta rows. */
  table.mobile-cards .mobile-subtitle {
    order: -1;
  }
  /* Shown only inside a card (e.g. the firstname appended into the lastname title cell on mobile). */
  table.mobile-cards .mobile-only-inline {
    display: inline;
  }
  table.mobile-cards .mobile-title[data-label]::before,
  table.mobile-cards .mobile-subtitle[data-label]::before {
    content: none;
  }
  table.mobile-cards .mobile-subtitle {
    opacity: 0.6;
    font-size: 13px;
  }
  table.mobile-cards .mobile-hidden {
    display: none !important;
  }
  /* Leading slot (checkbox|icon) pinned top-left of the card — a subtle tinted rounded square so the icon
     reads as an avatar/affordance (works on both light and dark themes via the translucent tint). */
  table.mobile-cards .mobile-lead {
    position: absolute;
    top: 12px;
    left: 12px;
    /* !important beats the generic `td { width:auto !important }` card reset (same reason
       margin/padding below carry it) so the tile keeps its fixed square size. */
    width: 64px !important;
    height: 64px !important;
    margin: 0 !important;
    padding: 0 !important;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(127, 127, 127, 0.1);
    border-radius: 6px;
  }
  /* A checkbox lead needs no tile background — keep just the control. */
  table.mobile-cards .mobile-lead-input {
    background: transparent;
  }
  /* Enlarged glyph (~1.8x the 18px desktop size). height:auto + line-height:1 unclip glyphs
     that carry a fixed height on desktop (e.g. `.folderIco { height:18px }` in Library). */
  table.mobile-cards .mobile-lead i {
    font-size: 32px;
    height: auto;
    line-height: 1;
  }
  /* Image-based leading icons (Library files, baseListItemsTable img slots) scale to match the
     bigger tile. Exclude any <img> that already carries a numbered width/height utility class
     (maxWidth20p, width40p, …) — ADR-001 forbids overriding those at any breakpoint. */
  table.mobile-cards .mobile-lead img:not([class*="idth"]):not([class*="eight"]) {
    max-width: 32px;
    max-height: 32px;
  }
  /* R-01: a row that carries BOTH a selection checkbox and a leading icon stacks them in the left
     column — the icon tile on top, the checkbox directly beneath it (reported on the Users list,
     where every deletable user shows a state icon AND a mass-delete checkbox). Previously the icon
     was dropped (display:none) so the card showed only one of the two. Both leads share the
     `left:12px` column; only their vertical offset differs. */
  table.mobile-cards > tbody > tr:has(.mobile-lead-input):has(.mobile-lead-ico) {
    min-height: 120px;
  }
  /* the icon tile keeps the top slot (inherits .mobile-lead top:12px, height:64px); the checkbox
     collapses to a compact control and drops below the icon tile (12px top + 64px tile + 8px gap). */
  table.mobile-cards > tbody > tr:has(.mobile-lead-ico) .mobile-lead-input {
    height: auto !important;
    top: 84px;
  }
  /* center the checkbox glyph horizontally in the column, matching the icon tile — the uniInput
     checkbox floats its widget left, so release the float and let the flex cell center it. */
  table.mobile-cards .mobile-lead-input .checkbox-container,
  table.mobile-cards .mobile-lead-input .checkboxTable {
    float: none !important;
    width: auto !important;
  }
  /* 3-dot dropdown. The kebab trigger sits absolute top-right of the card; the action <ul> is hidden
     until Alpine toggles `.table-menu-open`, then it drops as a panel. Each <li> becomes a full-width
     icon+text row. */
  table.mobile-cards .table-menu-kebab {
    display: flex;
    align-items: center;
    justify-content: center;
    position: absolute;
    top: 6px;
    right: 6px;
    width: 36px;
    height: 36px;
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    cursor: pointer;
    z-index: 2;
  }
  table.mobile-cards .table-menu-kebab i {
    font-size: 18px;
    opacity: 0.6;
  }
  table.mobile-cards .table-menu {
    display: none;
    position: absolute;
    top: 42px;
    right: 6px;
    z-index: 5;
    min-width: 180px;
    /* never let an open dropdown near the right edge push the page into horizontal scroll */
    max-width: calc(100vw - 24px);
    height: auto;
    margin: 0;
    padding: 0;
    background: inherit;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
  }
  table.mobile-cards .table-menu.table-menu-open {
    display: block;
  }
  table.mobile-cards .table-menu > li {
    display: flex !important;
    align-items: center;
    gap: 10px;
    width: 100% !important;
    min-width: 0;
    height: auto !important;
    margin: 0;
    padding: 10px 14px;
    float: none;
    text-align: left;
    overflow: hidden;
    box-sizing: border-box;
    /* The per-item box border (theme-colored, used as the icon frame on desktop) would double up
       between stacked rows here — A's bottom + B's top = a 2px line. Keep only a single bottom
       divider; width-only override preserves the theme border-color. */
    border-top: 0;
    border-left: 0;
    border-right: 0;
    border-radius: 0;
  }
  table.mobile-cards .table-menu > li:last-child {
    border-bottom: 0;
  }
  /* The desktop tooltip wrapper is width:100% — inside the dropdown it must shrink to the icon so the
     icon + text label sit on one row and the <li> never outgrows the dropdown panel. */
  table.mobile-cards .table-menu > li .tooltip-block {
    width: auto !important;
    flex: 0 0 auto;
  }
  table.mobile-cards .table-menu > li i {
    width: 16px;
    font-size: 15px;
  }
  table.mobile-cards .table-menu-mobile-label {
    flex: 1 1 auto;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  /* Spacer/empty action items carry no action — drop them from the dropdown. */
  table.mobile-cards .table-menu > li.empty {
    display: none;
  }
  table.mobile-cards .table-menu-mobile-label {
    display: inline;
  }
  /* Loader and "no records" rows use :colspan in table mode; in card mode show them as a full-width
     centered block instead of a stray cell. */
  table.mobile-cards > tbody[id$="-loader"] > tr > td,
  table.mobile-cards > tbody[id$="-no-records"] > tr > td {
    display: block;
    width: 100% !important;
    padding: 16px !important;
    text-align: center;
  }
  /* Header-hosted controls (etapa 8, opt-in `mobile-header-controls` on the table): some lists keep
     working controls in the header row (Library/OrgStructure go-up arrow, TrainingEvent evaluation
     bulk checkboxes) which the default header-hide rule above would silently remove. With this
     variant the header row is NOT hidden — it renders as a stacked control strip above the cards;
     only `th.mobile-keep` cells stay visible (full width), every other header cell is hidden. */
  table.mobile-cards.mobile-header-controls tr:has(> th) {
    display: flex !important;
    flex-direction: column;
    width: 100%;
    /* the header <tr> sits in an implicit tbody, so it also matches the card rule above — reset the
       card chrome entirely; each KEPT cell below carries its own compact-card look instead */
    padding: 0;
    border: 0;
    border-radius: 0;
    box-shadow: none;
  }
  table.mobile-cards.mobile-header-controls tr:has(> th) > th {
    display: none;
  }
  /* A kept header cell reads as a compact card in the card column (same chrome as the data cards).
     Its background/text colors come from the theme files — the desktop brand-colored header band
     must not survive into the strip (QA 2026-07-11: it rendered as a full-width brand bar). */
  table.mobile-cards.mobile-header-controls tr:has(> th) > th.mobile-keep {
    display: block;
    width: 100% !important;
    min-width: 0 !important;
    margin: 0 0 10px 0;
    padding: 10px 12px;
    border: 1px solid rgba(127, 127, 127, 0.14);
    border-radius: 4px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
    box-sizing: border-box;
    /* !important beats the `.center` utility carried by e.g. the Library go-up th — the back
       control aligns left in the strip card (Martin's QA, 2026-07-11) */
    text-align: left !important;
  }
  /* A clickable back control kept in the strip (OrgStructure's bare `<i>` arrow, the Library
     `.library-go-up-inner` arrow+label wrapper) must react to a tap ANYWHERE on the strip card, not
     just on the glyph: it becomes a block that absorbs the card's padding via negative margins, so
     its hit area IS the whole card. The `displayNone` toggle keeps winning (!important), so the root
     state stays hidden. Scoped to a DIRECT child control — control-hosting strip cells (TE
     evaluation checkbox/select) are wrapped in their own elements and stay untouched. */
  table.mobile-cards.mobile-header-controls tr:has(> th) > th.mobile-keep > i.cursorPointer,
  table.mobile-cards.mobile-header-controls tr:has(> th) > th.mobile-keep > .library-go-up-inner {
    display: block;
    width: auto;
    margin: -10px -12px;
    padding: 10px 12px;
  }
  /* Collapse the whole strip when no kept cell has visible content — e.g. the Library go-up arrow
     carries `displayNone` at folder root, and an empty padded bar above the cards is unwanted.
     Constraint: "visible content" means an ELEMENT not hidden via the displayNone /
     displayNoneImportant classes (on itself or an ancestor inside the cell); a kept th whose only
     content is bare text counts as empty — keep controls wrapped in an element. */
  table.mobile-cards.mobile-header-controls tr:has(> th):not(:has( > th.mobile-keep *:not(.displayNone):not(.displayNoneImportant):not(.displayNone *):not(.displayNoneImportant *))) {
    display: none !important;
  }
  /* In-flow action menu (etapa 8, opt-in `mobile-inline-menu` on .table-menu-wrap): a row with more
     than one tableMenu cannot fold them all into the single absolute top-right kebab slot — they
     would overlap. A wrap marked `mobile-inline-menu` renders its kebab in-flow inside its own
     (labelled) cell and anchors the dropdown to the wrap instead of the card corner. The generic
     actions menu of the row keeps the default kebab slot. The tableMenu partial has no class hook,
     so the class may equally sit on a HOSTING cell/wrapper (container opt-in — the s6 TrainingEvent
     evaluation name/certificate cells) or, for shared-template tables, the opt-in is keyed on the
     hosting cell's data-key (OrgStructure adm/man columns); all spellings share every rule below. */
  table.mobile-cards .table-menu-wrap.mobile-inline-menu,
  table.mobile-cards .mobile-inline-menu .table-menu-wrap,
  table.mobile-cards td[data-key="tableMenu-adm"] .table-menu-wrap,
  table.mobile-cards td[data-key="tableMenu-man"] .table-menu-wrap {
    /* intentionally NOT positioned — the dropdown keeps the card <tr> (position: relative) as its
       containing block, see the .table-menu override below. The tableMenu partial offers no wrap
       class hook, so the shared-template users-info menus (OrgStructure adm/man columns) opt in
       via their data-key cells instead of the class. */
    display: inline-block;
    vertical-align: middle;
  }
  table.mobile-cards .table-menu-wrap.mobile-inline-menu .table-menu-kebab,
  table.mobile-cards .mobile-inline-menu .table-menu-wrap .table-menu-kebab,
  table.mobile-cards td[data-key="tableMenu-adm"] .table-menu-wrap .table-menu-kebab,
  table.mobile-cards td[data-key="tableMenu-man"] .table-menu-wrap .table-menu-kebab {
    position: static;
    width: 28px;
    height: 28px;
  }
  table.mobile-cards .table-menu-wrap.mobile-inline-menu .table-menu,
  table.mobile-cards .mobile-inline-menu .table-menu-wrap .table-menu,
  table.mobile-cards td[data-key="tableMenu-adm"] .table-menu-wrap .table-menu,
  table.mobile-cards td[data-key="tableMenu-man"] .table-menu-wrap .table-menu {
    /* anchored to the CARD, dropping below it at (nearly) full card width — guaranteed inside the
       viewport no matter where in the cell the inline kebab happens to sit */
    top: 100%;
    left: 6px;
    right: 6px;
    min-width: 0;
  }
  /* Survey form sections list (story s7): a UL-based sortable list, not a real table — the column
     <th>s live in a detached header-only table (its th row hidden by mobile-cards above) and the
     rows are <li> elements with floated columns. Below 768px each row stacks into a card: name
     line first (title-styled), the category as a `label: value` line below it, the inline action
     icons last. Keyed on the class, NOT on the `survey-form-content-table` id — that id is
     duplicated on a sibling <div> (pre-existing defect, out of scope). CSS-only: the UL/LI markup
     is owned by the jQuery UI sortable (drag handles, collapse), so no DOM restructuring and no
     kebab machinery — the desktop inline icon row stays reachable inside the card. No color
     declarations — everything inherits the theme files. */
  ul.surveySectionUl > li {
    width: 100%;
    box-sizing: border-box;
  }
  /* The row wrapper becomes a flex column: float has no effect on flex items, so the desktop
     float columns stack, and `order` arranges the lines as title / category / actions regardless
     of the DOM order the desktop float layout requires. */
  ul.surveySectionUl > li > .survey-section-handler {
    display: flex;
    flex-direction: column;
    width: 100%;
    box-sizing: border-box;
  }
  /* Neutralize the fixed desktop column widths (the width150p/width100p utilities carry
     !important) on the stacked lines — overridden on our own selector, never by redefining the
     utility classes themselves (ADR-001). */
  ul.surveySectionUl > li > .survey-section-handler > div {
    width: auto !important;
    min-width: 0;
    white-space: normal;
    overflow-wrap: anywhere;
  }
  /* Card title: the section name line, hoisted to the top. The `.bold` utility already supplies
     the weight; the size bump makes it read as the card heading. */
  ul.surveySectionUl > li > .survey-section-handler > .survey-form-section-td.bold {
    order: -2;
    font-size: 16px;
    line-height: 1.3;
  }
  /* Category renders as a `label: value` meta line right below the name — the label text is
     injected from data-label in the row template (etapa-6 pattern). */
  ul.surveySectionUl > li > .survey-section-handler > .survey-form-section-td[data-label] {
    order: -1;
  }
  ul.surveySectionUl > li > .survey-section-handler > [data-label]:not(:empty)::before {
    content: attr(data-label) ": ";
    opacity: 0.6;
  }
  /* Actions line: keep the desktop inline icon row (no kebab — the sortable list must stay
     DOM-untouched), just give it breathing room below the meta lines. */
  ul.surveySectionUl > li > .survey-section-handler > div:has(> .table-menu-wrap) {
    margin-top: 6px;
  }
  /* Reports planned-tasks list (story s5): a bespoke headerless list — every data row is one <td>
     hosting a 2-row mini-<table class="task">, so the generic card cell rules above never reach the
     mini-table's cells. Stack them into full-width card lines here; their visible captions are
     hardcoded in the row template (studyReportsTasksListItem.hbs), no ::before labels needed. The
     CHILD combinators are load-bearing: the mini-table's second row nests ANOTHER table (the
     org-structure summary, studyReportsTasksListItem.hbs:37) whose cells must keep normal table
     flow. table.task itself keeps its width100 utility (100% stays honest, ADR 001). */
  table.study-reports-tasks-table table.task,
  table.study-reports-tasks-table table.task > tbody,
  table.study-reports-tasks-table table.task > tbody > tr {
    display: block;
    min-width: 0 !important;
  }
  /* Same width/padding reset the generic card cell rule uses: `width: auto` releases the fixed
     .widthNNNp column widths on the stacked cells, and the tight `!important` padding beats the
     desktop `#study-reports-tasks-table table.task > tbody > tr > td { padding: 13px }` id rule —
     it also collapses the emptied kebab-host cell instead of leaving a blank padded band. */
  table.study-reports-tasks-table table.task > tbody > tr > td {
    display: block;
    width: auto !important;
    min-width: 0 !important;
    padding: 1px 0 !important;
    line-height: 1.4;
    white-space: normal;
    overflow-wrap: anywhere;
  }
  /* A title cell hosting an in-flow menu keeps the NAME line and the menu host on one line, so
     the kebab sits next to the name instead of dropping under it. Scoped to the first block and
     the menu host only — further blocks in the cell (spacer, company name) stay stacked below. */
  table.mobile-cards .mobile-title:has(.mobile-inline-menu) > div:first-child,
  table.mobile-cards .mobile-title > div.mobile-inline-menu {
    display: inline-block;
    vertical-align: middle;
  }
  /* An inline-menu cell whose menu rendered empty (tableMenu.hbs emits nothing for an empty
     buttons array, e.g. a certificate not yet earned) must not show an orphan "label:" prefix —
     the whitespace children defeat the generic :not(:empty) guard. */
  table.mobile-cards td.mobile-inline-menu:not(:has(.table-menu-wrap))::before {
    content: none;
  }
  /* The TrainingEvent evaluation attendance cell carries its own per-control inline labels
     (attendance + lecturer spans) — rendering the generic data-label prefix on top of them would
     read "label: label: [control]". Keep the attribute (explicit label for the pass/tests),
     suppress only the rendered prefix; the mandatory cell has no inner label and keeps it. */
  #training-event-term-evaluation-list-table td[data-key="attendance"]::before {
    content: none;
  }
  /* Utility-hidden rows must stay hidden in card mode: the card rules above
     (table.mobile-cards > tbody > tr — specificity 0,1,3) beat the bare .displayNone
     utility (0,1,0). displayNoneImportant already survives on its own. */
  table.mobile-cards > tbody.displayNone,
  table.mobile-cards > tbody > tr.displayNone {
    display: none !important;
  }
  /* Library breadcrumb (home icon + nesting path): the desktop float layout wraps awkwardly on a
     narrow screen — switch the row to flex, give the home icon a finger-sized target and let a deep
     path scroll horizontally on its single line instead of wrapping. Left padding 12px lines the
     home glyph up with the strip's back arrow below (15px wrapper + 12px card padding); the
     home icon carries NO right padding — the path arrow's own 10px (.libPathArrow) supplies the
     gap, so home→arrow equals arrow→name spacing (Martin's QA, 2026-07-12). */
  .library-breadcrumb {
    display: flex;
    align-items: center;
    padding-left: 12px;
    padding-right: 15px;
    overflow-x: auto;
  }
  .library-breadcrumb > .fa-home {
    float: none;
    flex: 0 0 auto;
    font-size: 18px;
    padding: 8px 0;
  }
  .library-breadcrumb #library-path {
    display: flex;
    align-items: center;
    flex: 1 1 auto;
    white-space: nowrap;
  }
  .library-breadcrumb #library-path > * {
    float: none;
    flex: 0 0 auto;
  }
}
/*
  Responsive form tables (etapa 7). Below 768px a two-column label|input form table
  (the hand-written .default-table-body / .default-table skeletons around the uniInput
  partial) opts into a stacked layout by carrying the `mobile-stack` class: every row
  becomes label-above-input, both full width. The rules key EXCLUSIVELY on
  .mobile-stack — removing the class from a table restores the legacy two-column
  layout (opt-outs are recorded in .claude/specs/responsive-form-tables-2026-07-09.md).
  Child combinators keep nested inline tables (e.g. the phone prefix+number compound
  in userFormTabMain.hbs) unstacked; they only inherit the control-width capping.
  No color declarations here — cards inherit the theme files.
 */
@media (max-width: 768px) {
  table.mobile-stack,
  table.mobile-stack > tbody,
  table.mobile-stack > tbody > tr {
    display: block;
    width: 100% !important;
    min-width: 0 !important;
    table-layout: auto !important;
  }
  table.mobile-stack > tbody > tr > th,
  table.mobile-stack > tbody > tr > td {
    /* flow-root, not block: radio/checkbox (.checkbox-container) are floated and the
       original table-cell display contained them; a plain block would let them escape
       the cell and the next row's label would wrap around them. */
    display: flow-root;
    /* Beats the .widthNNNp utilities (width: ...px !important) via specificity (0,1,4 > 0,1,0). */
    width: 100% !important;
    min-width: 0 !important;
    /* .default-table-body th carries padding-right: 15px; content-box would overflow by it. */
    box-sizing: border-box;
  }
  /* Label cells sit directly above their input: drop the bottom padding and the tall
     36px line-height, and separate from the PREVIOUS row's input with top padding
     instead — the title must visually belong to the input below it, not the one
     above. `td:first-child:not(:only-child)` = the label cell of a two-cell row;
     single-cell (colspan) rows are left alone. */
  table.mobile-stack > tbody > tr > th,
  table.mobile-stack > tbody > tr > td:first-child:not(:only-child) {
    line-height: 20px;
    padding: 10px 0 0 0;
  }
  /* Width-flexible controls fill the cell. Checkbox / radio / toggleSwitch / colorpicker
     are deliberately NOT matched and keep their natural size inside the full-width cell.
     The descendant (not child) combinator after td is deliberate: controls sit inside
     wrappers. The :has() selector catches the autocomplete FILLED state — uniInput.hbs
     renders the chosen value as a <div class="{{ class }}"> carrying the same fixed
     .widthNNNp and no own class; its .autocompleteSpan child identifies it. */
  table.mobile-stack > tbody > tr > td input[type="text"],
  table.mobile-stack > tbody > tr > td input[type="password"],
  table.mobile-stack > tbody > tr > td textarea,
  table.mobile-stack > tbody > tr > td select,
  table.mobile-stack > tbody > tr > td .SumoSelect,
  table.mobile-stack > tbody > tr > td .SumoSelect .CaptionCont,
  table.mobile-stack > tbody > tr > td .SumoSelect .optWrapper,
  table.mobile-stack > tbody > tr > td div:has(> .autocompleteSpan) {
    width: 100% !important;
    max-width: 100%;
    box-sizing: border-box;
  }
  /* A control followed by a legend "i" icon keeps it on the same line: reserve the icon
     footprint instead of the full 100% width. The legend (span.tooltip-block.tooltip-right,
     legend.hbs) is rendered by uniInput.hbs as a direct td child right after the control.
     30px = 15px icon span + 10px marginLeft + inline whitespace (~4px), kept <= 10% of the
     375px-viewport cell so the control still counts as cell-filling for the etapa-7 spec
     (>= 90% assertion). Deliberately NOT the bare .tooltip-block — that class also wraps
     other tooltip carriers (e.g. the autocomplete hint), which must stay full width. */
  table.mobile-stack > tbody > tr > td:has(> .tooltip-block.tooltip-right) input[type="text"],
  table.mobile-stack > tbody > tr > td:has(> .tooltip-block.tooltip-right) input[type="password"],
  table.mobile-stack > tbody > tr > td:has(> .tooltip-block.tooltip-right) textarea,
  table.mobile-stack > tbody > tr > td:has(> .tooltip-block.tooltip-right) select,
  table.mobile-stack > tbody > tr > td:has(> .tooltip-block.tooltip-right) .SumoSelect,
  table.mobile-stack > tbody > tr > td:has(> .tooltip-block.tooltip-right) div:has(> .autocompleteSpan) {
    width: calc(100% - 30px) !important;
  }
  /* A control followed by a textAfter suffix (span.paddingLeft8 — uniInput.hbs renders it as a
     direct td child right after the control, e.g. the "[min]" unit; also the "ID: N" span in
     *FormTabMain.hbs) must keep the suffix on the SAME line as the control instead of letting the
     100%-wide input push it onto a new row. Unlike the fixed-width legend icon above, the suffix
     text is variable length, so its footprint cannot be reserved with a calc() constant. Make the
     cell an intrinsic-sizing flex row: the control flex-grows to fill the remaining width
     (min-width:0 lets it shrink below its content), while the suffix — and any trailing legend
     icon — keep their natural width and never wrap. Scoped to :has(> .paddingLeft8) so cells
     without a suffix are untouched; this rule follows the legend block so on a cell carrying both
     the suffix and a legend it wins the width declaration (equal specificity, later source). */
  table.mobile-stack > tbody > tr > td:has(> .paddingLeft8) {
    display: flex;
    align-items: center;
    flex-wrap: nowrap;
  }
  table.mobile-stack > tbody > tr > td:has(> .paddingLeft8) input[type="text"],
  table.mobile-stack > tbody > tr > td:has(> .paddingLeft8) input[type="password"],
  table.mobile-stack > tbody > tr > td:has(> .paddingLeft8) textarea,
  table.mobile-stack > tbody > tr > td:has(> .paddingLeft8) select,
  table.mobile-stack > tbody > tr > td:has(> .paddingLeft8) .SumoSelect,
  table.mobile-stack > tbody > tr > td:has(> .paddingLeft8) div:has(> .autocompleteSpan) {
    flex: 1 1 auto;
    width: auto !important;
    min-width: 0;
  }
  table.mobile-stack > tbody > tr > td:has(> .paddingLeft8) > .paddingLeft8,
  table.mobile-stack > tbody > tr > td:has(> .paddingLeft8) > .tooltip-block.tooltip-right {
    flex: 0 0 auto;
    white-space: nowrap;
  }
}
/*
  KPI admin form, scale tab. The pre-migration list printed the scale name in its own bold cell
  (.kpi-form-range-td.bold); the migrated list renders through the shared list table, which carries
  no per-cell class for plain text columns, so the emphasis is restored by table id + column key.
 */
#kpi-form-range-table td[data-key="name"] {
  font-weight: bold;
}
/*
  KPI player responsive layout. The player's goals-entry and evaluation blocks were rewritten
  from <table> markup to div/CSS-grid (App/Modules/KPI/Survey/Assets/MVC/detail/*.hbs). Desktop
  (> 768px) keeps the historical shape: 150px-label rows for entry fields, a 4-column grid for
  the evaluation sections (name+description | weight | fulfilled/rating | note) with flexible
  tracks instead of the old fixed 140/140/400px columns. At <= 768px (same breakpoint as the
  hamburger menu and the mobile-cards list tables above) everything stacks: labels above
  full-width inputs, one card per goal/competence, the goal delete action pinned to the card's
  top-right, and the evaluation cells labelled via data-label (same ::before technique as the
  mobile-cards tables). The eval header row and every eval card are SIBLING grids — they stay
  column-aligned because they share this one track definition; never fork it per block.
 */
/* Label/value field row (headers block, goal card rows, messageFromManager). */
.kpi-field {
  display: grid;
  grid-template-columns: 150px minmax(0, 1fr);
  column-gap: 15px;
  align-items: start;
  padding: 2px 0;
}
.kpi-field-label {
  text-align: left;
  line-height: 36px;
}
.kpi-field-value {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  line-height: 36px;
}
/* Title bar (KPI name left, user details right). */
.kpi-player-title-bar {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 15px;
}
/* One entered goal: field rows left, actions (delete) column right — replaces the old
   3×<tr> + rowspan="3" menu cell. */
.kpi-goal-card {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 50px;
  column-gap: 15px;
  padding-bottom: 15px;
}
.kpi-goal-fields {
  grid-column: 1;
  min-width: 0;
}
.kpi-goal-actions {
  grid-column: 2;
  padding-top: 9px;
}
/* Evaluation sections: header row + cards as sibling grids sharing .kpi-grid-cols(). */
.kpi-eval-head {
  display: grid;
  grid-template-columns: minmax(140px, 1.5fr) minmax(70px, 100px) minmax(90px, 120px) minmax(180px, 2fr);
  column-gap: 15px;
  font-weight: bold;
  text-align: left;
  line-height: 36px;
}
.kpi-eval-card {
  display: grid;
  grid-template-columns: minmax(140px, 1.5fr) minmax(70px, 100px) minmax(90px, 120px) minmax(180px, 2fr);
  column-gap: 15px;
  grid-template-rows: auto auto;
}
.kpi-eval-card > div {
  min-width: 0;
  line-height: 36px;
}
.kpi-eval-name {
  grid-column: 1;
  grid-row: 1;
}
.kpi-eval-desc {
  grid-column: 1;
  grid-row: 2;
  line-height: 22px;
}
.kpi-eval-weight {
  grid-column: 2;
  grid-row: 1 / span 2;
}
.kpi-eval-value {
  grid-column: 3;
  grid-row: 1 / span 2;
}
.kpi-eval-note {
  grid-column: 4;
  grid-row: 1 / span 2;
}
/* Manager statement sub-row: spans the card, its inner grid re-uses the same tracks so the
   rating/note land under the fulfilled/note columns. */
.kpi-eval-manager {
  grid-column: 1 / -1;
  grid-row: 3;
  display: grid;
  grid-template-columns: minmax(140px, 1.5fr) minmax(70px, 100px) minmax(90px, 120px) minmax(180px, 2fr);
  column-gap: 15px;
}
.kpi-eval-manager > div {
  min-width: 0;
  line-height: 36px;
}
.kpi-eval-manager-label {
  grid-column: 1 / 3;
}
.kpi-eval-manager-value {
  grid-column: 3;
}
.kpi-eval-manager-note {
  grid-column: 4;
}
.kpi-player-section-separator {
  border-top: 1px solid rgba(127, 127, 127, 0.3);
  margin: 15px 0;
}
@media (max-width: 768px) {
  /* Field rows stack: label above a full-width value. */
  .kpi-field {
    grid-template-columns: minmax(0, 1fr);
  }
  .kpi-field-label {
    line-height: 1.4;
    padding-top: 6px;
  }
  .kpi-field-value input,
  .kpi-field-value textarea,
  .kpi-field-value select {
    flex: 1 1 auto;
    width: auto !important;
    min-width: 0;
    box-sizing: border-box;
  }
  /* the goal weight input keeps its compact 50px desktop width on mobile too (Martin's request 2026-07-06) */
  .kpi-field-value input.kpi-goal-weight-input {
    flex: 0 0 auto;
    width: 50px !important;
  }
  .kpi-player-title-bar {
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
  }
  /* Goal card gets the mobile-cards visual (border, radius, shadow) and the delete action is
     pinned to the top-right corner (uniform 12px padding by Martin's request, 2026-07-06 —
     the icon floats over the short label line, no reserved column). */
  .kpi-goal-card {
    grid-template-columns: minmax(0, 1fr);
    margin: 0 0 10px 0;
    padding: 12px;
    border: 1px solid rgba(127, 127, 127, 0.14);
    border-radius: 4px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
    box-sizing: border-box;
  }
  .kpi-goal-actions {
    position: absolute;
    top: 8px;
    right: 8px;
    grid-column: auto;
    padding-top: 0;
  }
  /* Evaluation: hide the column header row, cards stack their cells in DOM order
     (name -> description -> weight -> fulfilled/rating -> note -> manager block). */
  .kpi-eval-head {
    display: none;
  }
  .kpi-eval-card {
    display: flex;
    flex-direction: column;
    margin: 0 0 10px 0;
    padding: 12px;
    border: 1px solid rgba(127, 127, 127, 0.14);
    border-radius: 4px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
    box-sizing: border-box;
  }
  .kpi-eval-card > div {
    line-height: 1.5;
  }
  .kpi-eval-name {
    font-weight: 700;
    font-size: 16px;
    line-height: 1.3;
  }
  /* label: value prefixes from data-label (only cells that carry one). */
  .kpi-eval-card [data-label]:not(:empty)::before {
    content: attr(data-label) ": ";
    opacity: 0.6;
  }
  /* An empty read-only value (templates are whitespace-trimmed so the cell is truly :empty)
     drops its whole row — no orphaned label, no blank line. */
  .kpi-eval-card [data-label]:empty {
    display: none;
  }
  /* The note and the manager statement rows are full-width; textareas fill the card. */
  .kpi-eval-card textarea,
  .kpi-eval-note input {
    width: 100% !important;
    box-sizing: border-box;
  }
  .kpi-eval-manager {
    display: flex;
    flex-direction: column;
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px dashed rgba(127, 127, 127, 0.3);
  }
}
/**
  Tabs in form.
 */
.form-caption {
  min-height: 30px;
  line-height: 30px;
  font-size: 26px;
  float: left;
  padding: 0 15px 0 15px;
  margin: 20px 0 20px 0;
}
.tab-ul {
  margin: 0;
  padding: 0;
  float: left;
  width: 100%;
  box-sizing: border-box;
  height: 44px;
}
.tab-ul li {
  outline-width: 0;
  list-style: none;
  float: left;
  position: relative;
  margin: 3px 0 0 2px;
  padding: 0;
  white-space: nowrap;
  cursor: pointer;
  line-height: 41px;
  padding: 0 15px 0 15px;
  border-top-left-radius: 4px;
  border-top-right-radius: 4px;
}
.tab-child {
  width: 100%;
  float: left;
  padding: 15px;
  box-sizing: border-box;
}
/*
  Responsive form tabs (form-tabs-responsive, stage 1) — shared mobile dropdown for baseTabs.hbs.
  Class-scoped, no ids: baseTabs renders multiple instances per page (page form + modals). Below
  the app-wide 768px breakpoint the .tab-ul bar is hidden (it STAYS in the DOM — the Profile card
  styling below keys on `:has(> .tab-ul)`) and replaced by the full-width .tab-mobile-select card
  control (same list-item-card look as the mobile back-nav bar) toggling the .tabs-more list.
  The desktop priority+ overflow of the next stage reuses .tabs-more for the tabs hidden from
  the bar.
 */
.tab-mobile-select {
  display: none;
}
/* positioning context for the .tabs-more overlay in BOTH modes (desktop toggle + mobile control) */
.base-tabs-root {
  position: relative;
}
.tabs-more {
  display: none;
  margin: 0;
  padding: 6px 0;
  border-radius: 4px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
}
.tabs-more.open {
  display: block;
}
.tabs-more .tabs-more-item {
  display: block;
  box-sizing: border-box;
  width: 100%;
  margin: 0;
  padding: 10px 14px;
  list-style: none;
  cursor: pointer;
  white-space: nowrap;
}
.tabs-more .tabs-more-item-active {
  font-weight: bold;
}
/*
  Desktop priority+ overflow (form-tabs-responsive, stage 2a). Tabs the reflow
  (tabsOverflow.tabsReflow, App/Assets/js/tabsResponsive.js) marked as hidden collapse from the
  bar; the "Více ⋯ (N)" toggle li opens the shared .tabs-more list as an absolute overlay under
  the bar (right-aligned; class-scoped and clamped to the viewport like .submenu-more-list).
  The toggle li itself has NO stylesheet display rule — its visibility is x-show-driven.
 */
@media (min-width: 769px) {
  .tab-ul li.tab-overflowed {
    display: none;
  }
  .base-tabs-root > .tabs-more.open {
    /* overlay under the bar; `top` is set by tabsOverflow.positionTabsList() on open —
       page floats push the bar down inside the root, so a fixed value cannot line up */
    position: absolute;
    right: 0;
    z-index: 1000;
    min-width: 180px;
    max-width: calc(100vw - 24px);
  }
}
@media (max-width: 768px) {
  .tab-ul {
    display: none;
  }
  .tab-mobile-select {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    width: 100%;
    box-sizing: border-box;
    min-height: 44px;
    padding: 0 15px;
    border-radius: 4px;
    cursor: pointer;
    line-height: 41px;
    white-space: nowrap;
  }
  .tab-mobile-select .tab-mobile-select-title {
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .tabs-more {
    /* overlay right below the .tab-mobile-select control — like an open selectbox, the
       page content must NOT shift down; `top` is set by tabsOverflow.positionTabsList() */
    position: absolute;
    left: 0;
    right: 0;
    z-index: 1000;
  }
}
/* The profile page is the only place a baseTabs card sits bare on the user page background, so it gets the
   dashboard-card look: the brand-coloured tab bar rounds the top corners, the tab body the bottom ones, and
   the baseTabs root carries the shadow (defined per theme in user-lightmode-color / user-darkmode-color).
   Scoped to #profile-main-div — .tab-ul / .tab-child are shared with the admin modals (UserForm, Term
   signed-users, …) and the legacy StudyReports tabs, which stay square. `:has(> .tab-ul)` pins the baseTabs
   root specifically: with GDPR disabled ProfileFacade emits no tabs model and #profile-main-div's first child
   is the bare form wrapper instead (see ProfileFormComponent.render). flow-root — not overflow:hidden — wraps
   the floated tab bar + tab body without clipping the escaping datepicker / sumoselect popups, so the corners
   are rounded on the children themselves. */
#profile-main-div > div:has(> .tab-ul) {
  display: flow-root;
  border-radius: 4px;
}
#profile-main-div .tab-ul {
  border-top-left-radius: 4px;
  border-top-right-radius: 4px;
}
#profile-main-div .tab-child {
  border-bottom-left-radius: 4px;
  border-bottom-right-radius: 4px;
}
/* The GDPR tab is padding0, so its list table reaches the tab body's rounded bottom corners. Each cell carries
   a `border-bottom` (see .user-*mode-color table.default-list-table > tbody > tr > td), and a child's border is
   painted outside the parent's border-radius clip — so the last row draws a straight 1px line across both
   corner arcs. Round the scroll wrapper too: it already computes `overflow: auto` (from its `overflow-x: auto`),
   which makes it clip its own descendants, so the arc cuts the border. The pager below it is `displayNone` on a
   single page, which is exactly when the wrapper reaches the card edge; once the pager shows, the wrapper sits
   above it and these radii are an invisible no-op. */
#profile-tab-gdpr > .list-table-scroll-wrap {
  border-bottom-left-radius: 4px;
  border-bottom-right-radius: 4px;
}
/* profileForm.hbs marks its wrapper .rounded-shadow-block because with GDPR disabled the form renders bare
   into #profile-main-div and IS the block on the page background. Inside the tabs card that same background
   is already painted by .tab-child, so the radius + shadow would draw a card inside a card. Neutralise it
   there; the id out-specifies the `.user-*mode-color .rounded-shadow-block` shadow rules. */
#profile-tab-form-div .rounded-shadow-block {
  border-radius: 0;
  box-shadow: none;
}
/**
  Ico in list
 */
.folderIco {
  height: 18px;
  float: left;
  font-size: 18px;
  line-height: 22px;
}
/* Library file-type icon (the per-extension <img>). Semantic class — replaces the numbered
   `maxWidth20p maxHeight20p` caps so the mobile-cards block may enlarge it (ADR-001). Desktop
   keeps the historical 20px cap. */
.library-file-ico {
  max-width: 20px;
  max-height: 20px;
}
/**
  Arrow in path in Library or OS
 */
.libPathArrow {
  line-height: 22px;
  padding: 0 10px 0 10px;
  float: left;
  display: inline;
}
/**
  Gridstack in admin
 */
.dashboard-grid-item .grid-stack-item-content {
  text-align: center;
  cursor: pointer;
}
.dashboard-grid-item .grid-stack-item-content {
  line-height: 50px;
}
.dashboard-grid-item[gs-h="2"] .grid-stack-item-content {
  line-height: 110px;
}
.dashboard-grid-item[gs-h="3"] .grid-stack-item-content {
  line-height: 170px;
}
.dashboard-grid-item[gs-h="4"] .grid-stack-item-content {
  line-height: 230px;
}
/**
  Dashboard-layout GridStack on the System settings page (#settings-system-dashboard-grid).

  GridStack 12.2.1 JS runs without its positioning stylesheet — the <link>s in
  public/entry_points/index.php:112-113 point at a missing node_modules path (404).
  v12 positions tiles by setting CSS vars on the container (--gs-column-width,
  --gs-cell-height) and inlining left/top/width/height per tile, but ONLY for x/y > 0
  and w/h > 1 (literal `t.w>1?…:null` etc. in v12 source). The base rules the stylesheet
  would supply — `position: absolute` and the 1-cell width/height defaults — are missing,
  so without the rules below the tiles collapse into document flow (renders as ~2 columns,
  overflows vertically). These reproduce that base, scoped to this grid; tiles with
  x/y/w/h beyond one cell still win via their inline style. (The user dashboard solves the
  same gap differently — it rebuilds the layout as static flow in userDashboard.css.less.)
 */
#settings-system-dashboard-grid {
  position: relative;
}
#settings-system-dashboard-grid > .grid-stack-item {
  position: absolute;
  left: 0;
  top: 0;
  width: var(--gs-column-width);
  height: var(--gs-cell-height);
}
#settings-system-dashboard-grid .grid-stack-item > .grid-stack-item-content {
  position: absolute;
  top: var(--gs-item-margin-top, 0);
  right: var(--gs-item-margin-right, 0);
  bottom: var(--gs-item-margin-bottom, 0);
  left: var(--gs-item-margin-left, 0);
  overflow: hidden;
}
/*
  Resize handle (GridStack default = SE only) and the drag/resize placeholder. An admin drags a
  tile's SE corner to switch it between 1 and 2 columns — there is no width input, the grid is the
  only width control. The handle auto-hides and reveals on hover (GridStack adds `ui-resizable-autohide`).

  The official GridStack stylesheet is now present (public/js/libs/gridstack.12.2.1.min.css, linked
  from index.php), so it supplies its own SE-handle styling: a `rotate(-45deg)` transform plus an SVG
  double-arrow anchored to the content-box corner via the --gs-item-margin-* vars. We keep our own flat
  grey corner grip instead, so the .ui-resizable-se rule below must (a) neutralise that inherited
  rotation and (b) anchor to the same content-box corner — otherwise the grip renders as a rotated
  arrow floating in the inter-tile gutter, outside the visible block.
 */
#settings-system-dashboard-grid .grid-stack-item > .ui-resizable-handle {
  position: absolute;
  z-index: 30;
}
#settings-system-dashboard-grid .grid-stack-item.ui-resizable-autohide > .ui-resizable-handle {
  display: none;
}
#settings-system-dashboard-grid .grid-stack-item:hover > .ui-resizable-handle {
  display: block;
}
#settings-system-dashboard-grid .grid-stack-item.ui-draggable-dragging > .ui-resizable-handle {
  display: none !important;
}
#settings-system-dashboard-grid .grid-stack-item > .ui-resizable-se {
  right: var(--gs-item-margin-right, 8px);
  bottom: var(--gs-item-margin-bottom, 8px);
  width: 14px;
  height: 14px;
  cursor: se-resize;
  transform: none;
  background: linear-gradient(135deg, transparent 0%, transparent 50%, #888 50%, #888 100%);
  border-bottom-right-radius: 2px;
}
#settings-system-dashboard-grid > .grid-stack-placeholder > .placeholder-content {
  position: absolute;
  top: var(--gs-item-margin-top, 0);
  right: var(--gs-item-margin-right, 0);
  bottom: var(--gs-item-margin-bottom, 0);
  left: var(--gs-item-margin-left, 0);
  border: 1px dashed #888;
  background: rgba(0, 0, 0, 0.06);
  border-radius: 2px;
}
/**
  Styles for block with organizational structure
 */
/* The header expand-all button has two faces: the text label (desktop) and the icon (below 768px,
   where "Vybrat vše | Rozbalit" would wrap in a narrow modal). Collection.js setExpandButton()
   keeps both faces plus the data-expanded state in sync. */
#organizational-structure-expand-button .os-expand-button-ico {
  display: none;
}
@media (max-width: 768px) {
  #organizational-structure-expand-button .os-expand-button-text {
    display: none;
  }
  #organizational-structure-expand-button .os-expand-button-ico {
    display: inline-block;
  }
}
.organizational-structure-pick-user-list {
  border-radius: 4px;
  max-height: 150px;
  overflow-y: auto;
  box-sizing: border-box;
  padding: 0;
}
.organizational-structure-pick-user-list-table {
  margin: 0;
  padding: 0;
  border-spacing: 0;
  border-collapse: collapse;
}
.organizational-structure-pick-user-list-table tr td {
  border-spacing: 0;
  border-collapse: collapse;
  padding: 9px 7px;
  font-size: 14px;
}
.organizational-structure-pick-user-list-table td:nth-child(2) {
  width: 10px;
  text-align: right;
}
.organizational-structure-ico {
  height: 20px;
  font-size: 20px;
  line-height: 22px;
  float: left;
  margin-top: 1px !important;
  margin-right: 10px;
}
.organizational-structure-table-selected {
  table-layout: fixed;
  border-collapse: collapse;
  border-spacing: 0;
}
.organizational-structure-table-selected > tbody > tr > td {
  vertical-align: top;
  width: 33%;
  border: 0;
  border-style: solid;
}
.organizational-structure-table-selected > tbody > tr > td {
  border-right-width: 1px;
}
.organizational-structure-table-selected > tbody > tr > td:last-child {
  border: 0 !important;
}
/* below the tablet breakpoint the selection columns stack under each other; each section except
   the last then ends with the same 1px rule that divides the columns when they sit side by side
   (rule color lives in the color-mode files), kept 15px away from both neighbouring sections */
@media (max-width: 768px) {
  .organizational-structure-table-selected,
  .organizational-structure-table-selected > tbody,
  .organizational-structure-table-selected > tbody > tr {
    display: block;
    width: 100%;
  }
  /* flow-root (not block) makes the cell contain its floated content, so it keeps a real height
     and the separator rule paints below the section instead of collapsing to its top edge */
  .organizational-structure-table-selected > tbody > tr > td {
    display: flow-root;
    width: 100%;
    border-right: 0 !important;
    border-bottom-width: 1px;
    padding-bottom: 15px;
    margin-bottom: 15px;
  }
}
.overflow-y-auto {
  overflow-y: auto;
}
.overflow-x-auto {
  overflow-x: auto;
}
.overflow-y-hidden {
  overflow-y: hidden;
}
.overflow-x-hidden {
  overflow-x: hidden;
}
.overflow-hidden {
  overflow: hidden;
  white-space: nowrap;
}
/* Button for open/hide filter in list with users and courses */
.toggle-filter-list,
#toggle-filter-list {
  box-sizing: border-box;
  line-height: 36px;
  width: 36px;
  height: 36px;
  margin-left: 12px;
  text-align: center;
  font-size: 24px;
  border-radius: 4px;
  transition: all 0.2s linear !important;
}
/* Table for filters in user's and course's list */
.filter-table {
  table-layout: fixed;
  width: 100%;
  box-sizing: border-box;
  border-spacing: 0;
  border-collapse: collapse;
}
.filter-table > tbody > tr > td,
.filter-table > tbody > tr > th {
  text-align: left;
  border-spacing: 0;
  font-weight: normal;
  line-height: 40px;
}
.filter-table > tbody > tr > th {
  width: 150px;
}
.filter-table > tbody > tr > td:last-child {
  width: 230px;
}
.filter-table table.filter-table-items {
  table-layout: fixed;
  width: 100%;
  box-sizing: border-box;
  line-height: 36px;
  border-spacing: 0;
  border-radius: 4px;
}
.filter-table table.filter-table-items td {
  border-spacing: 0;
  cursor: pointer;
  border-right-width: 0 !important;
  text-align: center;
}
.filter-table table.filter-table-items td:first-child {
  border-bottom-left-radius: 4px;
  border-top-left-radius: 4px;
}
.filter-table table.filter-table-items td:last-child {
  border-bottom-right-radius: 4px;
  border-top-right-radius: 4px;
  border-right-width: 1px !important;
}
.filter-table table.filter-table-items td[data-filter-type="lastname"]:first-child {
  width: 50px;
}
.invisibleHyperlink:hover,
.invisibleHyperlink:focus {
  text-decoration: none;
}
.course-score-stars {
  font-size: 20px;
}
/* date picker styles */
.ui-datepicker {
  -webkit-box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.2);
  -moz-box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.2);
  box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.2);
  width: 280px !important;
}
.ui-datepicker .ui-datepicker-prev,
.ui-datepicker .ui-datepicker-next {
  background: none;
  cursor: pointer;
}
.ui-datepicker .ui-datepicker-prev span,
.ui-datepicker .ui-datepicker-next span {
  background: none;
}
.ui-datepicker .ui-datepicker-prev,
.ui-datepicker .ui-datepicker-next {
  line-height: 1.8em;
}
.ui-datepicker .ui-datepicker-prev:before {
  font-family: "Font Awesome 5 Pro";
  content: "\f33a";
  font-weight: 400;
  font-size: 18px;
}
.ui-datepicker .ui-datepicker-next:before {
  font-family: "Font Awesome 5 Pro";
  content: "\f33b";
  font-weight: 400;
  font-size: 18px;
}
/** Iframe with certificate in course form. */
#certificate-iframe {
  border: 0;
  height: 1250px;
}
/** Iframe with DIS. */
#dis-form-iframe {
  border: 0;
  height: 400px;
  min-height: 400px !important;
}
/** Iframe with GDPR text bottom and top. */
#gdpr-top-text-iframe {
  border: 0;
  height: 275px;
  min-height: 275px !important;
}
#gdpr-bottom-text-iframe {
  border: 0;
  height: 275px;
  min-height: 275px !important;
}
.catalog-list-type,
.my-courses-list-type,
.submenu-filter-folded .filter-toggle {
  height: 36px;
  line-height: 34px;
  border-radius: 4px;
  width: 36px;
  text-align: center;
  margin: auto 0 auto 10px;
  display: inline-block;
  box-sizing: border-box;
  position: relative;
  cursor: pointer;
  outline: none;
  vertical-align: middle;
}
/* dlaždice s kurzy u uživatele */
/* pomocný div pod kterým bude tabulka */
.tileOverlay {
  background: rgba(0, 0, 0, 0.2);
  height: 218px;
  position: absolute;
  left: 0;
  top: 0;
  z-index: 1;
  text-align: center;
  transition: visibility 0s, opacity 0.3s linear;
  opacity: 0;
  cursor: pointer;
}
.userCourseTilesDiv .tileOverlay:hover {
  opacity: 1;
}
.tileOverlay .playButton {
  width: 185px;
  margin: 55px auto 0 auto;
  line-height: 40px;
  height: 40px;
  font-size: 14px;
}
.userCourseTilesDiv {
  /* 8px row gap — the app-wide inter-block gap. The COLUMN gap is applied inline as `margin-right` by
     recalculateSizeOfTiles() (Catalog / MyCourses list-item components), which also zeroes it on the last
     tile of each row; keep the two values in sync. */
  margin: 0 0 8px 0;
  min-width: 280px;
  height: 280px;
  position: relative;
  float: left;
  /* Round the tile corners to match the dashboard cards; the white bg + shadow are already applied
     via user-lightmode-color / user-darkmode-color. overflow:hidden clips the tile image to the radius. */
  border-radius: 4px;
  overflow: hidden;
}
.userCourseTilesDiv div.caption {
  max-height: 72px;
  height: 72px;
  margin-top: 6px;
  padding: 0 10px 0 10px;
  display: flex;
  align-items: center;
  align-content: center;
}
.userCourseTilesDiv div.caption-child {
  line-height: 24px;
  font-size: 16px;
  max-height: 72px;
  font-weight: bold;
  width: 100%;
  /*max-width:280px;*/
  overflow: hidden;
  text-overflow: ellipsis;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  display: -webkit-box;
  -webkit-box-orient: vertical;
}
.userCourseBottomTable {
  float: left;
  width: 200px;
  margin: 10px 0 10px 10px;
}
.userCourseBottomTable th {
  font-weight: normal;
  color: #888;
}
.userCourseBottomTable th,
.userCourseBottomTable td {
  vertical-align: top;
}
.userCourseInfoButton {
  width: 42px;
  height: 42px;
  border-radius: 50%;
  color: #FFF;
  float: right;
  line-height: 42px;
  padding: 0;
  margin: 10px 10px 0 0;
  text-align: center;
  font-size: 18px;
  transition: 0.2s linear all;
}
.userCourseInfoButtonDashboard {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  line-height: 28px;
  padding: 0;
  margin: 2px auto 0 0;
  text-align: center;
  font-size: 13px;
  transition: 0.2s linear all;
  float: right;
}
.userCourseInfoButton:hover,
.userCourseInfoButton:focus,
.userCourseInfoButtonLines:hover,
.userCourseInfoButtonLines:focus {
  cursor: pointer;
}
.userCourseInfoButton:focus,
.userCourseInfoButtonLines:focus {
  outline: none;
}
.userCourseInfoButtonLines {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  color: #FFF;
  line-height: 32px;
  padding: 0;
  margin: 1px auto 0 0;
  text-align: center;
  font-size: 15px;
  transition: 0.2s linear all;
}
.courseImgPreview {
  width: 280px;
  text-align: center;
  height: 130px;
  justify-content: center;
  padding: 0;
  display: table;
  margin: 0 auto;
}
.courseImgPreview div {
  vertical-align: middle;
  display: table-cell;
}
.courseImgPreview img {
  margin: auto;
  display: inline-block;
  vertical-align: middle;
  float: none;
}
.courseImgPreview i.coursePreview,
.courseIcoPreview i.coursePreview {
  font-size: 7em;
  line-height: 110px;
  color: #E6E6E6;
}
div.lectionsList {
  z-index: 10;
  overflow: hidden;
  position: relative;
}
div.lectionsList:before {
  font-family: 'Font Awesome 5 Pro';
  left: -45px;
  position: absolute;
  bottom: -45px;
  font-size: 200px;
  z-index: -1;
  display: block;
  color: rgba(0, 0, 0, 0.1);
  font-weight: 300;
  content: "\f05a";
}
table.lectionsList {
  border-collapse: collapse;
}
table.lectionsList th,
table.lectionsList td {
  padding: 5px 0;
  line-height: 18px;
}
.userCourseTableList,
.userSurveyTableList,
.userKPITableList,
.userTrainingEventsTableList {
  border-collapse: separate;
  border-spacing: 0 12px;
}
.userCourseTableList td,
.userSurveyTableList td,
.userKPITableList td,
.userTrainingEventsTableList td {
  line-height: 20px;
  vertical-align: middle;
}
/** course player menu */
.course-lessons-main-ul {
  margin: 10px 0;
}
.course-lessons-main-ul ul {
  margin: 0;
}
.course-lessons-main-ul,
.course-lessons-main-ul ul {
  padding: 0;
  width: 100%;
  box-sizing: border-box;
  list-style-type: none;
  line-height: 20px;
}
#study-reports-tasks-table table.task > tbody > tr > td {
  padding: 13px;
}
#study-reports-tasks-table tr td {
  vertical-align: top;
}
/** Icons in help modal CB,TB and DIS */
.cbHelpButton {
  width: 40px;
  height: 40px;
  line-height: 17px;
  text-align: center;
  margin-bottom: 6px;
  float: left;
  box-sizing: border-box;
  padding: 11px 0 0 0;
  border: 1px solid;
}
.cbHelpButton i {
  font-size: 17px;
}
.fc-toolbar h2 {
  font-size: 14px;
  font-weight: normal;
}
.fc-icsButton-button.fc-state-default:hover {
  background-image: none !important;
}
/* FullCalendar v6 overrides. The lib injects its own stylesheet into <head> at
   runtime (after these static <link>s), so plain `.fc-*` rules lose the cascade.
   Scope under `.fc` to raise specificity above the lib defaults. These rules are
   theme-independent (layout / weight / decoration); colors live in the *-color.php
   theme files. */
.fc .fc-toolbar-title {
  font-size: 14px;
  /* v3 title was bold with a small left inset; cs locale yields a lowercase month
     ("květen 2026") so capitalize the first letter back to "Květen 2026". */
  font-weight: bold;
  text-transform: capitalize;
  padding-left: 10px;
}
/* v6 leaves a large 1.5em gap below the toolbar; v3 sat the grid right under it.
   FC's own `.fc .fc-toolbar` rule has equal specificity and is injected later, so
   !important is needed to win the cascade. */
.fc .fc-header-toolbar.fc-toolbar {
  margin-bottom: 0px !important;
}
/* v6 default button border is dark navy (#2C3E50); v3 used a light gray outline. */
.fc .fc-button {
  border: none;
  border-radius: 0;
  height: 42px;
  width: 40px;
}
.fc .fc-button:focus {
  box-shadow: none !important;
}
/* The prev/next/today buttons carry v6's own `.fc-icon` span (fcicons font), which
   is CSP-blocked (data: font) and renders as an empty "tofu" box. We inject FA icons
   instead, so hide v6's span — on navigation FC re-adds it next to our injected <i>. */
.fc .fc-icon {
  display: none;
}
/* Day-of-week header + day-number are <a> elements in v6 and would inherit the
   themed link color — strip the link look so they read like plain labels. */
.fc .fc-col-header-cell-cushion,
.fc .fc-daygrid-day-number {
  text-decoration: none;
  font-weight: normal;
}
/* v3 placed the day number top-RIGHT of the cell — keep v6's row-reverse so the
   number sits on the right, with a small inset so it isn't glued to the cell edge
   (noticeable in the rightmost column). */
.fc .fc-daygrid-day-top {
  flex-direction: row-reverse;
  padding-right: 4px;
}
/* v3 showed the event icon top-LEFT, on the same row as the number (number right,
   icon left) — not stacked below it. The event area normally flows under the
   day-top; pull it into the top-left corner so the icon shares the number's row. */
.fc .fc-daygrid-day-events {
  position: absolute !important;
  top: 12px;
  left: 4px;
  right: auto;
  width: auto;
  margin: 0 !important;
  min-height: 0 !important;
}
/* No "today" background highlight (matches the v3 look). */
.fc .fc-day-today {
  background-color: transparent !important;
}
/* v3 showed calendar events as a bare colored icon, not v6's filled event bar.
   Strip the block-event background/border so only the injected icon shows; its
   color comes from the *-text class on the <i> (green-text / red-text / …). */
.fc .fc-daygrid-event,
.fc .fc-daygrid-event:hover {
  background: transparent;
  border: none;
  box-shadow: none;
}
.fc .fc-daygrid-event .fc-event-main {
  color: inherit;
}
.fc-icsButton-button.fc-button-primary:hover {
  background-image: none !important;
}
.adminDashboard3block {
  width: calc(33%);
  box-sizing: border-box;
}
.adminDashboard2block {
  /* Two blocks share one 8px inter-block gap, so each is (100% - 8px) / 2 = 50% - 4px. */
  width: calc(50% - 4px);
  box-sizing: border-box;
}
/* Admin-dashboard block spacing: tighten the shared 15px utility rhythm (.marginRight15 /
   .marginTop15) to an 8px inter-block gap, matching the 8px GridStack gap on the user dashboard.
   Scoped to the admin dashboard wrappers so the app-wide 15px utilities stay 15px everywhere else.
   !important is required because both utilities are themselves declared !important. */
#admin-dashboard-quicklinks.marginTop15,
#admin-dashboard-top.marginTop15 {
  margin-top: 8px !important;
}
#admin-dashboard-top > .marginRight15 {
  margin-right: 8px !important;
}
/* Right-panel block spacing: the blocks (logo, e-certificates, info, help) each carry `.marginTop15`, so
   both the gap between them and the panel's offset from the menu read 15px — nearly double the 8px card gap
   the dashboards use. Tighten the whole rhythm to 8px, scoped to the right panel so the app-wide 15px
   utility stays 15px everywhere else. Admin sidebar mode overrides the first block back to 0 (its band
   padding already supplies the 8px) — see the @media (min-width: 769px) block above. !important is required
   because `.marginTop15` is itself declared !important. */
#rightPanel-main-div > div > .marginTop15 {
  margin-top: 8px !important;
}
/* Main-column block spacing: the top-level page blocks space themselves with the generic `.marginTop15`
   utility, which predates the 8px card rhythm the dashboards and the right panel already use. Every page
   that was never retuned therefore reads 15px — both against the top bar and between blocks (Martin's QA,
   2026-07-09). Tighten it to 8px exactly where `.marginTop15` acts as the BLOCK gap:
     - `#main-col`'s direct children: facades that set `this.template` render their own root straight into
       the column, so no `#body-content-wrapper` exists at all (Profile, GDPR, the detail pages);
     - `#body-content-wrapper` itself: the default facade wrapper carries `default-white-block marginTop15`
       (AbstractBaseComponent.js), so this covers every page that does not override `stringTemplate` —
       the table pages (cmHelpdesk, …), catalog and library;
     - its direct children: the top-level blocks of the facades that DO override the wrapper, e.g.
       myTrainingEvents' calendar and the organizational-structure table;
     - `*-no-records`: the empty-state blocks, which sit one level deeper on some pages;
     - `.userCoursesTilesDiv`: the tile grid on the catalog-records and myCourses tile views;
     - `.support-table`: the Support page's blocks — this supplies both their gap to the top bar and the
       gap between them.
   Deliberately NOT retuned: a bare `.marginTop15` acting as intra-content spacing rather than a block gap —
   the library table (`#library-list-table`, nested inside `.list-table-scroll-wrap`) and the library
   folder-path row (`.library-breadcrumb`, a DIRECT child of `#body-content-wrapper` so it IS matched here
   unless excluded). Both must stay 15px, so `.library-breadcrumb` is excluded from the `#body-content-wrapper`
   selector below (it sits above the table with the same 15px rhythm the table row keeps). `!important` is
   required because `.marginTop15` is itself declared !important. Admin sidebar mode out-specifies these and
   zeroes the first block — its band padding already supplies the 8px (see the @media (min-width: 769px) block). */
#main-col > .marginTop15,
#body-content-wrapper.marginTop15,
#body-content-wrapper > .marginTop15:not(.library-breadcrumb),
[id$="-no-records"].marginTop15,
.userCoursesTilesDiv.marginTop15,
.support-table.marginTop15 {
  margin-top: 8px !important;
}
.displayFlex {
  display: flex;
}
.flexJustifyBetween {
  justify-content: space-between;
}
/* AdminDashboard top blocks — doughnut chart + legend (replaces the former 3-circle layout). */
.adminDashboardDonut {
  clear: both;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  /* Centre content per line. While the doughnut + legend sit side by side the legend's auto margins
     absorb the free space (overriding justify-content), so the doughnut stays at the start (heading-
     aligned). Once the legend wraps onto its own line the doughnut is alone on its line with no auto
     margin, so justify-content centres it. */
  justify-content: center;
  /* row-gap only — adds vertical space above the legend once it wraps under the doughnut; no column-gap
     so the legend's auto margins control the horizontal spacing. */
  gap: 15px 0;
  /* aligns the doughnut's left edge with the block heading (block padding, no negative margin). */
  margin-top: 15px;
}
.adminDashboardDonutChartWrap {
  position: relative;
  width: 100px;
  height: 100px;
  flex: 0 0 auto;
}
.adminDashboardDonutChartWrap canvas {
  display: block;
  max-width: 100%;
}
/* Zero-size anchor parked on the hovered arc's caret. The shared #tooltip-wrapper singleton positions
   itself against this element's rect, which lets the segment tooltip escape the 100px canvas bitmap
   that used to clip it. Invisible and inert — it only ever supplies a point to measure from. */
.adminDashboardDonutTooltipAnchor {
  position: absolute;
  width: 0;
  height: 0;
  pointer-events: none;
}
.adminDashboardDonutCenter {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  font-weight: normal;
  pointer-events: none;
}
.adminDashboardLegend {
  /* shrink to content and let the auto margins centre the legend in the space beside the doughnut
     (and centre it on its own line once it wraps below). */
  flex: 0 1 auto;
  min-width: 0;
  margin: 0 auto;
  padding: 0;
  list-style: none;
}
.adminDashboardLegend li {
  display: flex;
  align-items: center;
  margin-bottom: 12px;
  line-height: 28px;
  white-space: nowrap;
}
.adminDashboardLegend li:last-child {
  margin-bottom: 0;
}
.adminDashboardLegendBadge {
  display: inline-block;
  box-sizing: border-box;
  flex: 0 0 auto;
  min-width: 28px;
  height: 28px;
  margin-right: 8px;
  padding: 0 7px;
  border-radius: 14px;
  line-height: 28px;
  text-align: center;
  font-weight: bold;
  color: #fff;
}
.adminDashboardLegendBadge.green {
  background-color: #58b50d;
}
.adminDashboardLegendBadge.yellow {
  background-color: #f2d94c;
}
.adminDashboardLegendBadge.red {
  background-color: #dd0000;
}
/* Below the app-wide 768px responsive breakpoint stack the dashboard top blocks vertically so the
   doughnut + legend of each block get the full row width (avoids the cramped 3-up row and the
   clipped last block). Matches the hamburger/minWidth1000p breakpoint used elsewhere. */
@media (max-width: 768px) {
  #admin-dashboard-top {
    flex-wrap: wrap;
  }
  #admin-dashboard-top .adminDashboard2block,
  #admin-dashboard-top .adminDashboard3block {
    width: 100%;
    /* !important is required to override the inline `.marginRight15 { ... !important }` utility on
       the non-last blocks. Without it those blocks keep their 15px right margin and stop short of
       the right edge, while the last (margin-less) block reaches it — the uneven right alignment. */
    margin-right: 0 !important;
    margin-bottom: 8px;
  }
  /* The last block in each row drops its bottom margin so it does not stack on top of the next
     row's `marginTop15` (scoped to 8px on this page), which otherwise doubled the vertical gap
     between the donut row and the chart/news row below it (16px instead of the uniform 8px). */
  #admin-dashboard-top .adminDashboard2block:last-child,
  #admin-dashboard-top .adminDashboard3block:last-child {
    margin-bottom: 0;
  }
  /* ...except the page's final block (news, in the SECOND #admin-dashboard-top row — the one
     preceded by another #admin-dashboard-top): it has no row below to supply a `marginTop15` gap,
     so it keeps a bottom margin and is not glued to the viewport bottom. The higher-specificity
     sibling selector re-adds it only to that block; the donut row's last block stays at 0. */
  #admin-dashboard-top ~ #admin-dashboard-top .adminDashboard2block:last-child,
  #admin-dashboard-top ~ #admin-dashboard-top .adminDashboard3block:last-child {
    margin-bottom: 8px;
  }
  /* The quick-link buttons (floated) wrap onto several rows on narrow viewports; without a bottom
     margin the wrapped rows are vertically glued together. Add a 10px gap — scoped to this media
     query AND to #admin-dashboard-quicklinks so the `.addButton`/`.icoButton` used elsewhere are
     unaffected. See the 769-999px block below for the equivalent fix in that band. */
  #admin-dashboard-quicklinks .addButton,
  #admin-dashboard-quicklinks .icoButton {
    margin-bottom: 10px;
  }
}
/* 768-1000px responsive content (2026-07-02 stage). The quick-link buttons above relied on the app-wide
   1000px floor (now removed) to guarantee a single row above 768px; in this band they may now wrap earlier.
   Give the panel a wrapping flex layout with a 10px row-gap instead of a per-button bottom margin: the gap
   is added only BETWEEN wrapped rows, so on the many widths in this band where the buttons still fit on one
   row the panel keeps its natural height (a per-button margin-bottom inflated it by 10px the moment the
   viewport dropped below 1000px, even with nothing wrapping). The floated label + buttons become flex items
   laid out in the same left-to-right row (float is ignored on flex items, column-gap stays 0 so their
   horizontal spacing is unchanged); align-items:center keeps the 36px items vertically centred. The mobile
   block above keeps its per-button margin — there the buttons genuinely wrap (see the ≤768px stacked
   regression). */
@media (min-width: 769px) and (max-width: 999px) {
  #admin-dashboard-quicklinks {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    row-gap: 10px;
  }
}
.flexColumn {
  flex-direction: column;
}
.flexColumn > div {
  flex: 1;
  display: flex;
  align-items: center;
  width: 100%;
  justify-content: space-between;
}
.flexColumn > div:not(:first-child) {
  margin-top: 10px;
}
.flexDirectionRow {
  flex-direction: row;
}
.flexDirectionColumn {
  flex-direction: column;
}
/**
 * Line with superadmin nickname and disable user's interface
 */
div#sa-wrapper {
  min-width: 100%;
  margin: 0;
  padding: 0 15px 0 15px;
  box-sizing: border-box;
  float: left;
  height: 50px;
  line-height: 50px;
  text-align: center;
  color: #333;
  background-color: #AAA;
  border-bottom: 1px solid #888;
  z-index: 100;
}
/* Height of the band above, published for the layouts that have to make room for it. The band is a plain
   in-flow element here, so on the user desktop it simply pushes the page down and nothing needs this. But
   wherever the surrounding chrome is `position: fixed` — the admin docked sidebar (>= 769px) and the mobile
   hamburger bar (<= 768px) — that chrome would paint straight over the band, so those layouts pin the band
   themselves and offset everything else by --sa-band. Declared on the body and gated on the band actually
   showing, so the `var(--sa-band, 0px)` fallback keeps every offset at its original value for sessions with
   no superadmin behind the user. */
body:has(#sa-wrapper:not(.displayNone)) {
  --sa-band: 50px;
}
.preview-player-iframe {
  border: none;
}
.preview-player-td-menu {
  border-right: 1px solid #999;
}
/**
styles for div with full size in TD
 */
.fullTdSize {
  position: relative;
}
.fullTdSize > div {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}
/**
 * Hidden certificate tab for reload.
 */
.hiddenCertificateTab {
  left: -500px;
  top: -500px;
  height: 0;
  position: absolute;
  width: 0;
  padding: 0 !important;
}
.removeIcon {
  font-size: 18px;
  padding: 2px 5px 3px 5px;
  color: #FFF;
  background-color: #DD0000;
  margin-right: 8px;
}
.wordBreak {
  word-break: break-word;
}
.admin-list-filter-1-rows {
  height: 60px;
}
.admin-list-filter-2-rows {
  height: 100px;
}
.admin-list-filter-3-rows {
  height: 145px;
}
.admin-list-filter-4-rows {
  height: 190px;
}
/*
  The collapse/expand is a plain accordion: `height` alone, so every edge of the block and the page
  content below it move on ONE curve. It used to also animate `transform: translateY(-50px)`, which
  pulled the block's top edge 50px while its bottom edge travelled 240px (height 190 + the transform)
  and the content below travelled 190px — three speeds in one 300ms transition, which read as several
  things animating separately. The transform also ran on the compositor while `height` ran on the main
  thread, so the two visibly drifted apart whenever the main thread was busy.
 */
.admin-list-filter-1-rows,
.admin-list-filter-2-rows,
.admin-list-filter-3-rows,
.admin-list-filter-4-rows {
  opacity: 1;
  margin: initial;
  overflow: hidden;
  transition: opacity 0.3s, height 0.3s;
}
.admin-list-filter-hidden {
  opacity: 0;
  pointer-events: none;
  height: 0 !important;
  transition: opacity 0.3s, height 0.3s;
}
/*
  Page entry must not animate the filter block. It is rendered EXPANDED (the row-count class alone) and
  Alpine adds `admin-list-filter-hidden` only once the page's x-data has initialised, so the browser had
  a genuine expanded -> collapsed change to transition and the filter visibly slid up on arriving at the
  page. AbstractBaseComponent.render() stamps this class on every filter block it inserts and drops it
  two frames later, so the block paints in its final state and only user-driven toggles animate.
  !important is needed because the transition is declared on both the row-count and the hidden class.
 */
.admin-list-filter-anim-off {
  transition: none !important;
}
/*
  OS tree picker — two-line mobile item (os-picker-responsive, spec Rev B). The tree table opted
  out of mobile-cards (baseListTable.hbs, mobileCards: false); below 768px each data row flattens
  into a flex two-line item instead: line 1 = expander + folder + wrapping entity name + row
  actions, line 2 = both selection checkboxes with their .os-mobile-cb-label labels (label texts
  come resolved from the facade collection properties — ADMIN_USER_GROUPS_31/32 live in the
  server-side pack only). The <td>s and their float wrappers go display: contents, so the leaves
  become the row's flex items and are arranged purely by `order`; the .os-mobile-break span
  (flex-basis: 100%) carries the line break. Depth indent moves from the inline margin-left
  (lost with display: contents) to the --os-depth custom property stamped on the row. The table
  and its tbodies must blockify alongside (a display: table parent would collapse the flex rows
  to min-content width), which turns the header row into a flex strip as well. Desktop
  (>= 769px) is untouched — the helper labels are display: none outside the media block.
 */
.os-mobile-cb-label,
.os-mobile-break {
  display: none;
}
/* replaces the former marginRight10 utility on the tree-row checkbox: the mobile two-line
   layout needs the margin gone below 768px, and ADR-001 forbids overriding a numbered
   utility — desktop keeps the identical 10px through this semantic rule instead */
label.checkbox-container.organizational-structure-check {
  margin-right: 10px;
}
@media (max-width: 768px) {
  table[id^="organizational-structure-tree-table-"],
  table[id^="organizational-structure-tree-table-"] > tbody {
    display: block;
    width: 100%;
  }
  /* header becomes a flex strip: fixed-width utility ths keep their width, the name th flexes */
  table[id^="organizational-structure-tree-table-"] tr:has(> th) {
    display: flex;
    align-items: center;
    box-sizing: border-box;
    width: 100%;
  }
  table[id^="organizational-structure-tree-table-"] tr:has(> th) > th {
    display: block;
    box-sizing: border-box;
    flex: 0 0 auto;
  }
  table[id^="organizational-structure-tree-table-"] tr:has(> th) > th:not([class*="width"]) {
    flex: 1 1 auto;
  }
  table[id^="organizational-structure-tree-table-"] > tbody[id$="-items"] > tr:has(> td) {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    column-gap: 8px;
    row-gap: 6px;
    box-sizing: border-box;
    width: 100%;
    padding: 9px 10px 9px calc(10px + var(--os-depth, 0) * 12px);
    border-bottom: 1px solid rgba(127, 127, 127, 0.15);
  }
  /* Rev C2 — grayscale depth shading (the Rev C1 golden-angle hue palette was dropped on
     user request; return point: commit 23c6ce585 / tag os-picker-pre-depth-shading). Each
     nesting level tints the whole row with a NEUTRAL alpha ramp: light themes darken with
     black, dark themes lighten with white — 0.016/level, capped at 0.30 so 20 depths stay
     numerically distinct and the text readable. Hover adds a translucent +0.05 shift ON TOP
     of the depth tint; without these rules the opaque theme hover
     (.admin-*-color .default-list-table > tbody > tr:hover { #FAFAFA / #2A2A2A }) would
     erase the depth signal — these selectors out-specify it. Values are escaped: LESS must
     not evaluate rgba()/min()/calc() over a runtime var(). */
  [class*="lightmode-color"] table[id^="organizational-structure-tree-table-"] > tbody[id$="-items"] > tr:has(> td) {
    background: rgba(0, 0, 0, min(0.30, calc(var(--os-depth, 0) * 0.016)));
  }
  [class*="lightmode-color"] table[id^="organizational-structure-tree-table-"] > tbody[id$="-items"] > tr:has(> td):hover {
    background: rgba(0, 0, 0, min(0.35, calc(var(--os-depth, 0) * 0.016 + 0.05)));
  }
  [class*="darkmode-color"] table[id^="organizational-structure-tree-table-"] > tbody[id$="-items"] > tr:has(> td) {
    background: rgba(255, 255, 255, min(0.30, calc(var(--os-depth, 0) * 0.016)));
  }
  [class*="darkmode-color"] table[id^="organizational-structure-tree-table-"] > tbody[id$="-items"] > tr:has(> td):hover {
    background: rgba(255, 255, 255, min(0.35, calc(var(--os-depth, 0) * 0.016 + 0.05)));
  }
  /* dynamically hidden rows (collapsed children, per-entity loaders) must survive the flex
     rule above — same guard as the mobile-cards .displayNone fix */
  table[id^="organizational-structure-tree-table-"] > tbody > tr.displayNone {
    display: none !important;
  }
  /* the spacer row between companies and system entities carries no content — drop it */
  table[id^="organizational-structure-tree-table-"] > tbody > tr.organizational-structure-space {
    display: none;
  }
  /* flatten cells and their float wrappers; the leaves become the row's flex items */
  table[id^="organizational-structure-tree-table-"] > tbody[id$="-items"] > tr:has(> td) > td,
  table[id^="organizational-structure-tree-table-"] > tbody[id$="-items"] > tr:has(> td) > td > div,
  table[id^="organizational-structure-tree-table-"] > tbody[id$="-items"] > tr:has(> td) > td > div > div {
    display: contents;
  }
  /* line 1: expander, folder, name (wraps under itself), actions at the right edge.
     The expander and the no-children spacer share ONE fixed 12px slot so folder icons
     align across rows — the spacer div would otherwise flatten away with the generic
     display: contents rule below (higher specificity here wins). */
  table[id^="organizational-structure-tree-table-"] > tbody > tr i[id^="opened-indicator-"],
  table[id^="organizational-structure-tree-table-"] > tbody > tr > td.os-tree-name-td > div > div.width12p {
    display: block;
    order: 1;
    flex: 0 0 12px;
    width: 12px;
    box-sizing: border-box;
    float: none;
    margin: 0;
    padding: 0;
    height: auto;
  }
  table[id^="organizational-structure-tree-table-"] > tbody > tr .organizational-structure-ico {
    order: 2;
  }
  table[id^="organizational-structure-tree-table-"] > tbody > tr .entity-name {
    order: 3;
    /* basis 0 (not auto): a long name must shrink and wrap INSIDE its item, sharing
       line 1 with the action icons instead of pushing them onto their own line */
    flex: 1 1 0;
    min-width: 0;
    overflow-wrap: anywhere;
  }
  table[id^="organizational-structure-tree-table-"] > tbody > tr > td > ul.table-menu {
    order: 4;
    display: flex;
    align-items: center;
    gap: 14px;
    flex: 0 0 auto;
    margin: 0;
    padding: 0;
  }
  /* the break: a zero-height full-width flex item forces everything after it onto line 2 */
  table[id^="organizational-structure-tree-table-"] > tbody > tr .os-mobile-break {
    display: block;
    order: 5;
    flex-basis: 100%;
    height: 0;
  }
  /* line 2: select-with-children checkbox + label, then the single-entity checkbox + label */
  table[id^="organizational-structure-tree-table-"] > tbody > tr > td[class*="-pick-all-td-"] .checkbox-container {
    order: 6;
    float: none;
  }
  table[id^="organizational-structure-tree-table-"] > tbody > tr > td[class*="-pick-all-td-"] > .os-mobile-cb-label {
    order: 7;
  }
  table[id^="organizational-structure-tree-table-"] > tbody > tr > td.os-tree-name-td .checkbox-container {
    order: 8;
    float: none;
    /* kill the desktop 10px right margin (checkbox->label gaps must match the pick-all pair)
       and push the whole pair right so the two labeled checkboxes read as separate groups */
    margin: 0 0 0 12px;
  }
  table[id^="organizational-structure-tree-table-"] > tbody > tr > td.os-tree-name-td .os-mobile-cb-label {
    order: 9;
  }
  table[id^="organizational-structure-tree-table-"] > tbody > tr .os-mobile-cb-label {
    display: inline;
    font-size: 11px;
    line-height: 22px;
    opacity: 0.75;
    white-space: nowrap;
  }
}
/* Touch devices (coarse pointer): raise the 14px body base (@fontSizeNormal) and every
   explicit 14px design token to 16px. Pairs with the input bump in inputs.css.less — this
   stops iOS Safari auto-zooming on input focus, and keeps input labels (which inherit the
   body size) in sync with the now-16px inputs. Desktop (fine pointer) is unchanged. */
@media (pointer: coarse) {
  body {
    font-size: 16px;
  }
  #adminDashboardTable h3 {
    font-size: 16px;
  }
  .table-menu li i,
  .button-right-help i {
    font-size: 16px;
  }
  .organizational-structure-pick-user-list-table tr td {
    font-size: 16px;
  }
  .tileOverlay .playButton {
    font-size: 16px;
  }
  .fc .fc-toolbar-title {
    font-size: 16px;
  }
}
