/* ==========================================================================
   main.css - layout and components for ruya.social
   ==========================================================================

   Requires tokens.css to be loaded first.

   RTL here is structural, not a patch. Every directional property is a logical
   one - margin-inline-start, padding-block-end, inset-inline-end, border-block
   - so the layout follows the document's `dir` attribute. There is no
   [dir="rtl"] override anywhere in this file, and that is the point: a mirrored
   second stylesheet is a second thing to keep in sync, and it always rots.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Reset and document
   -------------------------------------------------------------------------- */

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

html {
  font-size: 106.25%;                 /* 17px base; see tokens.css */
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;

  /* The sticky header is 64px tall and would otherwise cover the top of any
     section reached through an anchor link - and, worse, would cover keyboard
     focus when it lands there. That is WCAG 2.2 AA "Focus Not Obscured
     (Minimum)". The value is the same token the header's height is set from,
     so the two cannot drift apart. */
  scroll-padding-block-start: calc(var(--header-h) + var(--space-6));
}

@media (prefers-reduced-motion: reduce) {
  /* Someone who asks the operating system to reduce motion is not given smooth
     scrolling either. Honouring the preference for decoration and then
     hijacking their scroll would defeat the point of asking. */
  html {
    scroll-behavior: auto;
  }
}

body {
  margin: 0;
  background-color: var(--bg);
  color: var(--fg);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  font-weight: 400;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;

  /* A long URL, an identifier or a pasted token must not force the whole page
     to scroll sideways. `anywhere` on the container rather than
     `word-break: break-all` on prose, which would also break ordinary words. */
  overflow-wrap: anywhere;
}

h1, h2, h3, h4, p, figure, ul, ol, blockquote {
  margin: 0;
}

ul, ol {
  padding: 0;
  list-style: none;
}

img, svg, picture {
  display: block;
  max-width: 100%;
}

img {
  height: auto;
}

a {
  color: var(--accent);
  text-underline-offset: 0.2em;
}

::selection {
  background-color: var(--accent);
  color: var(--fg-on-accent);
}

/* --------------------------------------------------------------------------
   Focus

   One visible ring on every interactive element, in both themes. :focus-visible
   rather than :focus, so a mouse click does not leave a ring behind while
   keyboard navigation always shows one. Two-colour ring so it is visible
   against both the page and a coloured button.
   -------------------------------------------------------------------------- */

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}

/* --------------------------------------------------------------------------
   Utilities
   -------------------------------------------------------------------------- */

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  inset-block-start: var(--space-2);
  inset-inline-start: var(--space-2);
  z-index: 100;
  padding: var(--space-3) var(--space-6);
  border-radius: var(--radius-md);
  background-color: var(--accent);
  color: var(--fg-on-accent);
  font-weight: 700;
  text-decoration: none;
  transform: translateY(-170%);
  transition: transform var(--dur-mid) var(--ease-out);
}

.skip-link:focus-visible {
  transform: translateY(0);
}

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: clamp(var(--space-5), 5vw, var(--space-10));
}

/* --------------------------------------------------------------------------
   Ornament

   The geometric motif from the base of the emblem, used as a background
   watermark. The brand guide permits 3%-5% opacity and no more.

   Painted on a ::before pseudo-element rather than on the element's own
   background, so the opacity applies to the pattern alone and never to the
   text sitting on top of it. Drawn through a mask so the motif takes the
   current theme's accent colour from one single-colour source file.

   The second mask layer is a radial fade, composited with `intersect`, so the
   pattern is densest behind the emblem and dissolves before it reaches the
   text. Where mask-composite is unsupported the first layer still applies and
   the result is an evenly tiled watermark - a graceful degradation, not a
   broken one.
   -------------------------------------------------------------------------- */

.ornament {
  position: relative;
  isolation: isolate;
}

.ornament::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-color: var(--accent);
  opacity: var(--ornament-opacity);
  pointer-events: none;

  -webkit-mask-image: url("/assets/img/pattern.svg");
  mask-image: url("/assets/img/pattern.svg");
  -webkit-mask-size: 132px 132px;
  mask-size: 132px 132px;
  -webkit-mask-repeat: repeat;
  mask-repeat: repeat;
}

.ornament--fade::before {
  -webkit-mask-image: url("/assets/img/pattern.svg"),
    radial-gradient(circle at 50% 34%, #000 0%, #000 26%, transparent 66%);
  mask-image: url("/assets/img/pattern.svg"),
    radial-gradient(circle at 50% 34%, #000 0%, #000 26%, transparent 66%);
  -webkit-mask-size: 132px 132px, 100% 100%;
  mask-size: 132px 132px, 100% 100%;
  -webkit-mask-repeat: repeat, no-repeat;
  mask-repeat: repeat, no-repeat;
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}

/* --------------------------------------------------------------------------
   Site header
   -------------------------------------------------------------------------- */

.site-header {
  position: sticky;
  inset-block-start: 0;
  z-index: 50;
  background-color: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: blur(14px) saturate(1.4);
  -webkit-backdrop-filter: blur(14px) saturate(1.4);
  border-block-end: 1px solid transparent;
  transition: border-color var(--dur-mid) var(--ease-soft),
              background-color var(--dur-mid) var(--ease-soft);
}

/* The rule under the header only appears once the page has scrolled. At the
   top it would be a line drawn across the hero for no reason. */
.site-header[data-scrolled="true"] {
  border-block-end-color: var(--line);
  background-color: color-mix(in srgb, var(--bg) 92%, transparent);
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  min-height: var(--header-h);
}

/* The brand keeps its size; the nav is the only part of the header allowed to
   give way, because it is the only part that can scroll. */
.brand {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  color: var(--fg);
  font-weight: 700;
  font-size: var(--text-lg);
  text-decoration: none;
  white-space: nowrap;
}

.brand__mark {
  width: 34px;
  height: 34px;
  border-radius: var(--radius-md);
}

/* --------------------------------------------------------------------------
   Navigation

   A one-page site still needs somewhere to stand: the previous version had no
   navigation at all, so a visitor had no map of the page and no indication of
   where they were in it.

   The active link is marked with aria-current="true" by app.js, driven by an
   IntersectionObserver. The styling follows the attribute rather than a class,
   so the accessible state and the visible state cannot disagree.
   -------------------------------------------------------------------------- */

/* On a page of nine sections, hiding the navigation on phones - which is what
   this used to do - leaves the majority of visitors with no map at all. It
   becomes a sideways-scrolling strip instead: no JavaScript, no disclosure
   button to manage focus for, and no layout that can trap the reader.

   The scrollbar is hidden because it would sit across the header rule, but the
   strip still scrolls by touch, by trackpad, and by keyboard once a link
   inside it has focus. */
.nav {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  /* Without this the strip can be squeezed to nothing by its flex siblings
     before it is allowed to scroll. */
  min-width: 0;
  /* A tapped link should not stop halfway under the edge of the strip. */
  scroll-snap-type: inline mandatory;
}

.nav::-webkit-scrollbar {
  display: none;
}

@media (min-width: 64rem) {
  .nav {
    overflow-x: visible;
  }
}

.nav__link {
  position: relative;
  display: inline-block;
  flex: none;
  white-space: nowrap;
  scroll-snap-align: center;
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-sm);
  color: var(--fg-muted);
  font-size: var(--text-sm);
  font-weight: 500;
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease-soft),
              background-color var(--dur-fast) var(--ease-soft);
}

.nav__link:hover {
  color: var(--fg);
  background-color: var(--accent-soft);
}

.nav__link[aria-current="true"] {
  color: var(--accent);
  font-weight: 700;
}

/* The active marker is a gold underline, but colour is not the only signal:
   the weight changes too, and aria-current carries the state to assistive
   technology. */
.nav__link[aria-current="true"]::after {
  content: "";
  position: absolute;
  inset-inline: var(--space-4);
  inset-block-end: 2px;
  height: 2px;
  border-radius: var(--radius-pill);
  background-color: var(--gold);
}

/* --------------------------------------------------------------------------
   Theme toggle

   Two buttons in a group rather than one button that changes meaning. A single
   toggle has to answer "does this label describe the current state, or the one
   I get if I press it?", and screen-reader users get whichever answer the
   author happened to pick. A radio-style group states both options and marks
   one pressed.

   34px square: above the 24px WCAG 2.2 target minimum, with 4px of separation.
   -------------------------------------------------------------------------- */

.theme-toggle {
  display: inline-flex;
  flex: none;
  gap: var(--space-1);
  padding: 3px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background-color: var(--bg-raised);
}

.theme-toggle__btn {
  display: inline-grid;
  place-items: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-pill);
  background: none;
  color: var(--fg-subtle);
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-soft),
              color var(--dur-fast) var(--ease-soft);
}

.theme-toggle__btn:hover {
  color: var(--fg);
}

.theme-toggle__btn[aria-pressed="true"] {
  background-color: var(--accent);
  color: var(--fg-on-accent);
}

.theme-toggle__btn svg {
  width: 17px;
  height: 17px;
}

/* Until the script runs there is no meaningful pressed state to show, so the
   control is hidden. Revealed by adding .js to <html>, which means a visitor
   with JavaScript disabled never sees a button that does nothing. */
html:not(.js) .theme-toggle {
  display: none;
}

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 48px;
  padding: var(--space-3) var(--space-8);
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  font-family: inherit;
  font-size: var(--text-base);
  font-weight: 700;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-soft),
              border-color var(--dur-fast) var(--ease-soft),
              box-shadow var(--dur-fast) var(--ease-soft),
              transform var(--dur-fast) var(--ease-soft);
}

.btn--primary {
  background-color: var(--accent);
  color: var(--fg-on-accent);
  box-shadow: 0 1px 2px rgb(18 26 22 / 12%), 0 8px 20px var(--accent-ring);
}

.btn--primary:hover {
  background-color: var(--accent-hover);
}

.btn--ghost {
  border-color: var(--line-strong);
  background-color: transparent;
  color: var(--fg);
}

.btn--ghost:hover {
  border-color: var(--accent);
  color: var(--accent);
}

/* Pressed feedback is immediate and applies even under reduced motion: it is
   confirmation that the tap registered, not decoration. */
.btn:active {
  transform: translateY(1px);
}

@media (prefers-reduced-motion: no-preference) {
  .btn--primary:hover {
    transform: translateY(-2px);
    box-shadow: 0 2px 4px rgb(18 26 22 / 12%), 0 14px 30px var(--accent-ring);
  }

  .btn--ghost:hover {
    transform: translateY(-2px);
  }
}

/* --------------------------------------------------------------------------
   Eyebrow, section headings
   -------------------------------------------------------------------------- */

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--fg-muted);
  font-size: var(--text-sm);
  font-weight: 500;
}

/* Gold hairline flanking the eyebrow. Decorative: it carries no information
   that is lost if it is not perceived. */
.eyebrow::before {
  content: "";
  width: 28px;
  height: 1px;
  background-color: var(--gold);
}

/* Half above and half below, so two adjacent sections add up to one full
   --section-pad between them rather than two. With every section on the same
   background there is no colour change to justify the larger gap, and at full
   value the space read as a missing section. */
.section {
  padding-block: calc(var(--section-pad) / 2);
}

/* The head and the reading column below it must share the same measure and the
   same centring, or their inline edges disagree and the heading appears to
   hang off to one side of its own text. Both use --measure so they cannot
   drift apart. */
.section__head {
  max-width: var(--measure);
  margin-inline: auto;
}

.section--center .section__head {
  margin-inline: auto;
  text-align: center;
}

.section--center .eyebrow {
  justify-content: center;
}

.section__title {
  margin-block-start: var(--space-4);
  font-size: var(--text-3xl);
  font-weight: 700;
  line-height: var(--leading-tight);
  letter-spacing: var(--track-display);

  /* Balanced wrapping is a progressive enhancement, not a guarantee that a
     particular word stays on the last line. The measure is bounded so the
     natural-wrap fallback is also acceptable at every width. */
  max-inline-size: 22ch;
  text-wrap: balance;
}

.section--center .section__title {
  margin-inline: auto;
}

.section__lead {
  margin-block-start: var(--space-5);
  max-inline-size: var(--measure);
  color: var(--fg-muted);
  font-size: var(--text-xl);
  line-height: var(--leading-loose);
}

.section--center .section__lead {
  margin-inline: auto;
}

/* --------------------------------------------------------------------------
   Hero
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  /* The section that follows supplies its own --section-pad on top. Using the
     full value here too stacked two full paddings into roughly 250px of empty
     page between the status chip and the first heading, which read as a
     missing section rather than as breathing room. */
  padding-block: clamp(var(--space-16), 9vw, var(--space-24)) var(--space-12);
  overflow: hidden;
}

.hero__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

/* The emblem is radially symmetric, so it is centred. Islamic ornament is
   symmetric by construction and fighting that to look "editorial" would be
   fighting the brand. The asymmetry on this page lives in the sections below. */
.hero__emblem {
  position: relative;
  width: min(260px, 54vw);
  margin-inline: auto;
}

.hero__emblem img {
  width: 100%;
  height: auto;
}

/* Soft glow behind the emblem, giving it somewhere to sit without drawing a
   box around it. */
.hero__emblem::before {
  content: "";
  position: absolute;
  inset: -22%;
  z-index: -1;
  background: var(--glow);
  pointer-events: none;
}

.hero__title {
  margin-block-start: var(--space-10);
  max-inline-size: 18ch;
  font-size: var(--text-display);
  font-weight: 700;
  line-height: var(--leading-tight);
  letter-spacing: var(--track-display);
  text-wrap: balance;
}

.hero__subtitle {
  margin-block-start: var(--space-6);
  max-inline-size: 46ch;
  color: var(--fg-muted);
  font-size: var(--text-xl);
  line-height: var(--leading-loose);
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-4);
  margin-block-start: var(--space-10);
}

/* Status is stated in the hero, not saved for the bottom of the page. Someone
   who arrives expecting to submit a dream should learn in the first screen
   that they cannot yet, rather than after scrolling through three sections. */
.hero__status {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  margin-block-start: var(--space-10);
  padding: var(--space-2) var(--space-5);
  border: 1px solid var(--gold-line);
  border-radius: var(--radius-pill);
  background-color: var(--bg-raised);
  color: var(--fg-muted);
  font-size: var(--text-sm);
}

.hero__status b {
  color: var(--fg);
  font-weight: 700;
}

/* A dot, not a pulsing animation: a continuously animating element is
   distracting and this one carries no urgency. */
.dot {
  width: 7px;
  height: 7px;
  flex: none;
  border-radius: var(--radius-pill);
  background-color: var(--gold);
}

/* --------------------------------------------------------------------------
   Principles

   Numbered rather than iconographic. Three identical bordered boxes with a
   glyph on top is the most repeated layout on the web, and it makes three
   distinct commitments look interchangeable. Numbering them says they are a
   set and gives the eye an order to read them in.
   -------------------------------------------------------------------------- */

.principles {
  display: grid;
  gap: var(--space-6);
  margin-block-start: var(--space-16);
  grid-template-columns: 1fr;
}

@media (min-width: 44rem) {
  .principles {
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-5);
  }
}

.principle {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: var(--space-8);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background-color: var(--bg-raised);
  overflow: hidden;
  transition: border-color var(--dur-mid) var(--ease-soft),
              box-shadow var(--dur-mid) var(--ease-soft),
              transform var(--dur-mid) var(--ease-soft);
}

/* Gold hairline along the top edge, drawn as a gradient so it fades out rather
   than stopping abruptly at the rounded corners. */
.principle::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  height: 2px;
  background: linear-gradient(to left, transparent, var(--gold), transparent);
  opacity: 0.8;
}

@media (prefers-reduced-motion: no-preference) {
  .principle:hover {
    transform: translateY(-3px);
    border-color: var(--line-strong);
    box-shadow: var(--shadow-md);
  }
}

.principle__num {
  font-size: var(--text-sm);
  font-weight: 700;
  color: var(--gold);
  font-variant-numeric: tabular-nums;

  /* The numerals are Latin digits inside an RTL paragraph. Isolating them
     stops the bidirectional algorithm from reordering them against adjacent
     punctuation. */
  unicode-bidi: isolate;
}

.principle__icon {
  display: inline-grid;
  place-items: center;
  width: 46px;
  height: 46px;
  margin-block-start: var(--space-5);
  border-radius: var(--radius-md);
  background-color: var(--accent-soft);
  color: var(--accent);
}

.principle__icon svg {
  width: 24px;
  height: 24px;
}

.principle__title {
  margin-block-start: var(--space-5);
  font-size: var(--text-2xl);
  font-weight: 700;
  line-height: var(--leading-snug);
}

.principle__text {
  margin-block-start: var(--space-3);
  color: var(--fg-muted);
  line-height: var(--leading-loose);
}

/* --------------------------------------------------------------------------
   Trust panel

   Brand guide, section 3: text carrying religious authority is set apart
   inside a block with a subtle gold border, so it is never confused with
   ordinary copy. This class is that block.

   It currently holds only the project's own statement about its limits. No
   verse, hadith or ruling is quoted anywhere on this site. The treatment
   exists so that quoted material has a correct home the day it is added and
   reviewed - not so that this page can pretend to religious authority it has
   not earned.
   -------------------------------------------------------------------------- */

.trust {
  position: relative;
  max-width: var(--measure);
  margin-inline: auto;
  margin-block-start: var(--space-16);
  padding: var(--space-10) var(--space-8);
  border: 1px solid var(--gold-line);
  border-radius: var(--radius-lg);
  background-color: var(--bg-raised);
  box-shadow: var(--shadow-sm);
  text-align: center;
}

.trust__label {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-4);
  border-radius: var(--radius-pill);
  background-color: var(--accent-soft);
  color: var(--accent);
  font-size: var(--text-xs);
  font-weight: 700;
}

.trust__label svg {
  width: 15px;
  height: 15px;
}

.trust__text {
  margin-block-start: var(--space-6);
  font-size: var(--text-xl);
  line-height: var(--leading-loose);
  text-wrap: pretty;
}

/* --------------------------------------------------------------------------
   Status section

   The prototype's call to action pointed at #submit-dream, an anchor that did
   not exist. Submissions cannot be accepted: there is no data model, no
   retention policy and no moderation queue for what would be highly sensitive
   personal information.

   An empty state should say what is missing AND offer something to do. This
   one has nowhere to send anyone yet, so it says exactly that instead of
   inventing a mailing-list box that nothing is listening to.
   -------------------------------------------------------------------------- */

.status {
  padding-block: var(--section-pad);
  background-color: var(--bg-sunken);
  border-block: 1px solid var(--line);
}

.status__inner {
  max-width: var(--measure);
  margin-inline: auto;
  text-align: center;
}

.status__badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-5);
  border: 1px solid var(--gold-line);
  border-radius: var(--radius-pill);
  background-color: var(--bg-raised);
  font-size: var(--text-sm);
  font-weight: 500;
}

.status__title {
  margin-block-start: var(--space-6);
  font-size: var(--text-3xl);
  font-weight: 700;
  line-height: var(--leading-tight);
  letter-spacing: var(--track-display);
  text-wrap: balance;
}

.status__text {
  margin-block-start: var(--space-6);
  color: var(--fg-muted);
  font-size: var(--text-lg);
  line-height: var(--leading-loose);
}

/* --------------------------------------------------------------------------
   Footer

   A fixed dark surface in both themes. The colours are literal rather than
   token-based precisely because they must not follow the theme.
   -------------------------------------------------------------------------- */

.site-footer {
  padding-block: var(--space-20) var(--space-12);
  background-color: #0f1512;
  color: #e9efeb;
}

.site-footer__inner {
  text-align: center;
}

.site-footer__mark {
  width: 52px;
  height: 52px;
  margin-inline: auto;
  border-radius: var(--radius-md);
}

.site-footer__name {
  margin-block-start: var(--space-4);
  font-size: var(--text-lg);
  font-weight: 700;
}

/* The disclaimer is the most important sentence on the page. It gets the gold
   frame so it reads as a formal statement rather than as small print, and it
   is not dimmed. */
.disclaimer {
  max-width: var(--measure);
  margin-inline: auto;
  margin-block-start: var(--space-10);
  padding: var(--space-6) var(--space-8);
  border: 1px solid rgb(194 155 87 / 45%);
  border-radius: var(--radius-lg);
  line-height: var(--leading-loose);
  text-wrap: pretty;
}

.disclaimer__label {
  display: block;
  margin-block-end: var(--space-2);
  color: #d9bd88;
  font-size: var(--text-sm);
  font-weight: 700;
}

.site-footer__rule {
  width: min(100%, 320px);
  height: 1px;
  margin: var(--space-10) auto 0;
  border: 0;
  background: linear-gradient(to left, transparent, rgb(233 239 235 / 22%), transparent);
}

.copyright {
  margin-block-start: var(--space-6);
  color: #9aa8a0;
  font-size: var(--text-sm);
}

/* --------------------------------------------------------------------------
   Scroll reveal

   The supplied prototype set `opacity: 0` on .section-animate unconditionally.
   If the script fails to load, is blocked by an extension, or the observer
   never fires, the page is blank: the content is in the DOM but invisible,
   which is the worst possible failure for a page that is entirely text.

   Here the hidden state applies only when BOTH conditions hold - the script
   has run (html.js) and the visitor has not asked for reduced motion. In every
   other case the content is visible by default.

   The transform is small. A 28px slide on six elements reads as a page that
   cannot sit still; 14px reads as settling.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: no-preference) {
  html.js .reveal {
    opacity: 0;
    transform: translateY(14px);
    transition: opacity var(--dur-slow) var(--ease-out),
                transform var(--dur-slow) var(--ease-out);
  }

  html.js .reveal.is-visible {
    opacity: 1;
    transform: none;
  }

  /* The hero holds five revealable elements and they are all on screen at
     load. Five things fading in at once reads as five competing animations -
     the guidance is one or two per view. A short cascade turns them into a
     single entrance instead. Delays are on a fixed ladder rather than
     generated in script, so no inline style is needed and the CSP stays
     strict. */
  html.js .hero__inner > .reveal:nth-child(1) { transition-delay: 0ms; }
  html.js .hero__inner > .reveal:nth-child(2) { transition-delay: 70ms; }
  html.js .hero__inner > .reveal:nth-child(3) { transition-delay: 140ms; }
  html.js .hero__inner > .reveal:nth-child(4) { transition-delay: 210ms; }
  html.js .hero__inner > .reveal:nth-child(5) { transition-delay: 280ms; }
}

/* --------------------------------------------------------------------------
   Prose

   Reading copy, as opposed to the short labelled fragments the page was made
   of before. Two things matter more in Arabic than they do in Latin text:

   - Line length. The measure is capped in `ch`, which scales with the font
     rather than with the viewport, so the line stays readable at any zoom.
     Arabic words are long and a 90-character line becomes genuinely hard to
     track back from.
   - Leading. Arabic ascenders and descenders travel further than Latin ones,
     and the dots below ب ج ي collide with the line beneath at a leading that
     would be comfortable for English. 1.95 is not decoration.
   -------------------------------------------------------------------------- */

.prose {
  max-width: var(--measure);
  margin-inline: auto;
  color: var(--fg-muted);
  font-size: var(--text-lg);
  line-height: 1.95;
}

.prose > p + p {
  margin-block-start: var(--space-5);
}

.prose > p {
  margin-block: 0;
}

/* A one-word answer. It is the whole point of the section it opens, so it is
   not left to look like the first line of a paragraph. */
.prose__answer {
  color: var(--accent);
  font-size: var(--text-2xl);
  font-weight: 700;
  line-height: 1.4;
}

.section__more {
  margin-block-start: var(--space-10);
  text-align: center;
}

.link-more {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-5);
  border-radius: var(--radius-pill);
  color: var(--accent);
  font-weight: 700;
  text-decoration: none;
  transition: background-color var(--dur-fast) var(--ease-soft),
              gap var(--dur-fast) var(--ease-soft);
}

.link-more:hover {
  background-color: var(--accent-soft);
  gap: var(--space-3);
}

.link-more svg {
  width: 1.1em;
  height: 1.1em;
  flex: none;
}

/* --------------------------------------------------------------------------
   Kinds of dream

   Three numbered cards. The count is the message of the section - the site
   previously named two - so the numerals are large enough to be read as a
   list rather than as decoration.
   -------------------------------------------------------------------------- */

.kinds {
  display: grid;
  gap: var(--space-5);
  margin-block-start: var(--space-10);
  margin-inline: auto;
  padding: 0;
  max-width: 68rem;
  list-style: none;
}

@media (min-width: 48rem) {
  .kinds {
    grid-template-columns: repeat(3, 1fr);
  }
}

.kind {
  position: relative;
  padding: var(--space-8) var(--space-6) var(--space-6);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background-color: var(--bg-raised);
  box-shadow: var(--shadow-sm);
}

/* The gold hairline sits inside the rounded corner rather than across it: a
   full-width rule would cut the corner radius and show two square ends. */
.kind::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: var(--space-6);
  height: 2px;
  border-radius: var(--radius-pill);
  background: linear-gradient(to left, transparent, var(--gold-line), transparent);
}

.kind__num {
  display: block;
  color: var(--gold);
  font-size: var(--text-lg);
  font-weight: 700;
  letter-spacing: 0.08em;
  /* Arabic-Indic numerals inside an RTL paragraph still need isolation, or a
     numeral adjacent to punctuation can be reordered on display. */
  unicode-bidi: isolate;
}

.kind__title {
  margin-block: var(--space-3) var(--space-3);
  font-size: var(--text-xl);
  line-height: 1.4;
}

.kind__text {
  margin: 0;
  color: var(--fg-muted);
  line-height: 1.9;
}

/* --------------------------------------------------------------------------
   Pull quote

   The project's own sentences, set apart from the prose around them. Not a
   scriptural quotation - those use .ayah, which looks different on purpose so
   the two can never be confused.
   -------------------------------------------------------------------------- */

.pull {
  max-width: var(--measure);
  margin-block-start: var(--space-10);
  margin-inline: auto;
  padding: var(--space-6) var(--space-6);
  border-inline-start: 3px solid var(--gold);
  border-radius: var(--radius-md);
  background-color: var(--bg-sunken);
}

.pull__text {
  margin: 0;
  font-size: var(--text-lg);
  line-height: 1.9;
}

.pull--strong {
  text-align: center;
  border-inline-start: 0;
  border: 1px solid var(--gold-line);
  padding-block: var(--space-8);
}

.pull--strong .pull__text {
  font-size: var(--text-2xl);
  font-weight: 700;
  line-height: 1.7;
}

/* --------------------------------------------------------------------------
   The two cases after a dream
   -------------------------------------------------------------------------- */

.cases {
  display: grid;
  gap: var(--space-5);
  margin-block-start: var(--space-10);
  margin-inline: auto;
  max-width: 62rem;
}

@media (min-width: 48rem) {
  .cases {
    grid-template-columns: repeat(2, 1fr);
  }
}

.case {
  padding: var(--space-6) var(--space-6);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background-color: var(--bg-raised);
}

/* The two cases are distinguished by an edge colour, but they are also in a
   fixed order and carry their own headings, so the colour is never the only
   thing telling them apart. */
.case--good {
  border-inline-start: 3px solid var(--accent);
}

.case--hard {
  border-inline-start: 3px solid var(--gold);
}

.case__title {
  margin-block: 0 var(--space-3);
  font-size: var(--text-xl);
}

.case__text {
  margin: 0;
  color: var(--fg-muted);
  line-height: 1.95;
}

/* --------------------------------------------------------------------------
   FAQ

   <details>/<summary>, so it works with no JavaScript at all, is keyboard
   operable for free, and is searchable by the browser's own find-in-page in
   current browsers. A hand-built accordion would need script, ARIA and focus
   management to reach the same place.
   -------------------------------------------------------------------------- */

.faq {
  max-width: 62rem;
  margin-block-start: var(--space-10);
  margin-inline: auto;
}

.faq__item {
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background-color: var(--bg-raised);
}

.faq__item + .faq__item {
  margin-block-start: var(--space-4);
}

.faq__item[open] {
  border-color: var(--accent-ring);
}

.faq__q {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-5) var(--space-6);
  border-radius: var(--radius-lg);
  font-size: var(--text-lg);
  font-weight: 700;
  line-height: 1.6;
  cursor: pointer;
  list-style: none;
}

/* Safari draws its own disclosure triangle on the ::-webkit-details-marker
   pseudo-element and ignores `list-style: none`. Both are needed. */
.faq__q::-webkit-details-marker {
  display: none;
}

/* Physical properties, deliberately, in a file that otherwise uses logical ones
   throughout. This chevron means "this opens downwards", and down is down in
   both writing directions. With border-inline-end it flipped to point sideways
   in RTL, which reads as "go to the next page". */
.faq__q::after {
  content: "";
  flex: none;
  margin-inline-start: auto;
  width: 0.6em;
  height: 0.6em;
  border-right: 2px solid var(--accent);
  border-bottom: 2px solid var(--accent);
  transform: rotate(45deg);
  transition: transform var(--dur-fast) var(--ease-soft);
}

.faq__item[open] .faq__q::after {
  transform: rotate(225deg);
}

.faq__q:hover {
  background-color: var(--accent-soft);
}

.faq__a {
  padding: 0 var(--space-6) var(--space-6);
  color: var(--fg-muted);
  line-height: 1.95;
}

.faq__a > p {
  margin-block: 0;
}

.faq__a > p + p {
  margin-block-start: var(--space-4);
}

/* --------------------------------------------------------------------------
   Qur'anic quotation

   This must not be mistakable for .pull, which carries the project's own
   sentences. The comment here used to claim the two looked different while
   both were centred, rounded, gold-bordered cards - they differed only in
   background tint, which is exactly the kind of difference nobody notices.
   They now differ in shape, which is the first thing anyone notices:

     .pull--strong   rounded card, gold border on all four sides
     .ayah           square-edged band, hairline rules above and below only

   A card is an aside. A band is a passage set into the page. The reference
   line is always present and is part of the component, not optional markup.
   -------------------------------------------------------------------------- */

.ayah {
  max-width: 58ch;
  margin-block: var(--space-8);
  margin-inline: auto;
  padding: var(--space-8) var(--space-6);
  border-block: 1px solid var(--accent-ring);
  border-inline: 0;
  border-radius: 0;
  background-color: var(--accent-soft);
  text-align: center;
}

.ayah__text {
  margin: 0;
  color: var(--fg);
  font-size: var(--text-2xl);
  font-weight: 500;
  /* Verses need more room than prose: the marks travel further and the text is
     set larger. */
  line-height: 2.2;
}

/* --fg-subtle measures 4.41:1 against the tinted --accent-soft ground, just
   under the AA floor. A verse reference is text, so it uses --fg-muted here
   rather than the lighter token it would use on the page background. */
.ayah__ref {
  margin-block-start: var(--space-4);
  color: var(--fg-muted);
  font-size: var(--text-sm);
}

/* Bidirectional isolation utility.
 *
 * Any identifier, verse reference, version or measurement rendered inside an
 * RTL paragraph must carry this class. `direction: ltr` alone is NOT enough:
 * without `unicode-bidi: isolate` the value still participates in the
 * surrounding paragraph's bidi run, and a string such as 12:4 can be displayed
 * as 4:12 - which, for a verse reference, is not a styling preference but a
 * wrong citation.
 *
 * Use together with the HTML attribute: <span class="ltr" dir="ltr">…</span>
 */
.ltr {
  direction: ltr;
  unicode-bidi: isolate;
}

/* --------------------------------------------------------------------------
   Secondary page head and breadcrumb
   -------------------------------------------------------------------------- */

.page-head {
  position: relative;
  padding-block: clamp(var(--space-12), 7vw, var(--space-16)) var(--space-10);
  overflow: hidden;
  text-align: center;
}

.page-head__title {
  margin-block: var(--space-5) 0;
  font-size: var(--text-3xl);
  line-height: 1.25;
}

.page-head__lead {
  max-width: 54ch;
  margin-block-start: var(--space-5);
  margin-inline: auto;
  color: var(--fg-muted);
  font-size: var(--text-lg);
  line-height: 1.9;
}

.crumbs {
  display: flex;
  justify-content: center;
  gap: var(--space-3);
  color: var(--fg-subtle);
  font-size: var(--text-sm);
}

.crumbs a {
  color: var(--fg-muted);
}

/* --------------------------------------------------------------------------
   Footer navigation
   -------------------------------------------------------------------------- */

.site-footer__nav {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-3) var(--space-6);
  margin-block-start: var(--space-6);
}

.site-footer__nav a {
  color: var(--fg-on-inverse);
  font-size: var(--text-sm);
  text-decoration: none;
  border-block-end: 1px solid transparent;
  transition: border-color var(--dur-fast) var(--ease-soft);
}

.site-footer__nav a:hover {
  border-block-end-color: var(--gold);
}

/* --------------------------------------------------------------------------
   Print
   -------------------------------------------------------------------------- */

@media print {
  .site-header,
  .skip-link,
  .hero__actions,
  .ornament::before {
    display: none;
  }

  body {
    background: #fff;
    color: #000;
  }

  .site-footer {
    background: #fff;
    color: #000;
  }

  .reveal {
    opacity: 1;
    transform: none;
  }
}
