/* =====================================================================
   Hackers.Training — front-end design system
   Dark "terminal HUD" aesthetic carried over from the original single-file
   prototype, re-expressed as a proper stylesheet with logical properties so
   a single rule set serves both RTL (Arabic) and LTR (English).
   ===================================================================== */
:root{
  /* Dark theme built on the brand navy #1C285B rather than the old near-black,
     with the brand red #840505 as the offensive accent and pure white text
     (not the previous light grey).
     Contrast note: #840505 and #1C285B are dark, so they carry *surfaces* here
     — cards, bars, buttons — with white text over them (10.5:1 and 14:1).
     Used as text on a dark background they would sit at ~1.4:1 and be
     unreadable, so the two --*-lit tints below are what colour any text; each
     clears 4.5:1 on the page background. */
  --night:#0D1430;          /* page background: the brand navy, deepened */
  --surface:#1C285B;        /* cards — the brand navy, exact */
  --surface-2:#26356F;      /* insets: table stripes, code blocks, wells */
  --line:#3A4788;           /* hairlines */
  --ink:#FFFFFF;            /* body text: pure white, not light grey */
  --ink-dim:#AFBADA;        /* secondary text, 8.4:1 on the page */

  /* Brand colours, exactly as specified:
       Hackers / اخترق  #750404
       Training / تدرّب #1C285B
       دافع            white                                             */
  --blue:#1C285B; --blue-deep:#101B42;
  --red:#750404;  --red-deep:#4E0202;
  /* Readable tints, still used for interface accents (links, pills, borders)
     where the brand colours would be unreadable on a dark surface. The
     wordmark and slogan themselves use the exact values above. */
  --red-lit:#CE1126; --blue-lit:#0D57A0;
  /* Hover ink. The brand red measures 2.48:1 on a card and 3.22:1 on the page
     — visible, but under the 4.5:1 that ordinary text needs to be comfortably
     readable. This is that same red lifted 40% towards white: still plainly the
     brand red, but 4.55:1 on a card and 5.90:1 on the page, so a link the
     pointer is resting on is easier to read than the rest of the line, not
     harder. The exact brand values remain untouched on the wordmark, the
     slogan and the certificate. */
  --red-hover:#E2707D;
  --silver:#C9D4E4; --silver-deep:#8792AE;

  --gold:#F2B33D; --gold-deep:#C98A16;
  --teal:#2FD3B4; --teal-deep:#1E8E7B;
  --violet:#9B7BFF; --green:#3ECF7A;

  --mono:'IBM Plex Mono',ui-monospace,monospace;
  --radius:14px; --accent:var(--blue-lit);
}
*{margin:0;padding:0;box-sizing:border-box}
html{scroll-behavior:smooth}
body{font-family:'Tajawal',system-ui,sans-serif;background:var(--night);color:var(--ink);
  min-height:100vh;line-height:1.7;overflow-x:hidden}
body[dir="ltr"]{font-family:'Inter',system-ui,sans-serif}
/* Depth washes: navy lifting from the base, one ember of the offensive red. */
body::before{content:'';position:fixed;inset:0;pointer-events:none;z-index:0;opacity:.9;
  background:
    radial-gradient(ellipse 60% 45% at 50% -12%, rgba(126,147,224,.10), transparent),
    radial-gradient(ellipse 55% 40% at 12% 106%, rgba(28,40,91,.55), transparent),
    radial-gradient(ellipse 45% 35% at 92% 94%, rgba(132,5,5,.22), transparent);}

/* No lattice or grid overlay: the page depth comes from the colour washes
   above alone. */
#app{position:relative;z-index:1;max-width:1140px;margin:0 auto;padding:0 20px 90px}
/* Administration is data, not prose.
   1140px is a reading measure — roughly ninety characters, which is where
   prose is comfortable and where an eleven-column table is not: the card
   stops at the measure and the table does not, so the background ends
   somewhere in the middle of its own content. These screens take the window
   instead, and everything a trainee reads keeps the measure. */
body[data-view="admin"] #app{max-width:none}

h1,h2,h3{font-weight:900;line-height:1.35}
a{color:var(--teal);text-decoration:none}
.mono{font-family:var(--mono)}
.hidden{display:none!important}
.eyebrow{font-family:var(--mono);font-size:.72rem;letter-spacing:.18em;color:var(--accent);
  text-transform:uppercase;margin-bottom:8px}
.eyebrow .atk{color:var(--red-lit)}
.eyebrow .tld{color:var(--blue-lit)}
.muted{color:var(--ink-dim)}
.center{text-align:center}

/* ---------- Top bar ---------- */
/* Full-bleed bar whose contents line up with the 1140px content column.
   (It is a direct child of <body>, which has no padding, so a negative margin
   here would push the brand off-screen.) */
/* Plain dark masthead: a clean near-black gradient, no lattice or sheen,
   closed by the red→navy edge below. */
/* One line, always, on anything wider than a phone.
   The bar wrapped because the navigation grew -- adding المختبرات pushed the
   language key onto a second row, where it sat under the logo looking like a
   mistake. The nav is the part that should give way, not the two things that
   anchor the ends: the brand at one end, the language key at the other. */
.topbar{position:sticky;top:0;z-index:60;display:flex;align-items:center;gap:16px;
  margin:0;padding:14px 20px;flex-wrap:nowrap;min-height:var(--head-h);
  background:linear-gradient(178deg, #090D1A 0%, #12182F 55%, #05070E 100%);
  border-bottom:none;
  box-shadow:0 6px 22px rgba(0,0,0,.6)}
/* The red edge fades into the navy across the bar. */
.topbar::after{content:'';position:absolute;inset-inline:0;bottom:0;height:3px;
  background:linear-gradient(90deg,#750404 0%,#750404 34%,#1C285B 66%,#1C285B 100%)}
/* One row, and a column beside the page.

   The header had grown to two rows because everything wanted to live on it:
   brand, tagline, five destinations, a greeting carrying a full name,
   sign-out and a language key. A row is a fixed budget, and الإدارة alone
   needs ten entries. So the destinations moved to a column — where a list can
   be as long as it needs to be — and the header keeps what is about the
   person: who is signed in, their language, and the way out. */
/* The mark is the reason the header exists, so it is drawn at full size and
   the header is as tall as that needs. Still one row rather than the two it
   replaced — the destinations are in the column now. */
/* A starting value only: renderTopbar measures the header and overwrites it,
   because a number typed here goes stale the moment the brand changes size. */
:root{--head-h:104px;--nav-w:246px}
body{--nav-cur:var(--nav-w)}
/* Hidden means gone, and the page takes the width back. */
body.nav-hidden{--nav-cur:0px}
/* And with nobody signed in there is no column at all — nor a handle for one,
   which would be a control that moves nothing. */
body.nav-none{--nav-cur:0px}
body.nav-none .sidenav,body.nav-none .nav-toggle{display:none}
/* The public destinations, on the header while there is room for them. */
.pubnav{display:flex;align-items:center;gap:8px;flex:0 0 auto}
/* The page steps aside for the column; the header spans the whole width, so
   the brand stays in the corner where a brand belongs. */
#app,.sitefooter,#sectionnav{padding-inline-start:calc(var(--nav-cur) + 20px)}
.topbar > .spacer{flex:1 1 0;min-width:0}
.topbar > .bar-end{flex:0 0 auto;display:flex;align-items:center;gap:8px}

/* The handle, on the column's own edge.

   A quarter of the way down the page, where a hand reaches without crossing
   the whole screen, and travelling with the column so it always marks the
   boundary it moves. The chevron points the way pressing it will go: inward
   when the column is open, outward when it is away. */
.nav-toggle{position:fixed;top:25%;z-index:56;
  inset-inline-start:var(--nav-cur);
  width:22px;height:58px;display:flex;align-items:center;justify-content:center;
  cursor:pointer;padding:0;
  border:1px solid #2A3352;border-inline-start:none;
  border-start-end-radius:9px;border-end-end-radius:9px;
  background:linear-gradient(165deg,rgba(126,147,224,.14),rgba(8,11,24,.96));
  box-shadow:2px 0 10px rgba(0,0,0,.45);
  transition:inset-inline-start .2s ease,border-color .18s,background .18s}
.nav-toggle:hover,.nav-toggle:focus-visible{border-color:var(--blue-lit);
  background:linear-gradient(165deg,rgba(126,147,224,.28),rgba(10,14,29,.98))}
/* Built from physical edges, deliberately. `border-inline-start` is the right
   edge in an RTL document and the left edge in an LTR one, so the same two
   declarations made a corner facing opposite ways in the two languages and no
   single rotation could be right for both — which is why it pointed up and
   down instead of along the row.

   top + left borders give a corner facing up-left: -45deg turns it to point
   left, 135deg to point right. The chevron always points the way the column
   will travel when pressed. */
.nav-toggle .chev{width:7px;height:7px;
  border-left:2px solid #C6D2F2;border-top:2px solid #C6D2F2;
  transition:rotate .2s ease,border-color .18s}
/* RTL: the column lives on the right. Open, pressing sends it right; away,
   pressing brings it back leftward. */
.nav-toggle .chev{rotate:135deg;margin-left:-3px}
.nav-toggle[aria-expanded="false"] .chev{rotate:-45deg;margin-left:3px}
/* LTR: the column is on the left, so both readings mirror. */
[dir="ltr"] .nav-toggle .chev{rotate:-45deg;margin-left:3px}
[dir="ltr"] .nav-toggle[aria-expanded="false"] .chev{rotate:135deg;margin-left:-3px}
.nav-toggle:hover .chev{border-color:#FFFFFF}

.brand-mini{display:flex;align-items:center;gap:14px;font-weight:900;letter-spacing:.02em;
  flex:0 0 auto}
/* The header brand plate is a link to the main page; give it the affordance. */
.brand-plate[data-go]{cursor:pointer}
.brand-plate[data-go]:hover{filter:brightness(1.08)}
.brand-plate[data-go]:focus-visible{outline:2px solid var(--blue-lit);outline-offset:4px;border-radius:10px}

/* Who is signed in, in words. The name is never shortened — that was the
   fault the two-row bar was trying and failing to solve — and there is no
   monogram beside it: two letters in a coloured square reads as a photograph
   that failed to load, and the platform holds no photograph to show. */
.greet{margin:0;min-width:0;flex:0 1 auto;font-size:.86rem;line-height:1.35;
  color:var(--ink-dim)}
.greet-hi{opacity:.85}
.greet b{color:var(--ink);font-weight:800}

/* The two keys that act on the session rather than navigate. */
.hkey{display:flex;align-items:center;gap:7px;padding:7px 12px;cursor:pointer;
  border:1px solid #2A3352;border-radius:9px;color:#C6D2F2;font:inherit;
  font-size:.82rem;font-weight:700;white-space:nowrap;
  background:linear-gradient(165deg,rgba(126,147,224,.10),rgba(6,9,20,.55));
  box-shadow:inset 0 1px 0 rgba(255,255,255,.05);
  transition:color .18s,border-color .18s,background .18s}
.hkey:hover,.hkey:focus-visible{color:#FFFFFF;border-color:var(--blue-lit);
  background:linear-gradient(165deg,rgba(126,147,224,.22),rgba(10,14,29,.7))}
/* The one destructive control takes the brand red, so it is identifiable
   without being read. */
.hkey.out{color:#E8A0A0}
.hkey.out:hover,.hkey.out:focus-visible{color:#FFE9E9;border-color:#B23B3B;
  background:linear-gradient(165deg,rgba(117,4,4,.34),rgba(20,6,6,.7))}
.hkey .flag{width:20px;height:14px;border-radius:2px;object-fit:cover}

/* ---------- The column ---------- */
.sidenav{position:fixed;inset-block:var(--head-h) 0;inset-inline-start:0;z-index:55;
  width:var(--nav-cur);overflow-y:auto;overflow-x:hidden;padding:14px 10px 26px;
  background:linear-gradient(180deg,#0B1020 0%,#080B18 100%);
  border-inline-end:1px solid #1B2136;
  transition:width .2s ease,translate .22s ease;scrollbar-width:thin}
.nav-group{margin-bottom:6px}
/* Each group's head is a dropdown toggle; its items collapse beneath it. */
.nav-head{display:flex;align-items:center;justify-content:space-between;gap:8px;
  width:100%;margin:0;padding:9px 13px;cursor:pointer;
  border:1px solid transparent;border-radius:9px;background:none;
  font:inherit;font-size:.86rem;font-weight:800;letter-spacing:.04em;
  text-transform:uppercase;color:#6B7AA3;white-space:nowrap;text-align:start;
  transition:color .18s,border-color .18s,background .18s}
.nav-head:hover,.nav-head:focus-visible{color:#C6D2F2;border-color:var(--blue-lit);
  background:linear-gradient(165deg,rgba(126,147,224,.14),rgba(10,14,29,.55))}
.nav-head-label{overflow:hidden;text-overflow:ellipsis}
/* Caret: points down when closed, up when open. */
.nav-chev{width:7px;height:7px;flex:0 0 auto;
  border-right:2px solid currentColor;border-bottom:2px solid currentColor;
  rotate:45deg;transition:rotate .2s ease}
.nav-group.open .nav-chev{rotate:-135deg}
.nav-group-items{display:flex;flex-direction:column;gap:2px;margin-top:2px;
  padding-inline-start:8px}
.nav-group-items[hidden]{display:none}
.nav-item{display:flex;align-items:center;width:100%;padding:9px 13px;
  margin-bottom:2px;cursor:pointer;border:1px solid transparent;border-radius:9px;
  background:none;color:#C6D2F2;font:inherit;font-size:.86rem;font-weight:700;
  text-align:start;transition:color .18s,border-color .18s,background .18s}
.nav-item:hover,.nav-item:focus-visible{color:#FFFFFF;border-color:var(--blue-lit);
  background:linear-gradient(165deg,rgba(126,147,224,.18),rgba(10,14,29,.6))}
/* Where you are, marked the way the platform marks a current thing. */
.nav-item.here{color:#FFFFFF;border-color:var(--blue-lit);
  background:linear-gradient(165deg,rgba(13,87,160,.55),rgba(10,14,29,.85));
  box-shadow:inset 0 1px 0 rgba(255,255,255,.10)}
.nav-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* Hidden: the column goes, rather than shrinking into a strip of blank rows.
   The entries carry names and nothing else now, so there is no icon rail to
   fall back to — and 70px of nothing is worse than the width it was keeping. */
body.nav-hidden .sidenav{translate:100% 0;border-inline-end:none}
[dir="ltr"] body.nav-hidden .sidenav{translate:-100% 0}

.nav-scrim{position:fixed;inset:0;z-index:54;background:rgba(4,7,18,.6);
  backdrop-filter:blur(2px)}

@media (max-width:900px){
  /* No width to trade on a narrow screen, so the column slides over the page
     and the next press anywhere else puts it away. */
  #app,.sitefooter,#sectionnav{padding-inline-start:20px}
  .sidenav{width:var(--nav-w);translate:100% 0}
  body.nav-open .sidenav,
  body.nav-open.nav-hidden .sidenav{translate:0 0;box-shadow:0 0 60px rgba(0,0,0,.7)}
  .hkey .hkey-label{display:none}
  .hkey{padding:7px 9px}
  .greet{font-size:.78rem}
  .greet-hi{display:none}
}
[dir="ltr"] .sidenav{translate:-100% 0}
@media (min-width:901px){ [dir="ltr"] .sidenav,.sidenav{translate:0 0} }

@media (max-width:560px){
  .greet b{max-width:34vw;display:inline-block;overflow:hidden;
    text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}
}
/* On a narrow screen the public header (brand + game/verify links + language)
   was wider than the viewport, so the links ran off the right edge. Let the bar
   wrap: the nav drops to its own full-width row and its buttons wrap, and the
   brand slogan shrinks so the first row fits. */
@media (max-width:680px){
  .topbar{flex-wrap:wrap;row-gap:8px}
  .pubnav{flex:1 1 100%;flex-wrap:wrap;justify-content:flex-start;gap:6px}
  .brand-tag{font-size:1.02rem}
}

@media (prefers-reduced-motion: reduce){
  .sidenav,.nav-toggle,.nav-toggle .bars i,.nav-item{transition:none}
}

.brand-plate{background:none;padding:0}
.wordmark-line{font-size:1.75rem;line-height:1.15;white-space:nowrap}
}
/* The logo file is silver artwork on a solid black plate, so it is used as a
   *luminance* mask rather than as a picture: the black plate masks to nothing
   and the bright artwork masks to solid, which is then filled with the theme
   gradient. That puts the shield in the same red→white→navy as the wordmark
   and the tagline instead of leaving it silver. */
/* Larger, and filled with the brand gradient through the luminance mask so the
   shield is fully legible on the white plate. */
/* On the dark bar the shield runs brand red → light core → brand navy, so the
   artwork keeps both brand colours while staying visible against black. */
/* The shield is filled with the brand colours themselves — red through a light
   core into blue — so the mark carries #CE1126 and #0D57A0 while its artwork
   stays visible against the dark bar.

   Masked on alpha, not luminance. The artwork in logo.png is a light outline
   on solid black, which wants a luminance mask; but `mask-mode: luminance` is
   not honoured everywhere, and where it is ignored the mask falls back to
   alpha — and that file has no alpha channel, so it is opaque everywhere and
   the mask reveals the entire square as a gradient rectangle. An @supports
   test does not catch it either: a browser can accept the declaration as
   valid and still not act on it.

   logo-mask.png is the same artwork with its luminance baked into an alpha
   channel, so ordinary default masking is correct. Regenerate it with
   scratchpad/_make_alpha_logo.py if the source mark ever changes. */
.logo-mark{display:block;width:104px;height:104px;flex:0 0 auto;
  background:linear-gradient(150deg,#CE1126 0%,#F2F5FB 50%,#0D57A0 100%);
  filter:drop-shadow(0 0 14px rgba(13,87,160,.45));
  -webkit-mask:url('../assets/logo-mask.png') center/contain no-repeat;
          mask:url('../assets/logo-mask.png') center/contain no-repeat}
/* The bar is light, so the sticky masthead needs its own separation from the
   dark page beneath rather than relying on the shared hairline. */
.topbar > *{position:relative;z-index:1}
/* The wordmark everywhere the name appears — top bar, hero, catalogue eyebrow
   and footer — in the exact brand colours as specified. */
/* Matching the certificate masthead exactly: on a dark ground the wordmark
   uses the readable values — Hackers in the lifted red, a white separator,
   Training in blue. No outline. */
.atk{color:#CE1126}
.dot{color:#FFFFFF}
.tld{color:#0D57A0}
.brand-text{display:flex;flex-direction:column;line-height:1.15}
/* تدرّب · اخترق · دافع under the wordmark, in the exact brand colours:
   تدرّب white, اخترق red, دافع navy. Sized up to sit as a companion to the
   wordmark rather than a footnote under it, but left at its natural width.

   Letter-spacing is deliberately absent. It was 0.14em, which on Arabic pulls
   apart letters that are meant to join — تدرّب is one connected word, not five
   separate glyphs — so the tracking that flattered the Latin was damaging the
   Arabic the platform actually leads with. */
/* Slogan "منصــة تدريــب الهاكــرز": elongated with kashida and stretched across
   80% of the wordmark width (space-between spreads the three words), sized up to
   read as a companion to the wordmark. No letter-spacing — it would break the
   Arabic letter joins the kashida is there to extend. */
.brand-tag{font-family:var(--mono);font-weight:700;font-size:1.3rem;
  text-transform:uppercase;color:var(--silver);margin-top:8px;
  width:80%;display:flex;justify-content:space-between;align-items:center;gap:8px;flex-wrap:nowrap}
/* منصة white, تدريب blue, الهاكرز red. English keeps the wordmark's own mapping:
   Hackers red, Training blue, Platform white. */
.brand-tag .s1{color:#FFFFFF}
.brand-tag .s2{color:#0D57A0}
.brand-tag .s3{color:#CE1126}
[dir="ltr"] .brand-tag .s1{color:#CE1126}
[dir="ltr"] .brand-tag .s3{color:#FFFFFF}
/* The English phrase has ~60% more characters than "Hackers.Training", so in
   monospace at the Arabic size it can't fit 80% of the wordmark width. Give it
   the proportional wordmark font in mixed case — far narrower per letter — so it
   can be sized right up close to the Arabic while still fitting inside 80%. */
[dir="ltr"] .brand-tag{font-family:inherit;text-transform:none;font-size:0.9rem}
.spacer{flex:1}
.lang-switch{display:flex;border:1px solid var(--line);border-radius:99px;overflow:hidden}
.lang-switch button{background:none;border:none;color:var(--ink-dim);padding:6px 12px;cursor:pointer;
  font-family:inherit;font-size:.82rem;display:flex;align-items:center;gap:6px}
.lang-switch button.active{background:var(--surface-2);color:var(--ink)}
.lang-switch .flag{width:20px;height:14px;border-radius:2px;object-fit:cover;display:inline-block}
.topnav{display:flex;gap:6px;flex-wrap:wrap}
/* The section bar: a horizontal echo of the side menu's current group, sitting
   at the top of the content area. Its inline-start padding comes from the shared
   rule above so its pills line up with the content beneath. */
.sectionnav{padding-top:16px;padding-inline-end:20px}
.sectionnav[hidden]{display:none}
.topnav button{background:none;border:1px solid var(--line);color:var(--ink-dim);padding:6px 14px;
  border-radius:99px;cursor:pointer;font-family:inherit;font-size:.85rem}
.topnav button:hover,.topnav button.active{color:var(--accent);border-color:var(--accent)}

/* ---------- HUD (gamification bar) ---------- */
.hud{display:flex;align-items:center;gap:14px;background:var(--surface);border:1px solid var(--line);
  border-radius:var(--radius);padding:14px 18px;margin:18px 0}
.hex{width:46px;height:52px;flex:0 0 auto;display:grid;place-items:center;
  clip-path:polygon(50% 0%,100% 25%,100% 75%,50% 100%,0% 75%,0% 25%);
  background:linear-gradient(160deg,var(--gold),var(--gold-deep));color:#1A1200;font-weight:900}
.hud .name{font-weight:700}
.hud .rank{font-size:.78rem;color:var(--gold)}
.xp-wrap{flex:1;min-width:150px}
.xp-meta{display:flex;justify-content:space-between;font-size:.72rem;color:var(--ink-dim);font-family:var(--mono)}
.xp-bar{height:8px;background:var(--surface-2);border-radius:99px;overflow:hidden;margin-top:4px}
.xp-fill{height:100%;width:0;background:linear-gradient(90deg,var(--gold-deep),var(--gold));
  border-radius:99px;transition:width .6s cubic-bezier(.2,.8,.2,1)}

/* ---------- Cards, buttons, forms ---------- */
.card{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:24px}
.grid{display:grid;gap:18px}
.g2{grid-template-columns:repeat(auto-fit,minmax(280px,1fr))}
.g3{grid-template-columns:repeat(auto-fit,minmax(240px,1fr))}
/* Primary action carries the offensive red; white text on #840505 is 10.5:1. */
.btn{display:inline-flex;align-items:center;gap:8px;font-family:inherit;font-weight:700;font-size:.98rem;
  background:linear-gradient(160deg,var(--red),var(--red-deep));color:#fff;border:none;
  border-radius:10px;padding:11px 26px;cursor:pointer;transition:transform .15s,box-shadow .15s}
.btn:hover{transform:translateY(-2px);box-shadow:0 8px 22px rgba(132,5,5,.24)}
.btn:disabled{opacity:.45;cursor:not-allowed;transform:none;box-shadow:none}
.btn.ghost{background:none;border:1px solid var(--line);color:var(--ink);transition:color .15s,border-color .15s}
/* The same collision as .attachment had: var(--blue) is #1C285B, the exact
   value of var(--surface), so a ghost button on a card lost its label the
   moment the pointer touched it. The lifted blue is the readable one.
   Danger buttons are left alone — `.btn.danger` below already gives them a
   readable red at rest and on hover. */
.btn.ghost:hover{border-color:var(--blue-lit);color:var(--blue-lit);box-shadow:none}
.btn.sm{padding:7px 16px;font-size:.85rem}
.btn.accent{background:linear-gradient(160deg,var(--blue),var(--blue-deep));color:#fff}
.field{margin-bottom:14px}
.field label{display:block;font-weight:700;font-size:.86rem;margin-bottom:6px}
.field input,.field select,.field textarea{width:100%;background:var(--night);border:1px solid var(--line);
  color:var(--ink);border-radius:10px;padding:11px 14px;font-family:inherit;font-size:.95rem}
.field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--accent)}
.row{display:flex;gap:12px;flex-wrap:wrap;align-items:center}
.pill{display:inline-block;padding:3px 12px;border-radius:99px;font-size:.74rem;font-family:var(--mono);
  border:1px solid var(--line);color:var(--ink-dim)}
.pill.gold{color:var(--gold);border-color:var(--gold-deep)}
.pill.teal{color:var(--teal);border-color:var(--teal-deep)}
.pill.red{color:var(--red-lit);border-color:var(--red)}
.pill.violet{color:var(--violet);border-color:var(--violet)}
.err{color:var(--red);font-size:.84rem;margin-top:8px;min-height:1em}

/* ---------- Hero ---------- */
.hero{display:grid;grid-template-columns:1.05fr .95fr;gap:44px;align-items:center;padding-top:5vh}
/* Same brand-tinted mark at hero size, with a soft navy halo behind it. */
.hero .logo{width:260px;height:260px;margin:0 auto 18px;
  filter:drop-shadow(0 0 30px rgba(126,147,224,.32))}
/* Same halo treatment as the masthead — no plate. */
.hero h1{font-size:clamp(2rem,5vw,3.2rem)}
.hero h1 .tld{font-family:var(--mono);color:#0D57A0;font-size:.5em}
.tagline{font-family:var(--mono);font-weight:700;font-size:clamp(1.15rem,2.6vw,1.75rem);
  letter-spacing:.04em;margin:6px 0 20px}
/* Slogan "تدرّب من الصفر حتى الاحتراف": تدرّب white, من الصفر حتى red, الاحتراف blue. */
.tagline .s1{color:#FFFFFF}.tagline .s2{color:#CE1126}.tagline .s3{color:#0D57A0}
/* The hero brand lockup reuses the header's brand-plate so it renders identically;
   it only needs a little space before the lead paragraph beneath it. */
.hero-brand{margin-bottom:22px}
.perk{display:flex;gap:12px;margin-bottom:12px}
.perk-ico{width:34px;height:38px;flex:0 0 auto;display:grid;place-items:center;
  clip-path:polygon(50% 0%,100% 25%,100% 75%,50% 100%,0% 75%,0% 25%);background:var(--surface-2);color:var(--teal)}
.perk b{display:block}.perk span{font-size:.84rem;color:var(--ink-dim)}

/* ---------- Catalogue ---------- */
.level-head{display:flex;align-items:center;gap:12px;margin:30px 0 14px}
.level-head .bar{width:5px;height:34px;border-radius:4px;background:var(--accent)}
.level-head h2{font-size:1.4rem}
.pathway-title{font-family:var(--mono);color:var(--ink-dim);font-size:.86rem;margin:16px 0 8px;
  border-inline-start:3px solid var(--line);padding-inline-start:10px}
.course-card{position:relative;overflow:hidden}
.course-card .code{font-family:var(--mono);font-size:.72rem;color:var(--accent);letter-spacing:.12em}
.course-card h3{font-size:1.05rem;margin:6px 0 8px}
.course-card .meta{display:flex;gap:8px;flex-wrap:wrap;font-size:.76rem;color:var(--ink-dim);font-family:var(--mono)}
/* Programme information on the card: a compact label/value list mirroring the
   معلومات البرنامج table on the course page. */
.cc-facts{margin-top:10px;padding-top:10px;border-top:1px solid var(--line);
  display:flex;flex-direction:column;gap:5px}
.cc-fact{display:flex;gap:8px;align-items:baseline;font-size:.76rem;line-height:1.5}
.cc-fact .k{flex:0 0 38%;color:var(--ink-dim);font-weight:700}
.cc-fact .v{flex:1;color:var(--ink);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
  overflow:hidden}
.course-card .price{margin-top:12px;display:flex;gap:10px;align-items:baseline}
.course-card .price .now{color:var(--gold);font-weight:900;font-size:1.1rem}
.course-card .price .was{color:var(--ink-dim);text-decoration:line-through;font-size:.85rem}
.stars{color:var(--gold);letter-spacing:2px}
.stars .off{color:var(--line)}

/* ---------- KSA meters ---------- */
.ksa-domain{margin-bottom:18px}
.ksa-domain h4{display:flex;justify-content:space-between;font-size:.9rem;margin-bottom:8px}
.meter{height:10px;background:var(--surface-2);border-radius:99px;overflow:hidden}
.meter i{display:block;height:100%;border-radius:99px;background:linear-gradient(90deg,var(--teal-deep),var(--teal))}
.ksa-knowledge .meter i{background:linear-gradient(90deg,var(--teal-deep),var(--teal))}
.ksa-skill .meter i{background:linear-gradient(90deg,var(--gold-deep),var(--gold))}
.ksa-ability .meter i{background:linear-gradient(90deg,#6a4fd0,var(--violet))}

/* ---------- Attachments ---------- */
.attachments{margin-top:22px;border-top:1px solid var(--line);padding-top:14px}
.attachments h3{font-size:.95rem;margin-bottom:10px}
.attachment{display:inline-flex;align-items:center;gap:8px;color:var(--ink);font-size:.9rem;
  padding:6px 0;text-decoration:none;transition:color .15s}
/* Hover was var(--blue) — #1C285B, the *identical* value to var(--surface),
   the card these links sit on: 1.00:1, so the link disappeared into its own
   background under the pointer. It now takes the lifted brand red, 4.55:1 on
   a card. */
.attachment:hover,.attachment:focus-visible{color:var(--red-hover);text-decoration:underline}
/* The description that trails a link is muted, and has to lift with it or the
   row half-changes colour. */
.attachment:hover .muted,.attachment:focus-visible .muted{color:var(--red-hover)}
.attach-row{display:flex;justify-content:space-between;align-items:center;gap:10px;
  padding:6px 0;border-top:1px solid var(--line)}
.field input[type=file]{padding:8px}

/* ---------- Rendered lesson content (Markdown subset) ---------- */
.lesson-body h2,.lesson-body h3,.lesson-body h4{margin:18px 0 8px;color:var(--accent)}
.lesson-body p{margin:10px 0}
.lesson-body ol{padding-inline-start:22px;margin:8px 0}
.lesson-body code{font-family:var(--mono);font-size:.88em;background:var(--surface-2);
  padding:1px 6px;border-radius:5px}
.lesson-body pre{background:var(--surface-2);border:1px solid var(--line);border-radius:10px;
  padding:14px;overflow-x:auto;margin:12px 0;direction:ltr;text-align:start}
.lesson-body pre code{background:none;padding:0;font-size:.85rem;line-height:1.6}
.lesson-body blockquote{border-inline-start:3px solid var(--blue-lit);padding-inline-start:14px;
  margin:12px 0;color:var(--ink-dim)}
.lesson-body hr{border:none;border-top:1px solid var(--line);margin:18px 0}
.lesson-body a{color:var(--blue-lit);text-decoration:underline}

/* Tables scroll inside their own box so a wide comparison table never
   sideways-scrolls the whole page. */
.md-table-wrap{overflow-x:auto;margin:14px 0}
.md-table{border-collapse:collapse;width:100%;font-size:.9rem}
.md-table th,.md-table td{border:1px solid var(--line);padding:8px 12px;text-align:start}
.md-table thead th{background:var(--surface-2);color:var(--ink);font-weight:700}
.md-table tbody tr:nth-child(even){background:rgba(255,255,255,.03)}

/* Callouts — note / tip / warning / danger */
.callout{display:flex;gap:12px;align-items:flex-start;margin:14px 0;padding:12px 14px;
  border-radius:10px;border-inline-start:4px solid var(--blue-lit);background:var(--surface-2)}
.callout>div{flex:1;min-width:0}
.callout p{margin:4px 0}
.callout ul{margin:6px 0;padding-inline-start:20px}
.callout-icon{font-size:1.1rem;line-height:1.6}
.callout.tip{border-inline-start-color:var(--teal)}
.callout.warn{border-inline-start-color:var(--gold)}
.callout.danger{border-inline-start-color:var(--red-lit)}
/* A correct answer. Teal rather than a new green: the palette already has one
   "this went well" colour, and a second would read as a different kind of
   success rather than the same one. */
.callout.ok{border-inline-start-color:var(--teal)}

/* ---------- التحديات — the practice hub ----------
   Five tabs in the body of the page rather than in the side menu: they switch
   between views of a single section, and promoting them would put the month's
   competition on the same footing as الدورات. */
.tabs{display:flex;gap:6px;flex-wrap:wrap;margin:0 0 18px;
  border-bottom:1px solid var(--line);padding-bottom:10px}
.tab{appearance:none;background:transparent;color:var(--ink-dim);cursor:pointer;
  border:1px solid transparent;border-radius:999px;padding:7px 15px;
  font:inherit;font-size:.86rem;font-weight:600}
.tab:hover{color:var(--ink);background:var(--surface-2)}
.tab.on{color:var(--ink);background:var(--surface-2);border-color:var(--line)}
.tab:focus-visible{outline:2px solid var(--teal);outline-offset:2px}

.drill-hud{background:linear-gradient(180deg,var(--surface-2),var(--surface))}

/* A pack card. Locked is dimmed, never hidden: the point of a gate is that
   the next one is visible, and a door nobody can see is a dead end rather
   than an incentive. */
.pack-card{transition:border-color .15s,transform .15s}
.pack-card:not(.locked):hover{border-color:var(--teal);transform:translateY(-2px)}
.pack-card:focus-visible{outline:2px solid var(--teal);outline-offset:2px}
.pack-card.locked{opacity:.62;border-style:dashed}

/* One exercise. Solved is marked on the edge rather than by greying the text:
   the explanation inside is still worth reading after the answer is known. */
.ex-card{margin-bottom:14px;border-inline-start:3px solid transparent}
.ex-card.solved{border-inline-start-color:var(--teal)}

.ex-opts{display:flex;flex-direction:column;gap:8px;margin:10px 0 0}
/* The whole row is the target, not only the control — a 14px radio button is
   a poor thing to ask somebody to hit on a phone. */
.ex-opt{display:flex;align-items:flex-start;gap:10px;cursor:pointer;
  padding:9px 11px;border:1px solid var(--line);border-radius:9px;
  background:var(--surface-2);line-height:1.7}
.ex-opt:hover{border-color:var(--teal)}
.ex-opt input{margin-top:.3rem;flex:0 0 auto}
.ex-opt span{flex:1;min-width:0;overflow-wrap:anywhere}
.ex-opt.ex-order input{margin-top:0;text-align:center}

/* Evidence: a log extract, a request, a scan result. Forced to LTR even in the
   Arabic interface, because a log line is not Arabic text — bidi reordering of
   an address or a path makes it unreadable and sometimes actively wrong. */
.ex-snippet{direction:ltr;text-align:left;unicode-bidi:isolate;
  background:var(--surface-2);border:1px solid var(--line);border-radius:9px;
  padding:11px 13px;margin:10px 0 0;overflow-x:auto;
  font-family:'IBM Plex Mono',ui-monospace,monospace;font-size:.78rem;line-height:1.75;
  white-space:pre}

@media (max-width:620px){
  .tabs{gap:4px}
  .tab{padding:6px 11px;font-size:.8rem}
}

/* ---------- Lesson resources, video and step-by-step ---------- */
.res-row{display:flex;align-items:center;gap:10px;padding:9px 0;border-top:1px solid var(--line)}
.res-row:first-child{border-top:none}
.res-ic{font-size:1.15rem;flex:0 0 auto}
.res-main{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}
.res-main b{overflow-wrap:anywhere}
.res-meta{font-size:.78rem;overflow-wrap:anywhere}
.res-title{font-weight:700;font-size:.92rem;margin-bottom:4px}
.res-add{margin-top:14px;padding-top:12px;border-top:1px solid var(--line)}
.inline-form{margin-top:12px;padding:14px;border:1px solid var(--line);
  border-radius:10px;background:var(--surface-2)}

/* Every video renders as a real player, sized to the column and never wider
   than the reading measure. */
.video-card{margin:14px 0}
.video-inline{display:block;width:100%;max-width:720px;aspect-ratio:16/9;height:auto;
  border:1px solid var(--line);border-radius:10px;background:#000}
iframe.video-inline{border:1px solid var(--line)}
.video-source{display:inline-block;margin-top:6px;font-size:.8rem;color:var(--blue-lit)}
.video-source:hover{text-decoration:underline}
/* The author's confirmation copy inside the resource list is deliberately
   smaller than the trainee's. */
.video-preview{margin-top:8px}
.video-preview .video-inline{max-width:320px}

.steps-block{margin-top:22px;border-top:1px solid var(--line);padding-top:14px}
.steps-block h3{font-size:.95rem;margin-bottom:12px}
.step-card{margin:12px 0;padding:14px;border:1px solid var(--line);border-radius:10px;
  background:var(--surface-2)}
.step-head{display:flex;align-items:center;gap:10px;margin-bottom:6px}
.step-no{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;
  width:26px;height:26px;border-radius:50%;background:var(--blue-lit);color:#fff;
  font-size:.82rem;font-weight:800}
.step-body{font-size:.92rem}
.step-shot{display:block;max-width:100%;max-height:360px;object-fit:contain;margin:10px 0 0;
  border:1px solid var(--line);border-radius:8px}

/* Proof that a lab step was carried out. Inset and tinted so it reads as the
   trainee's side of the step rather than more instruction, and pushed to the
   end of the card because it is what happens after the step is done. */
/* Which cohort of a programme is being planned. Above the timetable, because
   it decides what the timetable even refers to. */
/* Cutting the part that matters out of a screen capture. The stage is sized
   to the dialog and the image scaled to fit it; the crop itself is done in the
   image's own pixels, so what is sent is not a blurred fragment. */
/* Joining by code, beside the trainee's own programmes. Monospaced because a
   code is read character by character, and every character matters. */
/* Work handed in and not yet marked. Stated rather than left as silence: a
   trainee who has just submitted and sees nothing change concludes the
   measurement is broken rather than pending. */
/* A figure resting only on attendance and progress. Said, not implied: 90%
   from turning up must not read like 90% from marked work. */
.ksa-participation{margin-top:6px;padding:6px 10px;border-radius:6px;font-size:.78rem;
  color:var(--muted);border:1px solid var(--line);background:var(--surface-2)}

/* How many pieces are waiting, carried on the tab itself. A queue nobody can
   see is a queue nobody clears. */
.tab-count{display:inline-block;min-width:1.5em;padding:0 .4em;margin-inline-start:6px;
  border-radius:999px;background:var(--red);color:#fff;font-size:.72rem;font-weight:700;
  text-align:center;vertical-align:middle}

.ksa-pending{margin-top:6px;padding:6px 10px;border-radius:6px;font-size:.8rem;
  color:var(--gold,#d9a441);border:1px solid var(--line);background:var(--surface-2)}

.join-box input{width:14rem;font-family:var(--mono);text-transform:uppercase;letter-spacing:.04em}
#acc-code{font-family:var(--mono);letter-spacing:.06em}

/* The lab console: a whole page, because a desktop in a panel is not a
   desktop, and on a phone there is no room for anything beside it. */
/* A lab, offered. The running one is marked so it is not started twice. */
/* A submitted capture, shown rather than only linked: a marker should not have
   to download a file to see whether the exercise was done, and a trainee
   should be able to read back what they sent. */
.sub-shot{display:block;max-width:100%;max-height:420px;object-fit:contain;margin:8px 0;
  border:1px solid var(--line);border-radius:8px;background:var(--surface-2)}
.submitted-work{margin-top:10px;padding:10px 12px;border-radius:8px;
  border:1px solid var(--line);background:var(--surface)}
.submitted-work .sub-text{white-space:pre-wrap;font-size:.9rem;margin:6px 0}

/* The remedy under a down-range banner. Shown only to staff, so it may be
   specific about infrastructure. */
.range-remedy{margin-top:6px;font-size:.82rem}

.lab-card{display:flex;flex-direction:column;gap:2px}
.lab-card.live{border-color:var(--teal-deep)}

/* The sandbox lab's command screen. Not a terminal: one command, its output,
   and a box to type the next one. Drawn as what it is. */
.shell-wrap{display:flex;flex-direction:column;height:100%;min-height:0}
.shell-out{flex:1 1 auto;min-height:0;overflow:auto;margin:0;padding:14px 16px;
  font-family:var(--mono);font-size:.86rem;line-height:1.5;white-space:pre-wrap;
  word-break:break-word;color:#cfe3ff;background:#0b1020;direction:ltr;text-align:left}
.shell-out .shell-echo{color:var(--accent);font-weight:700}
.shell-out .shell-err{color:var(--red-lit)}
/* `help` output: a reference, not a result — softer, and it may carry Arabic
   descriptions, so let each line follow its own direction rather than the LTR
   of command output. */
.shell-out .shell-help{color:#9fb6d8;unicode-bidi:plaintext}

/* الطريق إلى الشهادة — the certificate-progress panel on اختباراتي */
.cp-card{display:flex;flex-direction:column;gap:2px}
.cp-sub{font-size:.74rem;color:var(--muted);margin:10px 0 4px;font-weight:600}
.req-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:5px}
.req{display:flex;gap:8px;align-items:flex-start;font-size:.84rem;line-height:1.4}
.req .req-mark{flex:0 0 auto;width:1.1em;text-align:center;font-weight:700}
.req.met .req-mark{color:var(--teal,#2FD3B4)}
.req.todo .req-mark{color:var(--muted)}
.req.todo{color:var(--muted)}
/* An actionable "what's left" step — starts the exam or opens the course */
.req.clickable{cursor:pointer;color:var(--fg);border-radius:6px;padding:3px 6px;margin:-3px -6px;
  transition:background .12s}
.req.clickable:hover{background:rgba(13,87,160,.14)}
.req.clickable .req-mark{color:var(--accent)}
.cp-left{margin-top:10px}
.cp-timeline{margin-top:10px;border-top:1px solid var(--line);padding-top:8px}
.cp-dots{display:flex;flex-wrap:wrap;gap:6px}
.cp-dot{display:inline-grid;place-items:center;min-width:2.1em;height:2.1em;padding:0 .3em;
  border-radius:6px;font-size:.72rem;font-weight:700;font-family:var(--mono);color:#0b1020}
.cp-dot.ok{background:linear-gradient(160deg,var(--green,#2FD36B),var(--teal-deep,#0f8f7a))}
.cp-dot.no{background:linear-gradient(160deg,var(--red,#e0574f),var(--red-deep,#8a2b25));color:#fff}

/* Exam sitting: a timer bar that survives redrawing each question */
.exam-bar{display:flex;justify-content:space-between;align-items:center;gap:10px;
  margin-bottom:10px;padding:8px 12px;border:1px solid var(--line);border-radius:10px;
  background:var(--surface-2)}
.exam-progress{font-family:var(--mono);font-size:.8rem;color:var(--muted)}
.exam-clock{font-family:var(--mono);font-weight:700;font-size:1.05rem;letter-spacing:.5px;
  padding:.15rem .55rem;border-radius:8px;background:rgba(13,87,160,.18);color:#cfe3ff}
.exam-clock.low{background:rgba(220,60,60,.22);color:#ffd9d4;animation:clockpulse 1s steps(2) infinite}
@keyframes clockpulse{50%{opacity:.55}}
.opt.picked{border-color:var(--accent);box-shadow:inset 0 0 0 2px var(--accent)}

/* Post-submission answer review */
.rv-card{margin-bottom:12px}
.rv-opts{list-style:none;margin:8px 0 0;padding:0;display:flex;flex-direction:column;gap:6px}
.rv-opt{display:flex;gap:8px;align-items:center;font-size:.85rem;padding:6px 10px;
  border:1px solid var(--line);border-radius:8px}
.rv-opt .rv-mark{width:1.1em;text-align:center;font-weight:700;color:var(--muted)}
.rv-opt.correct{border-color:var(--teal,#2FD3B4);background:rgba(47,211,180,.10)}
.rv-opt.correct .rv-mark{color:var(--teal,#2FD3B4)}
.rv-opt.wrong{border-color:var(--red,#e0574f);background:rgba(224,87,79,.10)}
.rv-opt.wrong .rv-mark{color:var(--red,#e0574f)}
.rv-expl{margin:10px 0 0;padding:8px 12px;border-radius:8px;background:var(--surface-2);
  font-size:.82rem;line-height:1.6;color:var(--fg)}

/* Admin participant roster (KPI + certificate status per trainee) */
.rost-card{display:flex;flex-direction:column;gap:2px}
.rost-ksa{display:flex;flex-wrap:wrap;gap:12px;margin-top:8px;font-size:.82rem}
.rost-courses{margin-top:10px;display:flex;flex-direction:column;gap:8px}
.rost-course{border:1px solid var(--line);border-radius:8px;padding:8px 10px}
.rost-meta{display:flex;flex-wrap:wrap;gap:12px;margin-top:6px;font-size:.74rem;color:var(--muted)}
.rost-step{margin:6px 0 0;font-size:.8rem;font-weight:600;color:var(--accent)}
/* Clickable participant name + KSA row -> opens the performance profile */
.rost-name{background:none;border:0;padding:0;text-align:inherit;cursor:pointer;color:inherit;font:inherit}
.rost-name:hover b{color:var(--accent);text-decoration:underline}
.rost-ksa.clickable{cursor:pointer;border-radius:8px;padding:6px 8px;margin:8px -8px 0;transition:background .12s}
.rost-ksa.clickable:hover{background:rgba(13,87,160,.12)}
.rost-open{margin-inline-start:auto;font-size:.74rem}
.shell-bar{display:flex;align-items:center;gap:8px;padding:8px 12px;
  border-top:1px solid var(--line);background:var(--surface-2);flex:0 0 auto}
.shell-prompt{font-family:var(--mono);color:var(--accent);font-weight:700}
.shell-bar input{flex:1;font-family:var(--mono);font-size:.88rem;direction:ltr;text-align:left}

.console-overlay{position:fixed;inset:0;z-index:400;display:flex;flex-direction:column;
  background:#0b1020}
body.console-open{overflow:hidden}
.console-bar{display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:6px 10px;background:var(--surface-2);border-bottom:1px solid var(--line);
  flex:0 0 auto}
.console-state{font-size:.8rem;color:var(--muted)}
/* noVNC sizes itself to this element, so it must have a real height rather
   than one that depends on its own content. */
/* A picture, opened over the page.
   Above the console overlay, because a screenshot is often opened from a
   panel that is itself over something. The frame is what "outside the image"
   means to a reader — its rounded border is the edge they aim past — so the
   backdrop and the padding around the picture both close it. */
.lightbox{position:fixed;inset:0;z-index:1200;display:flex;align-items:center;
  justify-content:center;padding:32px;background:rgba(4,7,18,.86);
  backdrop-filter:blur(3px);animation:lb-in .14s ease-out}
@keyframes lb-in{from{opacity:0}to{opacity:1}}
.lightbox-frame{margin:0;max-width:min(1200px,92vw);max-height:88vh;display:flex;
  flex-direction:column;background:var(--surface);border:1px solid var(--line);
  border-radius:14px;overflow:hidden;box-shadow:0 24px 70px rgba(0,0,0,.6)}
.lightbox-frame img{display:block;max-width:100%;max-height:calc(88vh - 46px);
  object-fit:contain;background:#0B1020}
.lightbox-frame figcaption{display:flex;align-items:center;justify-content:space-between;
  gap:14px;padding:9px 14px;font-size:.82rem;color:var(--ink-dim);
  border-top:1px solid var(--line);background:var(--surface-2)}
.lightbox-frame figcaption a{color:var(--accent);text-decoration:none}
.lightbox-frame figcaption a:hover{text-decoration:underline}
.lightbox-x{position:absolute;top:16px;inset-inline-end:20px;width:38px;height:38px;
  border-radius:50%;border:1px solid var(--line);background:var(--surface);
  color:var(--ink);font-size:1.05rem;cursor:pointer;line-height:1;
  display:flex;align-items:center;justify-content:center;transition:background .15s}
.lightbox-x:hover{background:var(--surface-2)}

/* The thumbnail says it can be opened. */
.sub-shot[data-zoom]{cursor:zoom-in}

@media (max-width:600px){
  .lightbox{padding:14px}
  .lightbox-x{top:8px;inset-inline-end:10px}
}

/* Handing the work in.
   The capture is shown before it is sent, at a size where it can actually be
   checked: evidence a trainee has not looked at is evidence they cannot stand
   behind. */
.handin-box{max-width:640px;max-height:86vh;overflow:auto}
.handin-shot{display:block;width:100%;max-height:340px;object-fit:contain;
  object-position:top;border:1px solid var(--line);border-radius:9px;
  background:#0B1020;margin:12px 0}

/* The panel that shows one piece of practical work.
   Wider than a dialog and scrolling inside itself: it carries a screenshot
   and a transcript side by side, and the default 560px column had them
   fighting over about 250px each. */
.labwork-box{width:min(900px,100%);max-height:88vh;overflow-y:auto}

/* Marked work, read side by side: what they saw next to what they ran.
   An instructor reading only the screenshot cannot tell a worked answer from
   a guessed one; the transcript is where that shows. */
.labwork-pair{display:grid;grid-template-columns:1fr 1fr;gap:14px;align-items:start}
.labwork-pair img{width:100%;border:1px solid var(--line);border-radius:9px;background:#0B1020}
.labwork-log{margin:0;max-height:420px;overflow:auto;padding:12px 14px;border-radius:9px;
  background:#0B1020;color:#CFE3FF;border:1px solid var(--line);
  font-family:var(--mono);font-size:.76rem;line-height:1.6;
  direction:ltr;text-align:left;white-space:pre-wrap;word-break:break-word}
@media (max-width:760px){ .labwork-pair{grid-template-columns:1fr} }

/* Why the exercise exists, set apart from the fiction around it.
   The scenario is a ticket from the network team; this is the platform
   speaking. Different voice, so it reads as a different kind of thing rather
   than as the first paragraph of the story. */
.brief-why{margin:0 0 16px;padding:13px 15px;border-radius:10px;
  background:var(--surface-2);border:1px solid var(--line)}
.brief-why b{display:block;margin-bottom:7px;font-size:.9rem;color:var(--accent)}
.brief-why p{margin:0 0 8px;font-size:.87rem;line-height:1.75;color:var(--ink-dim)}
.brief-why p:last-child{margin-bottom:0}
.handin-why{margin:12px 0}
.handin-why .brief-text p{font-size:.82rem;line-height:1.7;color:var(--ink-dim)}

/* What has been handed in from a lab, on the lab's own card. */
.lab-work-line{margin:2px 0 10px;font-size:.8rem;color:var(--ink-dim)}
.lab-work-line b{color:var(--ink);font-size:.95rem}

/* The scenario, read before anything starts.
   Set wider and looser than a dialog usually is, because this one is meant to
   be read rather than dismissed: a ticket at confirm-box density gets skipped,
   and a trainee who skips it runs the commands correctly and cannot say why
   any of it mattered. */
.brief-box{max-width:660px;max-height:82vh;overflow:auto}
.brief-box h3{margin:2px 0 10px;font-size:1.15rem}
.brief-role{color:var(--accent);font-size:.9rem;margin:0 0 12px;font-weight:600}
.brief-text p{margin:0 0 11px;line-height:1.75;font-size:.92rem}
.brief-goal{margin-top:14px;padding:12px 14px;border-radius:10px;
  background:var(--surface-2);border-inline-start:3px solid var(--accent)}
.brief-goal b{display:block;margin-bottom:6px;font-size:.88rem}
.brief-goal p{margin:0 0 6px;font-size:.88rem;line-height:1.7;color:var(--ink-dim)}

/* Folded shut beside a running lab: the steps are what they came back for,
   but the ticket stays one click away because an analyst rereads it. */
.guide-brief{margin-bottom:14px;border:1px solid var(--line);border-radius:9px;
  padding:8px 11px;background:var(--surface)}
.guide-brief summary{cursor:pointer;font-weight:700;font-size:.86rem}
.guide-brief[open] summary{margin-bottom:9px}
.guide-brief .brief-text p,.guide-brief .brief-goal p{font-size:.82rem}

/* The trainee's month, in two colours.
   Enrolled and open-to-join mean opposite things to the reader, so they are
   told apart at a glance — but never by colour alone: the legend names both,
   and every entry carries its kind in its title. */
.cal-legend{display:flex;align-items:center;gap:8px;margin:10px 0 12px;
  font-size:.8rem;color:var(--ink-dim);flex-wrap:wrap}
.cal-key{width:14px;height:14px;border-radius:4px;display:inline-block;
  border:1px solid var(--line)}
.cal-key.mine{background:var(--blue-lit,#4B7BE5)}
.cal-key.open{background:var(--gold,#d9a441)}
.cal-run{display:block;width:100%;margin-top:3px;padding:2px 5px;border-radius:5px;
  border:1px solid transparent;font:inherit;font-size:.7rem;font-weight:700;
  cursor:pointer;text-align:start;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cal-run.mine{background:rgba(75,123,229,.28);border-color:var(--blue-lit,#4B7BE5);color:#DCE7FF}
.cal-run.open{background:rgba(217,164,65,.24);border-color:var(--gold,#d9a441);color:#FFEBC4}
.cal-run:hover{filter:brightness(1.25)}
/* The same two colours on the lists beneath, so the grid and the cards read
   as one screen rather than two. */
.cal-card.mine{border-inline-start:3px solid var(--blue-lit,#4B7BE5)}
.cal-card.open{border-inline-start:3px solid var(--gold,#d9a441)}

/* A challenge, with its brief showing.
   The card used to carry a title and a points value; the brief that says what
   is being tested sat in the database, unread. */
/* التحديات page: each course's challenges under a heading that links to it. */
.chal-course{margin-bottom:28px}
.chal-course h2 .linklike{font:inherit;color:var(--ink);background:none;border:0;padding:0;
  cursor:pointer;text-align:start}
.chal-course h2 .linklike:hover,.chal-course h2 .linklike:focus-visible{color:var(--accent);
  text-decoration:underline;text-underline-offset:4px}
.chal-card .chal-brief{font-size:.86rem;line-height:1.8;margin:8px 0 4px}
.chal-card .chal-brief h3{font-size:.92rem;margin:12px 0 4px}
.chal-card .chal-brief p{margin:0 0 8px;color:var(--ink-dim)}
.chal-card .chal-brief code{font-size:.8rem}

/* Hints, revealed one at a time. Folded shut: a challenge should be attempted
   before it is explained, and an open panel is an invitation to read first. */
.chal-hints{margin-top:10px;border:1px solid var(--line);border-radius:9px;
  padding:9px 12px;background:var(--surface-2)}
.chal-hints summary{cursor:pointer;font-weight:700;font-size:.85rem}
.hint-list{margin:0;padding-inline-start:20px;display:flex;flex-direction:column;gap:10px}
.hint{font-size:.84rem;line-height:1.75;color:var(--ink-dim)}
.hint p{margin:0 0 6px}
.hint:last-of-type{color:var(--ink)}

/* The road across the top of a lesson.
   One mark per lesson, so the shape of the programme is visible at a glance
   rather than compressed into a percentage. The marks shrink rather than wrap
   as the count grows: a track that runs onto a second line stops reading as a
   single journey. */
.lesson-track{margin:10px 0 14px}
.tl-row{display:flex;align-items:center;gap:8px}
.tl-marks{display:flex;align-items:center;gap:3px;flex:1 1 auto;min-width:0;flex-wrap:nowrap}
/* The button is 22px tall and invisible; the bar inside it is 7px. What you
   aim at is far bigger than what you see, because a seven-pixel target is a
   picture rather than something a thumb or a keyboard can reach. */
.tl-mark{flex:1 1 0;min-width:3px;max-width:14px;height:22px;padding:0;border:0;
  background:none;display:flex;align-items:center;cursor:pointer}
.tl-mark::before{content:'';display:block;width:100%;height:7px;border-radius:3px;
  background:var(--surface-2);border:1px solid var(--line);
  transition:background .2s,height .2s}
.tl-mark.done::before{background:var(--blue-lit,#4B7BE5);border-color:var(--blue-lit,#4B7BE5)}
/* Where they are: taller and lit, so the eye lands on it first. */
.tl-mark.here::before{background:var(--accent);border-color:var(--accent);height:13px;
  box-shadow:0 0 0 2px rgba(126,147,224,.25)}
.tl-mark:hover::before{background:var(--accent);border-color:var(--accent);height:11px}
.tl-mark:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:4px}
.tl-goal{flex:0 0 auto;width:24px;height:24px;display:flex;align-items:center;
  justify-content:center;border-radius:7px;font-size:.82rem;padding:0;
  background:var(--surface-2);border:1px solid var(--line);color:var(--ink-dim)}
button.tl-goal{cursor:pointer}
button.tl-goal:hover{border-color:var(--accent);color:var(--ink)}
button.tl-goal:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.tl-goal.won{background:linear-gradient(135deg,#1C285B,#0D57A0);border-color:var(--blue-lit);
  color:#FFD777}
.tl-note{margin:7px 0 0;font-size:.78rem;color:var(--ink-dim)}
.tl-note b{color:var(--ink)}

/* Facts about a person, laid out as facts: label beside value, nothing
   pretending to be a form. */
.facts{display:grid;grid-template-columns:auto 1fr;gap:10px 18px;margin:0;
  font-size:.88rem;align-items:baseline}
.facts dt{color:var(--ink-dim);white-space:nowrap}
.facts dd{margin:0;color:var(--ink);font-weight:700;overflow-wrap:anywhere}
@media (max-width:520px){ .facts{grid-template-columns:1fr;gap:2px 0}
  .facts dd{margin-bottom:8px} }

/* How the labs work, said once at the top of the range.
   Set as something to read rather than something to dismiss: this replaced a
   notice about a missing container engine that no trainee could act on. */
.howto{margin-bottom:18px}
.howto h2{margin:0 0 12px;font-size:1.02rem}
.howto ol{margin:0;padding-inline-start:20px;display:flex;flex-direction:column;gap:12px}
.howto li b{font-size:.9rem;color:var(--ink)}
.howto li p{margin:4px 0 0;font-size:.86rem;line-height:1.75;color:var(--ink-dim)}
.howto-warn{margin:14px 0 0;padding:10px 13px;border-radius:9px;
  background:var(--surface-2);border-inline-start:3px solid var(--gold,#d9a441);
  font-size:.85rem;line-height:1.7;color:var(--ink-dim)}

/* Guidance beside the work.
   The console used to fill the overlay; it now shares it with the steps,
   because a brief in a file inside the container is a brief nobody opens.
   The column collapses, since on a narrow screen a desktop needs the width
   more than the reading does. */
.console-body{flex:1 1 auto;min-height:0;display:flex;align-items:stretch}
.console-guide{flex:0 0 340px;max-width:42%;overflow:auto;padding:14px 16px;
  border-inline-end:1px solid var(--line);background:var(--surface-2)}
.console-overlay.guide-collapsed .console-guide{display:none}
.guide-head{display:flex;align-items:center;justify-content:space-between;
  margin-bottom:10px;position:sticky;top:-14px;padding:6px 0;background:var(--surface-2)}
.guide-steps{margin:0;padding-inline-start:20px;display:flex;flex-direction:column;gap:14px}
.guide-step{font-size:.86rem;line-height:1.55}
.guide-step p{margin:4px 0;color:var(--muted)}
.guide-cmd{display:flex;align-items:center;gap:6px;margin:6px 0;flex-wrap:wrap}
.guide-cmd code{flex:1;min-width:0;font-family:var(--mono);font-size:.76rem;
  padding:4px 7px;border-radius:6px;background:#0b1020;color:#cfe3ff;
  border:1px solid var(--line);direction:ltr;text-align:left;
  overflow-x:auto;white-space:pre}
.guide-check{color:var(--gold,#d9a441);font-size:.8rem}

@media (max-width:820px){
  .console-body{flex-direction:column}
  .console-guide{flex:0 0 auto;max-width:none;max-height:38%;
    border-inline-end:none;border-block-end:1px solid var(--line)}
}

.console-stage{flex:1 1 auto;min-height:0;position:relative;background:#0b1020}
.console-stage canvas{display:block;touch-action:none}
.console-note{padding:24px;max-width:44rem;margin:0 auto;color:var(--muted)}

.crop-modal{max-width:min(92vw,980px);width:100%}
.crop-stage{position:relative;display:inline-block;max-width:100%;line-height:0;
  cursor:crosshair;touch-action:none;user-select:none;
  border:1px solid var(--line);border-radius:8px;overflow:hidden;background:var(--surface-2)}
.crop-stage img{display:block;max-width:100%;max-height:60vh;object-fit:contain;
  -webkit-user-drag:none;user-select:none}
.crop-sel{position:absolute;border:2px dashed var(--accent);background:rgba(80,150,255,.16);
  pointer-events:none;box-shadow:0 0 0 9999px rgba(4,6,16,.45)}

.run-bar{display:flex;align-items:flex-end;gap:10px;flex-wrap:wrap;
  padding:10px 12px;border-radius:8px;background:var(--surface-2);border:1px solid var(--line)}
.run-bar select{width:100%}

.proof-box{margin-top:12px;padding:10px 12px;border-radius:8px;
  border:1px dashed var(--line);background:var(--surface)}
.proof-box.done{border-style:solid;border-color:var(--teal-deep)}
.proof-box input[type=file]{max-width:62%;font-size:.8rem}
.proof-box input:not([type=file]){width:100%;margin-top:6px;font-size:.85rem}
.proof-sent-back{margin:6px 0;padding:6px 10px;border-radius:6px;font-size:.84rem;
  color:var(--red-lit);border:1px solid var(--red);background:rgba(200,40,60,.08)}
.proof-shot,.proof-preview{display:block;max-width:100%;max-height:260px;object-fit:contain;
  margin:8px 0;border:1px solid var(--line);border-radius:8px}
.step-row{display:flex;align-items:flex-start;gap:10px;padding:10px 0;border-top:1px solid var(--line)}
.step-row:first-child{border-top:none}
.step-main{flex:1;min-width:0}
.step-ctl{flex:0 0 auto}

/* ---------- Security: banners, idle warning, log ----------
   A security notice is not a toast: being told your account was used from
   another device has to stay on screen until it is acknowledged. */
.banners{padding:0 max(20px, calc((100% - 1140px) / 2));margin-top:14px}
.banner{display:flex;align-items:flex-start;gap:12px;padding:13px 16px;margin-bottom:10px;
  border-radius:10px;border:1px solid var(--line);border-inline-start:4px solid var(--blue-lit);
  background:var(--surface-2)}
.banner-ic{font-size:1.15rem;line-height:1.5;flex:0 0 auto}
.banner-body{flex:1;min-width:0}
/* A security notice is a line to read, not a paragraph to wade through:
   smaller and tighter than body copy, and it stays on one line where the
   width allows. */
.banner-body p{margin-top:4px;font-size:.8rem;color:var(--ink-dim);line-height:1.55}
.banner-x{background:none;border:none;color:var(--ink-dim);font-size:1rem;cursor:pointer;
  padding:0 4px;line-height:1;flex:0 0 auto}
.banner-x:hover{color:var(--ink)}
.banner.warn{border-inline-start-color:var(--gold)}
.banner.danger{border-inline-start-color:var(--red-lit)}
/* Something is limited, not broken. A missing container engine stops the
   container labs and leaves the rest running, and colouring that the same
   amber as a fault taught readers to discount both. */
.banner.info{border-inline-start-color:var(--blue-lit,#4B7BE5)}
/* Heads the stack whenever there is anything to clear, so the way out of a
   warning is visible at the same moment the warning is. */
.banner-bulk{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:8px 14px;margin-bottom:8px;font-size:.82rem;
  border:1px solid var(--line);border-radius:10px;background:var(--surface-2)}
.banner-bulk .btn{flex:0 0 auto}

/* Fixed to the viewport: the warning must be visible wherever you are on the
   page when the idle window is about to close. */
.idle-warn{position:fixed;inset-inline:0;bottom:-90px;z-index:120;
  display:flex;align-items:center;justify-content:center;gap:14px;
  margin:0 auto;width:max-content;max-width:calc(100% - 32px);
  padding:12px 18px;border-radius:12px;
  border:1px solid var(--gold-deep);background:linear-gradient(160deg,#2A2412,#12182F);
  box-shadow:0 10px 32px rgba(0,0,0,.6);
  opacity:0;transition:bottom .25s ease,opacity .25s ease}
.idle-warn.show{bottom:22px;opacity:1}
.idle-ic{font-size:1.1rem}
.idle-count{font-family:var(--mono);color:var(--gold);font-size:1.05rem}

.sec-table td{vertical-align:top}
.sec-dot,.sev-dot{display:inline-block;width:7px;height:7px;border-radius:50%;
  margin-inline-end:8px;background:var(--ink-dim);vertical-align:middle}
.sev-notice .sev-dot{background:var(--gold)}
.sev-warning .sev-dot{background:var(--gold-deep)}
.sev-critical .sev-dot{background:var(--red-lit);box-shadow:0 0 8px rgba(206,17,38,.7)}
.sev-critical td{background:rgba(206,17,38,.06)}
.hash{font-family:var(--mono);font-size:.8rem;color:var(--teal)}
/* A table inside this wrapper takes its natural width and the wrapper
   scrolls — which is what the wrapper was for. `table{width:100%}` made it
   shrink to fit instead, so overflow-x never engaged: eleven columns got
   about seventy pixels each and an institute's name was set one word per
   line, six lines tall, with the action buttons pushed clean out of the card.

   Cells hold their line by default. A column that genuinely wants prose asks
   for it with .wrap rather than every column having to cope. */
.table-wrap{overflow-x:auto;overscroll-behavior-x:contain}
.table-wrap table{width:auto;min-width:100%}
.table-wrap th,.table-wrap td{white-space:nowrap}
.table-wrap th.wrap,.table-wrap td.wrap{white-space:normal;min-width:190px}

/* A table drawn straight into a card, with no wrapper to scroll inside.
   Thirteen of them are written that way, and a fourteenth will be — so the
   table becomes its own scroll container rather than each one being wrapped
   by hand. `display:block` leaves the rows laying out as a table while making
   the table box itself scrollable; `min-width:100%` keeps a narrow one filling
   the card as before. */
.card > table{display:block;overflow-x:auto;max-width:100%;width:max-content;min-width:100%}
.card > table th,.card > table td{white-space:nowrap}
.card > table th.wrap,.card > table td.wrap{white-space:normal;min-width:190px}
.card > table td.actions{white-space:nowrap;text-align:end}
.card > table td.actions .btn{margin-inline-start:6px}
/* Actions stay together and stay reachable: they are the reason the row is
   being read at all. */
.table-wrap td.actions{white-space:nowrap;text-align:end}
.table-wrap td.actions .btn{margin-inline-start:6px}

/* A long name on a control truncates rather than stacking; the full value is
   already on the title attribute for anyone who needs it. */
.inline-edit > summary{max-width:190px;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;display:inline-block;vertical-align:middle}

/* ---------- Participant roster ---------- */
.meter.mini{height:6px;width:70px;margin-bottom:3px}
select.mini{padding:5px 8px;font-size:.8rem;border-radius:7px;background:var(--night);
  border:1px solid var(--line);color:var(--ink);font-family:inherit}
/* The candidate list scrolls rather than pushing the confirm button off screen
   when a large organisation is listed. */
.cand-list{max-height:320px;overflow-y:auto;border:1px solid var(--line);border-radius:10px}
.cand{display:flex;align-items:flex-start;gap:10px;padding:9px 12px;cursor:pointer;
  border-top:1px solid var(--line)}
.cand:first-child{border-top:none}
.cand:hover{background:rgba(255,255,255,.03)}
.cand input{margin-top:3px;flex:0 0 auto}
.cand-main{display:flex;flex-direction:column;gap:2px;min-width:0}
.cand-main .muted{font-size:.78rem}
.cand.blocked{background:rgba(242,179,61,.06)}
.cand-warn{font-size:.76rem;color:var(--gold)}

/* A programme with no places left is tinted rather than hidden — it still has
   a roster worth opening. */
.row-full td{background:rgba(206,17,38,.06)}

/* ---------- Examination results ---------- */
.not-sat{display:flex;flex-wrap:wrap;gap:6px}
.attempt-review{margin-top:14px;padding-top:12px;border-top:1px solid var(--line)}
/* Each question carries its verdict on the leading edge: right, wrong, or
   never answered — three states, not two, because a blank is not a mistake. */
.rev-q{margin:10px 0;padding:10px 12px;border-radius:9px;background:var(--surface-2);
  border-inline-start:3px solid var(--line)}
.rev-q.right{border-inline-start-color:var(--teal)}
.rev-q.wrong{border-inline-start-color:var(--red-lit)}
.rev-q.blank{border-inline-start-color:var(--gold)}
.rev-head{display:flex;align-items:baseline;gap:10px}
.rev-head b{flex:1;min-width:0}
.rev-no{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;
  width:22px;height:22px;border-radius:50%;background:var(--night);border:1px solid var(--line);
  font-family:var(--mono);font-size:.72rem}
.rev-opts{list-style:none;margin:8px 0 0;padding:0}
.rev-opts li{padding:3px 0;font-size:.86rem;color:var(--ink-dim)}
/* What they chose, and what was right — distinguishable without relying on
   colour alone, since one of them is often both. */
.rev-opts li.picked{color:var(--ink);font-weight:700}
.rev-opts li.correct{color:var(--teal)}
.rev-opts li.picked.correct{color:var(--teal)}
.rev-opts li.picked:not(.correct){color:var(--red-hover)}

/* ---------- Training calendar ---------- */
.cal-grid-head{display:grid;grid-template-columns:repeat(7,1fr);gap:6px;margin-bottom:6px}
.cal-grid-head span{text-align:center;font-size:.76rem;font-weight:700;color:var(--ink-dim);
  padding:4px 0}
.cal-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:6px}
.cal-cell{min-height:92px;padding:6px;border:1px solid var(--line);border-radius:9px;
  background:var(--night);display:flex;flex-direction:column;gap:4px;cursor:pointer;
  transition:border-color .15s,background .15s}
.cal-cell:hover{border-color:var(--blue-lit)}
.cal-cell.empty{border-style:dashed;opacity:.35;cursor:default}
.cal-cell.empty:hover{border-color:var(--line)}
.cal-cell.weekend{background:rgba(255,255,255,.02)}
.cal-cell.today{border-color:var(--gold);box-shadow:inset 0 0 0 1px var(--gold-deep)}
.cal-cell.has{background:var(--surface-2)}
.cal-num{font-family:var(--mono);font-size:.78rem;color:var(--ink-dim)}
.cal-cell.today .cal-num{color:var(--gold);font-weight:800}
/* One programme running on a day. Amber until its register is complete. */
.cal-chip{display:flex;flex-direction:column;gap:1px;width:100%;text-align:start;
  padding:4px 6px;border:1px solid var(--gold-deep);border-radius:6px;cursor:pointer;
  background:rgba(242,179,61,.10);color:var(--ink);font-family:inherit;font-size:.72rem;
  line-height:1.35}
.cal-chip:hover{border-color:var(--blue-lit);background:rgba(126,147,224,.16)}
.cal-chip b{font-family:var(--mono);font-size:.74rem}
.cal-chip span{color:var(--ink-dim)}
.cal-chip-meta{font-family:var(--mono)}
.cal-chip.done{border-color:var(--teal-deep);background:rgba(47,211,180,.10)}
.cal-chip.locked{opacity:.75;border-style:dashed}

/* The agreed run window, above the day-by-day plan. */
.run-window{display:flex;align-items:flex-end;gap:10px;flex-wrap:wrap;
  padding:10px 12px;border:1px solid var(--line);border-radius:10px;background:var(--surface-2)}
.run-window .field span{display:block;font-size:.78rem;font-weight:700;margin-bottom:4px}
.run-window input[type=date]{padding:6px 10px;font-family:var(--mono);font-size:.82rem;
  background:var(--night);border:1px solid var(--line);border-radius:7px;color:var(--ink)}

/* The run planner: one row per declared training day. */
.plan-table{font-size:.84rem}
.plan-table input{width:100%;min-width:110px;padding:5px 8px;font-size:.8rem;border-radius:7px;
  background:var(--night);border:1px solid var(--line);color:var(--ink);font-family:inherit}
.plan-table input[type=date],.plan-table input[type=time]{font-family:var(--mono)}
.plan-table input:disabled{opacity:.5}
.plan-table td{padding:5px 6px}

/* A programme name that opens its public page. */
.course-link{background:none;border:none;padding:0;font:inherit;color:var(--ink);
  cursor:pointer;text-align:start}
.course-link:hover{color:var(--red-hover)}

/* Evidence of taking part, listed beside each name on the register. */
.proof{max-width:280px}
.proof-item{display:block;font-size:.76rem;line-height:1.6;overflow-wrap:anywhere}

@media (max-width: 720px){
  .cal-cell{min-height:70px}
  .cal-chip{font-size:.66rem}
}

/* ---------- Attendance register ---------- */
.day-list{border:1px solid var(--line);border-radius:10px;overflow:hidden}
.day-row{display:flex;align-items:center;gap:12px;padding:11px 14px;border-top:1px solid var(--line)}
.day-row:first-child{border-top:none}
.day-row.locked{background:rgba(255,255,255,.03)}
.day-no{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;
  width:30px;height:30px;border-radius:8px;background:var(--surface-2);
  border:1px solid var(--line);font-family:var(--mono);font-weight:800;font-size:.85rem}
.day-row.locked .day-no{background:var(--blue-deep);border-color:var(--blue-lit);color:#fff}
.day-main{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}
.att-absent{color:var(--red-lit)}
.att-late{color:var(--gold)}

/* The sheet is a wide grid of radio columns, so it scrolls in its own box and
   the name column stays put while the marks scroll. */
.sheet-table{font-size:.86rem}
.sheet-table th.c,.sheet-table td.c{text-align:center;width:1%;white-space:nowrap;padding-inline:10px}
.sheet-table td input[type=radio]{width:16px;height:16px;cursor:pointer}
.sheet-table tbody tr:hover{background:rgba(255,255,255,.03)}
.mini-num{width:70px;padding:5px 8px;font-size:.8rem;border-radius:7px;
  background:var(--night);border:1px solid var(--line);color:var(--ink);font-family:var(--mono)}
.mini-note{width:150px;padding:5px 8px;font-size:.8rem;border-radius:7px;
  background:var(--night);border:1px solid var(--line);color:var(--ink);font-family:inherit}

/* ---------- Image picker (upload / paste / drop / link) ---------- */
.img-picker .img-drop{position:relative;display:flex;align-items:center;justify-content:center;
  min-height:130px;padding:14px;border:2px dashed var(--line);border-radius:10px;
  background:var(--night);cursor:pointer;transition:border-color .15s,background .15s}
.img-picker .img-drop:hover,.img-picker .img-drop:focus-visible{border-color:var(--blue-lit);outline:none}
.img-picker .img-drop.over{border-color:var(--teal);background:rgba(47,211,180,.07)}
.img-picker .img-drop.busy{opacity:.55;pointer-events:none}
.img-drop-empty{display:flex;flex-direction:column;align-items:center;gap:8px;text-align:center;
  color:var(--ink-dim);font-size:.84rem;line-height:1.7;max-width:34ch}
.img-drop-ic{font-size:1.6rem}
.img-drop-preview{max-width:100%;max-height:260px;object-fit:contain;border-radius:8px}

/* ---------- Markdown editing toolbar ---------- */
.md-bar{display:flex;flex-wrap:wrap;align-items:center;gap:4px;padding:6px;
  border:1px solid var(--line);border-bottom:none;border-radius:8px 8px 0 0;
  background:var(--surface-2)}
.md-btn{min-width:30px;height:28px;padding:0 8px;border:1px solid transparent;border-radius:6px;
  background:transparent;color:var(--ink);font-size:.85rem;cursor:pointer;line-height:1}
.md-btn:hover{background:var(--night);border-color:var(--line)}
.md-toggle{font-size:.8rem}
.md-toggle.on{background:var(--blue-lit);color:#fff}
.md-bar+textarea{border-radius:0 0 8px 8px}
.md-prev{min-height:160px;padding:14px;border:1px solid var(--line);border-radius:0 0 8px 8px;
  background:var(--night)}

/* ---------- Programme specification (course page) ---------- */
.prog-head{border-inline-start:4px solid var(--red-lit)}
.prog-head h1{font-size:1.75rem}
.prog-code{font-family:var(--mono);color:var(--blue-lit);font-size:.9rem;margin-top:6px;letter-spacing:.04em}
.prog-code span{color:var(--ink-dim)}
.prog-section{margin-top:18px}
.prog-section h2{font-size:1.2rem;margin-bottom:10px;padding-bottom:8px;
  border-bottom:2px solid var(--red-lit);display:inline-block}
.prog-text{line-height:2;color:var(--ink)}
/* Bullets use the ▪ of the printed programme sheet. */
.prog-list{list-style:none;margin-top:10px}
.prog-list li{position:relative;padding-inline-start:20px;margin-bottom:7px;line-height:1.9}
.prog-list li::before{content:'▪';position:absolute;inset-inline-start:0;color:var(--red-lit)}
.prog-list.lesson-links li::before{color:var(--blue-lit)}
.prog-table{width:100%;border-collapse:collapse;margin-top:6px}
.prog-table th{width:38%;text-align:start;font-weight:700;color:var(--ink);font-size:.9rem;
  text-transform:none;letter-spacing:0;background:var(--surface-2);padding:10px 14px;
  border:1px solid var(--line)}
.prog-table td{padding:10px 14px;border:1px solid var(--line);color:var(--ink-dim)}
.prog-day{margin-bottom:12px;border-inline-start:3px solid var(--blue-lit)}
.prog-day h3{font-size:1.02rem;margin-bottom:4px}

/* ---------- Certificate designer ---------- */
.mark-box{display:flex;align-items:center;gap:10px;min-height:52px;padding:8px 10px;margin-bottom:8px;
  border:1px dashed var(--line);border-radius:10px;background:var(--surface-2)}
.mark-box img{max-height:38px;max-width:130px;object-fit:contain}
/* The preview reproduces the issued document, which is a light printable
   sheet, so it deliberately does not follow the dark interface theme. */
.cert-preview{background:#fff;color:var(--ink);border-radius:8px;overflow:hidden;border:1px solid var(--line)}
.cp-band{background:#fff;color:var(--ink);padding:12px 16px;display:flex;align-items:center;gap:10px}
.cp-band img{width:34px;height:34px;object-fit:contain;filter:invert(1) contrast(1.1);mix-blend-mode:multiply}
.cp-word{font-weight:900;font-size:.92rem;line-height:1.1}
.cp-word .dot,.cp-word .tld{color:var(--ink)}
.cp-word small{display:block;font-family:var(--mono);font-size:.5rem;letter-spacing:.18em;
  text-transform:uppercase;color:var(--ink-dim);margin-top:2px}
.cp-org{margin-inline-start:auto;font-size:.68rem;color:var(--ink);font-weight:700}
.cp-rule{height:3px;background:linear-gradient(90deg,var(--red) 0 33.3%,#fff 33.3% 66.6%,var(--blue) 66.6% 100%);
  border-block:1px solid var(--line)}
.cp-body{padding:20px 18px;text-align:center}
.cp-body h2{font-size:1.15rem;margin-bottom:6px;color:var(--ink)}
.cp-lead{color:var(--ink-dim);font-size:.76rem;margin:6px 0 0}
.cp-name{display:inline-block;font-size:1.3rem;font-weight:900;padding:0 20px 6px;
  border-bottom:2px solid var(--blue);margin:8px 0}
.cp-course{font-weight:700;color:var(--ink);font-size:.9rem;margin-top:8px}
.cp-blurb{color:var(--ink-dim);font-size:.78rem;margin-top:8px;line-height:1.7}
.cp-meta{display:flex;justify-content:center;gap:0;margin:16px auto 0;max-width:340px;
  border:1px solid var(--line);border-radius:8px;overflow:hidden}
.cp-meta span{flex:1;padding:8px 4px;font-size:.6rem;color:var(--ink-dim);text-transform:uppercase;
  border-inline-start:1px solid var(--line)}
.cp-meta span:first-child{border-inline-start:none}
.cp-meta b{display:block;font-size:.92rem;color:var(--ink);text-transform:none}
.cp-sign{display:flex;justify-content:space-between;align-items:flex-end;margin-top:16px;
  font-size:.72rem;color:var(--ink);gap:12px}
.cp-sign small{color:var(--ink-dim)}
.cp-verify{font-family:var(--mono);font-size:.7rem;color:var(--ink-dim);border:1px dashed var(--line);
  border-radius:8px;padding:5px 9px}
.cp-sponsors{display:flex;justify-content:center;gap:16px;flex-wrap:wrap;margin-top:16px;
  border-top:1px solid var(--line);padding-top:12px}
.cp-sponsors figure{margin:0}
.cp-sponsors img{height:26px;object-fit:contain}
.cp-sponsors figcaption{font-size:.6rem;color:var(--ink-dim);margin-top:3px}

/* ---------- Modal (member picker) ---------- */
.modal{position:fixed;inset:0;z-index:300;background:rgba(4,6,16,.72);backdrop-filter:blur(3px);
  display:grid;place-items:center;padding:20px}
.modal-box{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  padding:22px;width:min(560px,100%);max-height:80vh;display:flex;flex-direction:column}
.pick-list{overflow-y:auto;display:flex;flex-direction:column;gap:6px;padding-inline-end:4px}
.pick-list .prereq-item input[type=checkbox]{accent-color:var(--blue-lit)}

/* ---------- Trainee: assignments, noticeboard, calendar ---------- */
.submit-box{margin-top:12px;border-top:1px solid var(--line);padding-top:12px}
.graded-box{margin-top:12px;border-top:1px solid var(--line);padding-top:12px;
  border-inline-start:3px solid var(--teal);padding-inline-start:12px}
.graded-box b{font-size:1.15rem;color:var(--teal)}
.notice{padding:10px 0;border-top:1px solid var(--line)}
.notice:first-of-type{border-top:none}
/* An unread announcement is marked, not shouted about. */
.notice.unread{cursor:pointer;border-inline-start:3px solid var(--red-lit);padding-inline-start:10px}
.cal-row{display:flex;gap:12px;align-items:baseline;padding:7px 0;border-top:1px solid var(--line);
  font-size:.86rem}
.cal-row:first-of-type{border-top:none}
.cal-when{font-family:var(--mono);font-size:.74rem;color:var(--ink-dim);flex:0 0 auto}
.cal-what{flex:1}

/* ---------- Training-objective editor ---------- */
.ob-row{display:flex;align-items:center;gap:9px;padding:5px 0;border-top:1px solid var(--line)}
.ob-row:first-child{border-top:none}
.ob-n{flex:0 0 auto;width:22px;text-align:center;font-family:var(--mono);font-size:.78rem;
  color:var(--ink-dim)}
.ob-t{flex:1;background:var(--night);border:1px solid var(--line);color:var(--ink);
  border-radius:8px;padding:8px 11px;font-family:inherit;font-size:.88rem}
.ob-t:focus{outline:none;border-color:var(--blue-lit)}

/* ---------- Question bank & grading ---------- */
/* Question screenshot, in the bank and while taking the examination. */
.q-shot{display:block;max-width:100%;max-height:340px;object-fit:contain;margin:10px 0;
  border:1px solid var(--line);border-radius:10px;background:var(--night)}
.q-expl{margin-top:8px;font-size:.86rem;color:var(--ink-dim);border-inline-start:3px solid var(--blue-lit);
  padding-inline-start:10px}
.mark-box img{max-height:64px}
.q-opts{list-style:none;margin-top:8px}
.q-opts li{font-size:.86rem;color:var(--ink-dim);padding:3px 0}
.q-opts li.ok{color:var(--ink);font-weight:600}
.opt-row{display:flex;align-items:center;gap:9px;margin-bottom:7px}
.opt-row input[type=radio],.opt-row input[type=checkbox]{width:16px;height:16px;accent-color:var(--blue-lit);flex:0 0 auto}
.opt-row .nq-t{flex:1;background:var(--night);border:1px solid var(--line);color:var(--ink);
  border-radius:8px;padding:8px 11px;font-family:inherit;font-size:.88rem}
.sub-text{background:var(--surface-2);border-radius:8px;padding:10px 12px;margin-top:8px;
  font-size:.88rem;white-space:pre-wrap}
.grade-box{display:flex;flex-direction:column;gap:6px;min-width:190px}

/* ---------- Inline table editors (ranks, organisations) ---------- */
.mini{background:var(--night);border:1px solid var(--line);color:var(--ink);border-radius:8px;
  padding:6px 9px;font-family:inherit;font-size:.85rem;width:92px}
.mini.wide{width:100%;min-width:130px}
.mini[type=color]{padding:2px;width:46px;height:32px;cursor:pointer}

/* ---------- Bulk selection bar ---------- */
.bulk-bar{display:flex;align-items:center;gap:12px;flex-wrap:wrap;padding:10px 12px;margin-bottom:12px;
  border:1px solid var(--line);border-radius:var(--radius);background:var(--surface-2)}
.bulk-bar .spacer{flex:1}
.vis-label{font-size:.82rem;color:var(--ink-dim)}
.switch input:checked ~ .vis-label{color:var(--teal)}

/* ---------- Prerequisite picker ---------- */
.prereq-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:8px;
  max-height:340px;overflow-y:auto;padding-inline-end:4px}
.prereq-item{display:flex;align-items:center;gap:9px;padding:8px 10px;border:1px solid var(--line);
  border-radius:10px;cursor:pointer;font-size:.86rem}
.prereq-item.on{border-color:var(--blue-lit);background:rgba(126,147,224,.12)}
.prereq-item input[type=checkbox]{width:16px;height:16px;accent-color:var(--blue);flex:0 0 auto}
.prereq-item .mono{font-family:var(--mono);color:var(--accent);flex:0 0 auto}
.prereq-item .pr-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.prereq-item .pr-grade{width:74px;flex:0 0 auto;background:var(--night);border:1px solid var(--line);
  color:var(--ink);border-radius:8px;padding:4px 7px;font-family:inherit;font-size:.8rem}
.prereq-item .pr-grade:disabled{opacity:.35}

/* ---------- Course authoring (admin) ---------- */
.btn.xs{padding:4px 10px;font-size:.76rem;border-radius:99px}
.btn.danger{color:var(--red-lit);border-color:var(--red)}
.btn.danger:hover{border-color:var(--red-lit);color:var(--red-lit)}
.mod-block{border:1px solid var(--line);border-radius:var(--radius);padding:14px;margin-bottom:12px;
  background:var(--surface-2)}
.lesson-list{list-style:none;margin-top:10px}
.lesson-list li{display:flex;justify-content:space-between;align-items:center;gap:10px;
  padding:7px 0;border-top:1px solid var(--line);font-size:.9rem}

/* ---------- Lesson links (trainee course view) ---------- */
.lesson-links{list-style:none}
.lesson-links li{padding:3px 0}
.lesson-link{background:none;border:none;color:var(--ink);font-family:inherit;font-size:.92rem;
  cursor:pointer;text-align:start;padding:2px 0;border-bottom:1px dotted transparent}
.lesson-link::before{content:'▸';color:var(--blue-lit);margin-inline-end:7px;transition:color .15s}
/* Hover picks up the brand red, marker included — in its lifted form, because
   these sit on a card where the exact value measures only 2.48:1. */
.lesson-link:hover,.lesson-link:focus-visible{color:var(--red-hover);border-bottom-color:var(--red-hover)}
.lesson-link:hover::before,.lesson-link:focus-visible::before{color:var(--red-hover)}

/* ---------- Switch (labelled checkbox, e.g. price visibility) ---------- */
.switch{display:inline-flex;align-items:center;gap:10px;cursor:pointer;user-select:none}
.switch input{width:18px;height:18px;accent-color:var(--blue-lit);cursor:pointer}
.switch span{font-size:.9rem}

/* ---------- Tables ---------- */
table{width:100%;border-collapse:collapse;font-size:.9rem}
th,td{text-align:start;padding:10px 12px;border-bottom:1px solid var(--line)}
th{color:var(--ink-dim);font-weight:700;font-size:.78rem;text-transform:uppercase;letter-spacing:.06em}
tr:hover td{background:rgba(255,255,255,.04)}

/* ---------- Lesson / quiz ---------- */
.lesson-body{line-height:1.9}
.lesson-body h3{margin:18px 0 8px;color:var(--accent)}
.lesson-body ul{padding-inline-start:22px;margin:8px 0}
.tip{background:var(--surface-2);border-inline-start:3px solid var(--gold);border-radius:8px;padding:12px 14px;margin:14px 0}
.opt{display:block;width:100%;text-align:start;background:var(--night);border:1px solid var(--line);
  color:var(--ink);border-radius:10px;padding:12px 16px;margin-bottom:10px;cursor:pointer;font-family:inherit}
.opt:hover{border-color:var(--accent)}
.opt.correct{border-color:var(--green);background:rgba(62,207,122,.12)}
.opt.wrong{border-color:var(--red-lit);background:rgba(224,104,90,.14)}

/* ---------- Site footer ---------- */
/* Black, matching the masthead, so the page is bracketed by the brand plate. */
.sitefooter{position:relative;z-index:1;background:#000000;border-top:1px solid var(--line);
  padding:18px max(20px, calc((100% - 1140px) / 2));
  display:flex;align-items:center;justify-content:center;gap:10px;flex-wrap:wrap;
  font-size:.82rem;color:var(--silver);text-align:center}
.sitefooter .sep{color:var(--silver-deep)}
/* The mark and slogan repeat in the footer, in the same brand colours. */
.foot-mark{width:40px;height:40px}
.foot-slogan{font-family:var(--mono);font-weight:700;font-size:.74rem;letter-spacing:.12em;
  color:var(--silver-deep)}
.foot-slogan .s1{color:#FFFFFF}
.foot-slogan .s2{color:#CE1126}
.foot-slogan .s3{color:#0D57A0}
/* Footer keeps the motto تدرّب · اخترق · دافع (white/red/blue). */
/* The platform name in the copyright line carries the brand red. */
.foot-brand{color:#CE1126;font-weight:700}
.sitefooter a{color:var(--blue-lit);text-decoration:none}
.sitefooter a:hover{text-decoration:underline}
/* The wordmark keeps its colours inside the footer line. */
.sitefooter .atk{color:var(--red-lit)}
.sitefooter .dot{color:#fff}
.sitefooter .tld{color:var(--blue-lit)}

/* ---------- Toast ---------- */
#toast{position:fixed;inset-block-end:24px;inset-inline-start:50%;transform:translateX(-50%) translateY(20px);
  background:var(--surface-2);border:1px solid var(--accent);border-radius:12px;padding:12px 22px;
  opacity:0;pointer-events:none;transition:.35s;z-index:200;max-width:90vw;text-align:center}
#toast.show{opacity:1;transform:translateX(-50%) translateY(0)}
body[dir="rtl"] #toast{transform:translateX(50%) translateY(20px)}
body[dir="rtl"] #toast.show{transform:translateX(50%) translateY(0)}

/* ---------- Console ---------- */
/* Deliberately stays dark even in the light theme: this is a real terminal
   surface and is read as one. */
.terminal{background:#0A0E16;border:1px solid var(--line);border-radius:10px;font-family:var(--mono);
  font-size:.82rem;color:#9fe6c8;padding:14px;min-height:180px;white-space:pre-wrap}

@media(max-width:760px){.hero{grid-template-columns:1fr;gap:24px;text-align:center}
  .hero .perks{text-align:start}}

/* ---------- إعدادات الجهات ----------
   A list of institutes and their tracks should read like a list, not a form.
   Detail lives behind a disclosure, so the common case — glance, move one up,
   close it — costs no reading. */

.level-block{border-top:1px solid var(--line);margin-top:16px;padding-top:14px}
.level-block:first-of-type{border-top:0}

/* One track, one line. The arrows sit outside the disclosure, so reordering
   never means opening anything first. */
.track-line{display:flex;align-items:flex-start;gap:8px;padding:6px 0}
.track-line + .track-line{border-top:1px solid var(--line)}
.track-line > details{flex:1}
.track-line > details > summary{cursor:pointer;padding:5px 6px;list-style:none;border-radius:8px}
.track-line > details > summary::-webkit-details-marker{display:none}
.track-line > details > summary::before{content:"\25B8";display:inline-block;
  margin-inline-end:8px;color:var(--blue-lit);transition:transform .15s}
.track-line > details[open] > summary::before{transform:rotate(90deg)}
body[dir="rtl"] .track-line > details > summary::before{content:"\25C2"}
body[dir="rtl"] .track-line > details[open] > summary::before{transform:rotate(-90deg)}
.track-line > details > summary:hover{background:var(--surface-2)}

/* The panel a disclosure opens — for a track, a level, or an institute row. */
.pop{background:var(--surface-2);border:1px solid var(--line);border-radius:10px;
  padding:12px;margin-top:8px}
.inline-edit{display:inline-block}
.inline-edit > summary{cursor:pointer;list-style:none}
.inline-edit > summary::-webkit-details-marker{display:none}

/* An editor opened from a table row.
   It used to be positioned inside the cell, so the card clipped it: the fields
   spilled over the rows beneath and the save button ended up below the fold
   with no way to reach it. Centring it on the viewport means it can never be
   cut off by whatever it was opened from, and it stays readable at any width. */
.inline-edit[open] > .pop{position:fixed;inset-block-start:50%;inset-inline-start:50%;
  transform:translate(-50%,-50%);z-index:60;width:min(420px,calc(100vw - 32px));
  max-height:min(80vh,640px);overflow-y:auto;margin:0;padding:18px;
  box-shadow:0 20px 60px rgba(0,0,0,.55);border-radius:14px;text-align:start}
/* In RTL `inset-inline-start` resolves to `right`, so the panel's right edge
   lands on the centre line; the translate goes the other way to bring it back. */
body[dir="rtl"] .inline-edit[open] > .pop{transform:translate(50%,-50%)}
/* A backdrop, so the panel reads as being in front of the page and clicking
   away is the obvious way to leave it. */
.inline-edit[open] > summary::after{content:"";position:fixed;inset:0;z-index:50;
  background:rgba(6,10,26,.6)}
.inline-edit[open] > .pop .field{margin-bottom:12px}
/* Text fields fill the panel; a tick box is a tick box. Without the exclusion
   the checkbox stretched to the full row width and pushed the name it labels
   clean out of the box. */
.inline-edit[open] > .pop select,
.inline-edit[open] > .pop input:not([type=checkbox]):not([type=radio]),
.inline-edit[open] > .pop textarea{width:100%}
.inline-edit[open] > .pop .row{margin-top:14px}

/* Programmes inside a track, in the order they are taken. */
.track-courses{margin:10px 0 0;padding-inline-start:18px;font-size:.86rem}
.track-courses li{padding:4px 0;display:flex;align-items:center;gap:6px;flex-wrap:wrap}

/* The institute currently open, marked in the list above it. */
tr.is-open{background:var(--surface-2)}
tr.is-open td:first-child{box-shadow:inset 3px 0 0 var(--blue-lit)}
body[dir="rtl"] tr.is-open td:first-child{box-shadow:inset -3px 0 0 var(--blue-lit)}

/* A field that has just become required — a مدير جهة needs an institute.
   Marked rather than announced: the sentence above it already says why. */
select.required, input.required{border-color:var(--blue-lit);
  box-shadow:0 0 0 2px rgba(13,87,160,.25)}

/* ---------- Choosing from a long catalogue ----------
   A scrolling, searchable tick-list. A dropdown of a hundred-odd programmes is
   not a way to choose; this is. */
.pick-list{max-height:280px;overflow-y:auto;overflow-x:hidden;border:1px solid var(--line);
  border-radius:10px;background:var(--surface-2);padding:4px}
/* One row per choice. The tick keeps its natural size and sits against the
   start edge; the name takes the rest and wraps if it needs to — an institute
   called «معهد كويت هاكرز للتدريب الأهلي» must be readable, not truncated to
   the first two words. Nothing here may scroll sideways. */
.pick-row{display:flex;align-items:flex-start;gap:10px;padding:8px 10px;border-radius:8px;
  cursor:pointer;font-size:.88rem;line-height:1.5}
.pick-row:hover{background:var(--surface)}
.pick-row input[type=checkbox]{margin:2px 0 0;flex:0 0 auto;width:16px;height:16px;
  accent-color:var(--blue-lit)}
.pick-row b{flex:0 0 auto;font-family:var(--mono);font-size:.8rem;color:var(--blue-lit)}
.pick-row span{flex:1 1 auto;min-width:0;overflow-wrap:anywhere}
.pick-row .pill{flex:0 0 auto}
.pick-row:has(input:checked){background:var(--surface);box-shadow:inset 2px 0 0 var(--blue-lit)}
body[dir="rtl"] .pick-row:has(input:checked){box-shadow:inset -2px 0 0 var(--blue-lit)}

/* ---------- The administrative hierarchy ----------
   Superadmin above, each institute below it, indented once. One level of
   indent is enough to read as a tree; more would be decoration. */
.tree{display:flex;flex-direction:column;gap:2px}
.tree-root{border-inline-start:3px solid var(--blue-lit);padding:10px 14px;
  background:var(--surface-2);border-radius:10px}
.tree-node{position:relative;margin-inline-start:26px;padding:10px 14px;
  border-inline-start:3px solid var(--node,var(--blue-lit));border-radius:10px}
.tree-node + .tree-node{margin-top:2px}
/* The elbow joining an institute to the platform above it. */
.tree-node::before{content:"";position:absolute;inset-inline-start:-14px;inset-block-start:-2px;
  width:14px;height:24px;border-inline-start:1px solid var(--line);
  border-block-end:1px solid var(--line);border-end-start-radius:8px}
.tree-node.is-open{background:var(--surface-2)}
.tree-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.tree-head b{font-size:.95rem}
.tree-head .muted{font-size:.8rem}
.tree-head button{margin-inline-start:auto}
.tree-people{list-style:none;margin:8px 0 0;padding:0;font-size:.85rem}
.tree-people li{display:flex;align-items:center;gap:8px;padding:3px 0;flex-wrap:wrap}
.tree-people .muted{font-size:.78rem}
.tree-more > summary{cursor:pointer;font-size:.82rem;padding:4px 0;list-style:none}
.tree-more > summary::-webkit-details-marker{display:none}
.tree-more > summary::before{content:"\25B8";display:inline-block;
  margin-inline-end:6px;color:var(--blue-lit)}
.tree-more[open] > summary::before{content:"\25BE"}
.pill.warn{background:rgba(242,179,61,.18);color:var(--gold,#F2B33D)}


/* A preview must never be mistaken for the published page: the reviewer has
   to know whether they are reading the programme or checking it. Warm, not
   alarming — this is a normal part of writing a course, not an error. */
.preview-bar{display:flex;align-items:center;justify-content:space-between;gap:12px;
  flex-wrap:wrap;margin:10px 0 4px;padding:9px 13px;border-radius:9px;
  background:rgba(214,168,74,.13);border:1px solid rgba(214,168,74,.42);
  color:var(--ink);font-size:.83rem}

/* The end of the road, drawn under the track it continues. Quiet by default;
   the earned state is the only one that celebrates, because it is the only
   one that has earned it. */
.milestone{margin:10px 0 14px;padding:12px 14px;border-radius:11px;
  background:var(--surface-2);border:1px solid var(--line)}
.milestone.won{background:linear-gradient(135deg,rgba(28,40,91,.55),rgba(13,87,160,.35));
  border-color:var(--blue-lit);display:flex;align-items:center;
  justify-content:space-between;gap:12px;flex-wrap:wrap}
.ms-head{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;margin-bottom:8px}
.ms-head .muted{font-size:.8rem}
.ms-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:7px}
.ms-row{display:flex;align-items:center;gap:9px;flex-wrap:wrap;font-size:.86rem}
/* Never the tick alone: a mark that is only a colour and a glyph is unreadable
   to anyone who cannot see either, so the state is also in the words beside it. */
.ms-row.done .ms-what{color:var(--ink-dim);text-decoration:line-through}
.ms-what{flex:1 1 auto;min-width:0}
.ms-tick{flex:0 0 auto}

/* Encouragement, not an announcement: it sits beside the count in the same
   quiet grey, one voice rather than two competing for the same glance. */
.tl-word{display:inline-block;margin-inline-start:8px;padding-inline-start:8px;
  border-inline-start:1px solid var(--line);color:var(--ink-dim)}
@media (max-width:520px){
  /* On a narrow screen the count matters more than the encouragement. */
  .tl-word{display:block;margin-inline-start:0;padding-inline-start:0;
    border-inline-start:0;margin-top:4px}
}

/* ---- reading a lesson --------------------------------------------------
 *
 * The bodies here are 800–2,300 characters. What made the page feel long was
 * the furniture around them and the line length, not the prose.
 */

/* The route back, on one line. The programme's name is truncated rather than
   wrapped: it is a signpost, and a signpost that takes two lines above every
   lesson competes with the lesson's own title. */
.lesson-crumb{display:flex;align-items:center;gap:8px;margin:14px 0 10px;
  font-size:.8rem;color:var(--ink-dim);min-width:0}
.crumb-course{max-width:min(38ch,40%);overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;flex:0 1 auto}
.crumb-sep{opacity:.5;flex:0 0 auto}
.crumb-mod{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1 1 auto;min-width:0}
.crumb-pos{flex:0 0 auto;margin-inline-start:auto;white-space:nowrap;
  font-variant-numeric:tabular-nums}
@media (max-width:640px){
  /* On a phone the position matters more than the trail that led here. */
  .crumb-course,.crumb-sep{display:none}
}

/* What is in the lesson, before the scrolling starts. */
.lesson-toc{margin:14px 0 18px;padding:12px 14px;border-radius:10px;
  background:var(--surface-2);border:1px solid var(--line)}
.toc-head{margin:0 0 8px;font-size:.78rem;letter-spacing:.02em;color:var(--ink-dim);
  text-transform:none}
.lesson-toc ol{margin:0;padding-inline-start:20px;display:flex;flex-direction:column;gap:5px}
.lesson-toc a{color:var(--ink);text-decoration:none;font-size:.88rem;line-height:1.5}
.lesson-toc a:hover,.lesson-toc a:focus-visible{color:var(--accent);text-decoration:underline}

/* A reading measure. Long lines are the commonest reason a page feels heavy:
   the eye loses its place on the return sweep. Prose is held to about 72
   characters; tables, code and images keep the full width because they are
   scanned rather than read. */
.lesson-card .lesson-body > p,
.lesson-card .lesson-body > ul,
.lesson-card .lesson-body > ol,
.lesson-card .lesson-body > blockquote{max-width:72ch}
.lesson-card .lesson-body > h3{margin-top:26px;scroll-margin-top:16px}
.lesson-card .lesson-body > h3:first-child{margin-top:4px}

/* The exercise is the one thing on the page to be acted on, and it was
   styled as an aside. Given its own weight, and the tick kept as the marker
   the lessons already use. */
.lesson-body blockquote:has(> p:first-child){border-inline-start-width:3px}
.lesson-card .lesson-body > blockquote{background:rgba(126,147,224,.07);
  border-inline-start:3px solid var(--accent);border-radius:0 9px 9px 0;
  padding:12px 14px;color:var(--ink)}
[dir="rtl"] .lesson-card .lesson-body > blockquote{border-radius:9px 0 0 9px}

/* ---- the exercise list -------------------------------------------------
 *
 * Thirty of them, each holding a full task and a submission box. Folded shut
 * on the course page, open inside a lesson.
 */
.ex{border:1px solid var(--line);border-radius:11px;margin-bottom:10px;
  background:var(--surface);overflow:hidden}
.ex > summary{display:flex;align-items:center;gap:10px;padding:11px 13px;
  cursor:pointer;list-style:none;font-size:.9rem}
.ex > summary::-webkit-details-marker{display:none}
.ex > summary:hover{background:var(--surface-2)}
.ex > summary:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.ex-state{flex:0 0 auto;font-size:.95rem}
.ex-name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;font-weight:600}
.ex-tags{flex:0 0 auto;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.ex-status{font-size:.78rem;color:var(--ink-dim);white-space:nowrap}
.ex-body{padding:0 13px 13px}

/* Required and optional read differently at a glance — and never by
   background alone: the pill names which it is, and the edge is weighted
   differently, so the distinction survives for a reader who cannot separate
   the two hues. On «which of these must I do», that matters. */
.ex.must{background:rgba(126,147,224,.07);border-color:rgba(126,147,224,.34);
  border-inline-start:3px solid var(--accent)}
.ex.may{background:var(--surface-2);border-inline-start:3px solid var(--line)}

/* Done recedes; still owed does not. */
.ex.ex-done{opacity:.72}
.ex.ex-done .ex-name{text-decoration:line-through;text-decoration-thickness:1px}
.ex.must.ex-todo{border-inline-start-color:var(--gold,#D6A84A)}

@media (max-width:560px){
  /* The name wraps rather than the status falling off the edge. */
  .ex > summary{flex-wrap:wrap}
  .ex-name{flex:1 1 100%;white-space:normal}
}

/* Says a reload is due, without taking the page away from whoever is using
   it. Bottom of the screen, out of the reading path, and dismissible. */
#update-bar{position:fixed;inset-inline-start:16px;inset-block-end:16px;z-index:60;
  display:flex;align-items:center;gap:10px;flex-wrap:wrap;max-width:min(92vw,460px);
  padding:10px 13px;border-radius:11px;font-size:.84rem;
  background:var(--surface-2);border:1px solid var(--blue-lit);
  box-shadow:0 10px 30px rgba(0,0,0,.35)}
@media (prefers-reduced-motion:no-preference){
  #update-bar{animation:update-in .22s ease-out}
  @keyframes update-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
}

/* 3-step training methodology strip on the landing page */
.method{max-width:1060px;margin:8px auto 56px;padding:0 20px;text-align:center}
.section-eyebrow{display:inline-block;font-size:.72rem;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:var(--accent);margin-bottom:8px}
.method-title{font-size:1.6rem;letter-spacing:.01em;margin-bottom:10px}
/* Slogan words in the title carry the approved brand colours: تدرّب white, اخترق red, دافع blue. */
.method-title .s1{color:#FFFFFF}.method-title .s2{color:#CE1126}.method-title .s3{color:#0D57A0}
/* Lead is kept to a single line on desktop; it wraps only on narrow screens. */
.method-lead{max-width:none;margin:0 auto 36px;white-space:nowrap}
.method-steps{display:flex;align-items:stretch;justify-content:center;gap:16px;flex-wrap:wrap}
.method-step{position:relative;overflow:hidden;flex:1 1 250px;max-width:310px;text-align:start;
  background:linear-gradient(180deg,var(--surface-2),var(--surface));
  border:1px solid var(--line);border-radius:18px;padding:30px 24px 26px;
  transition:transform .22s ease,border-color .22s ease,box-shadow .22s ease}
/* Top accent bar that lights up on hover — a modern, direction-neutral flourish. */
.method-step::before{content:'';position:absolute;inset-block-start:0;inset-inline:0;height:3px;
  background:linear-gradient(90deg,var(--blue-lit),var(--red-lit));opacity:0;transition:opacity .25s ease}
.method-step:hover{transform:translateY(-6px);border-color:var(--blue-lit);
  box-shadow:0 20px 44px -22px rgba(13,87,160,.75)}
.method-step:hover::before{opacity:1}
/* Modern-cyber step marker: a glowing mono accent number followed by the label.
   Number and label flow as one inline run, so the label begins on the same line
   as the number ("3 Earn your …") and wraps beneath it — rather than the whole
   label dropping to its own line under the number. */
.method-head{margin-bottom:16px;line-height:1.2}
.method-no{font-family:var(--mono);font-weight:800;font-size:1.5rem;color:var(--blue-lit);
  direction:ltr;unicode-bidi:isolate;text-shadow:0 0 14px rgba(13,87,160,.55);margin-inline-end:8px}
.method-kicker{font-family:var(--mono);font-weight:800;font-size:1.5rem;letter-spacing:.01em;color:var(--ink)}
.method-step h3{margin:0 0 8px;font-size:1.15rem}
.method-step p{font-size:.92rem;line-height:1.7}
.method-arrow{display:flex;align-items:center;font-size:1.4rem;color:var(--blue-lit);font-weight:700;opacity:.55}
/* Stacked on narrow screens: cards read top-to-bottom in step order, so the
   inline connector is hidden rather than left pointing the wrong way. */
@media (max-width:760px){.method-arrow{display:none}}

/* ---- the way in to صيد الهاكرز! -------------------------------------
   A card that behaves like the link it is, and a menu entry that admits it
   leaves the platform. */
.awcard{display:flex;align-items:center;justify-content:space-between;gap:16px;
  margin:0 0 16px;text-decoration:none;color:inherit;transition:border-color .18s,transform .12s}
.awcard:hover{border-color:var(--blue-lit,#0D57A0);transform:translateY(-1px)}
.awcard h3{font-size:1.05rem}
a.nav-item{display:flex;align-items:center;text-decoration:none}
