/* ==========================================================================
   Shared foundation — colour, type, spacing, radius and motion
   ==========================================================================

   Why this file exists
   --------------------
   Until this file was added, assets/css/ was empty and all 126KB of the site's
   CSS lived in twelve per-page inline <style> blocks. Nothing was shared, so
   the same card drifted into three different treatments on three pages: 109
   unique colours, 50 font sizes, 28 padding values, 25 shadows and 12 corner
   radii. That drift — not any single ugly rule — is what makes a site read as
   assembled rather than designed.

   This file is the single source of truth for colour, type, spacing, radius
   and motion. Pages migrate onto it one at a time; nothing breaks on the way
   because adding a token changes nothing until a page uses it.

   Where the design comes from
   ---------------------------
   The marketing site sets the house style, and the timetable app hanging off
   it looked like a different product entirely. The house style is:

     - white page, hairline rules, no shadows; separation comes from a 1px
       line and from whitespace, never from a drop shadow,
     - one brand ink for headings, links, the wordmark and the current nav
       item; near-black for body copy; muted grey for anything secondary,
     - a serif for headings and the wordmark against a sans for body copy,
     - a white header with a single hairline under it, not a solid brand bar,
     - dark mode by flipping the neutrals, and the logo recoloured with a CSS
       filter rather than shipping a second image file.

   The tokens below are that design. Element styling stays deliberately thin —
   family, colour and rules only, no margins — because the pages that consume
   this file still set their own spacing and a margin declared here would move
   content on every page at once.

   THREE PORTALS SHARE THIS FILE (Musally, alifsuite, Bolton)
   ----------------------------------------------------------
   Not one line here may name a portal or hardcode a portal's colour. The house
   style hardcodes a navy for its ink; here that role is --ink-brand, which
   reads --brand-primary. --brand-primary / --brand-accent / --brand-highlight
   / --brand-page-bg are emitted per-site from portal branding settings by
   outputBrandingStyles(), BEFORE this file loads, and are deliberately NOT
   redefined here. So every portal gains the same structure — white header,
   hairlines, serif headings, muted nav — while keeping its own colour, and a
   branding change in the admin still flows straight through.

   Rules
   -----
   1. No colour outside the palette below. If a value is needed and missing,
      add it HERE, not in a page.
   2. No spacing value outside the scale. 7px, 9px, 11px, 15px and 25px are
      what drift looks like.
   3. box-shadow is banned except for two cases: the focus ring, and a panel
      that floats over page content (the nav's Maps menu). A floating panel
      needs to read as being above the text it covers, and a hairline alone
      cannot say that. Nothing that sits IN the page may carry one.
   4. Nothing below 14px for body text. Much of this audience is older.
   ========================================================================== */

:root {
    /* --- Ink and structure. Brand-independent. --------------------------
       These are the house neutrals. They replaced a slightly cooler, slightly
       darker set so that a page built from tokens and the marketing site sat
       on the same white with the same grey between them.

       --ink-brand is the one token here that is NOT brand-independent, and it
       is the whole reason this palette can be shared: it carries the role the
       house style gives its navy — headings, links, the wordmark, the current
       nav item, primary buttons — while resolving to whatever colour the
       portal is branded with. The fallback is only for pages rendered before
       outputBrandingStyles() has run. */
    --paper:      #ffffff;  /* the page, cards, the header, the footer */

    /* The colour behind the whole page. Held as its own token so the dark block
       has something to override: --brand-page-bg is a per-site branding value
       and all three portals set it to a light colour, so a body reading it
       directly would stay white in dark mode while --ink went near-white. That
       was the single biggest thing keeping dark mode switched off. */
    --page-bg:    var(--brand-page-bg, var(--paper));

    --ink:        #1c2026;  /* body text on paper — 16.3:1 */
    --ink-mid:    #5b6773;  /* secondary text on paper — 5.8:1, replaces the
                               #64748b used in 120 places at a failing 4.35:1 */
    --ink-brand:  var(--brand-primary, #1e3a5f);
    --rule:       #dfe4ec;  /* every border, divider, table rule and hairline */
    --surface:    #f6f8fc;  /* zebra rows, inset panels, quiet card fills */
    --surface-2:  #eaeff7;  /* row hover, selected fill */

    /* Form controls — search boxes, selects, date fields, textareas.
       ------------------------------------------------------------------
       These are NOT --paper. A control sat on --paper is the page colour
       with a --rule border around it, and --rule is 1.28:1 against the
       page, so a row of six filters read as six floating labels with no
       visible boxes at all. The client's words: "all the filter boxes,
       dropdowns etc blend too much with the background of the site".

       --field is one clear step off the page in both themes (in dark it
       goes UP, not down, so a control reads as raised rather than as a
       hole), and --field-border is a border you can actually see at
       ~2.5:1 rather than a hairline that only exists in the stylesheet. */
    --field:        #e4ebf5;
    --field-border: #a3b3c8;
    --field-hover:  #d9e2ef;

    /* Sisters' facilities.
       ------------------------------------------------------------------
       One pair of tokens because five pages label this and they had drifted
       into three different colours: the directory badge and the Jumu'ah chip
       were green (--ok, which everywhere else on the site means "fine, no
       action"), while Eid, Taraweeh and Special Prayers were indigo. Green
       also collided with the "Also holds jama'ah" badge sitting beside it.
       Pink at 6.7:1 on its own fill and 7.9:1 as bare text. */
    --sisters-bg:  #fce7f3;
    --sisters-ink: #9d174d;

    /* --line and --surface-alt ARE NOT TOKENS. Do not add them.
       ------------------------------------------------------------------
       Several pages reach for those two names — `var(--line, #e2e6ee)` and
       `var(--surface-alt, #f6f8fc)` — and because neither is defined here or
       anywhere else, every one of those reads falls straight through to the
       hardcoded light hex written beside it as the fallback. A fallback never
       follows the palette, which is why those particular borders and fills
       stay pale on a dark page while everything around them flips. Nothing
       errors and nothing looks wrong in light mode, so it goes unnoticed.

       Both names already exist under the names above:

         --line         is  --rule
         --surface-alt  is  --surface-2, or --surface where the fill is a
                            quiet panel rather than a hover or selected state

       Defining them here as aliases would fix the symptom and leave the site
       with two names for one hairline, which is the drift this file was
       written to stop. So they stay undefined and the pages that use them are
       corrected instead. If you have arrived here because a page looked wrong
       in dark mode, the page is what needs the edit. */

    /* The only shadow on the site that is not the focus ring — see rule 3.
       Held as a token so there is exactly one of it and it can be deepened in
       dark mode, where a hairline on a dark ground carries even less weight. */
    --overlay-shadow: 0 8px 20px rgba(17, 24, 39, 0.10);

    /* Applied to the nav mark. `none` in light mode because a logo may be an
       uploaded masjid logo in arbitrary colours, and flattening one of those
       would be worse than leaving it alone. See the dark block for the flip.

       NOTE FOR DEPLOYMENT: the header is white now, so the logo a site names
       in its config must be the DARK mark. A white-stroke logo, which is what
       a dark bar needed, is invisible here. */
    --logo-filter: none;

    /* --- Semantic. STATE ONLY, never category colour-coding. ------------
       Category colour-coding is what produced the rainbow-badge look, where
       the same six concepts wore saturated colours on the events listing and
       pastels on the event detail page. */
    --ok:    #16603c;  --ok-bg:   #e8f3ed;
    --warn:  #8a5a00;  --warn-bg: #fbf2e0;
    --stop:  #a32020;  --stop-bg: #f9e9e9;

    /* --- Directory categories -------------------------------------------
       The ONLY category colours on the site, and the one sanctioned exception
       to the state-only rule above. Six muted inks at matched lightness (all
       between roughly 25% and 35%), so none of them reads as an alert and all
       clear 7:1 on white.

       Used as a 3px left rule on a card, a small square in the legend, and —
       since 3 Aug 2026 — as a SOLID FILL behind white text on the directory's
       type tag. That last one is safe precisely because of the matched
       lightness above: at 25-35% every one of these gives white between 8:1 and
       12:1, so a filled tag is as readable as an outlined one and scans far
       better down a multi-column grid.

       Still never the sole carrier of meaning — every card also prints its type
       as words, so the page works in greyscale and for a colour-blind reader. */
    --cat-masjid:      #1e3a5f;  /* deep navy    */
    --cat-musalla:     #4a3b6b;  /* muted plum   */
    --cat-prayer-room: #2f5d54;  /* muted teal   */
    --cat-jummah:      #6b4423;  /* muted umber  */
    --cat-madressah:   #3d4f7a;  /* slate blue   */
    --cat-funeral:     #4a4a52;  /* neutral grey */

    /* --- Partner cities --------------------------------------------------
       The "Listed via Dewsbury" chip on a mirrored masjid card. A SECOND
       categorical set, kept apart from --cat-* on purpose: those six already
       mean masjid / musalla / madressah elsewhere on the site, and reusing an
       ink would have one colour meaning two different things on two pages.

       Same discipline as --cat-* though — muted inks at matched lightness on a
       tint of their own hue, so no chip reads as an alert next to the crimson
       Early Jumu'ah strip, and four partners are told apart at a glance rather
       than by reading. Hues are spread (green / blue / violet / umber) so they
       survive the common colour-blindness types as two light-vs-dark pairs.

       Never the sole carrier of meaning: the chip always prints the city name,
       so it works in greyscale and for a screen reader. A partner with no entry
       here simply keeps the neutral base chip — nothing breaks. */
    --pv-gloucester: #1f5c3a;  --pv-gloucester-bg: #e7f2ec;
    --pv-leicester:  #5b3a72;  --pv-leicester-bg:  #f1eaf6;
    --pv-batley:     #7a4318;  --pv-batley-bg:     #f8ede3;
    --pv-dewsbury:   #1f4b7a;  --pv-dewsbury-bg:   #e7eff8;

    /* --- Type families. Two stacks, one job each. ------------------------
       The sans string was written out per page as `'Inter', sans-serif`, which
       meant nine copies of the same decision and no single place to change it.
       Declared once here so a page states which role it is playing rather than
       restating the stack.

       The fallbacks after Inter matter more than they look: if the webfont is
       slow or blocked, `sans-serif` alone lands on the browser default, which
       on Windows is noticeably wider than Inter and reflows headings. Naming
       the platform UI faces first keeps that fall back close.

       Inter stays as the body face even though the marketing site uses the
       plain system stack, for one concrete reason: Inter ships tabular
       figures, which is what keeps a column of prayer times aligned (see
       .t-num below). At body sizes the two are near-indistinguishable, so
       nothing is lost by keeping it.

       --font-serif is the visible half of the house style. Georgia is on every
       platform this site is read on, so it needs no webfont and cannot arrive
       late; the rest of the stack is for the handful that lack it.

       PRIVACY_POLICY.php and event-qr.php are standalone documents that do
       not load this file, so they repeat the sans stack literally. That is the
       one sanctioned copy — see the comment in each. */
    --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI',
                 Roboto, Helvetica, Arial, sans-serif;
    --font-serif: Georgia, 'Iowan Old Style', 'Times New Roman', serif;

    /* --- Type scale. Six sizes. -----------------------------------------
       Page titles are --t-xl and page ledes are --t-sm, on every page. That
       pairing is the whole scale as far as a page header is concerned; it
       is not a starting point to adjust per page. Titles had drifted to 24,
       28, 29.6 and 32px across eight pages and ledes to 14, 15 and 15.2px,
       which is what made the site read as assembled rather than designed.

       The sizes are unchanged by the house-style work — that standardisation
       is only just finished across every page and renaming or resizing would
       undo it. What changed is how they LOOK: --t-xl now arrives in the serif,
       at normal weight, in the brand ink.

       --t-2xl stays reserved for the next-prayer figure. A heading must not
       reach for it to feel more important — a hero already carries emphasis
       through its band, padding and weight. */
    --t-xs:   0.8125rem;  /* 13px — column headers and badges ONLY */
    --t-sm:   0.875rem;   /* 14px — secondary text, captions, footer */
    --t-base: 1rem;       /* 16px — body, table cells, times. The default. */
    --t-lg:   1.125rem;   /* 18px — card titles, sub-headings */
    --t-xl:   1.5rem;     /* 24px — page headings */
    --t-2xl:  2rem;       /* 32px — the next-prayer figure only */

    /* --- Spacing. 4px base, eight steps, nothing between. ----------------
       The house style's whitespace is generous rather than different: its
       section gap is 48px and its page padding 24px, both already on this
       scale as --s7 and --s5. Nothing to add. */
    --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px;
    --s5: 24px; --s6: 32px; --s7: 48px; --s8: 64px;

    /* --- Radius. Three values, replacing twelve. ------------------------
       3-4px reads as considered; 8-12px reads as rounded for its own sake —
       EXCEPT on a large quiet panel with a hairline border and a pale fill,
       which is exactly what the marketing site's panels and link cards are,
       and at that size a 4px corner reads as an unfinished box. --r-lg is for
       those and nothing else. It is additive: no existing card changes shape
       until it asks for it. */
    --r-sm: 3px;  /* badges, inputs, buttons */
    --r-md: 4px;  /* cards, panels, tables */
    --r-lg: 12px; /* full-width quiet panels and link cards only */
}

/* --------------------------------------------------------------------------
   Dark mode. Gated on `data-theme="dark"`, which includes/public-header.php
   stamps on <html> from a blocking script before the first paint.

   WHY AN ATTRIBUTE AND NOT `prefers-color-scheme` DIRECTLY
   --------------------------------------------------------
   It used to be `@media (prefers-color-scheme: dark)` narrowed to a
   `data-dark-ready` attribute. Two things were wrong with that:

     1. There was no way to choose. A visitor whose browser reported the wrong
        preference had no way out of it, and that is precisely what happened —
        Firefox resolves prefers-color-scheme from its own toolbar/content
        theme setting, not from Windows, so a Firefox user could get the dark
        palette while every other browser on the same machine stayed light, or
        end up half-switched against a page that had not fully migrated.
     2. It made the media query the source of truth, so nothing could override
        it per visitor without duplicating this entire block.

   The header now resolves the question once, in JS — a saved choice if there
   is one, otherwise the OS preference — and writes the answer to the
   attribute. This file only ever asks "is this document dark". One rule, one
   condition, and a manual Light / Dark / System control that actually works.

   The standalone documents that do NOT go through the shared header —
   event-qr.php (a print poster, which also pins `color-scheme: light`) and
   public-widget.php (embedded in other people's pages) — never get the
   attribute, so they keep their light treatment for free, exactly as before.

   With scripting off nothing sets the attribute and the site stays light. That
   is the deliberate trade: light is the designed default and reads correctly
   everywhere, whereas an automatic switch we cannot override is what caused
   the trouble in the first place.

   The blocker that kept dark mode switched off for months was never the pages:
   it was that body read --brand-page-bg, a per-site branding value that every
   portal sets to a light colour. --page-bg now sits in between, and the brand
   colours are remapped below.
   -------------------------------------------------------------------------- */
:root[data-theme="dark"] {
    /* The page colour stops following branding here. Every portal's
       --brand-page-bg is light (white, white and a cream), so honouring it
       would leave a light page under near-white text. */
    --page-bg: var(--paper);

    /* --brand-page-bg itself is remapped, and this is the fix for the pages
       that stayed stubbornly light after dark mode went on — Events, Musally
       Masaajid, Resources, a masjid page and an event page. Overriding
       --page-bg only ever fixed <body>. Nine page shells set their own
       background from the branding variable DIRECTLY —
       `.events-page`, `.resources-page`, `.mosques-page`,
       `.mosques-map-section`, `.ev-page` and `.mp-wrap` among them — so the
       body went dark underneath and the shell painted a light slab back over
       it. That is the white band that showed under the toolbar on the Events
       page.

       Remapping at source rather than editing nine shells is deliberate, and
       it is the same reasoning as the three brand colours below: the variable
       is read directly all over the site and a future page will read it again.

       It also lands correctly on the OTHER use of this variable, which is as
       TEXT on a brand fill — event.php sets `color: var(--brand-page-bg)` on
       its date card and its 404 button, meaning "the page colour, reversed out
       of the brand". In dark mode --brand-primary becomes a light tint, so
       that text has to become dark, and --paper is exactly the value it needs.
       Both roles want the same answer, which is what makes this safe. */
    --brand-page-bg: var(--paper);

    /* The branding colours are chosen to sit on white and several of them
       are near-black — Bolton's Primary and Highlight are both #000000 —
       so they cannot be used as-is on a dark page. outputBrandingStyles()
       emits a lightened counterpart for each, computed per site in
       management/includes/site-branding.php, and they are swapped in here.
       Redefining the brand variables rather than only --ink-brand is
       deliberate: pages use --brand-primary and --brand-accent directly,
       both as fills and as text (mosque.php sets `color: var(--brand-primary)`
       on a panel), and remapping at source keeps every one of those uses
       consistent instead of fixing the token in one place and leaving the
       direct readers black on near-black.

       The fallbacks cannot name the variable they are replacing — a custom
       property referring to itself is a cycle and drops the declaration —
       so they are a neutral light value for the rare page rendered before
       branding has run. */
    --brand-primary:   var(--brand-primary-dark, #e8ecf4);
    --brand-accent:    var(--brand-accent-dark, #e8ecf4);
    --brand-highlight: var(--brand-highlight-dark, #ffffff);

    --paper:     #0d1826;
    --ink:       #f2f5f9;
    --ink-mid:   #a8b4c2;
    --rule:      #24344d;
    --surface:   #142032;
    --surface-2: #1c2b41;

    /* Lighter than --paper on purpose — see the note in the light block.
       A dark control darker than an already-dark page is the version of
       this that looked worst. */
    --field:        #243855;
    --field-border: #456085;
    --field-hover:  #2c4467;

    /* 8.9:1 on the badge fill, 9.9:1 as bare text on the page. */
    --sisters-bg:  #3d1029;
    --sisters-ink: #f9a8d4;
    --overlay-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);

    /* The brand ink cannot stay as it is: a portal's primary is chosen to
       be legible on white and disappears on a dark page. On a dark ground
       the role passes to --brand-highlight, which is the light end of the
       same brand — so the site stays recognisably itself without this file
       naming anybody's colour. Note that --brand-highlight is the lightened
       value set a few lines above, not the raw branding one, so this is safe
       even for a portal whose Highlight is stored as black. */
    --ink-brand: var(--brand-highlight, #ffffff);

    /* The state colours have to flip too. --ok, --warn and --stop are read
       as text on the page in a dozen places (`color: var(--ok)` on a divider
       label, on a cost, on a badge), and the light-mode values are dark
       inks chosen for white — #16603c on a near-black page is unreadable.
       The -bg tints are rebuilt as dark tints of the same hue rather than
       left light, so an alert strip reads as a strip and not as a white
       card someone forgot. Each pair clears 6:1 on its own fill and 7.5:1
       or better on the page. */
    --ok:    #5fd0a0;  --ok-bg:   #16332a;
    --warn:  #e8b04b;  --warn-bg: #332811;
    --stop:  #f08c8c;  --stop-bg: #3a1f1f;

    /* Partner-city chips flip for the same reason the state colours do: the
       light values are dark inks chosen for white and vanish on a near-black
       page. Ink and tint swap roles — a light ink of the hue on a dark tint of
       the same hue — so the chip stays a chip rather than becoming a white
       patch, and the four cities stay as distinguishable as they are in light
       mode. */
    --pv-gloucester: #6fd3a0;  --pv-gloucester-bg: #16332a;
    --pv-leicester:  #c9a6e0;  --pv-leicester-bg:  #2c2038;
    --pv-batley:     #e3ab7b;  --pv-batley-bg:     #3a2718;
    --pv-dewsbury:   #8fb9ea;  --pv-dewsbury-bg:   #17293b;

    /* A mark drawn as a single flat ink on transparency flattens to pure
       white and keeps its line weight exactly, which is cheaper and more
       reliable than shipping and maintaining a second image file. */
    --logo-filter: brightness(0) invert(1);

    color-scheme: dark;
}

/* --------------------------------------------------------------------------
   Base elements. Family, colour and rules only — no margins.

   Margins are left alone on purpose. The shared header resets every default
   margin to zero (`*, *::before, *::after { margin: 0 }`) and every page has
   been built on top of that reset for years. An element selector here beats
   `*` on specificity, so a margin declared in this file would win and move
   content on every page at once. Spacing stays the page's business until a
   page opts into a layout class.
   -------------------------------------------------------------------------- */
body {
    /* --page-bg resolves to --brand-page-bg in light mode, so the portal's own
       page colour is still in charge and a portal wanting plain white sets it
       in Site Branding rather than needing a code change here. Dark mode
       overrides --page-bg alone, which is why body no longer reads the branding
       variable directly. */
    background: var(--page-bg);
    color: var(--ink);
    font-family: var(--font-sans);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

/* The serif-heading rule — the single most visible piece of the house style.

   Stops at h2. h3 and below are working labels inside cards and toolbars, not
   headings anyone reads as a heading, and a serif at 14-16px in a table header
   reads as a mistake rather than as a decision.

   Any page that sets its own colour on a heading still wins: page CSS is
   appended to <head> after this file via $headExtra, and a class selector
   outranks these element selectors anyway. */
h1,
h2,
.page-title {
    font-family: var(--font-serif);
    font-weight: 400;
    letter-spacing: 0.01em;
    color: var(--ink-brand);
}

/* The house style's page heading, offered as a class so a page can adopt the
   whole treatment — size included — in one word instead of restating it. */
.page-title {
    font-size: var(--t-xl);
    line-height: 1.25;
}

/* --------------------------------------------------------------------------
   Form controls.

   One rule for every text field, select, date box and textarea on the site,
   so a filter row reads as a row of controls instead of a row of labels.

   Why this is an element selector and not a class: the controls are spread
   across fifteen public pages under fifteen different class names
   (.filter-search, .cf-select, .ev-select, .dir-*, .find-*, .ft-mosque-*, .af-field
   select …), most of which set no background at all and simply inherited the
   page. Naming them all here would miss the next one somebody adds; naming
   the ELEMENT catches every control on the site including the ones not
   written yet.

   A page that genuinely needs something different still wins — page CSS is
   appended to <head> after this file and a class selector outranks these.
   That is deliberate: this is a floor, not a ceiling.

   :where() keeps the specificity of the :not() chain at zero so the bare
   element selector is all a page has to beat.
   -------------------------------------------------------------------------- */
input:where(:not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="button"]):not([type="reset"]):not([type="range"]):not([type="color"]):not([type="file"])),
select,
textarea {
    background-color: var(--field);
    border: 1px solid var(--field-border);
    border-radius: var(--r-sm);
    color: var(--ink);
    font: inherit;
}

/* Placeholders were --ink-mid on --paper, which is a legible 5.8:1 — but on
   the new fill they read as a filled-in value rather than a prompt. */
input::placeholder,
textarea::placeholder {
    color: var(--ink-mid);
    opacity: 0.85;
}

input:where(:not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="button"]):not([type="reset"])):hover,
select:hover,
textarea:hover {
    background-color: var(--field-hover);
}

/* A disabled control has to stop looking like something you can type in --
   without stopping looking like a control.

   This used --surface, and in dark mode --surface (#142032) is DARKER than the
   page (#0d1826). So Find a Prayer's Postcode ("Pick a city first") and Near me
   ("Location off"), both legitimately disabled until you choose something, read
   as holes punched in the page next to four normal fields. Fading the field
   itself keeps them in the same family: at 70% over the page the fill still
   lands clearly above it in both themes, and the whole control dims together
   rather than only its text. */
input:disabled,
select:disabled,
textarea:disabled {
    background-color: var(--field);
    border-color: var(--field-border);
    color: var(--ink-mid);
    opacity: 0.7;
    cursor: not-allowed;
}

/* A horizontal rule is a hairline like every other divider on the site, not
   the browser's default inset groove. */
hr {
    border: 0;
    border-top: 1px solid var(--rule);
}

/* --------------------------------------------------------------------------
   Times must use tabular figures.

   Inter's default figures are proportional, so a column of prayer times does
   not line up — 11:11 is visibly narrower than 08:45. Inter already ships
   tabular figures, so this costs one declaration and no font change. Apply
   .t-num to any element that outputs a time.
   -------------------------------------------------------------------------- */
.t-num,
time {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

/* --------------------------------------------------------------------------
   Motion. Colour transitions only — no transform, no opacity loops, no
   infinite anything. State changes are instant.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        transition: none !important;
        animation: none !important;
        scroll-behavior: auto !important;
    }
}

/* --------------------------------------------------------------------------
   Focus. One of the two permitted box-shadow/outline treatments on the site.

   Previously several interactive elements had `outline: none` with no
   replacement, leaving keyboard and switch users with no visible position.
   :focus-visible means mouse users never see it.

   Reads --ink-brand rather than --brand-primary directly so that the ring
   follows the palette in dark mode instead of staying a colour that has just
   become invisible.
   -------------------------------------------------------------------------- */
:focus-visible {
    outline: 2px solid var(--ink-brand);
    outline-offset: 2px;
    border-radius: var(--r-sm);
}

/* --------------------------------------------------------------------------
   Page width.

   Container widths had drifted per page — 420px on the homepage, 800px on
   Jumu'ah / Full Timetable / Find, 980px on a masjid page, 1100px on Mosques,
   Events, Nearby and Resources. On a 1900px desktop the 800px pages used well
   under half the screen and looked like a phone layout that had been left on.

   One fluid scale instead, applied by adding .page-wrap to a page's main
   container. It grows with the viewport and stops before lines get too long
   to read comfortably.

   The nav and the footer read --wrap-max too, so the wordmark, the first
   column of the page and the first column of the footer all start on the same
   vertical line at every width. They did not before: the bar was capped at a
   flat 1100px while the content under it went to 1500px, so on a wide desktop
   the nav was visibly inset from the page it belonged to.
   -------------------------------------------------------------------------- */
/* --wrap-max is the same scale expressed as a variable, for pages whose own
   container classes already carry padding and margins that their markup depends
   on. Those set `max-width: var(--wrap-max)` in place rather than adopting
   .page-wrap, which would double the padding. Both stay in step because the
   media queries below set the variable and the class together. */
:root { --wrap-max: 820px; }

.page-wrap {
    width: 100%;
    max-width: var(--wrap-max);
    margin-inline: auto;
    padding-inline: var(--s4);
}

@media (min-width: 1024px) {
    :root { --wrap-max: 1080px; }
}
@media (min-width: 1440px) {
    :root { --wrap-max: 1320px; }
}
@media (min-width: 1800px) {
    /* Stop here. Beyond this the eye has to travel too far across a row to
       match a masjid name to its time — wider stops being more useful. */
    :root { --wrap-max: 1500px; }
}

/* --------------------------------------------------------------------------
   Utilities. Deliberately few — these exist so migrating pages can drop a
   local rule rather than invent another one.
   -------------------------------------------------------------------------- */
.u-rule       { border: 1px solid var(--rule); }
.u-rule-top   { border-top: 1px solid var(--rule); }
.u-muted      { color: var(--ink-mid); }
.u-nowrap     { white-space: nowrap; }

/* The house style's short centred hairline between sections. A divider that
   does not run the full width reads as a pause rather than as a cut. */
.u-hairline {
    width: 3.5rem;
    height: 1px;
    margin: var(--s6) auto;
    background: var(--rule);
    border: 0;
}

/* Screen-reader-only text, for labelling controls that show just an icon. */
.u-sr-only {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

/* --------------------------------------------------------------------------
   Skip link. Emitted by includes/public-header.php as the first focusable
   thing inside <body>, pointing at the <main> that same file opens.

   Without it the first Tab on every page lands on the wordmark, then the
   appearance control, then up to nine nav items before reaching a word of
   content — and below the hamburger threshold the drawer holds around
   nineteen links, all of which have to be walked on every page in turn.

   Hidden by exactly the .u-sr-only pattern above, so it costs a sighted
   visitor nothing, and unhidden on focus into the top corner where a skip
   link is looked for. :focus rather than :focus-visible on purpose: the link
   is invisible until it has focus, so it cannot be reached with a pointer and
   there is no mouse case to suppress.

   It floats over page content, which is the second of the two cases rule 3
   permits a shadow for, so it carries the same --overlay-shadow the nav's
   menus do. Colours are tokens throughout, so it reverses with the palette
   and stays legible in both themes; z-index clears the sticky bar at 100.
   -------------------------------------------------------------------------- */
.skip-link {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

.skip-link:focus {
    position: fixed;
    top: var(--s2);
    left: var(--s2);
    z-index: 1000;
    width: auto; height: auto;
    margin: 0;
    padding: var(--s2) var(--s4);
    overflow: visible;
    clip: auto;
    background: var(--paper);
    color: var(--ink-brand);
    font-family: var(--font-sans);
    font-size: var(--t-sm);
    font-weight: 600;
    text-decoration: none;
    border: 1px solid var(--rule);
    border-radius: var(--r-sm);
    box-shadow: var(--overlay-shadow);
}

/* The skip link's destination. The header gives <main> tabindex="-1" so focus
   can be moved into it; this is the one place the shared focus ring is turned
   off, because it would draw a 2px outline around the entire page. That says
   nothing a visitor needs — they asked to be put at the start of the content,
   not to be shown its outer edge — and the ring is only ever suppressed here,
   on an element nobody can tab to. */
main[tabindex="-1"]:focus {
    outline: none;
}
