        /* ==========================================================================================
           App styles — Microsoft Fluent 2 look. Every colour, spacing, type size, radius, shadow and
           duration comes from css/fluent-tokens.css (loaded first); this file only applies them to
           the app's existing class names. Raw px appear only for 1px hairlines and fixed layout
           positions. Light/dark is handled entirely by the tokens (data-theme on <html>).
           ========================================================================================== */

        /* ---------- Base ---------- */
        *{margin:0;padding:0;box-sizing:border-box}
        /* Tailwind border reset (preflight is disabled) so border-* utilities render */
        *,::before,::after{border-width:0;border-style:solid;border-color:var(--border)}
        button,input,select,textarea{font:inherit;color:inherit}
        /* Tailwind's preflight is off, so unstyled <button>s would show the browser's grey face. */
        button{background-color:transparent;cursor:pointer}
        /* padding reserves the notch / home-indicator safe area on iOS & gesture-nav
           Android (needs viewport-fit=cover in the <meta viewport> to be non-zero) so
           that content and the fixed bottom bar never sit under the system UI. */
        /* height:100dvh (dynamic viewport height) overrides the 100vh fallback on browsers
           that support it — plain 100vh is the "largest" viewport (as if the mobile browser's
           address-bar toolbar were always collapsed), so while the toolbar is shown, a 100vh
           box runs taller than what's actually visible and the fixed bottom-nav-bar (pinned to
           the real visible screen) ends up overlapping the last ~toolbar-height of content.
           100dvh tracks the toolbar's current state, so this box always matches what's visible. */
        /* line-height is unitless (not Fluent's px values) so wrapped Arabic and large amounts
           never overlap the line above. */
        body{font-family:var(--fontFamilyBase);background:var(--bg);color:var(--text);direction:rtl;font-size:var(--fontSizeBase300);line-height:1.6;-webkit-font-smoothing:antialiased;height:100vh;height:100dvh;overflow:hidden;display:flex;flex-direction:column;padding:env(safe-area-inset-top,0px) env(safe-area-inset-right,0px) env(safe-area-inset-bottom,0px) env(safe-area-inset-left,0px)}
        #app{flex:1;min-height:0;overflow:hidden}
        a{color:var(--colorBrandForegroundLink)}
        a:hover{color:var(--colorBrandForegroundLinkHover)}
        ::placeholder{color:var(--colorNeutralForeground4);opacity:1}
        ::selection{background:var(--colorBrandBackground2Pressed);color:var(--colorNeutralForeground1)}
        input[type="checkbox"],input[type="radio"]{accent-color:var(--colorCompoundBrandBackground);width:16px;height:16px;cursor:pointer}
        input[type="number"]{appearance:textfield}
        input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{-webkit-appearance:none}
        /* Keyboard focus: Fluent's 2px focus stroke. An outline (not a box-shadow) so it also shows
           in Windows high-contrast mode. Text fields use their brand underline instead (below). */
        :focus-visible{outline:var(--strokeWidthThick) solid var(--colorStrokeFocus2);outline-offset:1px}
        /* Thin scrollbars, same in both themes. */
        *{scrollbar-width:thin;scrollbar-color:var(--colorNeutralStroke1) transparent}
        ::-webkit-scrollbar{width:4px;height:4px}
        ::-webkit-scrollbar-track{background:transparent}
        ::-webkit-scrollbar-thumb{background:var(--colorNeutralStroke1);border-radius:var(--borderRadiusCircular)}
        ::-webkit-scrollbar-thumb:hover{background:var(--colorNeutralStrokeAccessible)}
        /* Smooth cross-fade — enabled ONLY while toggling (JS adds .theme-anim for ~450ms),
           so there is no transition flash on first paint and no ongoing repaint cost. */
        html.theme-anim, html.theme-anim *, html.theme-anim *::before, html.theme-anim *::after{
          transition:background-color var(--durationSlow) var(--curveEasyEase), color var(--durationSlow) var(--curveEasyEase), border-color var(--durationSlow) var(--curveEasyEase), fill var(--durationSlow) var(--curveEasyEase), box-shadow var(--durationSlow) var(--curveEasyEase) !important;
        }
        @media (prefers-reduced-motion:reduce){
            *,*::before,*::after{animation-duration:1ms!important;animation-iteration-count:1!important;transition-duration:1ms!important}
        }

        /* ---------- Subtle icon buttons (theme toggle, bell, close buttons) ---------- */
        .theme-toggle,.notif-bell,.modal-close,.more-sheet-close,.chat-back-btn,.icon-btn{display:inline-flex;align-items:center;justify-content:center;width:var(--controlHeightMedium);height:var(--controlHeightMedium);padding:0;background:transparent;border:var(--strokeWidthThin) solid transparent;border-radius:var(--borderRadiusMedium);color:var(--colorNeutralForeground2);font-size:var(--fontSizeBase400);line-height:1;cursor:pointer;flex-shrink:0;transition:background-color var(--durationFaster) var(--curveEasyEase),color var(--durationFaster) var(--curveEasyEase)}
        .theme-toggle:hover,.notif-bell:hover,.modal-close:hover,.more-sheet-close:hover,.chat-back-btn:hover,.icon-btn:hover{background:var(--colorSubtleBackgroundHover);color:var(--colorNeutralForeground2BrandHover)}
        .theme-toggle:active,.notif-bell:active,.modal-close:active,.more-sheet-close:active,.chat-back-btn:active,.icon-btn:active{background:var(--colorSubtleBackgroundPressed)}
        /* The sun shows in dark mode, moon in light. */
        .theme-toggle .fa-sun{display:none}
        .theme-toggle .fa-moon{display:inline}
        :root[data-theme="dark"] .theme-toggle .fa-moon{display:none}
        :root[data-theme="dark"] .theme-toggle .fa-sun{display:inline}
        .theme-toggle--login{position:fixed;top:calc(14px + env(safe-area-inset-top,0px));left:calc(14px + env(safe-area-inset-left,0px));z-index:60}
        .icon-btn--danger{color:var(--tint-danger-fg)}
        .icon-btn--danger:hover{background:var(--tint-danger-bg);color:var(--tint-danger-fg)}

        /* ---------- Layout shell ---------- */
        /* mobile off-canvas sidebar drawer (used with Tailwind layout) */
        @media(max-width:768px){
            /* !important: Tailwind's CDN JIT stylesheet re-injects on every DOM mutation and can
               land after this rule in the cascade, so its same-specificity "py-3" padding utility
               (on the same element) would otherwise win the tie and silently drop this padding.
               position:fixed takes the drawer out of body's flow, so it doesn't inherit body's
               safe-area padding above — the bottom inset has to be added back explicitly here. */
            .sidebar-drawer{position:fixed;right:calc(-1 * var(--layout-drawer-offset));top:0;height:100vh;height:100dvh;width:var(--layout-drawer-offset);z-index:200;transition:right var(--durationSlow) var(--curveDecelerateMid);padding-top:calc(var(--layout-navbar-h) + env(safe-area-inset-top,0px))!important;padding-bottom:calc(var(--layout-bottombar-h) + env(safe-area-inset-bottom,0px))!important;box-shadow:var(--shadow16)}
            .sidebar-drawer.open{right:0}
            /* Closed: out of the Tab order and of screen readers too (it slides back in from the right, the start side). */
            .sidebar-drawer{visibility:hidden;overscroll-behavior:contain;transition:right var(--durationSlow) var(--curveDecelerateMid),visibility 0s linear var(--durationSlow)}
            .sidebar-drawer.open{visibility:visible;transition:right var(--durationSlow) var(--curveDecelerateMid)}
            .sidebar-overlay.open{display:block}
            /* The page behind an open menu doesn't scroll, and the assistant's button doesn't cover the menu. */
            body.nav-open #app main{overflow:hidden}
            body.nav-open #pa-dock{display:none}
        }
        .sidebar-overlay{display:none;position:fixed;inset:0;z-index:150;background:var(--colorBackgroundOverlay)}
        .loader-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.7);z-index:9999;display:none;align-items:center;justify-content:center;flex-direction:column;gap:var(--spacingVerticalL)}
        .loader-overlay.active{display:flex}
        /* Fluent "inverted" spinner: white arc on a faint track, readable on the dark overlay. */
        .loader-spinner{width:48px;height:48px;border:var(--strokeWidthThickest) solid rgba(255,255,255,0.25);border-top-color:var(--colorNeutralForegroundOnBrand);border-radius:50%;animation:spin 1s linear infinite}
        .loader-text{color:var(--colorNeutralForegroundOnBrand);font-size:var(--fontSizeBase400);font-weight:var(--fontWeightSemibold)}
        @keyframes spin{to{transform:rotate(360deg)}}

        /* Sidebar navigation (Fluent Nav): subtle items, selected = filled + 4×20 brand pill at the
           inline-start (right) edge. */
        /* The sidebar and header sit on the canvas (no panel, no divider). */
        .sidebar-drawer,#app > header{background:var(--bg)}
        /* Sections of the menu (Fluent Nav section header): a small grey label above its items. */
        .menu-group{margin-bottom:var(--spacingVerticalS)}
        .menu-group-label{padding:var(--spacingVerticalS) var(--spacingHorizontalL) var(--spacingVerticalXS);font-size:var(--fontSizeBase200);line-height:var(--lineHeightBase200);font-weight:var(--fontWeightSemibold);color:var(--colorNeutralForeground3)}
        a.menu-item,a.bottom-nav-item,a.more-sheet-item{text-decoration:none}
        a.menu-item{color:var(--colorNeutralForeground1)}
        .menu-item .menu-label{flex:1;min-width:0}
        .menu-item:focus-visible,.bottom-nav-item:focus-visible,.more-sheet-item:focus-visible{outline:var(--strokeWidthThick) solid var(--colorStrokeFocus2);outline-offset:calc(-1 * var(--strokeWidthThick))}
        .menu-item{position:relative;display:flex;align-items:center;gap:var(--spacingHorizontalM);width:calc(100% - 2 * var(--spacingHorizontalS));min-height:40px;margin:0 var(--spacingHorizontalS) var(--spacingVerticalXXS);padding:var(--spacingVerticalXS) var(--spacingHorizontalM);background:transparent;border:0;border-radius:var(--borderRadiusMedium);text-align:right;font-size:var(--fontSizeBase300);color:var(--colorNeutralForeground1);cursor:pointer;transition:background-color var(--durationFaster) var(--curveEasyEase),box-shadow var(--durationFaster) var(--curveEasyEase)}
        .menu-item:hover{background:var(--nav-hover)}
        .menu-item:active{background:var(--colorSubtleBackgroundPressed)}
        .menu-item.active{background:var(--nav-selected);box-shadow:var(--shadow2);font-weight:var(--fontWeightSemibold)}
        .menu-item.active::before{content:"";position:absolute;inset-inline-start:0;top:50%;width:var(--strokeWidthThicker);height:16px;margin-top:-8px;border-radius:var(--borderRadiusCircular);background:var(--colorCompoundBrandForeground1)}
        .menu-item i{width:20px;font-size:var(--fontSizeBase400);text-align:center;flex-shrink:0;color:var(--colorNeutralForeground2)}
        .menu-item.active i{color:var(--colorCompoundBrandForeground1)}
        .menu-item .badge{display:inline-flex;align-items:center;justify-content:center;min-width:24px;height:24px;padding:0 var(--spacingHorizontalS);border-radius:var(--borderRadiusCircular);background:var(--solid-danger);color:var(--colorNeutralForegroundOnBrand);font-size:var(--fontSizeBase200);font-weight:var(--fontWeightSemibold);margin-inline-start:auto;flex-shrink:0}
        .menu-item .badge[hidden],.bottom-nav-item .badge-dot[hidden],.more-sheet-item .badge-dot[hidden]{display:none}
        /* Content area: generous top/side margins on the canvas (phones: compact). */
        #app main{padding-top:var(--spacingVerticalXXL);padding-inline:var(--spacingHorizontalXXXL)}
        @media(max-width:768px){#app main{padding-top:var(--spacingVerticalM);padding-inline:var(--spacingHorizontalM)}}
        /* Sign-in: Microsoft-style soft backdrop with a centred card */
        #loginScreen{background:var(--login-backdrop)}
        .login-card{background:var(--login-card);padding:var(--spacingVerticalXXXL) var(--spacingHorizontalXXXL)}
        @media(max-width:480px){.login-card{padding:var(--spacingVerticalXXL) var(--spacingHorizontalXL)}}
        .page{display:none}
        .page.active{display:block;animation:fadeIn var(--durationNormal) var(--curveDecelerateMid)}
        @keyframes fadeIn{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}

        /* ---------- Card ---------- */
        .card{background:var(--colorNeutralBackground1);border-radius:var(--borderRadiusLarge);box-shadow:var(--shadow4);padding:var(--spacingVerticalL) var(--spacingHorizontalL);margin-bottom:var(--spacingVerticalL)}
        .card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:var(--spacingVerticalM);flex-wrap:wrap;gap:var(--spacingHorizontalSNudge)}
        .card-title{font-size:var(--fontSizeBase400);line-height:var(--lineHeightBase400);font-weight:var(--fontWeightSemibold);color:var(--colorNeutralForeground1)}

        /* ================= Page layout (Fluent 2 web, Microsoft account page pattern) =================
           • The page sits on the grey canvas inside a centred column (max 1120px, like the owner's
             Microsoft account reference; Fluent 2 web sets no max width).
           • The card that wraps a whole page is NOT a surface: `display:contents` dissolves it, so
             its header becomes the page title on the canvas and its children flow on the canvas.
           • Tabs, search fields and message bars stay on the canvas; every table, form and list
             becomes a Fluent "large" filled card (Background1, shadow4, radius 6px, 16px padding),
             12px apart. Only one card level — never a card in a card.
           • Grey tiles (--surface-2) turn white when they sit on the canvas, and stay grey inside cards. */
        .page{max-width:var(--page-max-w);margin-inline:auto;--surface-2:var(--colorNeutralBackground1)}
        .page > .card{display:contents}
        .page > .card > .card-header{margin:0 0 var(--spacingVerticalL);align-items:flex-end}
        @media(max-width:768px){.page > .card > .card-header{align-items:stretch}}   /* phones: title stays on the right (RTL start) */
        .page > .card:first-child > .card-header .card-title{font-size:var(--fontSizeHero700);line-height:var(--lineHeightHero700);font-weight:var(--fontWeightSemibold)}
        .page > .card + .card > .card-header{margin-top:var(--spacingVerticalXXXL)}
        .page > .card + .card > .card-header .card-title{font-size:var(--fontSizeBase500);line-height:var(--lineHeightBase500)}
        .page > .card > h4{margin-top:var(--spacingVerticalXXL)}
        /* Page titles carry no icon (Microsoft account pages); section/card titles keep theirs. */
        .page > .card:first-child > .card-header .card-title > i:first-child{display:none}
        /* Fluent SearchBox: a magnifier at the inline-start of the search field. */
        .search-box{position:relative}
        .search-box input:not([type="checkbox"]):not([type="radio"]){padding-inline-start:calc(var(--spacingHorizontalM) + 20px)}
        .search-box::before{content:"\f002";font-family:"Font Awesome 6 Free";font-weight:900;font-size:var(--fontSizeBase200);color:var(--colorNeutralForeground3);position:absolute;inset-inline-start:var(--spacingHorizontalM);top:calc(var(--controlHeightMedium) / 2);transform:translateY(-50%);pointer-events:none;z-index:1}
        @media (pointer:coarse){.search-box::before{top:calc(var(--touchTarget) / 2)}}
        .search-box:has(.fa-magnifying-glass)::before{content:none}   /* a page that draws its own icon */
        /* white cards on the canvas */
        .page .table-container,.page > .card > form,.page .notif-list,.page .session-panel > .table-container{background:var(--colorNeutralBackground1);border-radius:var(--borderRadiusLarge);box-shadow:var(--shadow4);margin-bottom:var(--spacingVerticalM)}
        .page .table-container{padding:var(--spacingVerticalXS) var(--spacingHorizontalS)}
        .page > .card > form{padding:var(--spacingVerticalL) var(--spacingHorizontalL)}
        .page .notif-list{overflow:hidden}
        /* ...but no second card level inside a real card, a form, a panel or a dialog */
        .page > .card .card .table-container,.page form .table-container,.page .settings-card .table-container,.page .teacher-rate-card .table-container,.page .bg-white .table-container,.modal .table-container{background:transparent;box-shadow:none;border-radius:0;padding:0;margin-bottom:0}
        .page > .card .card,.page form,.page .table-container,.page .settings-card,.page .teacher-rate-card,.page .bg-white,.page .notif-list,.page .chat-container,.page .ann-item{--surface-2:var(--colorSubtleBackgroundHover)}
        /* Dashboard / page greeting: title on the canvas, not a coloured banner */
        .page-hero{margin-bottom:var(--spacingVerticalL)}
        .page-hero .page-title{font-size:var(--fontSizeHero700);line-height:var(--lineHeightHero700);font-weight:var(--fontWeightSemibold);color:var(--colorNeutralForeground1)}
        .page-hero .page-subtitle{font-size:var(--fontSizeBase300);color:var(--colorNeutralForeground3);margin-top:var(--spacingVerticalXXS)}
        /* Announcement items: one card each */
        .ann-item{background:var(--colorNeutralBackground1);border-radius:var(--borderRadiusLarge);box-shadow:var(--shadow4);padding:var(--spacingVerticalL) var(--spacingHorizontalL);margin-bottom:var(--spacingVerticalM)}
        .ann-item.important{background:var(--tint-warning-bg)}

        /* ---------- Table (Fluent DataGrid look) ---------- */
        .table-container{overflow-x:auto;-webkit-overflow-scrolling:touch}
        table{width:100%;border-collapse:collapse;font-size:var(--fontSizeBase300);font-variant-numeric:tabular-nums}
        table th{background:transparent;padding:var(--spacingVerticalS) var(--spacingHorizontalM);text-align:right;font-weight:var(--fontWeightSemibold);color:var(--colorNeutralForeground2);border-bottom:var(--strokeWidthThin) solid var(--colorNeutralStroke1);white-space:nowrap}
        table td{padding:var(--spacingVerticalS) var(--spacingHorizontalM);border-bottom:var(--strokeWidthThin) solid var(--colorNeutralStroke2)}
        table tbody tr:hover{background:var(--row-hover)}
        @media(min-width:769px){table td{height:44px}}
        .parent-balance-cell{min-width:120px;white-space:nowrap;line-height:1.5}

        /* ---------- Phones: every table row becomes a card (app.js#stackTables, UX_PLAN 2.1) ----------
           No table scrolls sideways: each value sits on its own line after its column name (data-label), and
           the row's buttons sit at the bottom, with their words, wrapping. */
        @media(max-width:768px){
            .ux-stack,.ux-stack tbody{display:block;width:100%}
            .ux-stack thead{display:none}
            .ux-stack tr{display:block;padding:var(--spacingVerticalM) var(--spacingHorizontalS);border-bottom:var(--strokeWidthThin) solid var(--colorNeutralStroke2)}
            .ux-stack tr:last-child{border-bottom:0}
            .ux-stack tr:hover{background:transparent}
            .ux-stack td{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:var(--spacingVerticalXXS) var(--spacingHorizontalM);height:auto;min-height:28px;padding:var(--spacingVerticalXXS) 0;border:0;text-align:end}
            .ux-stack td[data-label]::before{content:attr(data-label);flex-shrink:0;font-size:var(--fontSizeBase200);line-height:var(--lineHeightBase200);color:var(--colorNeutralForeground3);text-align:start}
            .ux-stack td:first-child{display:block;padding-bottom:var(--spacingVerticalS);font-size:var(--fontSizeBase400);line-height:var(--lineHeightBase400);font-weight:var(--fontWeightSemibold);text-align:start}
            .ux-stack td:first-child::before{content:none}
            .ux-stack td.ux-td-acts{display:block;padding-top:var(--spacingVerticalS)}
            .ux-stack td.ux-td-acts::before{content:none}
            .ux-stack td[colspan]{display:block;text-align:start}
            .ux-stack td[colspan]::before{content:none}
            .page .ux-stack-wrap.table-container{overflow-x:visible}
        }
        /* ---------- Server-paged list (app.js#pagedListHtml) ---------- */
        .pg-tools{display:flex;flex-wrap:wrap;align-items:center;gap:var(--spacingVerticalS) var(--spacingHorizontalM);margin-bottom:var(--spacingVerticalM)}
        .pg-search{flex:1 1 var(--field-w-m);max-width:var(--field-w-l)}
        .pg-search input{width:100%}
        .pg-dates{display:flex;flex-wrap:wrap;align-items:center;gap:var(--spacingHorizontalS)}
        .pg-dates input{width:var(--field-w-s)}
        .pg-dates label{color:var(--colorNeutralForeground2);font-size:var(--fontSizeBase300)}
        .pg-filter{display:inline-flex;align-items:center;gap:var(--spacingHorizontalS);color:var(--colorNeutralForeground2);font-size:var(--fontSizeBase300);white-space:nowrap}
        .pg-filter select{width:auto;min-width:var(--field-w-xs)}
        .pg-csv{margin-inline-start:auto}
        .pg-sort{all:unset;cursor:pointer;display:inline-flex;align-items:center;gap:var(--spacingHorizontalXS);font:inherit;color:inherit;border-radius:var(--borderRadiusSmall)}
        .pg-sort i{font-size:var(--fontSizeBase100);color:var(--colorNeutralForeground4)}
        .pg-sort.on i{color:var(--colorBrandForeground1)}
        .pg-sort:hover{color:var(--colorNeutralForeground1)}
        .pg-sort:focus-visible{outline:var(--strokeWidthThick) solid var(--colorStrokeFocus2);outline-offset:var(--spacingHorizontalXXS)}
        .pg-msg{padding:var(--spacingVerticalL) var(--spacingHorizontalM);text-align:center;color:var(--colorNeutralForeground3)}
        .pg-msg-row:hover{background:transparent}
        .pg-pager{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--spacingVerticalS) var(--spacingHorizontalM);margin-bottom:var(--spacingVerticalM);color:var(--colorNeutralForeground2);font-size:var(--fontSizeBase300);font-variant-numeric:tabular-nums}
        .pg-pager:empty{display:none}
        .pg-nav{display:inline-flex;align-items:center;gap:var(--spacingHorizontalXS)}
        .pg-page{padding:0 var(--spacingHorizontalS);white-space:nowrap}
        .pg-size{display:inline-flex;align-items:center;gap:var(--spacingHorizontalS);white-space:nowrap}
        .pg-size select{width:auto;min-width:var(--field-w-xs)}
        /* Touch screens: the rows-per-page select and the list filters are full tap targets (MOBILE_REVIEW.md). */
        @media (pointer:coarse){.pg-size select,.pg-filter select{min-height:var(--touchTarget)}}
        @media(max-width:768px){
            .pg-pager{justify-content:center}.pg-count{width:100%;text-align:center}
            .pg-nav{flex-wrap:wrap;justify-content:center;row-gap:var(--spacingVerticalS);max-width:100%}
            .pg-page{order:-1;width:100%;text-align:center}
            .pg-dates{display:grid;grid-template-columns:auto 1fr;align-items:center;width:100%}
            .pg-dates input{width:100%}
        }
        .parent-balance-cell .pb-amount{font-weight:var(--fontWeightBold);color:var(--tint-success-fg);font-size:var(--fontSizeBase300)}
        .parent-balance-cell .pb-amount.pb-negative{color:var(--tint-danger-fg)}
        .parent-balance-cell .pb-level{font-size:var(--fontSizeBase200);color:var(--text-muted);margin-top:var(--spacingVerticalXXS)}
        .parent-balance-cell .pb-debt{font-size:var(--fontSizeBase200);color:var(--tint-danger-fg);margin-top:var(--spacingVerticalXXS)}

        /* ---------- Text fields (Fluent Input: 1px stroke, darker bottom edge, brand underline on focus) ---------- */
        .form-control,.search-box input,.settings-card input[type="time"],.teacher-rate-card .rate-item input,.cal-filter,.chat-search input,.chat-input input{min-height:var(--controlHeightMedium);padding:var(--spacingVerticalXS) var(--spacingHorizontalMNudge);background:var(--colorNeutralBackground1);color:var(--colorNeutralForeground1);border:var(--strokeWidthThin) solid var(--colorNeutralStroke1);border-bottom-color:var(--colorNeutralStrokeAccessible);border-radius:var(--borderRadiusMedium);font-size:var(--fontSizeBase300);line-height:var(--lineHeightBase300);transition:border-color var(--durationFaster) var(--curveEasyEase),box-shadow var(--durationNormal) var(--curveDecelerateMid)}
        .form-control:hover,.search-box input:hover,.settings-card input[type="time"]:hover,.teacher-rate-card .rate-item input:hover,.cal-filter:hover,.chat-search input:hover,.chat-input input:hover{border-color:var(--colorNeutralStroke1Hover);border-bottom-color:var(--colorNeutralStrokeAccessibleHover)}
        .form-control:focus,.search-box input:focus,.settings-card input[type="time"]:focus,.teacher-rate-card .rate-item input:focus,.cal-filter:focus,.chat-search input:focus,.chat-input input:focus{outline:none;border-bottom-color:var(--colorCompoundBrandStroke);box-shadow:inset 0 -1px 0 0 var(--colorCompoundBrandStroke)}
        .form-control:disabled,.form-control[readonly]{background:var(--colorNeutralBackgroundDisabled);border-color:var(--colorNeutralStrokeDisabled);color:var(--colorNeutralForeground3)}
        .form-control{width:100%}
        /* Field width follows its content (owner rule): sensible caps by field type. Override per
           field with .field-xs/-s/-m/-l/-xl or .field-full. Phones: max-width never exceeds 100%. */
        .form-control{max-width:var(--field-w-m)}
        :where(input[type="time"],input[type="number"]).form-control{max-width:var(--field-w-xs)}
        :where(input[type="date"],input[type="datetime-local"],input[type="month"]).form-control,:where(.decimal-input).form-control{max-width:var(--field-w-s)}
        :where(input[type="email"],input[type="url"],input[type="search"]).form-control{max-width:var(--field-w-l)}
        :where(textarea).form-control{max-width:var(--field-w-xl)}
        :where(input[type="file"]).form-control{max-width:none}
        .form-control.field-xs{max-width:var(--field-w-xs)}
        .form-control.field-s{max-width:var(--field-w-s)}
        .form-control.field-m{max-width:var(--field-w-m)}
        .form-control.field-l{max-width:var(--field-w-l)}
        .form-control.field-xl{max-width:var(--field-w-xl)}
        .form-control.field-full{max-width:none}
        .search-box input{max-width:var(--field-w-l)}
        .login-card .form-control{max-width:none}
        textarea.form-control{height:auto;min-height:64px;padding-top:var(--spacingVerticalSNudge);padding-bottom:var(--spacingVerticalSNudge);resize:vertical}
        input[type="file"].form-control{height:auto;padding:var(--spacingVerticalXS)}
        /* Native dropdowns ignore line-height, so pin them to the Fluent control height. */
        select.form-control,select.cal-filter{height:var(--controlHeightMedium);padding-top:0;padding-bottom:0}
        select[multiple].form-control{height:auto}
        input[type="time"]{font-size:var(--fontSizeBase300)}
        .search-box{display:flex;gap:var(--spacingHorizontalS);margin-bottom:var(--spacingVerticalM);flex-wrap:wrap}
        .search-box input{flex:1;min-width:150px}
        .form-group{margin-bottom:var(--spacingVerticalM)}
        .form-group label{display:block;font-weight:var(--fontWeightSemibold);margin-bottom:var(--spacingVerticalXS);font-size:var(--fontSizeBase300);color:var(--colorNeutralForeground1)}
        /* Inline form errors (phase 3, app-api.js#_submit): under the field, or above the form's buttons. */
        .field-error{margin-top:var(--spacingVerticalXS);font-size:var(--fontSizeBase200);line-height:var(--lineHeightBase200);color:var(--tint-danger-fg)}
        .form-control.is-invalid,.form-control[aria-invalid="true"]{border-color:var(--solid-danger)}
        .form-error{margin:var(--spacingVerticalM) 0}
        /* Required fields are marked (#23): a red asterisk after the label of a required field. */
        .form-group:has(> :is(input, select, textarea)[required]) > label::after,
        .form-group:has(> .les-pick :is(input, select, textarea)[required]) > label::after{content:" *";color:var(--tint-danger-fg)}
        /* Day one (#56): «nothing to choose yet» hints above a form. */
        .les-empty-hint{margin-bottom:var(--spacingVerticalM)}
        .les-empty-hint .btn{margin-inline-start:var(--spacingHorizontalS)}
        .form-row{display:grid;grid-template-columns:1fr 1fr;gap:var(--spacingHorizontalM)}
        .decimal-input{direction:ltr;text-align:center}

        /* ---------- Buttons (Fluent Button: default = secondary) ---------- */
        .btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--spacingHorizontalSNudge);min-height:var(--controlHeightMedium);padding:var(--spacingVerticalXXS) var(--spacingHorizontalM);background:var(--colorNeutralBackground1);color:var(--colorNeutralForeground1);border:var(--strokeWidthThin) solid var(--colorNeutralStroke1);border-radius:var(--borderRadiusMedium);font-size:var(--fontSizeBase300);line-height:var(--lineHeightBase300);font-weight:var(--fontWeightSemibold);text-decoration:none;cursor:pointer;transition:background-color var(--durationFaster) var(--curveEasyEase),border-color var(--durationFaster) var(--curveEasyEase),color var(--durationFaster) var(--curveEasyEase)}
        .btn:hover{background:var(--colorNeutralBackground1Hover);border-color:var(--colorNeutralStroke1Hover);color:var(--colorNeutralForeground1)}
        .btn:active{background:var(--colorNeutralBackground1Pressed);border-color:var(--colorNeutralStroke1Pressed)}
        .btn-primary{background:var(--colorBrandBackground);border-color:transparent;color:var(--colorNeutralForegroundOnBrand)}
        .btn-primary:hover{background:var(--colorBrandBackgroundHover);border-color:transparent;color:var(--colorNeutralForegroundOnBrand)}
        .btn-primary:active{background:var(--colorBrandBackgroundPressed);border-color:transparent}
        .btn-success{background:var(--solid-success);border-color:transparent;color:var(--colorNeutralForegroundOnBrand)}
        .btn-success:hover{background:var(--solid-success-hover);border-color:transparent;color:var(--colorNeutralForegroundOnBrand)}
        .btn-danger{background:var(--solid-danger);border-color:transparent;color:var(--colorNeutralForegroundOnBrand)}
        .btn-danger:hover{background:var(--solid-danger-hover);border-color:transparent;color:var(--colorNeutralForegroundOnBrand)}
        .btn-warning{background:var(--solid-warning);border-color:transparent;color:var(--colorNeutralForegroundOnBrand)}
        .btn-warning:hover{background:var(--solid-warning-hover);border-color:transparent;color:var(--colorNeutralForegroundOnBrand)}
        .btn-success:active,.btn-danger:active,.btn-warning:active{filter:brightness(0.9)}
        .btn-info{background:var(--tint-brand-bg);border-color:var(--tint-brand-border);color:var(--tint-brand-fg)}
        .btn-info:hover{background:var(--colorBrandBackground2Hover);border-color:var(--tint-brand-border);color:var(--tint-brand-fg)}
        .btn-outline{background:transparent;border-color:var(--colorNeutralStroke1);color:var(--colorNeutralForeground1)}
        .btn-outline:hover{background:var(--colorSubtleBackgroundHover);border-color:var(--colorNeutralStroke1Hover)}
        .btn-outline:active{background:var(--colorSubtleBackgroundPressed)}
        .btn:disabled,.btn[disabled]{background:var(--colorNeutralBackgroundDisabled);border-color:var(--colorNeutralStrokeDisabled);color:var(--colorNeutralForegroundDisabled);cursor:not-allowed;filter:none}
        .btn-sm{min-height:var(--controlHeightSmall);padding:0 var(--spacingHorizontalS);font-size:var(--fontSizeBase200);line-height:var(--lineHeightBase200);gap:var(--spacingHorizontalXS)}
        .btn-lg{min-height:var(--controlHeightLarge);padding:var(--spacingVerticalXS) var(--spacingHorizontalL);font-size:var(--fontSizeBase400);line-height:var(--lineHeightBase400)}
        .btn-xs{min-height:var(--controlHeightSmall);min-width:var(--controlHeightSmall);padding:0 var(--spacingHorizontalSNudge);font-size:var(--fontSizeBase200);line-height:var(--lineHeightBase200);gap:var(--spacingHorizontalXS)}
        .copy-btn{cursor:pointer;color:var(--colorBrandForeground1);transition:color var(--durationFaster) var(--curveEasyEase)}
        .copy-btn:hover{color:var(--colorBrandForegroundLinkHover)}

        /* ---------- Badges (Fluent tint badge) ---------- */
        .badge-status,.level-badge{display:inline-flex;align-items:center;gap:var(--spacingHorizontalXS);min-height:20px;padding:var(--spacingVerticalXXS) var(--spacingHorizontalS);border:0;border-radius:var(--borderRadiusCircular);font-size:var(--fontSizeBase200);line-height:var(--lineHeightBase200);font-weight:var(--fontWeightSemibold);vertical-align:middle}
        .badge-status.new,.badge-status.completed,.level-badge.a{background:var(--tint-brand-bg);color:var(--tint-brand-fg)}
        .badge-status.activated,.badge-status.approved,.badge-status.present{background:var(--tint-success-bg);color:var(--tint-success-fg)}
        .badge-status.used,.badge-status.requested,.badge-status.late,.level-badge.b{background:var(--tint-warning-bg);color:var(--tint-warning-fg)}
        .badge-status.disabled,.badge-status.rejected,.badge-status.cancelled,.badge-status.absent,.level-badge.c{background:var(--tint-danger-bg);color:var(--tint-danger-fg)}
        .badge-status.modified{background:var(--tint-purple-bg);color:var(--tint-purple-fg)}
        .notification-badge{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:20px;padding:0 var(--spacingHorizontalSNudge);border-radius:var(--borderRadiusCircular);background:var(--solid-danger);color:var(--colorNeutralForegroundOnBrand);font-size:var(--fontSizeBase100);font-weight:var(--fontWeightSemibold);margin-inline-start:var(--spacingHorizontalXS)}

        /* Message bar (Fluent MessageBar): a block with a status icon. Text is plain, so it can be
           set with textContent. */
        .msgbar{display:block;position:relative;padding:var(--spacingVerticalS) var(--spacingHorizontalM);padding-inline-start:calc(var(--spacingHorizontalM) + 24px);border:0;border-radius:var(--borderRadiusMedium);background:var(--tint-brand-bg);color:var(--colorNeutralForeground1);font-size:var(--fontSizeBase300);line-height:var(--lineHeightBase300);text-align:start}
        .msgbar::before{position:absolute;inset-inline-start:var(--spacingHorizontalM);top:var(--spacingVerticalS);font-family:"Font Awesome 6 Free";font-weight:900;font-size:var(--fontSizeBase400);line-height:var(--lineHeightBase300);content:"\f05a";color:var(--tint-brand-fg)}
        .msgbar.success{background:var(--tint-success-bg);border-color:var(--tint-success-border)}
        .msgbar.success::before{content:"\f058";color:var(--tint-success-fg)}
        .msgbar.warning{background:var(--tint-warning-bg);border-color:var(--tint-warning-border)}
        .msgbar.warning::before{content:"\f071";color:var(--tint-warning-fg)}
        .msgbar.danger{background:var(--tint-danger-bg);border-color:var(--tint-danger-border)}
        .msgbar.danger::before{content:"\f057";color:var(--tint-danger-fg)}
        /* Small coloured square used in colour legends (instead of coloured emoji). */
        .legend-dot{display:inline-block;width:12px;height:12px;border-radius:var(--borderRadiusSmall);vertical-align:-1px;border:var(--strokeWidthThin) solid}
        .legend-dot.tint-brand{background:var(--tint-brand-bg);border-color:var(--tint-brand-fg)}
        .legend-dot.tint-success{background:var(--tint-success-bg);border-color:var(--tint-success-fg)}
        .legend-dot.tint-warning{background:var(--tint-warning-bg);border-color:var(--tint-warning-fg)}
        .legend-dot.tint-danger{background:var(--tint-danger-bg);border-color:var(--tint-danger-fg)}
        .wa-icon{color:#25d366}

        /* ---------- Dialog (Fluent Dialog) ---------- */
        .modal{display:none;position:fixed;inset:0;background:var(--colorBackgroundOverlay);z-index:1000;align-items:center;justify-content:center;padding:var(--spacingVerticalL);padding-top:max(var(--spacingVerticalL),env(safe-area-inset-top,0px));padding-bottom:max(var(--spacingVerticalL),env(safe-area-inset-bottom,0px))}
        .modal.open{display:flex}
        .modal-content{background:var(--colorNeutralBackground1);color:var(--colorNeutralForeground1);border-radius:var(--borderRadiusXLarge);max-width:var(--layout-modal-max-w);width:100%;max-height:90vh;max-height:90dvh;overflow-y:auto;box-shadow:var(--shadow64);animation:modalIn var(--durationGentle) var(--curveDecelerateMid)}
        @keyframes modalIn{from{opacity:0;transform:scale(0.95)}to{opacity:1;transform:none}}
        .modal-header{padding:var(--spacingVerticalXXL) var(--spacingHorizontalXXL) var(--spacingVerticalS);display:flex;justify-content:space-between;align-items:center;gap:var(--spacingHorizontalS)}
        .modal-header h2{font-size:var(--fontSizeBase500);line-height:var(--lineHeightBase500);font-weight:var(--fontWeightSemibold)}
        .modal-close{font-size:var(--fontSizeBase500)}
        .modal-body{padding:var(--spacingVerticalS) var(--spacingHorizontalXXL) var(--spacingVerticalXXL)}

        /* ---------- Confirm / prompt dialog (js/dialogs.js; Fluent Dialog: 8px corners, 24px padding, shadow64) ---------- */
        .app-dialog{margin:auto;padding:0;border:0;border-radius:var(--borderRadiusXLarge);background:var(--colorNeutralBackground1);color:var(--colorNeutralForeground1);box-shadow:var(--shadow64);width:calc(100% - 2 * var(--spacingHorizontalL));max-width:480px;max-height:calc(100% - 2 * var(--spacingVerticalL));overflow-y:auto;animation:modalIn var(--durationGentle) var(--curveDecelerateMid)}
        .app-dialog::backdrop{background:var(--colorBackgroundOverlay)}
        /* ---------- Labelled actions (app.js#uxBtn / #rowActions, UX_PLAN.md): every action shows its word ---------- */
        .ux-acts{display:flex;flex-wrap:wrap;align-items:center;gap:var(--spacingVerticalXS) var(--spacingHorizontalS)}
        .ux-act{white-space:nowrap}
        .ux-act > i{font-size:var(--fontSizeBase200)}
        .btn.ux-danger{color:var(--tint-danger-fg);border-color:var(--tint-danger-fg)}
        .btn.ux-danger:hover{background:var(--tint-danger-bg);color:var(--tint-danger-fg);border-color:var(--tint-danger-fg)}
        .ux-acts-gap{flex:0 0 var(--spacingHorizontalL)}
        /* A destructive action never sits right next to a safe one (mobile review: «قبول»/«رفض», «تعديل»/«حذف» were 4px
           apart): it keeps 16px more than the row's own gap. Put it last, so it is the far one. */
        :is(.btn,.ux-act):not(.ux-danger,.btn-danger,.fin-btn-danger,.ppl-btn-danger) + :is(.ux-danger,.btn-danger,.fin-btn-danger,.ppl-btn-danger){margin-inline-start:var(--spacingHorizontalL)}
        .ux-act-wrap{display:inline-flex;flex-direction:column;align-items:flex-start;gap:var(--spacingVerticalXXS)}
        .ux-act-note{font-size:var(--fontSizeBase200);line-height:var(--lineHeightBase200);color:var(--colorNeutralForeground3);white-space:normal;max-width:var(--field-w-s)}
        .ux-acts-dialog{max-width:var(--field-w-l)}
        .ux-acts-list{display:flex;flex-direction:column;gap:var(--spacingVerticalS);margin-top:var(--spacingVerticalM)}
        .ux-acts-item{justify-content:flex-start;min-height:var(--touchTarget);font-size:var(--fontSizeBase300);gap:var(--spacingHorizontalM)}
        .ux-acts-head{margin-top:var(--spacingVerticalL);padding-top:var(--spacingVerticalM);border-top:var(--strokeWidthThin) solid var(--colorNeutralStroke2);font-size:var(--fontSizeBase200);font-weight:var(--fontWeightSemibold);color:var(--tint-danger-fg)}
        .ux-acts-head--first{margin-top:var(--spacingVerticalS);padding-top:0;border-top:0}
        .ux-acts-note{margin:calc(-1 * var(--spacingVerticalXS)) 0 0;font-size:var(--fontSizeBase200);color:var(--colorNeutralForeground3)}
        @media (pointer:coarse){.ux-acts{gap:var(--spacingVerticalS) var(--spacingHorizontalS)} .ux-act{min-height:var(--controlHeightLarge)}}
        .app-dialog--fallback{position:fixed;inset:0;margin:auto;height:fit-content;z-index:3000;box-shadow:0 0 0 100vmax var(--colorBackgroundOverlay),var(--shadow64)}
        .app-dialog-form{padding:var(--spacingVerticalXXL) var(--spacingHorizontalXXL)}
        .app-dialog-title{font-size:var(--fontSizeBase500);line-height:var(--lineHeightBase500);font-weight:var(--fontWeightSemibold);margin-bottom:var(--spacingVerticalS)}
        .app-dialog-msg{font-size:var(--fontSizeBase300);line-height:var(--lineHeightBase300);white-space:pre-line;overflow-wrap:anywhere}
        .app-dialog-field{margin:var(--spacingVerticalM) 0 0}
        .app-dialog-field .form-control{max-width:none}
        .app-dialog-error{margin-top:var(--spacingVerticalXS);font-size:var(--fontSizeBase200);line-height:var(--lineHeightBase200);color:var(--tint-danger-fg)}
        .app-dialog-actions{display:flex;flex-wrap:wrap;justify-content:flex-start;gap:var(--spacingHorizontalS);margin-top:var(--spacingVerticalXXL)}
        @media (max-width:640px){
            .app-dialog-form{padding:var(--spacingVerticalL) var(--spacingHorizontalM)}
            .app-dialog-actions .btn{flex:1 1 0}
        }

        /* ---------- Toasts (Fluent Toast: neutral surface + status icon) ---------- */
        /* Toasts never intercept taps/clicks on the buttons under them (R2-21). */
        #toastContainer{position:fixed;top:calc(70px + env(safe-area-inset-top,0px));left:calc(12px + env(safe-area-inset-left,0px));z-index:9999;display:flex;flex-direction:column;gap:var(--spacingVerticalSNudge);pointer-events:none}
        #toastContainer > *{pointer-events:none}
        .toast{display:flex;align-items:flex-start;gap:var(--spacingHorizontalS);min-width:200px;max-width:min(400px,calc(100vw - 24px));padding:var(--spacingVerticalM) var(--spacingHorizontalM);border:var(--strokeWidthThin) solid var(--colorNeutralStroke3);border-radius:var(--borderRadiusMedium);background:var(--colorNeutralBackground1);color:var(--colorNeutralForeground1);box-shadow:var(--shadow8);font-size:var(--fontSizeBase300);line-height:var(--lineHeightBase300);font-weight:var(--fontWeightSemibold);animation:toastIn var(--durationNormal) var(--curveDecelerateMid);transition:opacity var(--durationSlow) var(--curveEasyEase)}
        .toast::before{flex-shrink:0;font-family:"Font Awesome 6 Free";font-weight:900;font-size:var(--fontSizeBase400);line-height:var(--lineHeightBase300)}
        .toast.success::before{content:"\f058";color:var(--colorStatusSuccessForeground1)}
        .toast.error::before{content:"\f057";color:var(--colorStatusDangerForeground1)}
        .toast.warning::before{content:"\f071";color:var(--colorStatusWarningForeground1)}
        .toast.info::before{content:"\f05a";color:var(--colorBrandForeground1)}
        /* The container sits on the left edge, so toasts slide in from the left. */
        @keyframes toastIn{from{transform:translateX(-16px);opacity:0}to{transform:none;opacity:1}}

        /* ---------- Dashboard blocks ---------- */

        /* ---------- Tabs (Fluent TabList: selected = 3px brand pill under the label) ---------- */
        .report-tabs,.session-tabs{display:flex;gap:var(--spacingHorizontalXS);flex-wrap:wrap;margin-bottom:var(--spacingVerticalL);border-bottom:var(--strokeWidthThin) solid var(--colorNeutralStroke2)}
        .session-tabs{margin-bottom:var(--spacingVerticalM)}
        /* Phones: a tab bar always fits, with no hidden tab (mobile review): equal columns, and a long label wraps
           inside its own tab instead of pushing the last tab off the screen. */
        @media(max-width:768px){
            .report-tabs,.session-tabs{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr);gap:var(--spacingHorizontalXXS)}
            .report-tab,.session-tab{min-width:0;flex-wrap:wrap;white-space:normal;text-align:center;padding-inline:var(--spacingHorizontalXS);gap:var(--spacingHorizontalXS);line-height:var(--lineHeightBase200)}
        }
        .report-tab,.session-tab,.cal-viewbtn{position:relative;display:inline-flex;align-items:center;justify-content:center;gap:var(--spacingHorizontalSNudge);background:transparent;border:0;border-radius:var(--borderRadiusMedium);padding:var(--spacingVerticalMNudge) var(--spacingHorizontalM);cursor:pointer;font-size:var(--fontSizeBase300);line-height:var(--lineHeightBase300);color:var(--colorNeutralForeground2);transition:color var(--durationFaster) var(--curveEasyEase),background-color var(--durationFaster) var(--curveEasyEase)}
        .report-tab::after,.session-tab::after,.cal-viewbtn::after{content:"";position:absolute;inset-inline:var(--spacingHorizontalM);bottom:0;height:var(--strokeWidthThicker);border-radius:var(--borderRadiusCircular);background:transparent;transition:background-color var(--durationFaster) var(--curveEasyEase)}
        .report-tab:hover,.session-tab:hover,.cal-viewbtn:hover{color:var(--colorNeutralForeground2Hover);background:var(--colorSubtleBackgroundHover)}
        .report-tab:hover::after,.session-tab:hover::after,.cal-viewbtn:hover::after{background:var(--colorNeutralStroke1Hover)}
        .report-tab.active,.session-tab.active,.cal-viewbtn.active{color:var(--colorNeutralForeground1);font-weight:var(--fontWeightSemibold)}
        .report-tab.active::after,.session-tab.active::after,.cal-viewbtn.active::after{background:var(--colorCompoundBrandStroke)}
        .report-content{display:none}
        .report-content.active{display:block}
        .session-tab-count{background:var(--tint-neutral-bg);color:var(--tint-neutral-fg);border-radius:var(--borderRadiusCircular);padding:0 var(--spacingHorizontalSNudge);font-size:var(--fontSizeBase200);font-weight:var(--fontWeightSemibold);min-width:20px;text-align:center}
        .session-tab.active .session-tab-count{background:var(--colorBrandBackground);color:var(--colorNeutralForegroundOnBrand)}
        @media (max-width:640px){
            .session-tab{padding:var(--spacingVerticalS) var(--spacingHorizontalMNudge);font-size:var(--fontSizeBase200);flex:1}
        }

        /* ============================================================
           Calendar — month grid + week/day timelines. RTL-aware
           (accents on the inline-start / right edge). See loadCalendar() in app.js.
           ============================================================ */
        .cal-card{padding:var(--spacingVerticalM)}
        .cal-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:var(--spacingHorizontalMNudge);margin-bottom:var(--spacingVerticalS)}
        .cal-nav{display:flex;align-items:center;gap:var(--spacingHorizontalSNudge)}
        .cal-navbtn,.cal-todaybtn{height:var(--controlHeightMedium);border:var(--strokeWidthThin) solid var(--colorNeutralStroke1);background:var(--colorNeutralBackground1);border-radius:var(--borderRadiusMedium);cursor:pointer;color:var(--colorNeutralForeground1);transition:background-color var(--durationFaster) var(--curveEasyEase),border-color var(--durationFaster) var(--curveEasyEase)}
        .cal-navbtn{width:auto;min-width:var(--controlHeightMedium)}
        .cal-todaybtn{padding:0 var(--spacingHorizontalM);font-size:var(--fontSizeBase300);font-weight:var(--fontWeightSemibold)}
        .cal-navbtn:hover,.cal-todaybtn:hover{background:var(--colorNeutralBackground1Hover);border-color:var(--colorNeutralStroke1Hover)}
        .cal-navbtn:active,.cal-todaybtn:active{background:var(--colorNeutralBackground1Pressed)}
        .cal-title{font-size:var(--fontSizeBase400);line-height:var(--lineHeightBase400);font-weight:var(--fontWeightSemibold);color:var(--text);margin-inline-start:var(--spacingHorizontalSNudge)}
        .cal-views{display:inline-flex;gap:var(--spacingHorizontalXXS)}
        .cal-viewbtn{padding:var(--spacingVerticalSNudge) var(--spacingHorizontalM)}
        .cal-filters{display:flex;flex-wrap:wrap;gap:var(--spacingHorizontalSNudge);margin-inline-start:auto}
        .cal-filter{font-size:var(--fontSizeBase200);cursor:pointer;max-width:150px}
        .cal-legend{display:flex;flex-wrap:wrap;gap:var(--spacingHorizontalM);margin-bottom:var(--spacingVerticalMNudge);padding:var(--spacingVerticalSNudge) var(--spacingHorizontalXXS);font-size:var(--fontSizeBase200);color:var(--text-muted)}
        .cal-leg{display:inline-flex;align-items:center;gap:var(--spacingHorizontalXS)}
        .cal-dot{width:10px;height:10px;border-radius:var(--borderRadiusSmall);display:inline-block}
        /* status palette (bg / text) + solid dot */
        .cal-req{background:var(--tint-warning-bg);color:var(--tint-warning-fg)}    .cal-dot.cal-req{background:var(--colorStatusWarningBackground3)}
        .cal-appr{background:var(--tint-brand-bg);color:var(--tint-brand-fg)}      .cal-dot.cal-appr{background:var(--colorBrandBackground)}
        .cal-done{background:var(--tint-success-bg);color:var(--tint-success-fg)}  .cal-dot.cal-done{background:var(--colorStatusSuccessBackground3)}
        .cal-absent{background:var(--tint-neutral-bg);color:var(--tint-neutral-fg)} .cal-dot.cal-absent{background:var(--colorNeutralForeground4)}
        .cal-rej{background:var(--tint-danger-bg);color:var(--tint-danger-fg)}     .cal-dot.cal-rej{background:var(--colorStatusDangerBackground3)}
        /* month grid */
        .cal-viewport{overflow-x:auto}
        .cal-dow-row,.cal-grid{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:var(--spacingHorizontalXS)}
        .cal-dow-row{margin-bottom:var(--spacingVerticalXS)}
        .cal-dow{text-align:center;font-weight:var(--fontWeightSemibold);font-size:var(--fontSizeBase200);color:var(--text-muted);padding:var(--spacingVerticalXS)}
        .cal-cell{min-height:96px;border:var(--strokeWidthThin) solid var(--colorNeutralStroke2);border-radius:var(--borderRadiusMedium);background:var(--colorNeutralBackground1);padding:var(--spacingVerticalXS);display:flex;flex-direction:column;gap:var(--spacingVerticalXXS);transition:background-color var(--durationFaster) var(--curveEasyEase)}
        .cal-cell:hover{background:var(--colorNeutralBackground1Hover)}
        .cal-cell-empty{background:var(--colorNeutralBackground2);border-style:dashed;border-color:var(--colorNeutralStroke3);min-height:0}
        .cal-cell-empty:hover{background:var(--colorNeutralBackground2)}
        .cal-today{border-color:var(--colorCompoundBrandStroke);background:var(--colorBrandBackground2)}
        .cal-today:hover{background:var(--colorBrandBackground2)}
        .cal-daynum{font-weight:var(--fontWeightSemibold);font-size:var(--fontSizeBase300);color:var(--text)}
        .cal-today .cal-daynum{color:var(--colorBrandForeground1)}
        .cal-chips{display:flex;flex-direction:column;gap:var(--spacingVerticalXXS);overflow:hidden}
        .cal-chip{font-size:var(--fontSizeBase100);padding:var(--spacingVerticalXXS) var(--spacingHorizontalXS);border-radius:var(--borderRadiusSmall);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;cursor:pointer;border-inline-start:var(--strokeWidthThicker) solid currentColor}
        .cal-chip:hover{filter:brightness(0.97)}
        .cal-chip-t{font-weight:var(--fontWeightSemibold)}
        .cal-more{font-size:var(--fontSizeBase100);font-weight:var(--fontWeightSemibold);color:var(--colorBrandForegroundLink);cursor:pointer;padding:0 var(--spacingHorizontalXS)}
        .cal-more:hover{text-decoration:underline}
        /* week / day timeline */
        .cal-timeline{overflow-x:auto}
        .cal-tl-inner{display:flex;min-width:640px}
        .cal-day .cal-tl-inner{min-width:0}
        .cal-tl-gutter{flex:0 0 52px;display:flex;flex-direction:column}
        .cal-tl-corner{height:38px;flex:0 0 38px}
        .cal-tl-hour{position:relative;font-size:var(--fontSizeBase200);color:var(--text-faint);text-align:center}
        .cal-tl-hour span{position:absolute;top:-7px;inset-inline-end:var(--spacingHorizontalSNudge)}
        .cal-tl-cols{display:flex;flex:1;gap:0}
        .cal-tl-col{flex:1;min-width:0;border-inline-start:var(--strokeWidthThin) solid var(--colorNeutralStroke3)}
        .cal-tl-colhead{height:38px;display:flex;flex-direction:column;align-items:center;justify-content:center;font-size:var(--fontSizeBase200);font-weight:var(--fontWeightSemibold);color:var(--text-muted)}
        .cal-tl-todayhead{color:var(--colorBrandForeground1)}
        .cal-tl-date{font-size:var(--fontSizeBase400);font-weight:var(--fontWeightSemibold)}
        .cal-tl-body{position:relative}
        .cal-tl-todaycol .cal-tl-body{background:var(--colorBrandBackground2)}
        .cal-tl-line{border-top:var(--strokeWidthThin) solid var(--colorNeutralStroke3)}
        .cal-ev{position:absolute;border-radius:var(--borderRadiusMedium);padding:var(--spacingVerticalXXS) var(--spacingHorizontalXS);font-size:var(--fontSizeBase100);overflow:hidden;cursor:pointer;border-inline-start:var(--strokeWidthThicker) solid currentColor;box-shadow:var(--shadow2);transition:box-shadow var(--durationFaster) var(--curveEasyEase)}
        .cal-ev:hover{box-shadow:var(--shadow8);z-index:5}
        .cal-ev-time{font-weight:var(--fontWeightSemibold)}
        .cal-ev-name{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
        .cal-break{position:absolute;inset-inline:0;background:repeating-linear-gradient(45deg,var(--colorNeutralStroke2),var(--colorNeutralStroke2) 6px,var(--colorNeutralStroke3) 6px,var(--colorNeutralStroke3) 12px);border-radius:var(--borderRadiusSmall);opacity:.7}
        /* detail modal */
        .cal-detail{display:flex;flex-direction:column;gap:var(--spacingVerticalXXS);margin-bottom:var(--spacingVerticalS)}
        .cal-detail-badge{align-self:flex-start;padding:var(--spacingVerticalXXS) var(--spacingHorizontalM);border-radius:var(--borderRadiusCircular);font-size:var(--fontSizeBase200);font-weight:var(--fontWeightSemibold);margin-bottom:var(--spacingVerticalSNudge)}
        .cal-detail-row{display:flex;justify-content:space-between;gap:var(--spacingHorizontalM);padding:var(--spacingVerticalSNudge) var(--spacingHorizontalXXS);border-bottom:var(--strokeWidthThin) solid var(--colorNeutralStroke3);font-size:var(--fontSizeBase300)}
        .cal-detail-k{color:var(--text-muted);font-weight:var(--fontWeightSemibold)}
        .cal-detail-v{color:var(--text);font-weight:var(--fontWeightSemibold);text-align:end}
        .cal-detail-link{color:var(--colorBrandForegroundLink);font-weight:var(--fontWeightSemibold);text-decoration:none}
        .cal-detail-actions{display:flex;flex-wrap:wrap;gap:var(--spacingHorizontalS);margin-top:var(--spacingVerticalM)}

        /* ============================================================
           Chat — Teams-like Fluent chat, fully responsive.
           Desktop: a two-pane grid (conversation list + open conversation).
           Mobile (max-width:768px, block further below): a single full-screen
           pane at a time. Colours come from the --chat-* tokens.
           ============================================================ */
        /* Fluid, never-overflowing shell. Centered + capped on ultrawide so the
           conversation doesn't stretch to unreadable line lengths. */
        .chat-container{display:grid;grid-template-columns:minmax(280px,340px) 1fr;gap:0;height:min(76vh,760px);height:min(76dvh,760px);min-height:440px;max-width:1200px;margin-inline:auto;background:var(--chat-bg);border-radius:var(--borderRadiusLarge);overflow:hidden;box-shadow:var(--shadow4)}
        .chat-list{background:var(--colorNeutralBackground1);border-inline-end:var(--strokeWidthThin) solid var(--chat-divider);overflow-y:auto;overflow-x:hidden;padding:0}
        .chat-item{position:relative;padding:var(--spacingVerticalMNudge) var(--spacingHorizontalM);cursor:pointer;transition:background-color var(--durationFaster) var(--curveEasyEase);display:flex;align-items:center;gap:var(--spacingHorizontalMNudge)}
        .chat-item:hover{background:var(--colorSubtleBackgroundHover)}
        button.chat-item{width:calc(100% - 2 * var(--spacingHorizontalXS));border:0;background:transparent;color:inherit;font:inherit;text-align:start}
        #chat .chat-item[hidden],#chat .chat-nomatch[hidden]{display:none}
        .chat-item-go{flex:0 0 auto;font-size:var(--fontSizeBase200);color:var(--colorNeutralForeground3)}
        .chat-item .name-row,.chat-item .last-msg-row{display:flex}
        /* An empty screen: what it is for and the first step (app.js#firstStepHtml, UX_PLAN 6.2) */
        .ux-first{display:flex;flex-direction:column;align-items:center;gap:var(--spacingVerticalM);margin-bottom:var(--spacingVerticalL);padding:var(--spacingVerticalXXL) var(--spacingHorizontalL);border-radius:var(--borderRadiusLarge);background:var(--colorNeutralBackground1);box-shadow:var(--shadow4);text-align:center}
        .ux-first-icon{font-size:var(--fontSizeBase600);color:var(--colorBrandForeground1)}
        .ux-first-text{margin:0;max-width:var(--field-w-xl);font-size:var(--fontSizeBase400);line-height:var(--lineHeightBase400);color:var(--colorNeutralForeground1)}
        td .ux-first{margin:var(--spacingVerticalS) 0;box-shadow:none;background:transparent}
        /* Collapsed sections say what a tap does: «عرض ▾» / «إخفاء ▴» (app.js#sumToggle) */
        summary{cursor:pointer}
        .ux-sum-toggle{display:inline-flex;align-items:center;gap:var(--spacingHorizontalXS);margin-inline-start:auto;padding:0 var(--spacingHorizontalS);font-size:var(--fontSizeBase200);font-weight:var(--fontWeightSemibold);color:var(--colorBrandForegroundLink)}
        .ux-sum-toggle i{font-size:var(--fontSizeBase100);transition:transform var(--durationFast) var(--curveEasyEase)}
        .ux-sum-hide{display:none}
        details[open] > summary .ux-sum-show{display:none}
        details[open] > summary .ux-sum-hide{display:inline}
        details[open] > summary .ux-sum-toggle i{transform:rotate(180deg)}
        .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
        .chat-item.active{background:var(--colorNeutralBackground1Selected)}
        .chat-item .avatar,.chat-window-header .avatar{width:40px;height:40px;border-radius:50%;background:var(--colorBrandBackground2);color:var(--colorBrandForeground2);display:flex;align-items:center;justify-content:center;font-weight:var(--fontWeightSemibold);flex-shrink:0;font-size:var(--fontSizeBase300)}
        .chat-item .info{flex:1;min-width:0}
        .chat-item .name-row{display:flex;align-items:center;gap:var(--spacingHorizontalSNudge);flex-wrap:wrap}
        .chat-item .name{font-weight:var(--fontWeightSemibold);font-size:var(--fontSizeBase300);color:var(--text)}
        .chat-item .last-msg-row{display:flex;align-items:center;justify-content:space-between;gap:var(--spacingHorizontalSNudge)}
        .chat-item .last-msg{font-size:var(--fontSizeBase200);color:var(--text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
        .chat-item .last-time{font-size:var(--fontSizeBase200);color:var(--text-faint);flex-shrink:0}
        .chat-item .unread{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:20px;padding:0 var(--spacingHorizontalSNudge);background:var(--colorBrandBackground);color:var(--colorNeutralForegroundOnBrand);border-radius:var(--borderRadiusCircular);font-size:var(--fontSizeBase100);font-weight:var(--fontWeightSemibold)}
        /* Phone number / role chips — shown next to the name in the chat list (and in
           the conversation header) so they read as clearly separate, glanceable facts. */
        .chat-phone{display:inline-flex;align-items:center;gap:var(--spacingHorizontalXS);font-size:var(--fontSizeBase200);font-weight:var(--fontWeightSemibold);color:var(--tint-neutral-fg);background:var(--tint-neutral-bg);padding:0 var(--spacingHorizontalS);border-radius:var(--borderRadiusCircular);white-space:nowrap}
        .chat-phone i{font-size:var(--fontSizeBase100)}
        .chat-role{display:inline-flex;align-items:center;font-size:var(--fontSizeBase200);font-weight:var(--fontWeightSemibold);color:var(--tint-purple-fg);background:var(--tint-purple-bg);padding:0 var(--spacingHorizontalS);border-radius:var(--borderRadiusCircular);white-space:nowrap}
        .chat-window{background:var(--chat-bg);display:flex;flex-direction:column;overflow:hidden;min-width:0}
        .chat-window-header{padding:var(--spacingVerticalMNudge) var(--spacingHorizontalL);background:var(--chat-header);color:var(--chat-header-text);border-bottom:var(--strokeWidthThin) solid var(--chat-divider);display:flex;align-items:center;gap:var(--spacingHorizontalMNudge);flex-shrink:0}
        .chat-window-title-wrap{min-width:0;flex:1;display:flex;flex-direction:column;align-items:flex-start;gap:var(--spacingVerticalXXS)}
        .chat-window-title{font-weight:var(--fontWeightSemibold);font-size:var(--fontSizeBase400);line-height:var(--lineHeightBase400)}
        /* Only shown on mobile (see the max-width:768px block below) — desktop keeps
           both panes visible side by side, so there's nothing to "go back" from. */
        .chat-back-btn,.chat-back{display:none}
        .chat-messages{flex:1;padding:var(--spacingVerticalL) clamp(12px,4vw,28px);overflow-y:auto;overflow-x:hidden;display:flex;flex-direction:column;gap:var(--spacingVerticalS);background:var(--chat-bg);overscroll-behavior:contain}
        .chat-older{display:flex;justify-content:center}
        /* Bubbles: wide on phones (space is scarce), narrower share on big screens,
           but always capped so lines never run uncomfortably long. */
        .message{max-width:min(80%,560px);padding:var(--spacingVerticalS) var(--spacingHorizontalM);border-radius:var(--borderRadiusMedium);font-size:var(--fontSizeBase300);line-height:1.45;word-wrap:break-word;overflow-wrap:anywhere;position:relative;box-shadow:var(--shadow2);animation:msgIn var(--durationNormal) var(--curveDecelerateMid)}
        @keyframes msgIn{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}
        .message.sent{background:var(--chat-sent);color:var(--chat-sent-text);align-self:flex-end}
        .message.received{background:var(--chat-received);color:var(--chat-received-text);align-self:flex-start}
        .message .time{font-size:var(--fontSizeBase100);margin-top:var(--spacingVerticalXXS);display:block;color:var(--chat-meta);text-align:end}
        .chat-input{padding:var(--spacingVerticalMNudge) var(--spacingHorizontalM);padding-bottom:calc(var(--spacingVerticalMNudge) + env(safe-area-inset-bottom,0px));border-top:var(--strokeWidthThin) solid var(--chat-divider);background:var(--chat-input-bar);display:flex;align-items:center;gap:var(--spacingHorizontalS);flex-wrap:nowrap;flex-shrink:0}
        .chat-input input{flex:1;min-height:var(--controlHeightLarge);padding:var(--spacingVerticalS) var(--spacingHorizontalM);background:var(--chat-input-field);min-width:0}
        .chat-input .chat-buttons{display:flex;gap:var(--spacingHorizontalSNudge);flex-shrink:0}
        /* Square, tap-friendly action buttons in the compose bar. */
        .chat-input .chat-buttons .btn{width:auto;min-width:44px;height:44px;padding:0 var(--spacingHorizontalM);font-size:var(--fontSizeBase300)}
        .chat-input .chat-buttons .btn-primary{background:var(--chat-send);color:var(--colorNeutralForegroundOnBrand)}
        .chat-input .chat-buttons .btn-primary:hover{background:var(--chat-send-hover)}
        .chat-search{margin-bottom:0;padding:var(--spacingVerticalS);background:var(--colorNeutralBackground1);border-bottom:var(--strokeWidthThin) solid var(--chat-divider)}
        .chat-search input{width:100%}

        /* ---------- Settings / rates / activation ---------- */
        .teacher-rate-card,.settings-card{border-radius:var(--borderRadiusLarge);padding:var(--spacingVerticalM);margin-bottom:var(--spacingVerticalMNudge);background:var(--colorNeutralBackground1);box-shadow:var(--shadow4)}
        .settings-card{padding:var(--spacingVerticalL);margin-bottom:var(--spacingVerticalM)}
        .teacher-rate-card .teacher-name{font-weight:var(--fontWeightSemibold);font-size:var(--fontSizeBase400);color:var(--text)}
        .teacher-rate-card .rate-row{display:flex;flex-wrap:wrap;gap:var(--spacingHorizontalS);margin-top:var(--spacingVerticalS)}
        .teacher-rate-card .rate-item{flex:1;min-width:100px}
        .teacher-rate-card .rate-item label{font-size:var(--fontSizeBase200);color:var(--text-muted);display:block}
        .teacher-rate-card .rate-item input{width:100%}
        .settings-card label{font-weight:var(--fontWeightSemibold);font-size:var(--fontSizeBase300);display:block;margin-bottom:var(--spacingVerticalXS)}
        .settings-card input[type="time"]{width:150px}
        .available-slots{display:flex;flex-wrap:wrap;gap:var(--spacingHorizontalSNudge);padding:var(--spacingVerticalS) 0}
        .slot-item{background:var(--tint-success-bg);padding:var(--spacingVerticalXS) var(--spacingHorizontalM);border-radius:var(--borderRadiusMedium);font-size:var(--fontSizeBase200);color:var(--tint-success-fg)}
        .slot-item:hover{background:var(--colorStatusSuccessBackground2)}
        .no-slots{color:var(--tint-danger-fg);font-size:var(--fontSizeBase300)}
        /* Admin verification seal (علامة توثيق الإدارة) — a scalloped brand-coloured badge
           with a white check, shown ONLY next to Administration accounts (see verifiedBadge()
           in app.js). Inline, baseline-aligned so it sits neatly after the name. */
        .admin-verified{display:inline-block;width:1em;height:1em;vertical-align:-0.14em;margin-inline-start:var(--spacingHorizontalXS);
            flex:0 0 auto;animation:advPop var(--durationGentle) var(--curveDecelerateMid) both}
        .admin-verified .av-seal{fill:var(--colorBrandForeground1)}
        .admin-verified .av-check{fill:var(--colorNeutralForegroundOnBrand)}
        @keyframes advPop{0%{transform:scale(.4);opacity:0}60%{transform:scale(1.12)}100%{transform:scale(1);opacity:1}}

        /* ---------- Responsive ---------- */
        @media(max-width:768px){
            .form-row{grid-template-columns:1fr}
            .card-header{flex-direction:column;align-items:stretch}
            .card-header .btn{width:100%;justify-content:center}
            /* ===== Mobile chat =====
               Single full-screen pane at a time: the list OR the open conversation,
               toggled by the .chat-conversation-open class loadChat() sets on
               .chat-container, with a back button to return to the list — never both
               cramped into small stacked boxes like the old two-pane desktop layout.
               Colors/bubbles/header theming live in the base (unscoped) rules above
               and already apply here too — this block is purely structural. */
            .chat-container{display:block;grid-template-columns:none;min-height:360px;max-width:none;margin-inline:0;border-radius:0;box-shadow:none}
            .chat-list{display:flex;flex-direction:column;height:100%;max-height:none;border-inline-end:none}
            .chat-window{display:none;height:100%}
            .chat-container.chat-conversation-open .chat-list{display:none}
            .chat-container.chat-conversation-open .chat-window{display:flex}
            .chat-back-btn,.chat-back{display:inline-flex}
            .message{max-width:85%;font-size:var(--fontSizeBase300)}
            .chat-messages{padding:var(--spacingVerticalM) var(--spacingHorizontalM)}
            .cal-cell{min-height:74px;padding:var(--spacingVerticalXXS)}
            .cal-chip{font-size:var(--fontSizeBase100);padding:0 var(--spacingHorizontalXS)}
            .cal-toolbar{gap:var(--spacingHorizontalSNudge)}
            .cal-filters{margin-inline-start:0;width:100%}
            .cal-title{font-size:var(--fontSizeBase400)}
            .modal-content{max-width:100%;margin:var(--spacingVerticalMNudge)}
            .settings-card input[type="time"]{width:100%}
            .search-box{flex-direction:column}
            .search-box input{width:100%}
        }
        @media(max-width:480px){
            .card{padding:var(--spacingVerticalMNudge) var(--spacingHorizontalMNudge)}
            .modal-content{border-radius:var(--borderRadiusXLarge)}
            .modal-header{padding:var(--spacingVerticalM) var(--spacingHorizontalM) var(--spacingVerticalXS)}
            .modal-body{padding:var(--spacingVerticalS) var(--spacingHorizontalM) var(--spacingVerticalM)}
            table{font-size:var(--fontSizeBase200)}
            table th,table td{padding:var(--spacingVerticalXS) var(--spacingHorizontalSNudge)}
            .btn{font-size:var(--fontSizeBase200);padding:var(--spacingVerticalXS) var(--spacingHorizontalMNudge)}
            .btn-lg{font-size:var(--fontSizeBase400);padding:var(--spacingVerticalXS) var(--spacingHorizontalL)}
            .badge-status{font-size:var(--fontSizeBase100);padding:0 var(--spacingHorizontalSNudge)}
            .cal-cell{min-height:60px}
            .cal-views{width:100%;justify-content:center}
            .chat-input{padding-inline:var(--spacingHorizontalMNudge);gap:var(--spacingHorizontalSNudge)}
            .chat-input .chat-buttons{gap:var(--spacingHorizontalXS)}
            .chat-input .chat-buttons .btn{width:42px;height:42px}
            .available-slots{flex-direction:column}
        }
        /* Touch screens: bigger tap targets (Fluent: >= 32px controls, 40-44px for primary taps). */
        @media (pointer:coarse){
            .btn,.btn-sm,.btn-xs{min-height:var(--controlHeightMedium)}
            .btn-xs{min-width:var(--controlHeightMedium)}
            .form-control,.search-box input,.settings-card input[type="time"],.cal-filter,.chat-search input{min-height:var(--touchTarget)}
            select.form-control,select.cal-filter{height:var(--touchTarget)}
            .theme-toggle,.notif-bell,.modal-close,.more-sheet-close,.chat-back-btn,.icon-btn{width:var(--controlHeightLarge);height:var(--controlHeightLarge)}
            .menu-item{min-height:var(--touchTarget)}
            /* Fluent 2 web: touch targets are at least 44x44. The button keeps its Fluent size; an invisible
               ::before grows the tappable area around it (::after is used by some page styles). */
            .btn,.icon-btn,.theme-toggle:not(.theme-toggle--login),.notif-bell,.modal-close,.more-sheet-close,.chat-back-btn{position:relative}
            .btn::before,.icon-btn::before,.theme-toggle::before,.notif-bell::before,.modal-close::before,.more-sheet-close::before,.chat-back-btn::before{content:"";position:absolute;top:min(0px,calc((100% - var(--touchTarget)) / 2));bottom:min(0px,calc((100% - var(--touchTarget)) / 2));left:min(0px,calc((100% - var(--touchTarget)) / 2));right:min(0px,calc((100% - var(--touchTarget)) / 2))}
        }
        /* Windows high-contrast: shadows and coloured fills disappear, so mark selection with
           system colours and keep the field focus visible. */
        @media (forced-colors:active){
            .menu-item.active::before,.report-tab.active::after,.session-tab.active::after,.cal-viewbtn.active::after{background:Highlight}
            .form-control:focus,.search-box input:focus,.chat-input input:focus,.chat-search input:focus{outline:2px solid Highlight}
            .btn,.badge-status,.level-badge{border:1px solid ButtonText}
        }

        /* ===== Notification system ===== */
        /* Header bell + badge */
        /* Header controls with their word (index.html, UX rule). Phones: theme and sign-out move to the side menu
           and the «المزيد» sheet; «القائمة» opens the side menu. */
        .hdr-theme .fa-sun,.hdr-theme .hdr-to-light{display:none}
        :root[data-theme="dark"] .hdr-theme .fa-moon,:root[data-theme="dark"] .hdr-theme .hdr-to-dark{display:none}
        :root[data-theme="dark"] .hdr-theme .fa-sun,:root[data-theme="dark"] .hdr-theme .hdr-to-light{display:inline}
        .hdr-theme--login{position:fixed;top:calc(var(--spacingVerticalM) + env(safe-area-inset-top,0px));left:calc(var(--spacingHorizontalM) + env(safe-area-inset-left,0px));z-index:60}
        .hdr-bell{position:relative}
        .hdr-bell .notif-bell-badge{position:static;box-shadow:none}
        /* Phones: the header controls stay on one line (mobile review: with the 13/15px phone text they wrapped at 360px).
           On narrow phones the decorative avatar icon steps aside; the role word stays. */
        @media(max-width:768px){#app > header .flex-wrap{flex-wrap:nowrap}}
        @media(max-width:480px){#app > header .fa-user-circle{display:none}}
        .hdr-menu{display:none}
        .menu-extra{display:none}
        @media(max-width:768px){
            #app > header .hdr-theme,#app > header .hdr-logout{display:none}
            .hdr-menu{display:inline-flex}
            .menu-extra{display:flex;flex-direction:column;gap:var(--spacingVerticalS);margin:var(--spacingVerticalL) 0 0;padding:var(--spacingVerticalM) var(--spacingHorizontalM);border-top:var(--strokeWidthThin) solid var(--colorNeutralStroke2);position:sticky;bottom:calc(-1 * var(--spacingVerticalM));background:var(--bg)}
            .menu-extra .btn{justify-content:flex-start;min-height:var(--touchTarget)}
        }
        .notif-bell-wrap{position:relative;display:inline-flex}
        .notif-bell{position:relative}
        .notif-bell-badge{position:absolute;top:0;left:0;min-width:16px;height:16px;padding:0 var(--spacingHorizontalXS);background:var(--solid-danger);color:var(--colorNeutralForegroundOnBrand);border-radius:var(--borderRadiusCircular);font-size:var(--fontSizeBase100);font-weight:var(--fontWeightSemibold);align-items:center;justify-content:center;line-height:1;box-shadow:0 0 0 2px var(--colorNeutralBackground1)}

        /* Header dropdown (Fluent Popover) */
        .notif-dropdown{position:absolute;top:44px;left:0;width:340px;max-width:88vw;background:var(--colorNeutralBackground1);border:var(--strokeWidthThin) solid var(--colorNeutralStroke3);border-radius:var(--borderRadiusMedium);box-shadow:var(--shadow16);z-index:1100;overflow:hidden;animation:popIn var(--durationNormal) var(--curveDecelerateMid)}
        @keyframes popIn{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}
        .ndd-head{display:flex;align-items:center;justify-content:space-between;gap:var(--spacingHorizontalS);padding:var(--spacingVerticalMNudge) var(--spacingHorizontalM);border-bottom:var(--strokeWidthThin) solid var(--colorNeutralStroke2);font-weight:var(--fontWeightSemibold);font-size:var(--fontSizeBase300);color:var(--text)}
        .ndd-list{max-height:60vh;overflow-y:auto}
        .ndd-empty{text-align:center;padding:var(--spacingVerticalXXL) var(--spacingHorizontalMNudge);color:var(--text-faint);font-size:var(--fontSizeBase300)}
        button.ndd-item{width:100%;border-width:0 0 var(--strokeWidthThin);border-style:solid;border-color:var(--colorNeutralStroke2);background:transparent;color:inherit;font:inherit;text-align:start}
        .ndd-body,.ndd-title,.ndd-msg,.ndd-time{display:block}
        .ndd-new{margin-inline-start:var(--spacingHorizontalXS);font-size:var(--fontSizeBase100)}
        .ndd-item{display:flex;gap:var(--spacingHorizontalMNudge);align-items:flex-start;padding:var(--spacingVerticalMNudge) var(--spacingHorizontalM);border-bottom:var(--strokeWidthThin) solid var(--colorNeutralStroke3);cursor:pointer;transition:background-color var(--durationFaster) var(--curveEasyEase);position:relative}
        .ndd-item:hover{background:var(--colorSubtleBackgroundHover)}
        .ndd-item.unread{background:var(--colorBrandBackground2)}
        .ndd-item.unread:hover{background:var(--colorBrandBackground2Hover)}
        .ndd-icon{flex-shrink:0;width:32px;height:32px;border-radius:var(--borderRadiusMedium);display:flex;align-items:center;justify-content:center;font-size:var(--fontSizeBase400)}
        .ndd-body{min-width:0;flex:1}
        .ndd-title{font-weight:var(--fontWeightSemibold);font-size:var(--fontSizeBase300);color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
        /* A long title is cut with «…», never the «جديد» label after it (MOBILE_REVIEW.md). */
        .ndd-body .ndd-title{display:flex;align-items:center;gap:var(--spacingHorizontalXS);overflow:visible}
        .ndd-title-text{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
        .ndd-title .ndd-new{flex:none;margin-inline-start:0}
        .ndd-msg{font-size:var(--fontSizeBase200);color:var(--text-muted);margin-top:var(--spacingVerticalNone);overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
        .ndd-time{font-size:var(--fontSizeBase100);color:var(--text-faint);margin-top:var(--spacingVerticalXXS)}
        .ndd-dot{flex-shrink:0;width:8px;height:8px;border-radius:50%;background:var(--colorBrandBackground);margin-top:var(--spacingVerticalSNudge)}
        .ndd-foot{padding:var(--spacingVerticalS) var(--spacingHorizontalM);border-top:var(--strokeWidthThin) solid var(--colorNeutralStroke2);text-align:center}
        .ndd-foot .btn{width:100%}

        /* Notifications page rows */
        .notif-list{margin-top:var(--spacingVerticalXS)}
        .notif-row{display:flex;gap:var(--spacingHorizontalM);align-items:flex-start;padding:var(--spacingVerticalM);border-bottom:var(--strokeWidthThin) solid var(--colorNeutralStroke2);background:transparent;transition:background-color var(--durationFaster) var(--curveEasyEase)}
        .notif-row:hover{background:var(--colorSubtleBackgroundHover)}
        .notif-row.unread{background:var(--colorBrandBackground2)}
        .notif-cat-icon{flex-shrink:0;width:40px;height:40px;border-radius:var(--borderRadiusLarge);display:flex;align-items:center;justify-content:center;font-size:var(--fontSizeBase400)}
        .notif-main{flex:1;min-width:0}
        .notif-row-head{display:flex;align-items:center;gap:var(--spacingHorizontalS);flex-wrap:wrap}
        .notif-row-title{font-weight:var(--fontWeightSemibold);font-size:var(--fontSizeBase400);color:var(--text)}
        .notif-cat-chip{font-size:var(--fontSizeBase100);font-weight:var(--fontWeightSemibold);padding:0 var(--spacingHorizontalS);border-radius:var(--borderRadiusCircular)}
        .notif-new-dot{width:8px;height:8px;border-radius:50%;background:var(--colorBrandBackground);display:inline-block}
        .notif-row-msg{color:var(--text-muted);font-size:var(--fontSizeBase300);margin-top:var(--spacingVerticalXS);word-break:break-word}
        .notif-row-time{font-size:var(--fontSizeBase200);color:var(--text-faint);margin-top:var(--spacingVerticalSNudge);display:flex;align-items:center;gap:var(--spacingHorizontalXS)}
        .notif-unread-count{font-size:var(--fontSizeBase200);font-weight:var(--fontWeightSemibold);color:var(--tint-brand-fg);background:var(--tint-brand-bg);padding:0 var(--spacingHorizontalS);border-radius:var(--borderRadiusCircular);margin-inline-start:var(--spacingHorizontalSNudge)}

        /* Category colours (shared by dropdown icons and page chips/icons) */
        .cat-success,.cat-money{background:var(--tint-success-bg);color:var(--tint-success-fg)}
        .cat-error{background:var(--tint-danger-bg);color:var(--tint-danger-fg)}
        .cat-warning{background:var(--tint-warning-bg);color:var(--tint-warning-fg)}
        .cat-info{background:var(--tint-brand-bg);color:var(--tint-brand-fg)}
        .cat-lesson{background:var(--tint-purple-bg);color:var(--tint-purple-fg)}
        .cat-msg{background:var(--tint-teal-bg);color:var(--tint-teal-fg)}
        .cat-account{background:var(--tint-neutral-bg);color:var(--tint-neutral-fg)}

        /* Permission opt-in banner */
        .notif-perm-banner{position:static;margin:0 auto var(--spacingVerticalM);width:auto;max-width:720px;background:var(--colorNeutralBackground1);border:var(--strokeWidthThin) solid var(--colorNeutralStroke2);border-radius:var(--borderRadiusLarge);box-shadow:var(--shadow8);padding:var(--spacingVerticalM) var(--spacingHorizontalL);display:flex;align-items:center;gap:var(--spacingHorizontalM);z-index:9998;animation:slideUp var(--durationGentle) var(--curveDecelerateMid)}
        .notif-perm-banner .npb-icon{flex-shrink:0;width:44px;height:44px;border-radius:var(--borderRadiusLarge);background:var(--colorBrandBackground2);color:var(--colorBrandForeground1);display:flex;align-items:center;justify-content:center;font-size:var(--fontSizeBase500)}
        .notif-perm-banner .npb-text{flex:1;min-width:0}
        .notif-perm-banner .npb-title{font-weight:var(--fontWeightSemibold);font-size:var(--fontSizeBase400);color:var(--text)}
        .notif-perm-banner .npb-sub{font-size:var(--fontSizeBase200);color:var(--text-muted);margin-top:var(--spacingVerticalXXS)}
        .notif-perm-banner .npb-actions{display:flex;gap:var(--spacingHorizontalS);flex-shrink:0}
        @keyframes slideUp{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
        @media (max-width:640px){
            .notif-perm-banner{flex-direction:column;align-items:stretch;text-align:center}
            .notif-perm-banner .npb-actions{justify-content:center}
            .notif-dropdown{position:fixed;top:calc(56px + env(safe-area-inset-top,0px));left:calc(8px + env(safe-area-inset-left,0px));right:calc(8px + env(safe-area-inset-right,0px));width:auto}
        }

/* ============================================================
   Fixed Bottom Navigation Bar (mobile) — built from the same
   role-based menu items as the sidebar; see buildBottomNav() in app.js.
   ============================================================ */
.bottom-nav-bar {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    /* Fixed positioning takes this out of body's flow, so it doesn't get body's
       safe-area padding — grow the box itself and pad the extra into the inset
       so the icons stay in the original 64px zone, above the home-indicator /
       gesture-nav area, instead of being obscured by it. */
    height: calc(var(--layout-bottombar-h) + env(safe-area-inset-bottom, 0px));
    padding-bottom: env(safe-area-inset-bottom, 0px);
    background: var(--colorNeutralBackground1);
    border-top: var(--strokeWidthThin) solid var(--colorNeutralStroke2);
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: space-around;
    /* padding-inline only: a "padding" shorthand here would reset the padding-bottom above to 0 and put the
       icons back over the iPhone home indicator. Landscape notches get their side insets too. */
    padding-inline: calc(var(--spacingHorizontalSNudge) + env(safe-area-inset-right, 0px)) calc(var(--spacingHorizontalSNudge) + env(safe-area-inset-left, 0px));
}

.bottom-nav-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    flex: 1;
    min-width: 0;
    height: 100%;
    color: var(--colorNeutralForeground3);
    background: transparent;
    border: none;
    cursor: pointer;
    transition: color var(--durationFaster) var(--curveEasyEase);
    text-decoration: none;
    position: relative;
    padding: var(--spacingVerticalSNudge) 0;
    user-select: none;
}

.bottom-nav-item:hover {
    color: var(--colorNeutralForeground2Hover);
}

.bottom-nav-item.active {
    color: var(--colorBrandForeground1);
}

.bottom-nav-item.active .nav-label {
    font-weight: var(--fontWeightSemibold);
}

.bottom-nav-item .nav-icon-wrap {
    position: relative;
    font-size: var(--fontSizeBase500);
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Fluent mobile tab bars use the 10px caption size, so five Arabic labels fit on a 360px phone. */
.bottom-nav-item .nav-label {
    font-size: var(--fontSizeBase100);
    line-height: var(--lineHeightBase100);
    margin-top: var(--spacingVerticalXS);
    white-space: nowrap;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
}

.bottom-nav-item .badge-dot, .more-sheet-item .badge-dot {
    position: absolute;
    top: -8px;
    right: -12px;
    background: var(--solid-danger);
    color: var(--colorNeutralForegroundOnBrand);
    font-size: var(--fontSizeBase200);
    font-weight: var(--fontWeightSemibold);
    min-width: 20px;
    height: 20px;
    border-radius: var(--borderRadiusCircular);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 var(--spacingHorizontalXS);
    box-shadow: 0 0 0 2px var(--colorNeutralBackground1);
    line-height: 1;
}

/* "More" (المزيد) bottom sheet — lists every secondary (non-primary) sidebar
   item that didn't fit directly on the bottom bar. */
.more-sheet-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: var(--colorBackgroundOverlay);
    z-index: 1002;
}

.more-sheet-overlay.open {
    display: block;
}

.more-sheet-panel {
    overscroll-behavior: contain;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    background: var(--colorNeutralBackground1);
    border-radius: var(--borderRadiusXLarge) var(--borderRadiusXLarge) 0 0;
    box-shadow: var(--shadow64);
    z-index: 1003;
    max-height: 70vh;
    display: flex;
    flex-direction: column;
    transform: translateY(100%);
    transition: transform var(--durationSlow) var(--curveDecelerateMid);
    /* fixed + bottom:0, so (like the bar itself) it needs its own safe-area accounting */
    padding-bottom: calc(var(--layout-bottombar-h) + env(safe-area-inset-bottom, 0px));
}

.more-sheet-panel.open {
    transform: translateY(0);
}

.more-sheet-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: var(--spacingVerticalM) var(--spacingHorizontalL);
    border-bottom: var(--strokeWidthThin) solid var(--colorNeutralStroke2);
    font-weight: var(--fontWeightSemibold);
    font-size: var(--fontSizeBase400);
    flex-shrink: 0;
}

.more-sheet-body {
    overflow-y: auto;
    padding: var(--spacingVerticalM);
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--spacingHorizontalS);
}

/* «المزيد» uses the side menu's sections: a label over each group of tiles. */
.more-sheet-section { display: contents; }
.more-sheet-group {
    grid-column: 1 / -1;
    padding-top: var(--spacingVerticalS);
    font-size: var(--fontSizeBase200);
    line-height: var(--lineHeightBase200);
    font-weight: var(--fontWeightSemibold);
    color: var(--colorNeutralForeground3);
}
.more-sheet-item.active { background: var(--nav-selected); box-shadow: inset 0 0 0 var(--strokeWidthThick) var(--colorCompoundBrandStroke); }
.more-sheet-extra {
    grid-column: 1 / -1;
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacingHorizontalS);
    padding-top: var(--spacingVerticalS);
    border-top: var(--strokeWidthThin) solid var(--colorNeutralStroke2);
}
.more-sheet-extra .btn { flex: 1 1 0; min-height: var(--touchTarget); }

.more-sheet-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--spacingVerticalSNudge);
    padding: var(--spacingVerticalM) var(--spacingHorizontalSNudge);
    border-radius: var(--borderRadiusLarge);
    background: var(--colorSubtleBackgroundHover);
    border: none;
    cursor: pointer;
    position: relative;
    transition: background-color var(--durationFaster) var(--curveEasyEase);
}

.more-sheet-item:hover, .more-sheet-item:active {
    background: var(--colorSubtleBackgroundPressed);
}

.more-sheet-item i {
    font-size: var(--fontSizeBase500);
    color: var(--colorBrandForeground1);
}

.more-sheet-item span {
    font-size: var(--fontSizeBase200);
    font-weight: var(--fontWeightSemibold);
    color: var(--text);
    text-align: center;
    line-height: 1.3;
}

/* The counter's number is white on red: `.more-sheet-item span` above would make it dark (2.6:1, MOBILE_REVIEW.md). */
.more-sheet-item .badge-dot, .more-sheet-item .badge-dot span, .bottom-nav-item .badge-dot span {
    color: var(--colorNeutralForegroundOnBrand);
    line-height: 1;
}

.more-sheet-item .badge-dot {
    position: absolute;
    top: var(--spacingVerticalSNudge);
    right: var(--spacingHorizontalMNudge);
}

/* The bottom nav bar + "More" sheet are a mobile-only affordance — desktop
   keeps the full sidebar, so hide them past the sidebar-drawer breakpoint. */
@media (min-width: 769px) {
    .bottom-nav-bar, .more-sheet-overlay, .more-sheet-panel {
        display: none !important;
    }
}

/* Phones: the assistant's floating button never covers a save button or the last rows of a table (#27). Pages get
   room below their content, and the button steps aside while a form is being filled in or a dialog is open. */
@media (max-width: 768px) {
    #app main { padding-bottom: calc(var(--controlHeightLarge) + var(--spacingVerticalXXL)); }
    body:has(#app main form:focus-within) #pa-dock,
    body:has(#app main [data-form]:focus-within) #pa-dock,
    body:has(#modal.open) #pa-dock { display: none; }
}
@media (max-width: 768px) {
    #app {
        /* 64px clears the bar itself; the extra 16px is a safety margin against
           browsers/edge-cases where the dynamic-toolbar height calc (see the
           100dvh comment on body, above) isn't exact, so the last bit of page
           content never ends up flush against — or under — the bar. */
        padding-bottom: calc(var(--layout-bottombar-h) + var(--spacingVerticalL));
    }
    /* Fixed-position overlays anchor to the viewport, not #app, so they don't
       inherit its padding-bottom — without this the bottom-nav-bar sits on
       top of (and mostly hides) this banner. Clear the 64px bar (plus its own
       safe-area growth on notch/gesture-nav phones) and the banner's 18px gap. */
    .notif-perm-banner {
        bottom: auto;
    }
}

/* Touch screens: every tab, sort header, pager and list control is at least 44×44 (UX_PLAN 5). */
@media (pointer:coarse){
    .session-tab,.report-tab,.pg-sort,.cal-viewbtn,.cal-todaybtn{min-height:var(--touchTarget)}
    .pg-sort{display:inline-flex;align-items:center;padding-inline:var(--spacingHorizontalXS)}
    .pg-nav{gap:var(--spacingHorizontalS)}
}

/* A message at the top of a page the router opened instead of the one asked for (router.js#routeNotice). */
.rt-notice{margin-bottom:var(--spacingVerticalL)}

/* Faint logo watermark in the top-left corner of the page area (below the header; not on login). */
.app-watermark{background-image:url(/icons/app-watermark.svg);background-repeat:no-repeat;background-position:left 16px top 16px;background-size:clamp(150px,25vw,300px) auto}

/* A page's helper line under its title (PM 8: the family's pages, `pageHelpHtml`). The title card is dissolved, so it
   sits on the canvas like a subtitle. */
.page-help{margin:0 0 var(--spacingVerticalM);font-size:var(--fontSizeBase300);line-height:var(--lineHeightBase300);color:var(--colorNeutralForeground2)}
/* «المزيد» items with a helper line (PM 8) take a whole row: icon, then the name over its line, read from the start. */
.more-sheet-item--help{grid-column:1 / -1;flex-direction:row;justify-content:flex-start;align-items:center;gap:var(--spacingHorizontalM);padding:var(--spacingVerticalS) var(--spacingHorizontalM);min-height:var(--touchTarget)}
.more-sheet-item--help .more-sheet-text{display:flex;flex-direction:column;align-items:flex-start;gap:var(--spacingVerticalXXS);min-width:0}
.more-sheet-item--help .more-sheet-text > span{text-align:start}
.more-sheet-item .more-sheet-help{font-weight:var(--fontWeightRegular);color:var(--colorNeutralForeground3);overflow-wrap:anywhere}
