/*
 * QuranWay theme.
 *
 * Tokens come from brand/BRAND.md, which derives them from the client's logo
 * and records the measured contrast of every pair. Two rules from that file
 * are load-bearing and are the reason this stylesheet looks the way it does:
 *
 *   gold on white is 2.52:1 and gold on teal is 2.01:1.
 *
 * Both fail. So gold is never text on those grounds. It is a rule, a border,
 * a shape, or a background with dark text on it. Teal carries the typography.
 */

:root {
  --qw-teal: #107A88;
  --qw-teal-deep: #0B5A65;
  --qw-gold: #C89D3D;
  --qw-gold-text: #8A6A1F;   /* the only gold that may be text on white */
  --qw-ink: #0B2F34;
  --qw-sand: #FAF7F0;
  --qw-line: #E4DDD0;
  --qw-white: #fff;

  --qw-body: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --qw-display: 'Playfair Display', Georgia, 'Times New Roman', serif;
  --qw-arabic: 'Noto Naskh Arabic', serif;

  --wrap: 1140px;
  --gut: 24px;

  /* The widgets are the product and style themselves. They take one variable
     from the host theme and only one. */
  --uw-accent: var(--qw-teal);
}

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* The header is sticky and 78px tall, so a bare anchor jump would land the
     section title underneath it. */
  scroll-padding-top: 92px;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  font-family: var(--qw-body);
  font-size: 17px;
  line-height: 1.65;
  color: var(--qw-ink);
  background: var(--qw-white);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 {
  font-family: var(--qw-display);
  font-weight: 600;
  line-height: 1.12;
  letter-spacing: -0.015em;
  margin: 0 0 .5em;
  color: var(--qw-ink);
}

h1 { font-size: clamp(2.2rem, 5.2vw, 3.6rem); }
h2 { font-size: clamp(1.7rem, 3.4vw, 2.5rem); }
h3 { font-size: 1.2rem; }

p { margin: 0 0 1em; }

a { color: var(--qw-teal); text-underline-offset: 3px; }
a:hover { color: var(--qw-teal-deep); }

img { max-width: 100%; height: auto; display: block; }

/* <picture> is inline by default and would sit between a flex/grid parent and
   its image, breaking rules like `.hero-media img { height: 100% }`.
   `display: contents` removes its box so the img lays out as a direct child. */
picture { display: contents; }

.wrap { width: min(var(--wrap), 100% - (var(--gut) * 2)); margin-inline: auto; }

/* Keyboard users land here first. It is invisible until focused, and it is
   the difference between the site being usable without a mouse and not. */
.skip {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden; clip-path: inset(50%);
  white-space: nowrap;
  background: var(--qw-ink); color: #fff;
  z-index: 100;
}
.skip:focus {
  width: auto; height: auto;
  margin: 0; padding: 12px 20px;
  clip-path: none; overflow: visible;
  inset-block-start: 0; inset-inline-start: 0;
  border-radius: 0 0 8px 0;
}

:where(a, button, [tabindex]):focus-visible {
  outline: 3px solid var(--qw-gold);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ---------- buttons ---------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: .5rem;
  font-family: var(--qw-body);
  /* Sized to match the buttons on theummah.io, measured rather than guessed:
     40px tall from 10px/16px padding on 14px text with a 20px line box. The
     old 11.5px/21.6px on 15.7px text made a 51px slab. */
  font-weight: 600; font-size: 14px; line-height: 20px;
  padding: 10px 16px;
  border-radius: 999px;
  border: 1.5px solid transparent;
  /* Explicit, because a <button> otherwise keeps the UA's `buttonface` grey
     and any variant that sets a light text colour becomes invisible. An <a>
     has no default background, which is why this only ever showed on the
     button variants. */
  background: transparent;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color .18s ease, color .18s ease, border-color .18s ease;
}
.btn--fill { background: var(--qw-teal); color: #fff; }
.btn--fill:hover { background: var(--qw-teal-deep); color: #fff; }
.btn--ghost { border-color: currentColor; color: var(--qw-teal); background: transparent; }
.btn--ghost:hover { background: var(--qw-teal); color: #fff; border-color: var(--qw-teal); }
/* The hero pair, matching theummah.io's large variant: 52px from 14px/32px
   on 16px text with a 24px line box. */
.btn--lg { padding: 14px 32px; font-size: 16px; line-height: 24px; }

/* ---------- nav ---------- */

.nav {
  position: sticky; top: 0; z-index: 50;
  background: rgba(255,255,255,.94);
  backdrop-filter: saturate(160%) blur(10px);
  border-bottom: 1px solid var(--qw-line);
}
.nav-in { display: flex; align-items: center; gap: 1.5rem; min-height: 78px; }
/* `flex-shrink: 0` matters: the header is a flex row and at 390px the logo
   was being compressed to 78x52 against a natural 300x160, squashing the
   wordmark by a fifth. A client's mark is the one thing on the page that must
   never be distorted. */
.brand { flex-shrink: 0; }
.brand img { width: auto; height: 52px; max-width: none; }
@media (max-width: 400px) { .brand img { height: 44px; } }
/* Logical, not physical. `margin-left: auto` pushes right in both
   directions, so in the Arabic build it shoved the nav group away from the
   end edge instead of towards it. `margin-inline-start` mirrors with dir. */
.nav-links { display: flex; gap: 1.6rem; margin-inline-start: auto; }
.nav-links a {
  color: var(--qw-ink); text-decoration: none;
  font-weight: 500; font-size: .96rem;
  padding: .35rem 0;
  border-bottom: 2px solid transparent;
}
.nav-links a:hover { color: var(--qw-teal); border-bottom-color: var(--qw-gold); }
.nav-right { display: flex; align-items: center; gap: .9rem; margin-inline-start: auto; }
.nav-links + .nav-right { margin-inline-start: 0; }

.burger {
  display: none;
  width: 44px; height: 44px;
  background: none; border: 0; padding: 10px;
  flex-direction: column; justify-content: center; gap: 6px;
}
.burger span { display: block; height: 2px; background: var(--qw-ink); border-radius: 2px; }

.drawer {
  position: fixed; inset: 78px 0 0; z-index: 49;
  background: #fff; padding: 2rem var(--gut);
  display: flex; flex-direction: column; gap: 1.1rem;
  overflow-y: auto;
}
.drawer a { color: var(--qw-ink); text-decoration: none; font-size: 1.2rem; font-weight: 500; }
.drawer[hidden] { display: none; }

@media (max-width: 860px) {
  .nav-links { display: none; }
  .burger { display: flex; }
  /* Restores the push-right that `.nav-links + .nav-right` cancels. The
     sibling rule still matches once .nav-links is display:none, which is what
     stranded the burger in the middle of the header. */
  .nav-links + .nav-right { margin-inline-start: auto; }
}

/* Below ~420px the logo, the language switcher, the primary button and the
   burger do not fit on one row: at 320px the header ran 38px past the
   viewport. The drawer already carries the same call to action, so the header
   copy of it goes rather than the switcher, which has nowhere else to live. */
@media (max-width: 520px) {
  .nav-right > .btn--fill { display: none; }
  .nav-in { gap: .6rem; }
}

/* ---------- sections ---------- */

.sec { padding: clamp(1.75rem, 4vw, 3.25rem) 0; scroll-margin-top: 92px; }
.sec--tint { background: var(--qw-sand); }
.sec--ink { background: var(--qw-ink); color: #fff; }
.sec--ink h2, .sec--ink h3 { color: #fff; }
/* Gold clears AA on the ink ground (5.68:1), so here it may carry text. */
.sec--ink .eyebrow { color: var(--qw-gold); }
.sec--ink a:not(.btn) { color: var(--qw-gold); }

.eyebrow {
  display: inline-block;
  font-family: var(--qw-body);
  font-size: .78rem; font-weight: 700;
  letter-spacing: .13em; text-transform: uppercase;
  color: var(--qw-gold-text);
  margin-bottom: .7rem;
}
.sec-sub { font-size: 1.12rem; max-width: 62ch; color: #3C5459; }
.sec--ink .sec-sub { color: rgba(255,255,255,.82); }

/* A short gold rule under a heading. This is gold doing what gold is for. */
.rule::after {
  content: ''; display: block;
  width: 56px; height: 3px; border-radius: 2px;
  background: var(--qw-gold);
  margin-top: 1.1rem;
}

/* ---------- footer ---------- */

.foot { background: var(--qw-ink); color: rgba(255,255,255,.78); padding: 2rem 0 1rem; }
.foot-grid {
  display: grid; gap: 2.5rem;
  grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr));
  padding-bottom: 2.5rem;
  border-bottom: 1px solid rgba(255,255,255,.14);
}
.foot-logo { height: 62px; width: auto; }
.foot-ar { font-family: var(--qw-arabic); font-size: 1.15rem; margin-top: .9rem; color: var(--qw-gold); }
.foot h4 {
  font-family: var(--qw-body);
  font-size: .78rem; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--qw-gold);
  margin: 0 0 .9rem;
}
.foot p { margin: 0 0 .4rem; font-size: .95rem; }
.foot a { display: block; color: rgba(255,255,255,.78); text-decoration: none; font-size: .95rem; margin-bottom: .4rem; }
.foot a:hover { color: #fff; }
.foot-base {
  display: flex; flex-wrap: wrap; gap: 1rem;
  justify-content: space-between;
  padding-top: 1.6rem;
  font-size: .87rem; color: rgba(255,255,255,.6);
}
.foot-base .credit a { display: inline; color: var(--qw-gold); }

/* ---------- holding page ---------- */

body.holding { display: flex; flex-direction: column; min-height: 100vh; }
body.holding main { flex: 1; display: flex; }

.hold {
  flex: 1;
  display: grid; place-items: center;
  padding: 4rem var(--gut);
  text-align: center;
  background:
    radial-gradient(circle at 50% 0%, rgba(200,157,61,.13), transparent 62%),
    var(--qw-sand);
}
.hold-in { max-width: 620px; }
.hold-logo { width: min(340px, 78vw); height: auto; margin: 0 auto 2.5rem; }
.hold-eyebrow {
  font-size: .78rem; font-weight: 700;
  letter-spacing: .15em; text-transform: uppercase;
  color: var(--qw-gold-text);
  margin-bottom: .8rem;
}
.hold h1 { margin-bottom: .6rem; }
.hold-sub { font-size: 1.12rem; color: #3C5459; margin-bottom: 2rem; }
.hold-note { margin-top: 2.2rem; font-size: .85rem; color: #6C8085; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ==================================================================
   Page sections
   ================================================================== */

.wrap--narrow { width: min(760px, 100% - (var(--gut) * 2)); }
.sec-head { margin-bottom: 1.6rem; }
.sec-head--center { text-align: center; margin-inline: auto; max-width: 720px; }
.sec-sub--center { margin-inline: auto; }
.sec-head--center .rule::after { margin-inline: auto; }

/* ---------- draft review bar ---------- */

.draftbar {
  background: var(--qw-gold);
  color: #2A1F06;            /* dark on gold: gold can hold text this way round */
  font-size: .88rem;
  line-height: 1.5;
  padding: .7rem 0;
}
.draftbar-in { display: flex; flex-wrap: wrap; gap: .5rem; }
.draftbar strong { font-weight: 700; }

/* ---------- hero ---------- */

.hero {
  position: relative;
  display: grid;
  place-items: center;
  text-align: center;
  isolation: isolate;
  /* The photograph is 3:2. Matching that ratio is what stops the hero
     cropping the group shot down to a band of faces. Capped so it cannot
     take more than the fold on a short screen. */
  width: 100%;
  aspect-ratio: 3 / 2;
  max-height: 88vh;
  min-height: 460px;
  overflow: hidden;
}
/* `display: block` overrides the global `picture { display: contents }`.
   Without it the picture has no box, so `position: absolute` does nothing:
   the <img> becomes a grid item, takes the first row, pushes the copy into a
   second row that `overflow: hidden` clips away, and sits above the scrim
   because an in-flow child outranks a z-index:-1 sibling. The hero then
   renders as a bare photograph with no heading and no darkening, which is
   exactly what shipped. */
.hero-img { display: block; position: absolute; inset: 0; z-index: -2; }
.hero-img img { width: 100%; height: 100%; object-fit: cover; object-position: center 55%; }
.hero-scrim {
  position: absolute; inset: 0; z-index: -1;
  /* Measured, not eyeballed. See the note in index.njk: the brightest pixel
     under the text sits at L~0.98, so anything lighter than this leaves white
     text below 4.5:1 somewhere in the block. */
  background: linear-gradient(180deg,
    rgba(11,47,52,.68) 0%,
    rgba(11,47,52,.72) 55%,
    rgba(11,47,52,.80) 100%);
}
.hero-in { position: relative; max-width: 50rem; padding-block: 2rem; }
.hero-kicker {
  font-size: .8rem; font-weight: 700;
  letter-spacing: .18em; text-transform: uppercase;
  /* Not --qw-gold. Measured against the scrimmed photograph, the gold lands
     at 2.26:1 against the brightest pixel behind this line. The warm cream
     keeps the same temperature at 5.27:1. */
  color: #FDF6E6;
  margin-bottom: 1rem;
}
.hero h1 {
  color: #fff;
  font-size: clamp(2.2rem, 5.4vw, 4rem);
  margin-bottom: .8rem;
  text-wrap: balance;
}
.hero-sub {
  color: #fff;
  font-size: clamp(1rem, 1.5vw, 1.18rem);
  max-width: 44ch;
  margin: 0 auto 2.2rem;
}
.hero-cta { display: flex; flex-wrap: wrap; gap: .8rem; justify-content: center; }

.btn--gold { background: var(--qw-gold); color: #2A1F06; }
.btn--gold:hover { background: #D8AD4D; color: #2A1F06; }
.btn--onteal { border-color: rgba(255,255,255,.8); color: #fff; backdrop-filter: blur(3px); }
.btn--onteal:hover { background: #fff; color: var(--qw-ink); border-color: #fff; }
.btn--onink { border-color: rgba(255,255,255,.6); color: #fff; }
.btn--onink:hover { background: #fff; color: var(--qw-ink); }

@media (max-width: 760px) {
  /* 3:2 is too letterboxed to carry a headline on a phone. */
  .hero { width: 100%; aspect-ratio: 4 / 5; max-height: none; min-height: 540px; }
  .hero-img img { object-position: center 48%; }

  /* Full-width, stacked. Capped so they do not become absurd slabs on a
     large phone or a small tablet, and centred once capped. */
  .hero-cta { flex-direction: column; align-items: stretch; width: 100%; }
  .hero-cta .btn { width: 100%; max-width: 26rem; margin-inline: auto; }
}

/* ---------- trust strip ---------- */

.facts { background: var(--qw-ink); padding: 1.1rem 0; }
.facts-in { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.6rem; text-align: center; }
.fact-n { font-family: var(--qw-display); font-size: 1.28rem; font-weight: 600; color: var(--qw-gold); margin: 0 0 .15rem; }
.fact-t { font-size: .92rem; color: rgba(255,255,255,.76); margin: 0; }
@media (max-width: 680px) {
  .facts-in { grid-template-columns: 1fr; gap: 1.2rem; }
}

/* ---------- notes ---------- */

.notes { display: grid; gap: 1.4rem; grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr)); }
.note {
  background: #fff;
  border: 1px solid rgba(11,47,52,.06);
  border-radius: 12px;
  padding: 1.7rem 1.5rem;
  /* A coloured stroke along the top of a card is the house style of every
     generated template on the internet. A soft shadow lifts the card instead
     and says nothing about where it came from. */
  box-shadow: 0 1px 2px rgba(11,47,52,.05), 0 6px 18px -6px rgba(11,47,52,.12);
  transition: box-shadow .2s ease, transform .2s ease;
}
.note:hover {
  box-shadow: 0 2px 4px rgba(11,47,52,.06), 0 14px 30px -10px rgba(11,47,52,.18);
  transform: translateY(-2px);
}
.note h3 { margin-bottom: .45rem; font-size: 1.1rem; }
.note p { margin: 0; color: #3C5459; font-size: .98rem; }

/* ---------- steps ---------- */

.steps {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: 1.6rem;
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
}
.step { position: relative; padding-top: 3.4rem; }
.step-n {
  position: absolute; top: 0; left: 0;
  width: 2.5rem; height: 2.5rem;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--qw-gold); color: #2A1F06;
  font-weight: 700; font-size: 1.05rem;
}
.step h3 { font-size: 1.12rem; margin-bottom: .35rem; }
.step p { color: rgba(255,255,255,.8); margin: 0; font-size: .98rem; }
.enroll-cta { display: flex; flex-wrap: wrap; gap: .8rem; justify-content: center; margin-top: 3rem; }

/* ---------- faq ---------- */

.faq { border-top: 1px solid var(--qw-line); }
.qa { border-bottom: 1px solid var(--qw-line); }
.qa summary {
  cursor: pointer; list-style: none;
  padding: 1.15rem 2.5rem 1.15rem 0;
  font-weight: 600; font-size: 1.04rem;
  position: relative;
}
.qa summary::-webkit-details-marker { display: none; }
.qa summary::after {
  content: '+';
  position: absolute; right: .4rem; top: 50%; transform: translateY(-50%);
  font-size: 1.5rem; font-weight: 400; color: var(--qw-teal);
  line-height: 1;
}
.qa[open] summary::after { content: '\2212'; }
.qa p { margin: 0 0 1.3rem; color: #3C5459; max-width: 62ch; }

/* ---------- visit ---------- */

.visit-grid { display: grid; gap: 3rem; grid-template-columns: 1fr 1fr; align-items: center; }
.visit-media { margin: 0; }
.visit-media img { border-radius: 12px; aspect-ratio: 4 / 3; object-fit: cover; object-position: center 62%; }
.dl { margin: 2rem 0 0; }
.dl > div {
  display: grid; grid-template-columns: 8rem 1fr;
  gap: 1rem; padding: .8rem 0;
  border-top: 1px solid var(--qw-line);
}
.dl dt { font-weight: 600; font-size: .9rem; color: #5A7075; }
.dl dd { margin: 0; }
@media (max-width: 860px) {
  .visit-grid { grid-template-columns: 1fr; }
  .dl > div { grid-template-columns: 1fr; gap: .2rem; }
}

/* ---------- language switcher ---------- */

.lang { position: relative; }
.lang-btn {
  display: inline-flex; align-items: center; gap: .4rem;
  height: 38px; padding: 0 .75rem;
  font-family: var(--qw-body); font-size: .85rem; font-weight: 600;
  letter-spacing: .04em;
  color: var(--qw-ink);
  background: #fff;
  border: 1.5px solid var(--qw-line);
  border-radius: 999px;
  cursor: pointer;
  transition: border-color .18s ease, background-color .18s ease;
}
.lang-btn:hover { border-color: var(--qw-teal); }
.lang-btn[aria-expanded="true"] { border-color: var(--qw-teal); background: var(--qw-sand); }
.lang-caret { transition: transform .18s ease; }
.lang-btn[aria-expanded="true"] .lang-caret { transform: rotate(180deg); }

.lang-menu {
  position: absolute; top: calc(100% + .5rem); inset-inline-end: 0;
  z-index: 60;
  min-width: 11rem;
  margin: 0; padding: .35rem;
  list-style: none;
  background: #fff;
  border: 1px solid var(--qw-line);
  border-radius: 14px;
  box-shadow: 0 4px 10px rgba(11,47,52,.06), 0 18px 40px -12px rgba(11,47,52,.28);
}
.lang-menu[hidden] { display: none; }
.lang-menu a {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: .6rem .75rem;
  border-radius: 10px;
  color: var(--qw-ink); text-decoration: none;
  font-size: .95rem;
}
.lang-menu a:hover { background: var(--qw-sand); color: var(--qw-teal); }
.lang-menu [aria-selected="true"] a { background: var(--qw-sand); font-weight: 600; }
.lang-abbr { font-size: .74rem; font-weight: 700; letter-spacing: .08em; color: #5A7075; }

/* ---------- gallery ---------- */

.chips { display: flex; flex-wrap: wrap; gap: .5rem; margin-bottom: 1.4rem; }
.chip {
  font-family: var(--qw-body); font-size: .88rem; font-weight: 600;
  padding: .45rem 1.05rem;
  border-radius: 999px;
  border: 1.5px solid var(--qw-line);
  background: #fff; color: var(--qw-ink);
  cursor: pointer;
  transition: background-color .18s ease, border-color .18s ease, color .18s ease;
}
.chip:hover { border-color: var(--qw-teal); color: var(--qw-teal); }
.chip.is-on { background: var(--qw-teal); border-color: var(--qw-teal); color: #fff; }

/* One ratio for every tile. Mixed ratios were the complaint, and a grid only
   reads as a grid when the cells agree. */
.grid {
  display: grid;
  gap: .75rem;
  /* 168px was too wide to fit two columns inside a 390px phone once the
     gutters and the gap were taken out, so the grid silently collapsed to one
     column and the gallery ran to nearly 8000px. 140px keeps two columns on
     the narrowest phone and still gives five or six on a desktop. */
  grid-template-columns: repeat(auto-fill, minmax(min(140px, 100%), 1fr));
}
.tile {
  padding: 0; border: 0; background: var(--qw-line);
  border-radius: 10px; overflow: hidden; cursor: pointer;
  aspect-ratio: 4 / 5;
  transition: transform .22s ease, box-shadow .22s ease;
}
.tile[hidden] { display: none; }
.tile img { width: 100%; height: 100%; object-fit: cover; }
.tile:hover { transform: translateY(-3px); box-shadow: 0 12px 26px -10px rgba(11,47,52,.35); }
.grid-empty {
  margin: 2rem 0 0; text-align: center;
  color: #5A7075; font-size: .96rem;
}

/* ---------- sticky action bar (phones and tablets) ---------- */

/* Enroll and Donate, fixed to the bottom of the screen. Gamal asked for both
   in the header; the bottom is the better place for the same reason his
   parents will mostly be on a phone, where a thumb already rests there and
   the header CTA is hidden at these widths anyway. Desktop keeps the header
   button and gets no bar.

   z-index sits one below the drawer (49) on purpose: above all page content,
   but covered by the open menu rather than floating over it. The gallery
   lightbox is 200 and covers it too. */
.actionbar { display: none; }

@media (max-width: 860px) {
  .actionbar {
    display: flex;
    gap: .5rem;
    position: fixed;
    inset-inline: 0;
    bottom: 0;
    z-index: 48;
    padding: .55rem 1rem;
    /* The iPhone home indicator sits in this strip; without the inset the
       buttons end up underneath it. */
    padding-bottom: calc(.55rem + env(safe-area-inset-bottom, 0px));
    background: rgba(255, 255, 255, .94);
    border-top: 1px solid var(--qw-line);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
  }
  /* Equal halves, and allowed to shrink: min-width 0 keeps a long Arabic
     label from pushing the pair wider than the screen. */
  .actionbar .btn {
    flex: 1 1 0;
    min-width: 0;
    justify-content: center;
  }
  /* The bar floats over the page, so the end of the footer needs room to
     clear it instead of sitting underneath. */
  body { padding-bottom: calc(3.4rem + env(safe-area-inset-bottom, 0px)); }
}

/* ---------- lightbox ---------- */

.lb {
  position: fixed; inset: 0; z-index: 200;
  display: grid; place-items: center;
  gap: 1rem;
  grid-template-columns: auto 1fr auto;
  padding: clamp(1rem, 4vw, 3rem);
  background: rgba(7,30,33,.93);
  backdrop-filter: blur(4px);
}
.lb[hidden] { display: none; }
.lb-img {
  grid-column: 2;
  max-width: 100%; max-height: 88vh;
  width: auto; border-radius: 6px;
  box-shadow: 0 30px 80px -20px rgba(0,0,0,.6);
}
.lb-nav, .lb-close {
  background: rgba(255,255,255,.1);
  border: 1.5px solid rgba(255,255,255,.28);
  color: #fff;
  border-radius: 999px;
  cursor: pointer;
  display: grid; place-items: center;
  transition: background-color .18s ease;
}
.lb-nav { width: 46px; height: 46px; font-size: 1.8rem; line-height: 1; }
.lb-prev { grid-column: 1; }
.lb-next { grid-column: 3; }
.lb-nav:hover, .lb-close:hover { background: rgba(255,255,255,.22); }
.lb-close {
  position: absolute; top: 1rem; inset-inline-end: 1rem;
  width: 42px; height: 42px; font-size: 1.6rem;
}
@media (max-width: 600px) {
  .lb { grid-template-columns: 1fr; }
  .lb-img { grid-column: 1; }
  .lb-nav { position: absolute; bottom: 1.2rem; }
  .lb-prev { inset-inline-start: 25%; }
  .lb-next { inset-inline-end: 25%; }
}

/* ---------- right to left ---------- */

[dir="rtl"] .rule::after { margin-inline: 0 auto; }
[dir="rtl"] .step { padding-inline: 0 0; }
[dir="rtl"] .step-n { left: auto; right: 0; }
[dir="rtl"] .qa summary { padding: 1.15rem 0 1.15rem 2.5rem; }
[dir="rtl"] .qa summary::after { right: auto; left: .4rem; }
[dir="rtl"] .lb-prev { transform: scaleX(-1); }
[dir="rtl"] .lb-next { transform: scaleX(-1); }
/* Arabic sits better in Naskh than in a Latin serif that has no Arabic at
   all and would silently fall back to whatever the OS picks. */
[lang="ar"] h1, [lang="ar"] h2, [lang="ar"] h3,
[dir="rtl"] h1, [dir="rtl"] h2, [dir="rtl"] h3 { font-family: var(--qw-arabic); line-height: 1.4; }
[dir="rtl"] body, [lang="ar"] { font-family: var(--qw-arabic); }

/* Show-more. Eighteen tiles is four screens of scrolling on a phone and
   eighteen image requests the visitor did not ask for. The rest are revealed
   on demand, and because they are lazy they are not fetched until then. */
.grid-more { display: flex; justify-content: center; margin-top: 1.25rem; }
.grid-more[hidden] { display: none; }

/* ---------- film tiles ---------- */

.tile--video { position: relative; }
.tile--video img { width: 100%; height: 100%; object-fit: cover; }
.tile-play {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  color: #fff;
  background: linear-gradient(180deg, rgba(11,47,52,.10), rgba(11,47,52,.45));
  pointer-events: none;
}
.tile-play svg {
  width: 46px; height: 46px; padding: 11px;
  border-radius: 50%;
  background: rgba(11,47,52,.62);
  border: 1.5px solid rgba(255,255,255,.75);
  transition: background-color .2s ease, transform .2s ease;
}
.tile--video:hover .tile-play svg { background: var(--qw-teal); transform: scale(1.06); }

.lb-vid {
  grid-column: 2;
  max-width: 100%; max-height: 88vh;
  border-radius: 6px; background: #000;
  box-shadow: 0 30px 80px -20px rgba(0,0,0,.6);
}
.lb-vid[hidden], .lb-img[hidden] { display: none; }
@media (max-width: 600px) { .lb-vid { grid-column: 1; } }

/* ---------- footer additions ---------- */

.foot .foot-blurb {
  /* `.foot p` sets the `margin` shorthand and outranks a bare `.foot-blurb`,
     which silently zeroed this and left the text flush against the mark.
     Scoped to `.foot` so it wins on specificity rather than on ordering. */
  margin-top: 1.75rem;
  max-width: 34ch;
  font-size: .92rem;
  line-height: 1.6;
  color: rgba(255,255,255,.72);
}
.foot-legal { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1.1rem; }
.foot-sitemap { display: flex; flex-wrap: wrap; gap: .4rem .9rem; }
.foot-sitemap a {
  display: inline; margin: 0;
  font-size: .85rem;
  color: rgba(255,255,255,.6);
  text-decoration: none;
}
.foot-sitemap a:hover { color: #fff; text-decoration: underline; }

/* ---------- mail fallback ---------- */

/* This used to sit on the ink band, where it was white text on a translucent
   white panel. It lives in Visit now, which is beige, so every colour in it
   had to invert or it would have been invisible. */
.visit-cta { margin-top: 1.6rem; }
.mailfall {
  max-width: 34rem;
  margin: 1rem 0 0;
  padding: 1rem 1.15rem;
  border: 1px solid var(--qw-line);
  border-radius: 14px;
  background: #fff;
}
.mailfall[hidden] { display: none; }
.mailfall p { margin: 0 0 .8rem; font-size: .95rem; color: var(--qw-ink); }
.mailfall p a { color: var(--qw-gold-text); }
.mailfall-actions { display: flex; flex-wrap: wrap; gap: .6rem; }
.mailfall-actions .btn { padding: .5rem 1rem; font-size: .9rem; }

/* ---------- donate ---------- */

.btn--sm { padding: 8px 14px; font-size: 13px; line-height: 18px; }
.nav-donate { border-color: var(--qw-gold); color: var(--qw-gold-text); }
.nav-donate:hover { background: var(--qw-gold); color: #2A1F06; border-color: var(--qw-gold); }
/* Two buttons plus the switcher is too much for a narrow header; the drawer
   already carries Donate as a nav item there. */
@media (max-width: 1080px) { .nav-donate { display: none; } }

/* Copy left, widget right. The widget is a fixed-width vertical card, so the
   columns are not 1fr 1fr: the text takes the slack and the widget column is
   sized to the thing that goes in it. */
.donate-grid {
  display: grid; gap: clamp(1.8rem, 4vw, 3rem);
  /* 520px, not 400px. The widget is a real donation form now — fund picker,
     one-time/monthly, four preset amounts, a custom amount and a fee-cover
     checkbox. At 400px the fund dropdown clips its own label and "One-time"
     breaks onto two lines. It needs about 440px before it stops fighting
     itself, so the column is sized to the form rather than to a guess. */
  grid-template-columns: minmax(0, 1fr) minmax(0, 520px);
  align-items: center;
}
/* No card around either widget, on purpose. Each draws its own: white panel,
   rounded corners, a header and a Powered by footer. Wrapping one in a second
   background, radius and shadow produced a card inside a card, with two
   rounded edges a few pixels apart. They sit flat and the widget is the card.
   Height has to be set here because an iframe cannot size itself to
   cross-origin content. */
.widget-frame { width: 100%; }
.widget-frame iframe { width: 100%; height: 100%; border: 0; display: block; }

/* The widget cannot size itself and nothing here can make it: its root is
   `h-screen` and its card is capped at `calc(100vh - 3rem)`, so inside an
   iframe it stretches to exactly the height we give it and then scrolls its
   own list internally. It broadcasts no height on postMessage either, and it
   is cross-origin, so the host has to state a height outright.

   What must never be clipped is the FIRST ROW of cards plus the widget's own
   "Powered by Ummah" footer — a half-cut card is what looked broken. Row
   height depends only on how wide the frame is, not on how many programs
   exist, so these numbers hold as the catalogue grows; past one row the
   widget's own scroll takes over, which is how it is built.

   Measured 2026-10-01 against a real published program. The frame is the
   viewport minus the 48px wrap gutters, capped at 1140, and the widget
   switches column count on its OWN width at 640/768/1024 — so the height
   needed climbs as cards widen, then drops when a column is added. Worst
   case is just below a breakpoint:

     frame  260  342  420  472  500  592  639 | 640  720  767 | 768  900 1023 | 1024 1140
     cols     2    2    2    2    2    2    2 |   3    3    3 |   4    4    4 |    5    5
     needs  523  543  593  627  645  652  683 | 556  592  612 | 538  583  624 |  562  593

   Bands below are those peaks plus a little headroom, keyed to the viewport
   width that produces them (frame + 48). Verified by sweeping every 20px from
   300 to 1500 with zero internal overflow. */
#ummah-programs { height: 640px; }
/* frame 640-767, 3 columns, peak 612 */
@media (max-width: 815px) { #ummah-programs { height: 628px; } }
/* frame 500-639, 2 wide columns: the tallest cards the widget ever draws */
@media (max-width: 687px) { #ummah-programs { height: 700px; } }
/* frame 382-499, 2 columns */
@media (max-width: 547px) { #ummah-programs { height: 656px; } }
/* frame <=381, 2 narrow columns */
@media (max-width: 429px) { #ummah-programs { height: 585px; } }

.donate-widget {
  width: 100%;
  /* An iframe cannot size itself to cross-origin content, so this height is
     measured rather than chosen, and it is measured against the LAST thing in
     the form: the Continue button. At 600px that button was cut off at every
     width, which meant nobody could finish a donation. Narrower is taller,
     because the labels wrap more, hence the three values. */
  height: 700px;
}
.donate-widget iframe { width: 100%; height: 100%; border: 0; display: block; }

@media (max-width: 900px) {
  .donate-grid { grid-template-columns: minmax(0, 1fr); gap: 1.8rem; }
  /* Centred and capped: the form is built for a column, and stretched across
     a full tablet width it reads as a broken layout rather than a card. */
  .donate-widget { max-width: 460px; margin-inline: auto; height: 740px; }
}
@media (max-width: 420px) { .donate-widget { height: 790px; } }

.ticks { list-style: none; margin: 1.4rem 0 0; padding: 0; }
.ticks li {
  position: relative;
  padding-inline-start: 1.7rem;
  margin-bottom: .6rem;
  color: rgba(255,255,255,.85);
  font-size: .98rem;
}
.ticks li::before {
  content: '';
  position: absolute; inset-inline-start: 0; top: .55em;
  width: 9px; height: 5px;
  border-inline-start: 2px solid var(--qw-gold);
  border-bottom: 2px solid var(--qw-gold);
  transform: rotate(-45deg);
}


/* ---------- touch sizing ---------- */

/* On a touch screen every control needs roughly a fingertip of height. These
   only apply to coarse pointers, so the desktop keeps its tighter proportions.
   Measured on iPhone SE/12/14, Pixel 5, Galaxy S9+ and iPad Mini, where the
   burger was 34x44, the language button 38 tall, the chips 33 and the footer
   links 22. */
@media (pointer: coarse) {
  /* The buttons are 40px by design now, which is under a fingertip. On touch
     they get a floor rather than the desktop proportions. */
  .btn { min-height: 44px; }
  /* flex-shrink again: width alone loses to the flex row, exactly as it did
     on the logo. */
  .burger { width: 44px; height: 44px; flex: 0 0 44px; }
  .lang-btn { height: 44px; padding-inline: .9rem; }
  .chip { padding: .7rem 1.1rem; min-height: 44px; }
  .lang-menu a { padding: .8rem .75rem; }
  /* Padding alone left these at 38-39px. A min-height with the label centred
     in it is exact, and does not depend on the font's line box. */
  .foot a { display: flex; align-items: center; min-height: 44px; margin-bottom: 0; }
  .foot-sitemap { gap: 0 .9rem; }
  .foot-sitemap a { min-height: 44px; }
  .qa summary { padding-block: 1.35rem; }
  .tile { min-height: 44px; }
}

/* ---------- curriculum ---------- */

.subjects {
  display: grid; gap: 1.1rem 2.4rem;
  /* `min(300px, 100%)` rather than a bare 300px: on a 320px phone the column
     only has 272px after gutters, and a bare minimum larger than the track
     overflows instead of shrinking. Same trap as the gallery grid. */
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
}
.subject { display: flex; gap: .85rem; align-items: flex-start; }
.subject h3 {
  font-size: 1.2rem; color: var(--qw-teal);
  margin-bottom: .25rem;
}
.subject-icon { flex: 0 0 auto; color: var(--qw-gold-text); line-height: 0; margin-top: .15rem; }
.subject-letter {
  font-family: var(--qw-arabic);
  font-size: 1.5rem; line-height: 1;
  display: inline-block;
}
.subject-icon svg {
  width: 26px; height: 26px;
  fill: none; stroke: currentColor;
  stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round;
}
.subject p { margin: 0; color: #3C5459; font-size: .99rem; max-width: 46ch; }

/* U+FDFA is not in Playfair or Inter. Noto Naskh Arabic, already loaded for
   the Arabic build, covers it. Without this it renders as a tofu box. */
.salawat { font-family: var(--qw-arabic); font-size: 1.05em; }
@media (max-width: 680px) { .subjects { gap: 1.4rem; } }

/* The Admin link is for the people who run the school, not for visitors, so
   it sits quietly beside the credit rather than in the navigation. nofollow
   because there is nothing here for a crawler. */
.credit-sep { opacity: .5; margin: 0 .15rem; }
.admin-link { color: rgba(255,255,255,.6) !important; }
.admin-link:hover { color: #fff !important; }
