/*
 * gateway-redesign.css — "Path" brand restyle for the Kolibri 0.19.5 app shell.
 *
 * Served by the gateway sidecar (nginx) at /__path/brand.css (bind-mounted
 * from docker/gateway-redesign.css, see docker-compose.yml) and linked into
 * every :8080 text/html page via the sub_filter rule in gateway-nginx.conf.
 * Kolibri's CSP allows style-src 'self' + 'unsafe-inline', so a same-origin
 * <link> plus the pre-existing inline chip-hide <style> are both valid.
 *
 * LAWS (docs/DESIGN-LEARNER-UI.md):
 *   - ZERO external URLs: no url(), @import, http(s) references anywhere.
 *   - The channel-logo hide rule keeps its exact upstream effect.
 *   - Only UN-MINIFIED bundle classes / data-testids proven in
 *     .build/redesign-recon (never [data-v-*] hashes).
 *   - Scope aggressively: cards target [data-testid^='HybridLearningContentCard']
 *     and [data-testid='channel-cards'] so sign-in / bookmarks / other pages
 *     cannot be reached by card rules.
 *   - !important is required throughout: Kolibri paints app-bar/toolbar colors
 *     as INLINE styles and its JSS stylesheets are appended to <head> AFTER
 *     this link (document order would otherwise beat equal specificity, and
 *     upstream Vue scoped selectors are 0,2,0 vs our 0,1,0).
 *
 * Edit flow: change this file -> live immediately (Cache-Control: no-cache);
 * no container restart is needed for CSS edits (bind mount). nginx config
 * changes DO need: docker exec lms-portal-gateway-1 nginx -t && docker compose
 * up -d --force-recreate gateway.
 */

/* ---- design tokens (docs/DESIGN-LEARNER-UI.md §3) ---------------------- */
:root {
  --path-green-950: #00371e;
  --path-green-800: #00562d;   /* rgb(0, 86, 45)  — hero/headers */
  --path-green-600: #006838;   /* rgb(0, 104, 56) — interactive */
  --path-green-100: #e8f3ee;   /* wash/hover */
  --path-gold-500: #e0a820;
  --path-gold-700: #b7791f;
  --path-ink: #101840;
  --path-muted: #5b6472;
  --path-line: #e5e3dc;
  --path-paper: #f7f4ee;   /* warm paper (Style D adopted token — §(n); was #f7f6f2) */
  --path-card: #ffffff;
  --path-shadow-rest: 0 1px 2px rgba(16, 24, 64, .05), 0 6px 18px rgba(16, 24, 64, .07);
  --path-shadow-hover: 0 1px 2px rgba(16, 24, 64, .05), 0 10px 28px rgba(16, 24, 64, .10);
  /* (s) the sign-in split: the brand panel's share of a wide screen, and the
   * width the form column keeps on a phone. Layout only - no new hue. */
  --path-signin-panel: 42%;
  --path-signin-form: 420px;
}

/* ---- 0. channel-thumbnail chip — upstream rule preserved verbatim ------ */
/* (also still injected inline by gateway-nginx.conf; kept here so the hide
 * survives even if the inline injection is ever dropped) */
img.channel-logo { display: none !important; }

/* ---- (a)+(b) app bar + topic toolbar → deep green, white text ----------
 * Library: div.app-bar carries INLINE background rgb(255,213,51)/color #000
 * (theme default); topic: .k-toolbar--type-clear carries INLINE rgb(0,0,0).
 * Both are beaten with !important on the same properties. Chrome is already
 * Noto Sans (bundled) — no font changes, per spec. */
.app-bar,
.app-bar .k-toolbar,
.k-toolbar--type-clear {
  background-color: var(--path-green-800) !important;
  color: #fff !important;
}
/* icons inside the bars inherit currentColor */
.app-bar svg,
.k-toolbar--type-clear svg {
  fill: currentColor;
}
/* app-bar sub-nav tabs (Home/Library/Bookmarks, logged-in): upstream paints
 * them ink-on-gold; on the green bar they go white, active gets the gold
 * accent underline (spec §3: gold = short accent rules only). */
.app-bar a.tab {
  color: #fff !important;
}
.app-bar a.tab.router-link-active {
  border-bottom-color: var(--path-gold-500) !important;
}

/* ---- (d) content wash ---------------------------------------------------
 * Recon (ancestor probe): the grey page background is painted on BODY
 * (rgb(245,245,245)); every container above the cards is transparent.
 * One body rule gives the paper tone with no seams between regions.
 * Sign-in paints its own full-viewport themed layer above body, so it is
 * unaffected (verified by capture). */
body {
  background-color: var(--path-paper) !important;
}

/* ---- (c) side nav -------------------------------------------------------
 * .side-nav / .side-nav-wrapper proven in core bundle; links render as
 * a.core-menu-option.tab inside the nav. Warm-paper drawer (§(n) Style D
 * harmonisation — was the white card), ink links, green hover wash;
 * active/hovered link gets the gold left rule as a 3px inset shadow
 * (identical look, zero layout shift vs a real border on these rounded,
 * margined menu options). */
.side-nav {
  background-color: var(--path-paper) !important;
}
.side-nav a.tab,
.side-nav a.core-menu-option {
  color: var(--path-ink) !important;
  border-radius: 0 !important;
}
.side-nav a.tab:hover,
.side-nav a.core-menu-option:hover,
.side-nav a.tab.router-link-active,
.side-nav a.core-menu-option.router-link-active {
  background-color: var(--path-green-100) !important;
  color: var(--path-green-600) !important;
  box-shadow: inset 3px 0 0 0 var(--path-gold-500);
}
/* logo block spacing + header strip: upstream paints the side-nav header
 * gold (theme token) — spec keeps the drawer calm warm paper (§(n)) */
.side-nav-header {
  padding: 16px 24px;
  background-color: var(--path-paper) !important;
  color: var(--path-ink) !important;
}
.side-nav-header svg {
  fill: currentColor;
}
.side-nav img.logo {
  display: block;
}

/* ---- (e)+(f) session / quiz cards (topic page) --------------------------
 * Wrapper: div.card.drop-shadow[data-testid='HybridLearningContentCard-N'];
 * painted surface: a.card.card-link (inline bg from theme surface).
 * Upstream DOM order is header-bar → thumbnail → text; flex column + order:-1
 * lifts the thumbnail to a true full-bleed top (no DOM control upstream —
 * same technique as the library hero, Decision Trace #4). The wrapper clips
 * the thumbnail to the 12px radius via overflow:hidden. */
[data-testid^='HybridLearningContentCard'] {
  background-color: var(--path-card) !important;
  border-radius: 12px !important;
  box-shadow: var(--path-shadow-rest) !important;
  transition: transform .15s ease, box-shadow .15s ease !important;
  overflow: hidden;
}
[data-testid^='HybridLearningContentCard']:hover {
  transform: translateY(-2px);
  box-shadow: var(--path-shadow-hover) !important;
}
[data-testid^='HybridLearningContentCard'] .card-link {
  background-color: var(--path-card) !important;
  border-radius: 12px !important;
  display: flex !important;
  flex-direction: column;
}
[data-testid^='HybridLearningContentCard'] .thumbnail {
  order: -1;
}
/* header-bar shrinks from a fixed 48px strip to content height (chip row);
 * sits between the full-bleed thumbnail and the title */
[data-testid^='HybridLearningContentCard'] .header-bar {
  height: auto !important;
  min-height: 0 !important;
  padding: 10px 16px 0 !important;
  order: 1;
}
/* card title: ink 16px/700 */
[data-testid^='HybridLearningContentCard'] .title {
  color: var(--path-ink) !important;
  font-size: 16px !important;
  font-weight: 700 !important;
}

/* Activity chip pill — .learning-activity-label wraps an inner
 * span.learning-activity; the pill is applied to the OUTER label so it
 * renders regardless of inner node structure (per brief).
 * NOTE (channel metadata): the deployed channel's nodes carry no
 * learning_activities, so Kolibri renders the label EMPTY (no text/icon).
 * The :not(:has(svg)) guard keeps that empty state invisible; the pill
 * below activates automatically once activity metadata exists.
 * QUIZ gold tint (spec §3/Decision Trace #6): deferred — Kolibri renders no
 * kind-specific class/attribute on the chip, so it cannot be targeted
 * without guessing selectors (forbidden). Revisit with the metadata pass. */
[data-testid^='HybridLearningContentCard'] .learning-activity-label {
  width: auto !important;
  display: inline-flex;
  align-items: center;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 11px !important;
  font-weight: 700 !important;
  letter-spacing: .14em;
  text-transform: uppercase;
  background-color: var(--path-green-100);
  color: rgb(0, 86, 45);
}
[data-testid^='HybridLearningContentCard'] .learning-activity-label:not(:has(svg)) {
  display: none;
}

/* ---- (g) progress indicators (latent until progress exists) ------------- */
[data-testid^='HybridLearningContentCard'] .progress-bar-wrapper,
[data-testid='channel-cards'] .progress-bar-wrapper {
  background-color: rgba(16, 24, 64, .12) !important;
}
[data-testid^='HybridLearningContentCard'] .progress-bar,
[data-testid='channel-cards'] .progress-bar {
  background-color: var(--path-gold-500) !important;
}
/* THE PROGRESS TICK IS THE BRAND GOLD.
 * The marker is Kolibri's own ProgressIcon component: the DEPLOYED Learn UI
 * bundle renders it as `<ProgressIcon class="progress-icon">` on the page
 * bar (LearningActivityBar.vue) and as `<ProgressIcon class="completion-icon">`
 * inside the card's `p.completion-label` (ProgressBar.vue). Its visible form
 * is a 24px circle badge (class "icon", scoped style:
 * `.icon { width: 24px; height: 24px; border-radius: 50% }`) whose
 * BACKGROUND is an inline style - iconStyle() paints it with the theme's
 * "progress" / "mastered" token - and whose glyph is the theme's inverted
 * text. So the badge is overridden here, with !important (an inline style
 * beats a stylesheet), and the glyph stays white on it, exactly as the
 * upstream component draws it.
 *
 * WHY gold-700 and NOT gold-500: the badge is a filled graphic that has to
 * read at a glance against the white card, and gold-700 clears 3:1 there
 * (3.64:1) where gold-500 does not (2.14:1). It is the same gold-700 the
 * portal uses for its tick, so both surfaces mark progress in one colour.
 *
 * THE STARTED STATE IS THIS SAME MARKER: the component draws a clock for
 * "In progress" and a star for "Completed", and for "Not started" it draws
 * NOTHING at all (the template's v-if / v-else-if has no third branch) - so
 * a module nobody has begun cannot pick up the gold by accident, and no
 * rule is needed to keep it neutral. */
[data-testid^='HybridLearningContentCard'] .progress-icon .icon,
[data-testid='channel-cards'] .progress-icon .icon,
[data-testid^='HybridLearningContentCard'] .completion-icon .icon,
[data-testid='channel-cards'] .completion-icon .icon {
  background-color: var(--path-gold-700) !important;
  color: var(--path-card) !important;
}
[data-testid^='HybridLearningContentCard'] .progress-icon svg,
[data-testid='channel-cards'] .progress-icon svg,
[data-testid^='HybridLearningContentCard'] .completion-icon svg,
[data-testid='channel-cards'] .completion-icon svg {
  fill: var(--path-card);
}

/* ---- (h) library channel card → hero ------------------------------------
 * a.card-main-wrapper inside div.grid[data-testid='channel-cards'].
 * Live DOM (verified by probe, logged-in variant):
 *   channel-cards > div.pure-g > div.grid-item.pure-u-8-24 (1/3 cell!)
 *     > a.card-main-wrapper > div > [h3.title, div > div.pure-g > (6/24
 *     thumbnail + 18/24 description)]. The anonymous variant instead has
 *     title and pure-g as two DIRECT wrapper children — both are handled.
 * Steps: widen the 1/3 cell to the full row (hero), lift the thumbnail row
 * above the title with flex order, stretch the thumbnail column to 16/9
 * cover. Title loses its inline 1px border-bottom. Decision Trace #4. */
[data-testid='channel-cards'] .card-main-wrapper {
  display: flex !important;
  flex-direction: column !important;
  background-color: var(--path-card) !important;
  border-radius: 12px !important;
  box-shadow: var(--path-shadow-rest) !important;
  max-height: none !important;
  min-height: 0 !important;
  padding: 20px !important;
  transition: transform .15s ease, box-shadow .15s ease !important;
}
[data-testid='channel-cards'] .card-main-wrapper:hover {
  transform: translateY(-2px);
  box-shadow: var(--path-shadow-hover) !important;
}
/* the 1/3 grid cell the card lives in → full-width hero row */
[data-testid='channel-cards'] .pure-u-8-24 {
  width: 100% !important;
}
/* anonymous variant: title and pure-g row are direct wrapper children */
[data-testid='channel-cards'] .card-main-wrapper > div:has(> .pure-g) {
  order: -1;
  margin: 0 !important;
}
/* logged-in variant: title and pure-g row share ONE inner div — flex it and
 * lift its pure-g child above the title */
[data-testid='channel-cards'] .card-main-wrapper > div {
  display: flex;
  flex-direction: column;
}
[data-testid='channel-cards'] .card-main-wrapper > div > div:has(> .pure-g) {
  order: -1;
  margin: 0 !important;
}
[data-testid='channel-cards'] .card-main-wrapper .pure-u-6-24 {
  width: 100% !important;
}
[data-testid='channel-cards'] .card-main-wrapper .pure-u-18-24 {
  width: 100% !important;
  margin-top: 16px;
  color: var(--path-muted);
  font-size: 15px;
  line-height: 1.6;
}
[data-testid='channel-cards'] .card-thumbnail-wrapper {
  width: 100% !important;
  height: auto !important;
  aspect-ratio: 16 / 9;
  min-height: 180px;
  background-size: cover !important;
  border-bottom: 0 !important;      /* upstream 5px transparent artifact */
  border-radius: 8px !important;    /* inner block radius, spec §3 */
}
[data-testid='channel-cards'] .card-main-wrapper .title {
  border-bottom: 0 !important;      /* inline 1px #e6e6e6 upstream */
  padding: 0 !important;
  margin: 16px 0 0;
  color: var(--path-ink) !important;
  font-size: 20px !important;
  font-weight: 700 !important;
}

/* ---- (i) topic page header --------------------------------------------- */
h1[data-testid='header-title'] {
  color: var(--path-ink) !important;
  font-size: 28px !important;
  font-weight: 700 !important;
  letter-spacing: -0.01em;
}
[data-testid='header-breadcrumbs'] a {
  color: var(--path-green-600) !important;
}
[role='tablist'] a {
  color: var(--path-ink);
}
[role='tablist'] a.router-link-active {
  color: var(--path-green-600) !important;
  border-bottom-color: var(--path-gold-500) !important;
}
[role='tablist'] a .inner {
  border-bottom-color: var(--path-gold-500);
}

/* ---- (j) focus discipline -----------------------------------------------
 * 2px solid interactive green, 2px offset, keyboard only — never removed. */
a:focus-visible,
button:focus-visible {
  outline: 2px solid var(--path-green-600) !important;
  outline-offset: 2px !important;
}

/* ---- (k) uniform card grid ----------------------------------------------
 * Owner report: Learn topic pages show 3 cards per row on module pages but
 * 4 on Surah Practice. Live recon (grid-uniform/assert.js, before phase,
 * 1280x800): BOTH views share ONE container —
 * div.cards-grid.grid-type-2.level-5[data-testid='non-mobile-card-grid'] —
 * an upstream flex-wrap row whose card children are sized by per-level
 * percentage width rules (grid-type-N / level-M classes; 25% = 4 slots).
 * Module 1 simply has only 3 cards, so its one row leaves the 4th slot
 * empty; Surah Practice's 12 cards fill 3 rows of 4. Upstream also wobbles
 * between 2/3/4 columns across the 640-1099px band (the level-M class
 * follows Kolibri's window level). FIX: turn this one container into a real
 * CSS grid with a fixed column template — 3 columns >=1100px, 2 columns
 * 640-1099px, 1 column <640px — and neutralise the per-level percentage
 * widths on the direct card children (width:auto so each card fills its
 * minmax(0,1fr) track; the 0 minimum stops long titles from forcing
 * overflow). The upstream 8px child margin is untouched, so spacing and the
 * cards' radius/shadow/hover treatment are unchanged. The mobile topic
 * browser (.cards-grid[data-testid='mobile-card-grid'], below ~600px,
 * already 1-per-row) and the library hero ([data-testid='channel-cards'])
 * are deliberately NOT touched. */
.cards-grid[data-testid='non-mobile-card-grid'] {
  display: grid !important;
  grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
}
.cards-grid[data-testid='non-mobile-card-grid'] > .card,
.cards-grid[data-testid='non-mobile-card-grid'] > [data-testid^='HybridLearningContentCard'] {
  width: auto !important;   /* beats the upstream per-level percentage widths */
}
@media (max-width: 1099px) {
  .cards-grid[data-testid='non-mobile-card-grid'] {
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
  }
}
@media (max-width: 639px) {
  .cards-grid[data-testid='non-mobile-card-grid'] {
    grid-template-columns: minmax(0, 1fr) !important;
  }
}

/* ---- (l) boot splash loader → Path logo ----------------------------------
 * Every :8080 page boots through a static splash painted inline in the
 * served HTML <rootvue> (recon: .build/splash-fix/served-root.html):
 *   div.flapping-kolibri > svg[role="img"][aria-label="Kolibri loader"]
 * — Kolibri's blue bird, 250x250 (viewBox 0 0 200 200, fill="none"), whose
 * body outline + six wing strokes are drawn ONLY through presentation
 * attributes on 7 <use href="#…" stroke="#4368F5"> elements cloning <defs>
 * paths. Wing "flapping" = opacity keyframes (.wing-inner/.wing-middle/
 * .wing-outer) on those <use> elements; the parent div carries a 1s-delay
 * fadeIn. Served-page recon counted the loader exactly ONCE per page
 * (root /, /en/auth/, /en/learn/ → 1 each), so the attribute selector below
 * covers every boot surface; no sibling spinner/label exists to preserve.
 *
 * FIX (CSS-only): beat the presentation attributes with author CSS —
 * presentation attributes always lose to stylesheet rules, and !important
 * hardens that against future upstream CSS. fill/stroke none + opacity 0 on
 * ALL svg descendants removes every painted bird part (the <use> shadow
 * clones inherit stroke from their host element, so killing it on the host
 * kills the clone too). The element's box is untouched (its width/height
 * attributes stay authoritative) and the Path logo is painted on the svg's
 * own background — /static/assets/discover_islam/logo.png is a SAME-ORIGIN
 * gateway-served asset (verified 200 image/png), so no external URL enters
 * this file. The parent div's fadeIn is deliberately KEPT (upstream pacing:
 * blank for 1s, then a gentle 1s fade-in — now fading in our logo); the
 * wing-flap animation dies via the opacity kill below (nothing else
 * animates on the svg itself). Once the SPA mounts, Kolibri replaces the
 * <rootvue> splash content entirely, so nothing is left to hide. */
svg[role="img"][aria-label="Kolibri loader"] {
  background: url("/static/assets/discover_islam/logo.png") center / contain no-repeat;
}
svg[role="img"][aria-label="Kolibri loader"] * {
  fill: none !important;
  stroke: none !important;
  opacity: 0 !important;
}

/* =========================================================================
 * ---- (m) MOBILE LEARNER PASS — real-phone fixes (360/390/414) ------------
 * Evidence: .build/mobile-pass/{before,after}/ (capture.cjs + measurements).
 *
 * Owner-reported defects (2026-09, Memorization shelf @ narrow width):
 *   1. Cards render enormous — two cards fill a phone screen.
 *   2. Card footer (Completed progress label + info button) escapes the card
 *      and stacks/overlaps at the wrong place.
 *   3. Desktop-scaled rhythm: dead white bands under card titles.
 *
 * LIVE-DOM ROOT CAUSES (probes in .build/mobile-pass/tools/, Kolibri 0.19.5):
 *   • li.k-card (the mobile ResourceCard / KCard) computes position:static
 *     while its footer div.footer computes position:absolute; bottom:0 —
 *     with no positioned ancestor the footer anchors to the PAGE bottom, so
 *     every card's Completed-label + info button piles up at the grid end,
 *     overlapping the last cards (the owner's "collision"). Fix m1 restores
 *     the positioning context; fix m2 additionally makes the footer row
 *     in-flow so progress row and info button can never overlap.
 *   • .k-thumbnail is a fixed 180px regardless of phone width (m3 caps it).
 *   • The card body renders an ALWAYS-EMPTY activity chip (.k-above-title >
 *     .learning-activity, channel nodes carry no activity metadata) plus
 *     16px paddings → ~60px of dead white under the thumbnail (m4/m5).
 *
 * SCOPING: m1 is unscoped because KCard surfaces (mobile grids + Home
 * "Continue" cards) are outside the desktop regression gates (library,
 * shelf, module, lesson, quiz at 1280 render HybridLearningContentCard /
 * hero / viewer — zero li.k-card), and the fix is a bug fix, not restyle.
 * Every purely-visual tightening (m2-m6) is scoped to max-width:639px so
 * 768/1280 stay pixel-identical.
 * ========================================================================= */

/* m1 — footer containment: give the mobile card a positioning context so the
 * absolute-positioned .progress-section .footer (bottom:0) anchors to ITS
 * card instead of the page. Root-cause fix for the Completed/info pile-up. */
li.k-card {
  position: relative !important;
}

/* m2 — footer row becomes in-flow flex: progress/completed on the left,
 * info button on the right, one clean row, explicit margins (no overlap
 * is geometrically possible in a single flex row with space-between).
 * Upstream paints it absolute (see m1) — in-flow also stops it covering
 * the card body on short cards. */
li.k-card .progress-section {
  margin-top: 4px;
}
li.k-card .progress-section > .footer {
  position: static !important;
  display: flex !important;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  width: auto !important;
}
/* m2b — (completes m2; measured gap in the first pass) upstream paints the
 * row's two CHILDREN absolute as well (.progress-bar-wrapper pins to the
 * card's bottom-left, .footer-icons to the bottom-right), so they ignored
 * flex placement and still crossed by a few px (4x24px on completed cards,
 * 4x4px on in-progress ones — .build/mobile-pass/after). Making them static
 * hands them to the flex row; space-between then guarantees separation.
 * The dropdown .menu inside .footer-icons is NOT a direct child and keeps
 * its own absolute positioning (open menu behaviour untouched). */
li.k-card .progress-section > .footer > * {
  position: static !important;
}
li.k-card .progress-section > .footer > .progress-bar-wrapper {
  flex: 0 1 auto;
  min-width: 0;
  max-width: calc(100% - 60px); /* 44px button + 8px gap + 8px slack */
}
/* the info button is the only interactive control in the row: 44px hit area.
 * margin-left:auto keeps it right-aligned even on cards with no progress
 * element (single flex child + space-between would otherwise park it left,
 * inconsistent with completed cards and with the desktop cards). */
li.k-card .progress-section .footer-icons {
  flex: 0 0 auto;
  margin-left: auto;
}
li.k-card .progress-section .footer-icons button {
  min-width: 44px !important;
  min-height: 44px !important;
  margin: 0 !important;
}

/* ---- mobile-only rhythm fixes (≤639px — true phone widths) -------------- */
@media (max-width: 639px) {
  /* m3 — thumbnail cap: fixed 180px → 150px so a card fits within roughly
   * one screen-third (150 thumb + ~90 body ≈ 240px < 844/3 ≈ 281). The inner
   * span[data-testid='thumbnail-img'] is width/height 100% and follows. */
  li.k-card .k-thumbnail {
    height: 150px !important;
    min-height: 0 !important;
  }
  li.k-card .k-thumbnail span[data-testid='thumbnail-img'] {
    height: 100% !important;
  }

  /* m4 — kill the always-empty activity chip row (~30px of dead white on
   * every card: channel nodes carry no learning_activities metadata).
   * Same guard style as §(e/f): only hidden while it has no svg icon, so a
   * future metadata pass re-enables it automatically. */
  li.k-card .k-above-title .learning-activity:not(:has(svg)) {
    display: none;
  }

  /* m5 — tighten the title zone: 16px→10px vertical paddings around the
   * title block (title font stays upstream 16px/600). */
  li.k-card .k-around-title {
    padding: 10px 16px !important;
  }
  /* larger tap target for the title link (upstream 22px tall) */
  li.k-card h3.k-heading a.k-title {
    display: inline-block;
    padding: 5px 0;
  }

  /* m6 — library hero card: cap the cover on phones (upstream §(h) rules
   * give it aspect-ratio 16/9 + min-height 180 → ~202-220px at phone
   * widths). 150px keeps the same cap as the topic cards. Must come after
   * §(h) in this file so it wins the cascade at equal specificity. */
  [data-testid='channel-cards'] .card-thumbnail-wrapper {
    height: 150px !important;
    min-height: 0 !important;
    aspect-ratio: auto !important;
  }

  /* m7 — card-description "Show more" toggle (Kolibri metadata side panel,
   * opened from the card info button): explicit breathing room so the toggle
   * can never crowd the description above or the metadata sections below.
   * (.side-panel measured live: panel.cls = "side-panel".) */
  .side-panel .metadata .show-more-button,
  .side-panel .metadata .section {
    margin-top: 10px;
    margin-bottom: 10px;
  }

  /* m8 — HybridLearningContentCard header-bar: explicit minimum spacing at
   * narrow widths (defensive: this grid normally renders ≥600px, but if it
   * ever appears squeezed, the chip row keeps clear of the thumbnail). */
  [data-testid^='HybridLearningContentCard'] .header-bar {
    margin-bottom: 6px !important;
  }
}
/* ---- end (m) mobile learner pass ---------------------------------------- */

/* =========================================================================
 * ---- (n) STYLE D SHELL ALIGNMENT — elevate the Learn shell to the same
 * design language as the adopted Style D content pages (docs/DESIGN-LEARNER-UI.md
 * §10: warm paper #f7f4ee, Georgia editorial serif, green-800 headings,
 * gold #E0A820/#B7791F accents, hairline #e5e3dc borders). Evidence:
 * .build/shell-d-align/. Selectors derived from live DOM recon
 * (shell-d-align/tools/dom-recon.cjs) — no [data-v-*] hashes, no bundle
 * guesses. Everything stays inside the established tokens; NO new colors.
 * The §(m) mobile rules and §(k) grid above compose untouched: every rule
 * here targets desktop-and-up shared classes that §(m) never overrides, or
 * adds properties §(m) does not set (verified at 360/390/414 — G-gates).
 * ========================================================================= */

/* n2 — page titles: editorial serif + short gold rule beneath (Style D motif).
 * Targets the H1 surfaces of the Learn shell, live-DOM proven:
 *   topic/shelf header (desktop):  h1[data-testid='header-title']  ("Module 1 — …")
 *   topic/shelf header (mobile):   h1[data-testid='mobile-title']  (TopicsMobileHeader,
 *                                  inside div.scrolling-header — same treatment so the
 *                                  publication reads the same on phones)
 *   library:             h1.channels-label                     ("Your library")
 *   library section:     h1.section-heading                    ("Other libraries")
 * Sizes stay upstream (28/32px, 24px mobile) — only family, color and the rule
 * change. The mobile rule adds ~13px inside the scrolling header; §(m) G-gates
 * re-verified clean at 360/390/414. */
h1[data-testid='header-title'],
h1[data-testid='mobile-title'],
h1.channels-label,
h1.section-heading {
  font-family: Georgia, 'Times New Roman', serif !important;
  color: var(--path-ink) !important;
  letter-spacing: -0.01em;
}
h1[data-testid='header-title']::after,
h1[data-testid='mobile-title']::after,
h1.channels-label::after,
h1.section-heading::after {
  content: "";
  display: block;
  width: 48px;
  height: 3px;
  margin-top: 10px;
  border-radius: 2px;
  background-color: var(--path-gold-500);
}

/* n3 — cards: soften to the Style D language. White ground + 12px radius are
 * kept from §(e-h); add the hairline border, replace the two-layer shadow
 * with a single calm one (hover lift kept), and move card titles to
 * green-800 to match Style D's heading color. Scoped to the two proven card
 * families only (session/quiz cards + library hero); home class links and
 * bookmarks cards untouched. */
[data-testid^='HybridLearningContentCard'] {
  border: 1px solid var(--path-line) !important;
  box-shadow: 0 1px 2px rgba(16, 24, 64, .05) !important;
}
[data-testid^='HybridLearningContentCard']:hover {
  box-shadow: 0 2px 6px rgba(16, 24, 64, .08), 0 10px 24px rgba(16, 24, 64, .10) !important;
}
[data-testid^='HybridLearningContentCard'] .title {
  color: var(--path-green-800) !important;
}
[data-testid='channel-cards'] .card-main-wrapper {
  border: 1px solid var(--path-line) !important;
  box-shadow: 0 1px 2px rgba(16, 24, 64, .05) !important;
}
[data-testid='channel-cards'] .card-main-wrapper:hover {
  box-shadow: 0 2px 6px rgba(16, 24, 64, .08), 0 10px 24px rgba(16, 24, 64, .10) !important;
}
[data-testid='channel-cards'] .card-main-wrapper .title {
  color: var(--path-green-800) !important;
}

/* n4 — THE SIGN-IN PAGE, REDESIGNED: ONE TITLE, A MASTHEAD, A FIELD THAT
 * COMPOSES THE PAGE, A BUTTON THAT LOOKS ALIVE.
 *
 * WHAT THE OWNER SAW (measured on the live page — evidence in
 * .build/signin-redesign/before/): a cream card floating in a very large
 * flat green field; TWO titles (a green badge with gold letterspaced
 * "AIMAN.ACADEMY" and, five lines below it, a serif "Aiman"); a NEXT
 * button that rendered as a PALE MINT slab; "This field is required" in
 * Kolibri's bright red; and a white language band cutting the green in
 * half.
 *
 * THE BRAND TO MATCH is the landing page (templates/landing/base.html):
 * the deep-green hero gradient, the 4px DOUBLE GOLD RULE under it, the
 * .72rem / .28em / 700 uppercase GOLD wordmark, the cream paper card and
 * the muted notes.
 *
 * LIVE DOM (Kolibri 0.19.5, captured from the running container):
 *   div.wrapper-table                      ← the auth wrapper (AuthBase)
 *     > div.table-row.main-row > div.table-cell.main-cell
 *       > div.box                         ← the card (border-box, 360px)
 *         > div > div:has(> h1.kolibri-title)   ← the wordmark's wrapper
 *           > h1.kolibri-title             ← "AIMAN.ACADEMY" (AuthBase.logoText)
 *         > div.auth-context-header > h2  ← "Aiman" (the theme's siteTitle)
 *         > form.login-form               ← the field + the NEXT button
 *     > div.table-row > div.table-cell.footer-cell
 *       > div.language-switcher-wrapper    ← the language band
 *
 * SCOPE: .wrapper-table is the AUTH wrapper — the Learn app and every other
 * Kolibri surface render no .wrapper-table, so nothing here can reach them.
 * ---------------------------------------------------------------------- */

/* n4a — THE FIELD. The card used to float in a flat wall of green, and the
 * reason was NOT this stylesheet: Kolibri paints its OWN overlay over the
 * whole auth cell, inline —
 *   div.main-cell > div.background
 *     style="background-color: rgb(34,130,77);
 *            background-image: linear-gradient(rgba(0,0,0,.25),rgba(0,0,0,.25)),
 *                              url(/static/assets/discover_islam/background.svg);
 *            filter: blur(2px); position: absolute; inset: 0; z-index: 0"
 * — the brand background art under a 25% black scrim. It sat ON TOP of
 * every background this stylesheet could paint, which is why the field read
 * as one flat green and the card read as an island in it. The overlay is
 * aria-hidden and purely decorative, so it is REPLACED (not fought with)
 * by the composed field below.
 *
 * THE COMPOSED FIELD, four layers, all of them palette colours:
 *   1. a GOLD GLOW from the top right, at 16% — the brand background art's
 *      own warm light, kept as a tint of gold-500;
 *   2. a green-600 SPOTLIGHT — a pool of light behind the card, so the
 *      card reads as lit on a stage rather than dropped on a wall;
 *   3. a VIGNETTE — the corners fall away to the deep green;
 *   4. the landing page's hero gradient (green-800 → green-950), COMPRESSED
 *      into the upper half so the page has a lit top and a deep bottom.
 * The old 4px double gold rule on the wrapper is gone: the gold now closes
 * the MASTHEAD (n4c), where it belongs, instead of drawing a line under a
 * white band at the page edge. */
.wrapper-table {
  background-color: var(--path-green-950) !important;
  background-image:
    radial-gradient(56% 38% at 86% 6%, rgba(224, 168, 32, .16) 0%, rgba(224, 168, 32, 0) 72%),
    radial-gradient(56% 32% at 50% 45%, rgba(0, 104, 56, .92) 0%, rgba(0, 104, 56, 0) 78%),
    radial-gradient(125% 95% at 50% 38%, rgba(0, 0, 0, 0) 40%, rgba(0, 20, 10, .55) 100%),
    linear-gradient(180deg, var(--path-green-800) 0%, var(--path-green-950) 52%, var(--path-green-950) 100%) !important;
  border-bottom: 0 !important;
  color: #fff !important;
}
.wrapper-table .main-cell > div.background {
  display: none !important;
}

/* n4b — THE CARD. Proportioned (420px, 12px gutters at 360 so it is a card
 * and not a slab), centred, cream, and lifted off the field by a deep
 * shadow. The padding is exposed as two variables because the masthead's
 * bleed (n4c) has to equal it exactly at every width. */
.wrapper-table .box {
  --signin-pad-y: 26px;
  --signin-pad-x: 32px;
  box-sizing: border-box !important;
  width: calc(100% - 24px) !important;
  max-width: 420px !important;
  margin-left: auto !important;
  margin-right: auto !important;
  padding: var(--signin-pad-y) var(--signin-pad-x) 30px !important;
  background-color: #fffdf8 !important;         /* Style D card cream */
  border: 1px solid var(--path-line) !important;
  border-radius: 14px !important;
  box-shadow: 0 20px 52px rgba(0, 22, 11, .50) !important;
  color: var(--path-ink) !important;
}

/* n4b2 — THE GOLD RULE MOTIF. The landing page marks every section with a
 * 40x3px gold bar above the heading (templates/landing/base.html,
 * `h2::before`). The sign-in has no section heading, so the same bar sits
 * under the card as the composition's anchor: it gives the lower half of
 * the green field something to look at and ties the page to the landing
 * page's visual language. */
.wrapper-table .main-cell::after {
  content: "";
  display: block;
  width: 40px;
  height: 3px;
  margin: 30px auto 0;
  border-radius: 2px;
  background-color: var(--path-gold-500);
}

/* n4c — THE MASTHEAD. §(n) already intended this band, but keyed it on
 * `> img.logo`; the theme hook ships NO signIn.topLogo
 * (kolibri_theme/kolibri_discover_islam_theme/kolibri_plugin.py), so there
 * is no img.logo and the rule NEVER MATCHED — which is exactly why the card
 * had no header. The element that IS there is the wordmark's own wrapper,
 * so the band is keyed on the wordmark it actually carries.
 * The negative margins equal the card's padding, so the band bleeds to the
 * card's top/left/right edges, and the landing page's 4px DOUBLE GOLD RULE
 * closes it. */
.wrapper-table .box > div > div:has(> h1.kolibri-title) {
  margin: calc(-1 * var(--signin-pad-y)) calc(-1 * var(--signin-pad-x)) 22px !important;
  padding: 22px var(--signin-pad-x) 20px !important;
  background-color: var(--path-green-800) !important;
  background-image: linear-gradient(180deg, var(--path-green-800) 0%, var(--path-green-950) 100%) !important;
  border-bottom: 4px double var(--path-gold-500) !important;
  border-radius: 13px 13px 0 0 !important;      /* clip inside the card's 14px */
  text-align: center !important;
  color: #fff !important;
}

/* n4d — THE ONE TITLE. The h1 is the wordmark (AuthBase.logoText =
 * "AIMAN.ACADEMY"). Its inline style from the theme hook paints it as a
 * green BADGE — a box inside the green band — so the badge is stripped and
 * the wordmark becomes gold ON the band, which is the masthead treatment
 * §(n) always intended. The wordmark VALUES are the canonical ones
 * (.72rem / .28em / 700 / uppercase), identical to the landing page's
 * kicker, the side nav and the admin header. */
.wrapper-table .box h1.kolibri-title {
  width: auto !important;
  margin: 0 !important;
  padding: 0 !important;
  background-color: transparent !important;
  background-image: none !important;
  box-shadow: none !important;
  border-radius: 0 !important;
  color: var(--path-gold-500) !important;
  font-family: "Segoe UI", system-ui, -apple-system, Roboto, Arial, sans-serif !important;
  font-size: .72rem !important;
  font-weight: 700 !important;
  line-height: 1.4 !important;
  letter-spacing: .28em !important;
  text-transform: uppercase !important;
  text-align: center !important;
}

/* n4e — THE SECOND NAME GOES. .auth-context-header renders the theme's
 * siteTitle ("Aiman") as an <h2> above the form: the plain product name,
 * alone, in a second typeface, under the wordmark. Exactly one name may
 * remain on the page and the plain one is the one that goes. The
 * component keeps rendering it — only the duplicate is hidden. On the
 * password step the same header also carries the "Change learning
 * facility" back action, and that action is NOT touched here. */
.wrapper-table .auth-context-header h2 {
  display: none !important;
}
.wrapper-table .auth-context-header {
  margin: 0 !important;
  padding: 0 !important;
  min-height: 0 !important;
}

/* n4f — THE FIELD. Kolibri's textbox is an underline field with a floating
 * label; its colours are set INLINE by the component (the label, the input
 * and the floating label text all carry style="… rgb(0,104,56)"), so every
 * override here has to be !important to beat the inline style. The grey
 * field plate Kolibri paints (rgb(245,245,245)) is replaced with a 5%
 * green-600 wash, so the field belongs to the cream card instead of
 * looking like a rectangle pasted onto it.
 *
 * The UNDERLINE's colour is deliberately NOT overridden: Kolibri already
 * paints it green-600 (rgb(0,104,56)) on the live field and greys it on
 * the spent username field of the password step, which is the right signal
 * and the vendor's own intent. Only the invalid state (n4g) repaints it. */
.wrapper-table .box .ui-textbox-label {
  background-color: rgba(0, 104, 56, .05) !important;
}
.wrapper-table .box .ui-textbox-input {
  font-size: 1.0625rem !important;
  color: var(--path-ink) !important;
}
.wrapper-table .box .ui-textbox-label-text {
  font-size: 1rem !important;
}

/* n4g — THE ERROR IS A NOTE, NOT AN ALARM. Kolibri prints the validation
 * message in its own bright red (rgb(210,30,0), set INLINE on
 * .ui-textbox-feedback-text). The brand palette has no red, so the note
 * takes the quiet muted ink (#5B6472) at 13px and the FIELD carries the
 * attention cue in the brand's gold. THE VALIDATION BEHAVIOUR IS UNTOUCHED
 * — when the vendor shows the message, this only changes how it looks.
 *
 * The gold dot is scoped to .is-invalid because Kolibri renders the
 * feedback element EMPTY on a valid field — an unscoped ::before would
 * paint a lone dot under an untouched input. */
.wrapper-table .box .ui-textbox-feedback-text {
  color: var(--path-muted) !important;
  font-size: .8125rem !important;
  font-weight: 400 !important;
  letter-spacing: .01em !important;
}
.wrapper-table .box .ui-textbox.is-invalid .ui-textbox-feedback-text::before {
  content: "";
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 8px;
  border-radius: 50%;
  background-color: var(--path-gold-700);
  vertical-align: middle;
}
.wrapper-table .box .ui-textbox.is-invalid .ui-textbox-label,
.wrapper-table .box .ui-textbox.is-invalid .ui-textbox-input {
  border-bottom-color: var(--path-gold-700) !important;
}

/* n4h — THE BUTTON LOOKS ALIVE. Kolibri's disabled state is `opacity: .5`
 * on the whole button, which composites the brand green over the cream card
 * and turns it into the pale mint slab the owner called broken. The
 * opacity is removed: the button is a SOLID brand green in both states, and
 * the two states differ by COLOUR and by the 3px solid base under the
 * label — a raised, brighter button that is ready; a flat, deeper one that
 * is waiting. Both keep white text (6.9:1 and 8.9:1 on the cream card).
 *
 * WHY THE SELECTORS ARE THIS SPECIFIC: Kolibri's KButton injects its own
 * <style> into the head AT RUNTIME, after this stylesheet, with
 *   ._1qzohrl:disabled { opacity: .5 !important; box-shadow: none !important }
 *   ._1qzohrl          { background-color: rgb(34,130,77) !important }
 * Those are !important at (0,2,0) and (0,1,0), so a (0,2,0) rule of ours
 * would TIE and lose on source order. The rules below sit at (0,3,0) —
 * .wrapper-table .box .login-btn — and win on specificity. */
.wrapper-table .box .login-btn {
  opacity: 1 !important;
  background-color: var(--path-green-800) !important;
  color: #fff !important;
  border-radius: 8px !important;
  min-height: 52px !important;
  width: 100% !important;
  box-shadow: none !important;
  font-size: .95rem !important;
  font-weight: 700 !important;
  letter-spacing: .08em !important;
}
.wrapper-table .box .login-btn:not(:disabled) {
  background-color: var(--path-green-600) !important;
  box-shadow: 0 3px 0 var(--path-green-950) !important;
}
/* ---- end (n4) the sign-in page ------------------------------------------ */

/* ---- (n2) sign-in: hide the vendor footer line + the guest link --------
 * The Kolibri sign-in page still carries Learning Equality's own footer
 * line ("Kolibri 0.19.5 - Usage and privacy") and an "Explore without
 * account" link to the guest-access screen. Neither belongs on the Aiman
 * sign-in: the version line is vendor chrome, and the guest link lets a
 * visitor walk into the learner app without an account.
 *
 * Live-DOM proof (Kolibri 0.19.5 sign-in page, dumped from the running
 * container; evidence: .build/landing-signin/signin-report.json):
 *   div.wrapper-table > div.table-row > div.footer-cell.table-cell
 *     > div.small-text
 *         > span.version-string  "Kolibri 0.19.5"
 *         > span                " - "
 *         > a.link > span.link-text  "Usage and privacy"
 *   div.wrapper-table > div.main-row.table-row > div.main-cell.table-cell
 *     > div.box > div > p.alternative-link.small-text
 *         > a[href="/en/guestaccess/"] > span.kexlink-inner
 *             > span.link-text  "Explore without account"
 *
 * Scope: .wrapper-table is the AUTH wrapper (AuthBase) - the Learn app and
 * every other Kolibri surface render no .wrapper-table, so these rules
 * cannot reach them (same argument as the (n) Style D shell block above).
 * The guest link is additionally pinned by its own href, so no other link
 * is ever hidden.
 *
 * COSMETIC ONLY: this hides the two elements. Anonymous API access to the
 * channel is still technically possible (the Kolibri public API endpoints
 * are not covered by this stylesheet). A hard block needs a Kolibri-level
 * setting that does not exist in 0.19.5.
 */
.wrapper-table .version-string,
.wrapper-table .version-string + span,
.wrapper-table .version-string ~ a {
  display: none !important;
}
.wrapper-table a[href="/en/guestaccess/"] {
  display: none !important;
}
.wrapper-table p.alternative-link:has(a[href="/en/guestaccess/"]) {
  display: none !important;
}

/* ---- (n5) THE BOTTOM OF THE SIGN-IN PAGE: NO WHITE BAND, NO LOOSE
 *      LANGUAGES, A LANDING-PAGE FOOTER -----------------------------------
 *
 * THE WHITE BAND. Kolibri paints .footer-cell white INLINE, so the bottom
 * of the sign-in page was a white slab cutting the green in half, and it
 * carried the language picker (a globe plus eight languages and a MORE
 * LANGUAGES button). Two problems, one cause:
 *
 *   1. THE BAND. A white slab across the bottom of a deep-green page is
 *      not part of any composition. It is replaced here by the landing
 *      page's own footer treatment — a hairline gold rule and one quiet
 *      line — so the green field owns the page from the masthead to the
 *      foot.
 *
 *   2. THE LANGUAGES. Every topic title in the channel is ENGLISH (the
 *      course content is English only), but Kolibri's UI is translated
 *      into 35 languages, so the picker offered a learner a Kiswahili
 *      sign-in screen and English lessons — a promise the course cannot
 *      keep. The band is therefore hidden on THIS page.
 *
 * M7-LANG — HOW LOCALISATION TURNS IT BACK ON.
 *   NOTHING IS DELETED. Kolibri's translation files are untouched, the
 *   switcher is still in the DOM, and the CSS that hides it is ONE marked
 *   block. When M7 lands the translated content, deleting the block below
 *   restores the picker on the sign-in page — no plugin edit, no wheel
 *   rebuild, no code change. Until then the page never promises a
 *   language the course cannot teach in.
 *
 * SCOPE: .wrapper-table is the auth wrapper, so this cannot reach any
 * other Kolibri surface. */
.wrapper-table .language-switcher-wrapper {
  display: none !important;
}
.wrapper-table .footer-cell {
  background-color: transparent !important;
  background-image: none !important;
  box-shadow: none !important;
  border-top: 1px solid rgba(224, 168, 32, .32) !important;
  padding: 14px 16px 18px !important;
  vertical-align: top !important;
}
.wrapper-table .footer-cell::after {
  content: "New Muslim Course";
  display: block;
  font-family: "Segoe UI", system-ui, -apple-system, Roboto, Arial, sans-serif;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .22em;
  text-transform: uppercase;
  text-align: center;
  color: rgba(255, 253, 248, .74);
}

/* ---- (n6) PHONE FIRST. The audience is on cheap phones, often outdoors,
 *      so the sign-in is built for a thumb at 360px: no horizontal scroll,
 * a 48px button, and the field within reach of one hand. The card's own
 *      gutters (12px a side) and the tightened padding keep the field at
 *      the same 294px it had when the card ran edge to edge. */
@media (max-width: 480px) {
  .wrapper-table .box {
    --signin-pad-y: 20px;
    --signin-pad-x: 20px;
    padding-bottom: 24px !important;
  }
  .wrapper-table .box > div > div:has(> h1.kolibri-title) {
    margin-bottom: 18px !important;
    padding-top: 20px !important;
    padding-bottom: 18px !important;
  }
}

/* ---- (o) MODULE MEDALLION + PER-MODULE TOP EDGE BAR ----------------------
 * Every module of the course gets a numbered medallion in its own hue, so a
 * learner can tell the seven modules apart at a glance. The medallion
 * REPLACES the "Module N - " prefix of the module title, so the heading
 * reads "[3] Salah: The Daily Prayer" instead of "Module 3 - Salah: ...".
 *
 * WHO PRODUCES THE MEDALLION: the gateway serves /__path/module-badges.js
 * (see docker/gateway-nginx.conf) and injects it next to title.js. The script
 * swaps the prefix for <span class="aiman-mod" data-mod="N">N</span>; the
 * seven [data-mod='N'] rules below paint that span in the module's hue.
 *
 * PROVEN live selectors (Kolibri 0.19.5 Learn UI, dumped from the running
 * container - evidence: .build/module-badges/probe3-folders.json and
 * probe4-styles.json):
 *   module shelf heading   main.main-content-grid h2 a.folder-header-link
 *                          > span.link-text          <- the module title
 *   lesson / video card    [data-testid^='HybridLearningContentCard'] .title
 * The side-panel topic tree (a.side-panel-folder-link > span.link-text) is
 * deliberately NOT targeted: it is a navigation list, not a module card, and
 * the medallion count must stay exactly one per module.
 *
 * THE HUES are owner-fixed and sit inside the brand's warm-paper family:
 *   1 #00562D green (brand)   2 #96601A gold (brand)   3 #A64B2A terracotta
 *   4 #1F6F6B teal            5 #6B3A62 plum            6 #5E6B2E olive
 *   7 #33427A indigo
 * The medallion uses the full hue; the 3px top edge bar of the module block
 * uses the same hue (a ~12% tint would also be acceptable - change the seven
 * border-top-color values below and nothing else).
 */
.aiman-mod {
  display: inline-block;
  box-sizing: border-box;
  width: 30px !important;
  height: 30px !important;
  margin-right: 10px !important;
  border-radius: 50% !important;
  background-color: #00562D !important;   /* module 1 default; per-module below */
  color: #fff !important;
  font-family: Georgia, 'Times New Roman', serif !important;
  font-size: 15px !important;
  font-weight: 700 !important;
  line-height: 30px !important;
  text-align: center !important;
  text-decoration: none !important;
  vertical-align: middle !important;
  -webkit-font-smoothing: antialiased;
}
.aiman-mod[data-mod='1'] { background-color: #00562D !important; }
.aiman-mod[data-mod='2'] { background-color: #96601A !important; }
.aiman-mod[data-mod='3'] { background-color: #A64B2A !important; }
.aiman-mod[data-mod='4'] { background-color: #1F6F6B !important; }
.aiman-mod[data-mod='5'] { background-color: #6B3A62 !important; }
.aiman-mod[data-mod='6'] { background-color: #5E6B2E !important; }
.aiman-mod[data-mod='7'] { background-color: #33427A !important; }

/* the module heading row: medallion and title sit on one baseline, centred */
main.main-content-grid h2 a.folder-header-link > span.link-text {
  display: inline-flex;
  align-items: center;
}

/* TOP EDGE BAR of the module block. The heading row is the top edge of the
 * module (heading + its card grid), so the bar is painted on it. Every shelf
 * heading gets the same 3px strip and the same padding (transparent for the
 * non-module shelves, e.g. "Qur'an Memorization", so the rhythm is identical
 * and only the modules carry a colour). */
main.main-content-grid h2 {
  border-top: 3px solid transparent !important;
  padding-top: 14px !important;
}
main.main-content-grid h2:has(.aiman-mod[data-mod='1']) { border-top-color: #00562D !important; }
main.main-content-grid h2:has(.aiman-mod[data-mod='2']) { border-top-color: #96601A !important; }
main.main-content-grid h2:has(.aiman-mod[data-mod='3']) { border-top-color: #A64B2A !important; }
main.main-content-grid h2:has(.aiman-mod[data-mod='4']) { border-top-color: #1F6F6B !important; }
main.main-content-grid h2:has(.aiman-mod[data-mod='5']) { border-top-color: #6B3A62 !important; }
main.main-content-grid h2:has(.aiman-mod[data-mod='6']) { border-top-color: #5E6B2E !important; }
main.main-content-grid h2:has(.aiman-mod[data-mod='7']) { border-top-color: #33427A !important; }

/* ---- (p) VENDOR CHROME OUT, THE AIMAN WORDMARK IN ----------------------
 * The learner app must carry no vendor chrome. Live-DOM proof (Kolibri
 * 0.19.5 Learn app, dumped from the running container; evidence:
 * .build/learner-surface/probe2-out.json and probe3-out.json):
 *
 *   div.side-nav-scrollable-area-footer
 *     > img.side-nav-scrollable-area-footer-logo   (56x77 logo icon)
 *     > div.side-nav-scrollable-area-footer-info > p   "Aiman - New Muslim Course"
 *     > div.side-nav-scrollable-area-footer-info
 *         > p  "Kolibri 0.19.5"              <- vendor name + version
 *         > p  "(c) 2026 Learning Equality" <- vendor copyright
 *         > p > a.privacy-link.link > span.link-text   "Usage and privacy"
 *   div.app-bar .k-toolbar-right > span > svg[ariaLabel="Points earned"]
 *                                   + div.points-description   "4,000"
 *   div.side-nav .user-information > div.points-wrapper.points
 *                                       (tooltip "You earned 4,000 points")
 *   section.section[data-testid="classes"]     "Your classes"
 *   div.modal > h1#modal-title                "Welcome to Kolibri!"
 *
 * The two vendor PARAGRAPHS, the welcome heading, the wordmark and the
 * usage link are TEXT the SPA renders, so /__path/brand-app.js rewrites
 * them (the gateway serves it; see gateway-nginx.conf). Everything below
 * is structural and belongs in CSS.
 */

/* the top-bar points balance: the icon and the number. The balance for
 * the signed-in demo learner was 4,000 points (Kolibri gamification, not
 * an Aiman concept) - it goes, icon and number alike. */
.app-bar svg[ariaLabel="Points earned"],
.app-bar .points-description,
.side-nav .points-wrapper.points {
  display: none !important;
}

/* the same balance on the LEARNER'S OWN PROFILE page (/en/profile/): the
 * "Points" row - the balance, its leaf icon and the "You earned 4,000
 * points" tooltip - is the first row of that table and the first thing a
 * student sees on their own profile. Live-DOM proof (Kolibri 0.19.5
 * profile page, dumped from the running container; evidence:
 * .build/learner-surface/probe-profile-out.json):
 *   tr > th "Points"
 *     + td.points-cell > svg[ariaLabel="Points earned"] + "4,000"
 * The row is matched by its td.points-cell (the row label is TEXT, so CSS
 * cannot match it); every other row of that table is untouched - user
 * type, facility, full name, username, gender and birth year. */
tr:has(> td.points-cell) {
  display: none !important;
}

/* the Classes surface: the learner reaches the course from the channel
 * card in the "Explore channels" section of the home page, never from a
 * class list. The classroom MEMBERSHIP is untouched - only the student
 * facing surface of it is hidden. */
section[data-testid="classes"] {
  display: none !important;
}

/* ---- (q) THE LEARNER APP'S BRAND CHROME --------------------------------
 * The course app is a third-party application: only the BRAND CHROME is
 * aligned here (the band, the section headings, the links) - its buttons,
 * cards, quiz UI and lesson pages are untouched.
 *
 * THE BAND: the same deep-green gradient closed by the same 4px double gold
 * rule the other four surfaces use (the portal's .hero / .portal-head and
 * the admin's #header). Before: a flat --path-green-800 bar with no rule.
 *
 * THE SECTION HEADINGS: the brand green plus the gold tick above them, the
 * same treatment the portal's h2 carries (assets/css/portal.css). The
 * module headings are EXCLUDED FROM THE TICK - they already carry the
 * per-module 3px hue bar and the numbered medallion, and a second rule
 * above them would collide with that treatment. They do take the brand
 * green, like every other h2.
 *
 * THE LINKS: the brand green (--path-green-600, the same value as the
 * portal's --green-600). The card titles keep their own ink (they are the
 * cards) and the active navigation item keeps its own state colour.
 */
.app-bar,
.app-bar .k-toolbar,
.k-toolbar--type-clear {
  background-image: linear-gradient(180deg, var(--path-green-800) 0%, var(--path-green-950) 100%) !important;
}
.app-bar,
.k-toolbar--type-clear {
  border-bottom: 4px double var(--path-gold-500) !important;
}
/* The live DOM puts the app's content headings inside div#main.main-wrapper
 * (the home page's sections) and the topic page's shelves inside
 * main.main-content-grid (which is inside #main too) - so #main covers
 * both. The module headings are EXCLUDED: they already carry the
 * per-module 3px hue bar and the numbered medallion, and a second rule
 * above them would collide with that treatment. */
#main h2 {
  color: var(--path-green-800) !important;
}
/* On the topics page the heading's TEXT is painted by a link inside the
 * h2 (a.folder-header-link > span.link-text), which carries a colour of
 * its own - so the h2's own colour never reaches the pixels and the
 * module heading stays Kolibri's black. The heading is still a HEADING,
 * so its text takes the brand green too.
 *
 * The numbered medallion (span.aiman-mod, white on a green disc) is NOT
 * touched: it is the per-module treatment the tick must not collide
 * with. */
#main h2 a.folder-header-link,
#main h2 a.folder-header-link span.link-text {
  color: var(--path-green-800) !important;
}
#main h2:not(:has(.aiman-mod))::before {
  content: "";
  display: block;
  width: 40px;
  height: 3px;
  border-radius: 2px;
  background: var(--path-gold-500);
  margin-bottom: .55rem;
}
/* THE LINKS: the brand green (--path-green-600, the same value as the
 * portal's --green-600).
 *
 * SCOPE: the app's own NAVIGATION - the drawer's items - and nothing else.
 * The card titles keep their OWN colour, because they are the cards:
 * live-DOM proof (probe-k-title.cjs, .build/brand-audit) gives the home
 * page's resource titles as
 *     a.k-title < h3.k-heading < div.k-around-title
 *              < div.k-upper-card-area < div.k-card-area
 * i.e. the title link sits INSIDE div.k-card-area, and on the topics page
 * the same cards are a.card.card-link with their own blue titles. Colouring
 * #main's links green would have restyled the cards in one view and not
 * the other - the third-party app's cards are out of scope.
 *
 * The active navigation item keeps its own state colour (white on the green
 * band), which is what the router-link-*-active classes mark. */
.side-nav a.core-menu-option:not(.router-link-active):not(.router-link-exact-active),
.side-nav a.link:not(.router-link-active):not(.router-link-exact-active) {
  color: var(--path-green-600) !important;
}

/* the drawer carries the wordmark ONCE: the chip at the top (where the
 * brand icon was) stays, the duplicate in the footer goes - the footer
 * keeps the course name and the usage-policy link. */
.side-nav-scrollable-area-footer .aiman-wordmark {
  display: none !important;
}

/* the AIMAN wordmark - ONE definition, ONE carrier:
 *   - the nav TOP wordmark: generated by THIS stylesheet, on the
 *     scrollable area's ::before, where the crescent icon used to be.
 * (The footer wordmark span the gateway script inserts is hidden above -
 * the drawer carries the mark once, at the top.)
 *
 * The landing page draws its wordmark as the hero kicker: uppercase,
 * .28em letter-spacing, 700, gold on the deep-green band
 * (templates/landing/base.html). The same treatment travels here - the
 * nav sits on warm paper, so the wordmark carries the green band it
 * needs to stay readable. */
.side-nav .aiman-wordmark,
.side-nav-scrollable-area::before {
  display: inline-block;
  background-color: var(--path-green-800) !important;
  color: var(--path-gold-500) !important;
  font-family: "Segoe UI", system-ui, -apple-system, Roboto, Arial, sans-serif;
  font-size: .72rem;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: .28em;
  text-transform: uppercase;
  padding: .55rem .7rem;
  border-radius: 4px;
}

/* the wordmark at the top of the drawer, and the crescent that leaves
 * with it. Live-DOM proof (Kolibri 0.19.5 Learn app, dumped from the
 * running container; evidence: .build/learner-surface/probe-header-out.json):
 *   div.side-nav-scrollable-area > img.logo
 *     (src=/static/assets/discover_islam/logo.png, alt="Discover Islam",
 *      64x64, the FIRST child of the scrollable area - the brand icon
 *      that sits under the "Aiman" title row)
 * The brand rule (wordmark-led) says no icon in the nav header, so the
 * icon goes and the wordmark takes its place. The (c) block above still
 * paints img.logo; this rule wins. */
.side-nav-scrollable-area::before {
  content: "AIMAN.ACADEMY";
  margin: .5rem 0 .9rem 16px;
}
.side-nav-scrollable-area > img.logo {
  display: none !important;
}

/* =========================================================================
 * ---- (r) HOME / BROWSE SCREEN — ONE BAND, ONE GOLD ----------------------
 * Owner report (360px, signed-in learner, /en/learn/#/home):
 *   "the home screen is too shabby and cluttered with what looks like
 *    stacked up headers very amateurish!"
 *
 * Reading the rendered page top-to-bottom at 360x780 gives FOUR gold
 * accents above the first card and THREE things that read as a header:
 *
 *   y   0- 56   div.k-toolbar.app-bar.k-toolbar--type-clear   <- header 1
 *               (≡ Learn ............ avatar demo_learner)
 *               closed by its OWN 4px double gold rule at y=56
 *   y  56-101   div.subpage-nav                              <- header 2
 *               (Home | Library | Bookmarks)
 *   y 101-105   the band's SECOND 4px double gold rule
 *   y 122-155   h2 "Continue learning on your own"           <- header 3
 *               (40x3 gold bar above it)
 *   y 1988      h2 "Explore channels"  (a second identical gold bar)
 *
 * MEASURED ROOT CAUSES (live DOM, .build/home-redesign/before/facts.json):
 *
 *  1. `.app-bar` is a class on BOTH the outer container (div.app-bar, 105px)
 *     AND the inner toolbar (div.k-toolbar.app-bar.k-toolbar--type-clear,
 *     56px). Every `.app-bar` rule in §(a)/(q) therefore paints BOTH:
 *       • the green-800→green-950 gradient is painted twice, so the inner
 *         toolbar re-runs the gradient over its own 56px. At the seam the
 *         band jumps from green-950 (toolbar bottom) back to green-800
 *         (outer band at 53%), which is the "second green tab bar with its
 *         OWN background tone" the owner saw;
 *       • `border-bottom: 4px double gold` lands on the inner toolbar AND
 *         on the outer band — the band is closed by gold TWICE (y=56 and
 *         y=101). Two gold rules on one band is what makes it read as two
 *         stacked headers.
 *     `.app-bar:not(.k-toolbar)` is the ONLY stable way to name the outer
 *     container: both boxes share the class, only the outer one lacks
 *     `.k-toolbar`.
 *
 *  2. `#main` paints rgb(245,245,245) on the home screen (and only there —
 *     the topic/library `#main` is transparent). The warm paper the rest of
 *     the brand sits on never reaches the learner's home.
 *
 *  3. `#main` has 8px side padding on home, so cards run 344px inside a
 *     360px phone with 8px gutters and 16px internal padding — the cramped
 *     "shabby" edge.
 *
 *  4. `#main h2:not(:has(.aiman-mod))::before` (the §(q) gold tick) fires on
 *     BOTH home section headings, and it fires again as a 40x3 bar sitting
 *     ABOVE the heading rather than attached to it, so each section opens
 *     with a rule that looks like another piece of chrome. Combined with the
 *     gold tab underline and the two gold band rules that is four gold
 *     accents above the first card, none of them primary.
 *
 *  5. The home card (li.k-card, 344x265 at 360px) is 150px photo + 82px
 *     text + a 4px progress line. The progress line is upstream's
 *     `div.ui-progress-linear` at 4px tall with a #e6e6e6 track and a
 *     8.4px rgb(51,51,51) fill — a full-width grey hairline with a dark nub,
 *     which reads as a stray border rather than progress.
 *
 * THE DESIGN DECISION — ONE BAND (merge, not flatten):
 *   The app bar and the tab row are merged into ONE green surface with one
 *   hairline between the rows, rather than flattening the tab row onto paper.
 *   Reason: div.subpage-nav lives INSIDE div.app-bar, and div.app-bar is the
 *   app's fixed/scrolling header (div.scrolling-header > div.app-bar). Flat-
 *   -tening the tabs onto paper would leave the tabs in the same scrolling
 *   box as the content, so they would ride over the cards mid-scroll and the
 *   white inactive labels would need re-tuning against paper for contrast.
 *   Merging keeps the tabs on the surface they already sit on (white labels,
 *   8.86:1) and only removes the seam and the duplicate rule.
 *
 * ONE GOLD AT A TIME:
 *   Gold is now reserved for exactly THREE meanings — the ACTIVE tab
 *   underline (which tab you are on), the section tick (which is content
 *   emphasis), and PROGRESS (the bars and the badge).
 *   WHY PROGRESS IS GOLD TOO: THE OWNER DECIDED ONE GOLD SYSTEM FOR EVERY
 *   PROGRESS INDICATOR, because differently coloured progress read as
 *   different kinds of thing rather than one kind of thing — a green bar
 *   beside gold bars read as a second, separate system instead of the same
 *   signal.
 *   The band's 4px double gold rule is CHROME REPETITION (it says "header
 *   ends here" a second time), so it goes: the band closes on a 1px
 *   green-950 hairline instead. Gold count above the first card: 4 -> 3,
 *   and no two of them are the same length, weight or meaning.
 *
 * SCOPE / SAFETY:
 *   • Every band rule requires `.app-bar:not(.k-toolbar)`, a box that exists
 *     ONLY on the Learn app shell. The topic/lesson pages render NO
 *     `.app-bar` at all (verified: probe3-out.json -> lesson.appBar = null),
 *     so their `.k-toolbar--type-clear` band, including its 4px double gold
 *     rule, is untouched.
 *   • The heading + gutter rules are scoped to `#main > div > section.section`,
 *     the browse-page section wrapper. The module shelf headings on topic
 *     pages are `main.main-content-grid h2` and carry the per-module hue bar
 *     + medallion; they are NOT inside section.section and are not matched.
 *   • The card rules are scoped to `#main > div > section.section li.k-card`
 *     — the home browse sections' KCard. Bare `li.k-card` also matches the
 *     in-app library's "Recent" grid, so the section prefix keeps the
 *     library list byte-identical. Nothing here touches
 *     [data-testid^='HybridLearningContentCard'] or [data-testid='channel-cards'].
 *   • Nothing is display:none'd except the profile EDIT control (r6), which
 *     is a control the gateway refuses server-side anyway.
 * ========================================================================= */

/* r1 — ONE BAND. The outer container is the only painter.
 *      Background: §(q)'s single gradient, kept, so the band still runs
 *      green-800 -> green-950 across its full height — but now ONCE, over
 *      105px, instead of restarting inside the toolbar row.
 *      The inner toolbar goes transparent: it is the same surface. */
.app-bar:not(.k-toolbar) {
  background-image: linear-gradient(180deg, var(--path-green-800) 0%, var(--path-green-950) 100%) !important;
  background-color: var(--path-green-800) !important;
}
.app-bar:not(.k-toolbar) .k-toolbar {
  background-color: transparent !important;
  background-image: none !important;
  /* removes the SECOND 4px double gold rule (the one at y=56) */
  border-bottom: 0 !important;
}
/* ONE hairline between the two rows — the "one background, one hairline"
 * half of the brief. white at .16 alpha over green-800/950 reads as a crease,
 * not as a divider of two bands. */
.app-bar .subpage-nav {
  border-top: 1px solid rgba(255, 255, 255, .16) !important;
}
/* the band closes ONCE, on a hairline in the palette's darkest green, instead
 * of the 4px double gold that made it read as two stacked headers. */
.app-bar:not(.k-toolbar) {
  border-bottom: 1px solid var(--path-green-950) !important;
}
/* the tabs no longer jump by 2px when the active one grows its gold rule:
 * every tab reserves the 2px, only the active one paints it gold. */
.app-bar a.tab {
  border-bottom: 2px solid transparent !important;
}
.app-bar a.tab.router-link-active {
  border-bottom-color: var(--path-gold-500) !important;
}

/* r2 — THE CONTENT GROUND: warm paper, not upstream grey.
 * TWO painters have to be named, not one. Measured live (probe5-out.json):
 *   div#main.main-wrapper   rgb(245,245,245) on the browse screens
 *                           (transparent on the topic/library shells, where
 *                            the body paper already shows)
 *   HTML ELEMENT            rgb(245,245,245) — upstream paints the page
 *                           canvas grey, so on any screen whose #main is
 *                           shorter than the viewport (the profile page is
 *                           535px in a 780px window) the canvas shows through
 *                           BELOW #main. Painting only #main left the profile
 *                           page two-tone, cream above 535px and grey below.
 * `html` is the element the body background propagates FROM, so it must be
 * painted too or the canvas stays grey. */
html {
  background-color: var(--path-paper) !important;
}
#main {
  background-color: var(--path-paper) !important;
}

/* r3 — GUTTERS AT 360px. `#main`'s 8px side padding puts the cards 8px from
 * the glass while the card itself pads 16px internally — the "shabby" edge.
 * 16px outside matches 16px inside. Guarded by :has(section.section) so the
 * topic/lesson shells (whose #main padding is 0px and whose own wrappers set
 * their gutters) are not moved. Phone widths only, so 768/1280 keep the
 * pixel-identical discipline of §(m). */
@media (max-width: 639px) {
  #main:has(> div > section.section) {
    padding-left: 16px !important;
    padding-right: 16px !important;
  }
}

/* r4 — SECTION HEADINGS READ AS CONTENT, NOT CHROME.
 * The brand pairing is serif headings / sans UI text (templates/landing/
 * base.html: --serif Georgia, --sans Segoe UI). The section headings were
 * the app's own sans at 18.72px/700 — i.e. the same weight and family as the
 * app-bar's own label, which is why they read as a third header.
 * Now: serif, one step smaller (17px), one step lighter (600), same
 * green-800. Subordinate to the band by family and weight, not by being
 * hidden.
 * The gold tick stays (gold is sanctioned for section rules) but drops from
 * a 40x3 bar floating ABOVE the heading to a 28x2 tick attached to it, and
 * its gap tightens from 8.8px to 6px so it groups with the words. */
#main > div > section.section h2:not(:has(.aiman-mod)) {
  font-family: Georgia, 'Times New Roman', serif !important;
  font-size: 17px !important;
  font-weight: 600 !important;
  line-height: 1.3 !important;
  letter-spacing: 0 !important;
  color: var(--path-green-800) !important;
  margin: 22px 0 12px !important;
}
#main > div > section.section h2:not(:has(.aiman-mod))::before {
  content: "" !important;
  display: block !important;
  width: 28px !important;
  height: 2px !important;
  border-radius: 1px !important;
  background: var(--path-gold-500) !important;
  margin-bottom: 6px !important;
}
/* the section heading's LEADING ICON is a black 24px arrow
 * (h2 > span.labeled-icon-wrapper > span.icon > svg, role="presentation",
 *  inline fill rgb(0,0,0)). It is decoration — no link, no handler — but it
 * is a THIRD colour sitting inside the heading, and black against the green
 * serif reads as a leftover artefact. It takes the heading's green so the
 * heading is one object. Nothing about the element's box changes: the
 * label's inline `margin-left: 1.975em` still reserves its space. */
#main > div > section.section h2:not(:has(.aiman-mod)) .labeled-icon-wrapper .icon svg {
  fill: var(--path-green-800) !important;
}
/* the first section's rule sits under the band hairline — keep one rhythm
 * instead of the 22px that would read as a gap */
#main > div > section.section:first-of-type h2:not(:has(.aiman-mod)) {
  margin-top: 16px !important;
}

/* r5 — DE-CLUTTER THE HOME CARD (li.k-card at 360px: 344x265).
 * Parts, measured before (.build/home-redesign/pre/facts.json -> home.cards):
 *   div.k-thumbnail          150px tall, inner img 320x180 offset -15 (clipped)
 *   div.k-around-title       padding 10px 16px
 *   div.k-above-title        padding-bottom 8px, 12px #666 eyebrow
 *   h3.k-heading             16px/600, 2 lines = 40px
 *   div.k-footer             padding 0 16px 16px
 *   div.ui-progress-linear   4px, track #e6e6e6, fill 8.4px rgb(51,51,51)
 * SCOPE: `#main > div > section.section` — the browse-page section wrapper.
 * `li.k-card` ALONE is not narrow enough: the in-app library's "Recent" grid
 * renders the same KCard (`#/library`, measured in pre/facts.json ->
 * library.cards, thumbH 150, title 16px), so an unscoped rule reflows the
 * library list as a side effect. The library's card rhythm is a separate
 * surface with its own sign-off; it is deliberately left byte-identical here.
 * Only the phone band is touched; desktop card rhythm is unchanged. */
@media (max-width: 639px) {
  /* r5a — the photo: 150px -> 132px, so the card is 2.6:1 and the text block
   * is no longer the smaller half of the card. Must come after §(m) m3 in
   * this file to win at equal specificity. */
  #main > div > section.section li.k-card .k-thumbnail {
    height: 132px !important;
    min-height: 0 !important;
  }
  #main > div > section.section li.k-card .k-thumbnail span[data-testid='thumbnail-img'],
  #main > div > section.section li.k-card .k-thumbnail img {
    height: 100% !important;
    object-fit: cover !important;
    object-position: center 35% !important;
  }
  /* r5b — the eyebrow: 12px #666 -> 11px muted, single line, ellipsis. A
   * module title like "Module 3 — Salah: The Daily Prayer" must never wrap
   * onto the title's line. */
  #main > div > section.section li.k-card .k-above-title {
    padding-bottom: 4px !important;
  }
  #main > div > section.section li.k-card .k-above-title .collection-title {
    font-size: 11px !important;
    line-height: 1.4 !important;
    letter-spacing: .04em !important;
    text-transform: uppercase !important;
    color: var(--path-muted) !important;
    white-space: nowrap !important;
    overflow: hidden !important;
    text-overflow: ellipsis !important;
    max-width: 100% !important;
  }
  /* r5c — the title: 16px -> 15px and capped at two lines. The clamp lives on
   * the h3 (the block box); the anchor stays inline-block so its 5px tap
   * padding from §(m) m5 survives. */
  #main > div > section.section li.k-card h3.k-heading {
    font-size: 15px !important;
    line-height: 1.36 !important;
    max-height: calc(2 * 1.36em + 10px) !important;   /* 2 lines + m5's 2x5px */
    overflow: hidden !important;
  }
  #main > div > section.section li.k-card .k-around-title {
    padding: 8px 16px 10px !important;
  }
  /* r5d — the stray progress line becomes a progress indicator: a 3px rounded
   * ink-tint track (rgba(16, 24, 64, .10)) carrying a gold-500 fill, both ends
   * at 999px radius, so the upstream 4px hairline reads as a bar and not as a
   * stray border.
   *
   * WHY gold-500: THE OWNER DECIDED ONE GOLD SYSTEM FOR EVERY PROGRESS
   * INDICATOR. Progress is gold on every surface — §(g)'s progress bars are
   * gold-500 and its progress/completion badge is gold-700 — and this fill
   * joins them. The reason is that differently coloured progress read as
   * different kinds of thing rather than one kind of thing: a green bar
   * standing next to gold bars said "a second, separate system", so the
   * learner could not read the two as the same signal. Green stays the
   * INTERACTIVE colour (links, buttons, focus rings); only PROGRESS is gold. */
  #main > div > section.section li.k-card .progress-section {
    margin-top: 8px !important;
  }
  #main > div > section.section li.k-card .progress-bar-wrapper .ui-progress-linear {
    height: 3px !important;
    border-radius: 999px !important;
    background-color: rgba(16, 24, 64, .10) !important;
    overflow: hidden !important;
  }
  #main > div > section.section li.k-card .progress-bar-wrapper .ui-progress-linear > div {
    border-radius: 999px !important;
    background-color: var(--path-gold-500) !important;
  }
  #main > div > section.section li.k-card .k-footer {
    padding: 0 16px 14px !important;
  }
}

/* r6 — THE PROFILE PAGE READS AS INFORMATION, NOT A FORM THAT LIES.
 * /en/profile/ renders an EDIT control (a.button, href="#/edit") at the top
 * of the page. It cannot work: the gateway refuses PATCH/PUT on
 * /api/auth/facilityuser/ (docker/gateway-nginx.conf:543) because that is the
 * only thing stopping a learner renaming their own username — and the portal
 * joins to a learner by that derived username, so a rename silently detaches
 * their progress. The learner's editable details are moving to My Aiman.
 *
 * Live DOM (probe2-out.json, real render of /en/profile/ at 360px):
 *   div#main.main-wrapper > div.page-container.small > div > div.pure-g
 *     > div.grid-item.pure-u-24-24 > div > h1 > a.button._1qzohrl.raised
 *                                            [href="#/edit"]
 * `a[href="#/edit"]` is the ONLY element on that page whose href mentions
 * edit (editHrefs = ["#/edit"]), and `.page-container` + the href together
 * cannot match any other surface. The h1 that wraps it holds nothing else,
 * so it goes too — otherwise the page keeps an empty heading.
 * EVERYTHING ELSE ON THE PAGE IS UNTOUCHED: the Profile h1, the username, and
 * the six information rows (user type, facility, full name, username, gender,
 * birth year) all still render. */
#main div.page-container h1:has(> a.button[href="#/edit"]) {
  display: none !important;
}
#main div.page-container a.button[href="#/edit"] {
  display: none !important;
}

/* ---- end (r) home / browse screen -------------------------------------- */

/* =========================================================================
 * ---- (s) THE SIGN-IN PAGE, SPLIT: A BRAND PANEL AND A PAPER FORM -------
 *
 * THE OWNER (signed out, 360px and 1280px):
 *   "i expected such a login page instead of what we have now, i dont like
 *    the aggressive green everywhere login page its too ugly!"
 *
 * WHAT WE HAD: a cream card floating in a FULL-BLEED green gradient field
 * (n4a), with a SECOND green masthead band on the card (n4c). Two loud
 * greens, and not one square of paper on the page.
 *
 * WHAT IT IS NOW - the owner's own reference, a split:
 *   WIDE (>=901px)  TWO PANELS
 *     LEFT  the BRAND panel: deep green (--path-green-950), the gold
 *           AIMAN.ACADEMY wordmark, the 40x3 gold rule, one plain line
 *           about the course.
 *     RIGHT the FORM on paper (--path-paper), the card white (--path-card),
 *           the field / NEXT button / validation note exactly as shipped.
 *   PHONE (<=900px) it STACKS: a SLIM brand band across the top - the
 *           wordmark and the gold rule, ~57px - then the form on paper.
 *           NEVER a full-screen green page: that was the complaint.
 *
 * LIVE DOM (Kolibri 0.19.5, BOTH sign-in steps - the password step has the
 * same shape, and its "Change user" back action is a BUTTON inside
 * .auth-context-header, NOT inside the h2 that (n4e) hides; evidence
 * .build/three-changes/probe5-out.json and probe8.cjs):
 *   div.wrapper-table               display:table
 *     > div.main-row.table-row      position:relative; inset:0
 *       > div.main-cell.table-cell  the form column
 *         > div.box                 the card (position:relative; z-index:1)
 *           > div                   the wordmark wrapper
 *             > div:has(> h1.kolibri-title)   THE MASTHEAD (the wordmark)
 *           > div:has(> form.login-form)      the form block
 *             > div.auth-context-header       (h2 "Aiman" + the back action)
 *             > form.login-form
 *           > div (empty)
 *           > div (the guest link, hidden by (n2))
 *         > div.background           Kolibri's own sign-in background layer
 *     > div.table-row > div.footer-cell
 *
 * THE WORDMARK MOVES WITH CSS ALONE. The wordmark IS the h1 inside the
 * masthead, and the masthead is the card's FIRST child - so the card cannot
 * simply gain a second column: the wordmark would sit in the wrong half.
 * Instead the MASTHEAD is taken out of flow and pinned to the left of the
 * page, and the card keeps only the form. One element, one place - the
 * single-title rule survives untouched, and there is still exactly ONE
 * wordmark on the page.
 *
 * THE BRAND PANEL IS FLAT, NOT THE THEME'S background.svg. The theme points
 * signIn.background at assets/kolibri-theme/background.svg - a GREEN gradient
 * with gold glows - and Kolibri paints it as div.background with the theme's
 * own 25% black scrim. Putting that on the brand panel would put the
 * owner's complaint back in a different place: the brief asks for a panel
 * that is "calm and restrained", their reference screenshot is a DARK panel,
 * and the gold wordmark on that image's own bright green (#046A39, under
 * the scrim) measures 4.6:1 - marginal, and the image's gold glow lightens
 * it further. The flat deep green measures 6.3:1 and is the brand's own
 * landing-page hero. So: FLAT --path-green-950, ONE subtle gold glow in the
 * panel's lower right corner, and the theme's div.background stays HIDDEN
 * (display:none, 0x0 box) - it can never cover the form. Asserted.
 *
 * SCOPE: .wrapper-table is the AUTH wrapper. The Learn app and every other
 * Kolibri surface render no .wrapper-table, so none of this can reach the
 * learner app. A SIGNED-IN learner who opens /en/auth/ is redirected by
 * Kolibri to /en/learn/#/home and never sees this page at all (verified).
 * ========================================================================= */

/* s1 — THE PAGE IS PAPER. The green field of (n4a) is replaced by the
 * warm paper the whole rest of the brand sits on, so the green that is
 * left on the page is the BRAND PANEL and nothing else. */
.wrapper-table {
  position: relative !important;          /* the brand panel's containing block */
  background-color: var(--path-paper) !important;
  background-image: none !important;
  color: var(--path-ink) !important;
}

/* s2 — THE BRAND PANEL (wide screens only). The masthead - the block that
 * carries the wordmark - IS the brand panel: it is taken out of the card's
 * flow and pinned to the left of the page.
 *
 * THE CONTAINING BLOCK: the masthead's ancestors are the card (div.box),
 * the cell and the row. For the masthead to be pinned to the PAGE, every
 * one of them has to stop being a containing block, so div.box and
 * div.main-row are set to position:static here and .wrapper-table
 * (position:relative, above) becomes the nearest positioned ancestor.
 * The form block is then given position:relative + z-index:1 so it still
 * paints ABOVE the panel if the two ever met.
 *
 * THE SELECTORS ARE (0,3,0) ON PURPOSE. Kolibri's own JSS stylesheets are
 * appended to <head> AT RUNTIME - after this file - so an equal-specificity
 * !important rule LOSES on source order (see the LAWS at the top of this
 * file). .wrapper-table .main-row is (0,2,0) and TIES with upstream's
 * .table-row[data-v-df909c7e] { position: relative; transform: translateZ(1px) },
 * so the class is named twice to win on specificity.
 *
 * AND THE TRANSFORM HAS TO GO AS WELL. Upstream puts
 * `transform: translateZ(1px)` on every .table-row - a compositing hack
 * that makes a table-row honour `z-index` - and A TRANSFORM MAKES THE
 * ELEMENT A CONTAINING BLOCK for absolutely positioned descendants exactly
 * like position:relative does. With it in place the brand panel's
 * containing block stayed the main row (943px) instead of the page
 * (1000px), and the panel stopped 57px short of the foot. */
@media (min-width: 901px) {
  .wrapper-table .main-row.table-row {
    position: static !important;
    transform: none !important;
  }
  .wrapper-table .main-cell .box {
    position: static !important;
    /* the card sits in the RIGHT column and is the only thing on the page
     * that is raised off the paper */
    background-color: var(--path-card) !important;
    border: 1px solid var(--path-line) !important;
    border-radius: 14px !important;
    box-shadow: 0 10px 30px rgba(16, 24, 64, .13) !important;
  }
  /* the form column: the brand panel takes the left 42% of the page */
  .wrapper-table .main-cell {
    padding-left: var(--path-signin-panel) !important;
    background-color: transparent !important;
  }
  /* the brand panel itself */
  .wrapper-table .box > div > div:has(> h1.kolibri-title) {
    position: absolute !important;
    top: 0 !important;
    left: 0 !important;
    bottom: 0 !important;
    width: var(--path-signin-panel) !important;
    z-index: 0 !important;
    margin: 0 !important;
    padding: 44px 44px !important;
    background-color: var(--path-green-950) !important;
    background-image: radial-gradient(46% 30% at 88% 96%, rgba(224, 168, 32, .14) 0%, rgba(224, 168, 32, 0) 70%) !important;
    border: 0 !important;
    border-radius: 0 !important;
    display: flex !important;
    flex-direction: column !important;
    align-items: flex-start !important;
    justify-content: center !important;
    text-align: left !important;
    color: #fff !important;
  }
  /* the form block: the right column's content, raised above the panel */
  .wrapper-table .box > div:has(> form.login-form) {
    position: relative !important;
    z-index: 1 !important;
  }
  /* the wordmark: left-aligned on the panel, gold on deep green (6.3:1) */
  .wrapper-table .box h1.kolibri-title {
    text-align: left !important;
  }
  /* the brand panel's plain line about the course */
  .wrapper-table .box > div > div:has(> h1.kolibri-title)::after {
    content: "A seven-module, self-paced course for new Muslims";
    display: block;
    max-width: 24ch;
    margin-top: 20px;
    font-family: Georgia, 'Times New Roman', serif;
    font-size: 1.0625rem;
    line-height: 1.6;
    color: var(--path-paper);
  }
  /* the gold rule under the wordmark: the landing page's h2::before motif,
   * and the ONLY gold on the brand side. */
  .wrapper-table .box h1.kolibri-title::after {
    content: "";
    display: block;
    width: 40px;
    height: 3px;
    margin-top: 18px;
    border-radius: 2px;
    background-color: var(--path-gold-500);
  }
  /* the footer's own gold rule is for the green field it lived on; on
   * paper it becomes the palette's hairline, and its line becomes muted
   * ink so it is readable (5.5:1 on paper). The hairline is redrawn as a
   * ::before INSIDE the cell's content box, so it stops at the brand
   * panel's edge instead of running across it. */
  .wrapper-table .footer-cell {
    border-top: 0 !important;
    padding-left: var(--path-signin-panel) !important;
  }
  .wrapper-table .footer-cell::before {
    content: "";
    display: block;
    border-top: 1px solid var(--path-line);
    margin-bottom: 12px;
  }
  .wrapper-table .footer-cell::after {
    color: var(--path-muted);
  }
  /* and the gold rule that used to sit under the card (n4b2) goes: the
   * gold now means "the brand", and the brand is the left panel. */
  .wrapper-table .main-cell::after {
    display: none !important;
  }
}

/* s3 — THE PHONE (and the tablet in portrait): it STACKS, and the brand
 * band is SLIM. The band is the masthead, back in the flow, full-bleed
 * across the top of the page - the wordmark and the gold rule, nothing
 * else. It is ~57px tall, so the form is never pushed off a short screen.
 *
 * The card stops being a card here: full-bleed, no border, no radius, no
 * shadow, so the band can run edge to edge and the form can sit on the
 * paper. The form block keeps a 420px measure and centres itself.
 *
 * THE VERTICAL BALANCE IS DONE WITH FLEXBOX, NOT WITH ARITHMETIC. The
 * auth cell's height is already settled by the table (the viewport minus
 * the footer row), so making the cell a flex column and the card flex:1
 * gives the form block the space BELOW the band to sit in - and the form
 * centres in it. No 100vh maths, so a short viewport simply makes the
 * space smaller: at 360x480 the band is 42px, the form is at y=160..307
 * and the page does not scroll at all. */
@media (max-width: 900px) {
  .wrapper-table {
    background-color: var(--path-paper) !important;
    background-image: none !important;
  }
  .wrapper-table .main-cell {
    padding-left: 0 !important;
    background-color: transparent !important;
    /* the band runs across the TOP of the page, so the cell's content
     * starts at the top instead of being centred in the row. */
    vertical-align: top !important;
    display: flex !important;
    flex-direction: column !important;
  }
  .wrapper-table .box {
    width: 100% !important;
    max-width: none !important;
    margin: 0 !important;
    padding: 0 !important;
    flex: 1 1 auto !important;
    display: flex !important;
    flex-direction: column !important;
    background-color: transparent !important;
    border: 0 !important;
    border-radius: 0 !important;
    box-shadow: none !important;
  }
  /* the band: the first row of the card's flex column */
  .wrapper-table .box > div:has(> div > h1.kolibri-title) {
    flex: 0 0 auto !important;
  }
  .wrapper-table .box > div > div:has(> h1.kolibri-title) {
    position: static !important;
    width: auto !important;
    height: auto !important;
    margin: 0 !important;
    padding: 13px 20px !important;
    background-color: var(--path-green-950) !important;
    background-image: none !important;
    border: 0 !important;
    border-radius: 0 !important;
    display: block !important;
    text-align: center !important;
  }
  .wrapper-table .box h1.kolibri-title {
    text-align: center !important;
  }
  .wrapper-table .box h1.kolibri-title::after {
    margin: 12px auto 0 !important;
  }
  /* the plain line is for the wide screen's brand panel; the phone band
   * stays slim. */
  .wrapper-table .box > div > div:has(> h1.kolibri-title)::after {
    content: none !important;
  }
  .wrapper-table .box > div:has(> form.login-form) {
    box-sizing: border-box !important;
    flex: 1 1 auto !important;
    width: 100% !important;
    max-width: var(--path-signin-form) !important;
    margin: 0 auto !important;
    padding: 26px 20px 22px !important;
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
  }
  .wrapper-table .footer-cell {
    border-top-color: var(--path-line) !important;
    padding-left: 16px !important;
    padding-right: 16px !important;
  }
  .wrapper-table .footer-cell::after {
    color: var(--path-muted);
  }
  .wrapper-table .main-cell::after {
    display: none !important;
  }
}

/* s4 — THE THEME'S BACKGROUND LAYER STAYS HIDDEN. Kolibri paints
 * div.background over the whole auth cell with the theme's signIn
 * background image and a 25% black scrim. It is decorative and it is
 * ABOVE the content in the source order, so it is not fought with - it is
 * left switched off (0x0 box, display:none), which means it cannot cover
 * the form at any width. The brand panel above is painted by the
 * stylesheet, from the palette, with no url() of any kind. */
.wrapper-table .main-cell > div.background {
  display: none !important;
}

/* ---- end (s) the split sign-in ----------------------------------------- */

/* =========================================================================
 * ---- (t) THE HOME CHANNEL CARD: THE REAL THUMBNAIL IS THE COVER -------
 *
 * THE OWNER (360px, signed in, Home > Explore channels):
 *   the card shows the title, a description, a small Aiman mark, and then
 *   ~150px of BLANK WHITE where the channel cover should be.
 *
 * MEASURED ROOT CAUSE (live DOM, .build/three-changes/probe3-out.json):
 *   a.card-link.base-channel-card   312x218   (the whole card)
 *     > h3.title                     280x22    "Aiman - New Muslim Course"
 *     > div.content                  312x161   (border-top 1px #e6e6e6)
 *       > div.pure-g                 300x132
 *         > div.pure-u-6-24           75x132
 *           > span.channel-thumbnail.channel-thumbnail-wrapper  59x132
 *             > img.image             59x33     <- the Aiman mark
 *         > div.pure-u-18-24         225x132
 *           > ... "A seven-module, self-paced course for new Muslims"
 * Upstream Kolibri hard-codes TWO heights (probe: the bundle's own rules,
 *   .base-channel-card[data-v-...]      { height: 218px; }
 *   .channel-thumbnail-wrapper[data-v-...] { height: 132px; })
 * - a 132px-tall COVER SLOT and a 218px-tall card. The Aiman channel has a
 * THUMBNAIL but no cover, so the slot was reserved and never filled: the
 * 33px mark floated in a 132px white box and ~150px of the card was
 * nothing at all. Upstream is NOT a regression and NOT caused by this
 * stylesheet - the card was never touched by it.
 *
 * THE FIX - THE REAL THUMBNAIL IS THE COVER. The channel's own artwork is
 * 320x180 (measured on the live <img>): it IS 16:9, and the card is 312px
 * wide at 360 and 317px at 1280 - so the cover renders at 1:1 with the
 * source and stays pixel-sharp. It is the channel's own brand card
 * (deep green, gold geometry, the Aiman wordmark), so presenting it as
 * the cover is truthful - this is the "real thumbnail" option, not a
 * gradient or a stock photo. The alternative - collapsing the slot - would
 * leave a 59x33 logo beside a line of text under 200px of white card, which
 * reads as an unfinished card rather than a designed one.
 *
 * THE COVER IS PLACED WITH display:contents. The thumbnail is four levels
 * down (div.content > div.pure-g > div.pure-u-6-24 > div > span), so it
 * cannot become the card's first block without the chain being dissolved;
 * display:contents does exactly that and nothing else - the elements stay
 * in the DOM, in the accessibility tree, and in their order.
 *
 * SCOPE: a[data-testid='channelLink'] is the HOME page's card. The
 * in-app LIBRARY page's channel card is a different element
 * (a.card-main-wrapper inside div[data-testid='channel-cards']) and keeps
 * its own (h) hero treatment - untouched here.
 * ========================================================================= */
a.base-channel-card[data-testid='channelLink'] {
  display: flex !important;
  flex-direction: column !important;
  height: auto !important;
  min-height: 0 !important;
  max-height: none !important;
  margin: 0 !important;
  padding: 0 !important;
  background-color: var(--path-card) !important;
  border-radius: 12px !important;
  overflow: hidden !important;
  box-shadow: var(--path-shadow-rest) !important;
}
/* dissolve the wrappers: the card's own blocks become the flex items */
a.base-channel-card[data-testid='channelLink'] .content,
a.base-channel-card[data-testid='channelLink'] .content > .pure-g,
a.base-channel-card[data-testid='channelLink'] .content > .pure-g > .pure-u-6-24,
a.base-channel-card[data-testid='channelLink'] .content > .pure-g > .pure-u-6-24 > div {
  display: contents !important;
}
/* t1 — THE COVER: the channel's own 16:9 artwork, full width. */
a.base-channel-card[data-testid='channelLink'] .channel-thumbnail-wrapper {
  order: 1 !important;
  position: relative !important;
  display: block !important;
  width: 100% !important;
  height: auto !important;
  min-height: 0 !important;
  aspect-ratio: 16 / 9 !important;
  overflow: hidden !important;
  background-color: var(--path-green-950) !important;
  background-image: none !important;
  border: 0 !important;
  border-radius: 0 !important;
}
a.base-channel-card[data-testid='channelLink'] .channel-thumbnail-wrapper img {
  position: absolute !important;
  inset: 0 !important;
  display: block !important;
  width: 100% !important;
  height: 100% !important;
  max-width: none !important;
  object-fit: cover !important;
  object-position: center center !important;
}
/* t2 — THE TITLE, under the cover. */
a.base-channel-card[data-testid='channelLink'] h3.title {
  order: 2 !important;
  margin: 0 !important;
  padding: 14px 16px 0 !important;
  font-size: 16px !important;
  font-weight: 700 !important;
  line-height: 1.35 !important;
  color: var(--path-green-800) !important;
}
/* t3 — THE DESCRIPTION, under the title. */
a.base-channel-card[data-testid='channelLink'] .pure-u-18-24 {
  order: 3 !important;
  width: 100% !important;
  padding: 6px 16px 16px !important;
  font-size: 13px !important;
  line-height: 1.5 !important;
  color: var(--path-muted) !important;
}

/* ---- end (t) the home channel card ------------------------------------ */

/* =========================================================================
 * ---- (u) THE SUB-NAV: LIBRARY AND BOOKMARKS BELONG TO THE DRAWER -------
 *
 * Home | Library | Bookmarks sits in the sub-nav. For a learner with ONE
 * course, Library duplicates Home (its only channel card IS the course
 * Home already shows) and Bookmarks is empty until the learner bookmarks
 * something. The rule that governs this change is a hard one:
 *
 *   NEVER REMOVE A ROUTE THAT IS THE ONLY WAY TO REACH THE COURSE.
 *
 * So the hiding is CONDITIONAL, and each entry is conditioned on a fact
 * about the live DOM rather than on a guess.
 *
 * BOOKMARKS - the drawer already lists it. Live DOM (signed in, the side
 * nav of the Learn app):
 *   div.side-nav a[href='#/home']       "Home"
 *   div.side-nav a[href='#/library']    "Library"
 *   div.side-nav a[href='#/bookmarks']  "Bookmarks"
 * So moving Bookmarks out of the top tab bar is exactly "reduce to a drawer
 * entry" and the route is untouched. The rule is written so that it only
 * fires WHILE the drawer offers it: if a future build drops the drawer
 * entry, the tab comes back by itself.
 *
 * LIBRARY - the drawer lists it too, but the home page is the route the
 * gateway's own welcome modal points the learner at ("open Explore
 * channels to begin a module"), so the tab is only redundant while the
 * home page is actually SHOWING the course. The condition is therefore:
 *   body:has(section[data-testid='exploreChannels'] a[data-testid='channelLink'])
 * - the home page's "Explore channels" section is present AND holds a
 * channel card. If the course is filtered out of the home page (coach /
 * class filtering) the section renders empty or not at all, the condition
 * fails, and the Library tab stays. Asserted in the evidence.
 *
 * A NOTE ON THE MARKER: the brief names [data-testid='channel-cards'].
 * On this Kolibri 0.19.5 build that testid does NOT exist on the home
 * page - it belongs to the IN-APP LIBRARY page's channel list (div.grid
 * [data-testid='channel-cards']), which is where the earlier (h) section
 * points. The home page's own markers are section[data-testid=
 * 'exploreChannels'] and a[data-testid='channelLink'], and those are what
 * this section uses - the brief's marker would have keyed the rule on the
 * wrong page (it is true exactly when the learner is ALREADY in the
 * library).
 *
 * :has() SUPPORT: this rule needs :has(), and so does the stylesheet
 * already (n4c, n4e, n6, r3, r4). :has() is Baseline across the target
 * browsers - Chrome/Edge 105+, Safari 15.4+, Firefox 121+ - and it is
 * checked live in the evidence (CSS.supports('selector(:has(*))')). If a
 * browser did not support it the whole rule is dropped, the tabs come
 * back, and nothing is stranded: the rule can only ever HIDE, and the
 * drawer and the home page both keep working.
 * ========================================================================= */
body:has(section[data-testid='exploreChannels'] a[data-testid='channelLink']):has(.side-nav a[href='#/library'])
  .app-bar li.list-item-navigation:has(> a[href='#/library']) {
  display: none !important;
}
body:has(.side-nav a[href='#/bookmarks'])
  .app-bar li.list-item-navigation:has(> a[href='#/bookmarks']) {
  display: none !important;
}

/* ---- end (u) the sub-nav ------------------------------------------------ */

