/* Musally — shared site styles.
   Same-origin stylesheet (no CDN, no external fonts). Navy ink on white,
   Georgia wordmark, hairline rules.

   DARK MODE is gated on `data-theme="dark"`, which assets/theme.js stamps on
   <html> before the first paint. It used to fire straight off
   prefers-color-scheme, which meant a visitor whose browser reported the wrong
   preference had no way out of it — and Firefox resolves that query from its
   own theme setting rather than from Windows, so it regularly disagreed with
   every other browser on the same machine. theme.js resolves the question once
   (a saved choice if there is one, otherwise the browser preference) and this
   file only ever asks "is this document dark".

   With scripting off nothing sets the attribute and the site stays light. That
   is the deliberate trade: light is the designed default. */

:root {
  --ink:        #00177a;
  --text:       #1c2026;
  --muted:      #5b6773;
  --hairline:   #dfe4ec;
  --page:       #ffffff;
  --panel:      #f6f8fc;
  --logo-filter: none;
}

:root[data-theme="dark"] {
  --ink:      #ffffff;
  --text:     #f2f5f9;
  --muted:    #a8b4c2;
  --hairline: #24344d;
  --page:     #0d1826;
  --panel:    #12203440;
  /* The mark is a single navy ink on transparency, so flattening it to
     white keeps the line weight identical rather than shipping a second file. */
  --logo-filter: brightness(0) invert(1);
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  background: var(--page);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  line-height: 1.6;
}

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

   PORTED FROM THE TIMETABLE'S SHARED HEADER, 5 Aug 2026.

   The menu bar was one width here and a different one on /times. This
   bar capped at 60rem (960px) while /times sizes its bar from a responsive
   scale reaching 1500px, so the header physically jumped - different width,
   different height, different type size, a different appearance control - every
   time a visitor crossed between musally.co.uk and musally.co.uk/times. Nine
   items also stopped fitting in 960px, which is why the Appearance control had
   wrapped onto a second line.

   Everything below mirrors includes/public-header.php: the same --wrap-max
   scale, the same 56px bar, the same 0.875rem links, the same 1080px collapse
   to a drawer, the same appearance menu. Change one, change both.

   The one deliberate difference is the appearance icon. /times draws it with
   Font Awesome; this site loads no external CSS or fonts by design, so it is an
   inline SVG here. Same shape, no CDN.
   ---- */

/* Mirrors base.css so the wordmark, the first column of the page and the
   footer all start on the same vertical line at every width. */
:root { --wrap-max: 820px; }
@media (min-width: 1024px) { :root { --wrap-max: 1080px; } }
@media (min-width: 1440px) { :root { --wrap-max: 1320px; } }
@media (min-width: 1800px) { :root { --wrap-max: 1500px; } }

.site-header {
  border-bottom: 1px solid var(--hairline);
  background: var(--page);
  position: sticky;
  top: 0;
  z-index: 100;
}

.nav {
  width: 100%;
  max-width: var(--wrap-max);
  margin: 0 auto;
  padding: 0 1rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* 56px, the same figure /times uses. Not taste - it is what makes the two
     bars the same object. */
  height: 56px;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  text-decoration: none;
  color: var(--ink);
  white-space: nowrap;
  font-family: Georgia, "Iowan Old Style", "Times New Roman", serif;
  font-size: 1.2rem;
  letter-spacing: 0.02em;
}

.brand img {
  width: 26px;
  height: 26px;
  display: block;
  flex-shrink: 0;
  filter: var(--logo-filter);
}

.brand span { font: inherit; letter-spacing: inherit; }

/* The right-hand group: links, appearance, hamburger. Wrapped so they stay
   together on the right instead of being strung across the bar. */
.nav-right {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.nav-links {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.nav-links a {
  text-decoration: none;
  color: var(--muted);
  font-size: 0.875rem;
  /* Stated so an <a> and the <button> triggers beside it are the same box.
     Omitting it is exactly what put "Maps" out of line on /times. */
  line-height: 1.5;
  letter-spacing: 0.03em;
  padding: 6px 0;
  border-bottom: 2px solid transparent;
  transition: color 0.2s, border-color 0.2s;
}

.nav-links a:hover { color: var(--ink); }

.nav-links a[aria-current="page"] {
  color: var(--ink);
  border-bottom-color: var(--ink);
}

/* Grouped menus - Prayer Times and Maps. The trigger is a real <button>, not a
   hover target: hover cannot be reached from a keyboard, does not exist on a
   touch screen, and a hover-open panel makes the first tap look like it did
   nothing because the panel was already showing. */
.nav-drop { position: relative; display: flex; align-items: center; }

.nav-drop-btn {
  /* `font: inherit`, not property-by-property. A <button> inherits none of its
     typography and the browser substitutes its own; naming them one at a time
     is how a trigger ends up a shade heavier than the links beside it. Size and
     line-height are restated after, since the shorthand resets both. */
  font: inherit;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--muted);
  letter-spacing: 0.03em;
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  padding: 6px 0;
  margin: 0;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  transition: color 0.2s, border-color 0.2s;
}

.nav-drop-btn:hover { color: var(--ink); }
.nav-drop.is-active .nav-drop-btn {
  color: var(--ink);
  border-bottom-color: var(--ink);
}

.nav-drop-caret { font-size: 0.7em; line-height: 1; transition: transform 0.15s; }
.nav-drop.open .nav-drop-caret { transform: rotate(180deg); }

.nav-drop-menu {
  display: none;
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  min-width: 13rem;
  background: var(--page);
  border: 1px solid var(--hairline);
  border-radius: 4px;
  /* The one shadow on this site. A panel covering page text has to read as
     being above it, and a hairline between two identical surfaces cannot. */
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.14);
  padding: 4px;
  z-index: 110;
}

.nav-drop.open .nav-drop-menu { display: block; }

/* These sit inside .nav-links, so `.nav-links a` matches them at equal
   specificity - this block has to come after it to win. */
.nav-drop-menu a {
  display: block;
  white-space: nowrap;
  padding: 8px 12px;
  border-radius: 3px;
  border-bottom: 0;
  color: var(--muted);
  font-size: 0.875rem;
}
.nav-drop-menu a:hover { color: var(--ink); background: var(--panel); }

/* Appearance. Outside .nav-links so it survives the drawer breakpoint -
   appearance is not a destination, and burying it behind a hamburger on the
   phones where a dark page matters most would be the wrong way round. */
.nav-theme-btn {
  padding: 6px;
  border-bottom: 0;
  border-radius: 3px;
  line-height: 0;
}
.nav-theme-btn svg { width: 17px; height: 17px; display: block; }
.nav-theme .nav-drop-menu { min-width: 9rem; }

.nav-theme-opt {
  display: block;
  width: 100%;
  margin: 0;
  text-align: left;
  font: inherit;
  font-size: 0.875rem;
  background: none;
  border: 0;
  cursor: pointer;
  white-space: nowrap;
  color: var(--muted);
  padding: 8px 12px;
  border-radius: 3px;
}
.nav-theme-opt:hover { color: var(--ink); background: var(--panel); }
.nav-theme-opt[aria-pressed="true"] {
  color: var(--ink);
  background: var(--panel);
  font-weight: 600;
}

.nav-toggle {
  display: none;
  background: none;
  border: none;
  margin: 0;
  width: auto;
  color: var(--muted);
  font-size: 1.4rem;
  cursor: pointer;
  padding: 4px;
  line-height: 1;
}
.nav-toggle:hover { color: var(--ink); }

.nav-mobile {
  display: none;
  background: var(--page);
  border-top: 1px solid var(--hairline);
  padding-block: 8px 12px;
  /* Full-bleed so the border runs edge to edge, but the items start on the same
     line as the wordmark above them. */
  padding-inline: max(1rem, calc((100% - var(--wrap-max)) / 2 + 1rem));
  /* The drawer sits inside the sticky header, so with no cap the part of it
     past the bottom of a phone screen can never be reached — the bar stays
     pinned and the swipe scrolls the page behind instead. Give it its own
     scroll under the 56px bar. dvh because iOS Safari's vh is the taller
     URL-bar-hidden height; the vh line is the fallback. overscroll-behavior
     stops the swipe handing off to the page at either end. */
  max-height: calc(100vh - 56px);
  max-height: calc(100dvh - 56px);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}
.nav-mobile a {
  display: block;
  color: var(--muted);
  font-size: 0.875rem;
  text-decoration: none;
  padding: 10px 0;
  border-bottom: 1px solid var(--hairline);
}
.nav-mobile a:last-child { border: none; }
.nav-mobile a:hover,
.nav-mobile a[aria-current="page"] { color: var(--ink); }

/* Groups in the drawer are a LABEL with the destinations indented under it, not
   a second thing to tap open - the whole point of opening the drawer is to see
   where you can go. */
.nav-mobile-group {
  color: var(--muted);
  font-size: 0.8125rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  padding: 12px 0 2px;
}
.nav-mobile a.nav-mobile-sub { padding-left: 14px; }

/* Same collapse point as /times, for the same reason: below this the nine items
   and the wordmark stop fitting the column --wrap-max gives them. */
@media (max-width: 1079px) {
  .nav-links { display: none; }
  .nav-toggle { display: block; }
  .nav-mobile.open { display: block; }
}

/* ---- Main ---- */

main {
  flex: 1 0 auto;
  width: 100%;
  max-width: 44rem;
  margin: 0 auto;
  padding: 3rem 1.5rem 3.5rem;
}

.hero { text-align: center; }

.mark {
  width: 84px;
  height: 84px;
  margin: 0 auto 1.5rem;
  display: block;
  filter: var(--logo-filter);
}

h1 {
  margin: 0;
  font-family: Georgia, "Iowan Old Style", "Times New Roman", serif;
  font-size: clamp(2.25rem, 8vw, 3.25rem);
  font-weight: 400;
  letter-spacing: 0.02em;
  color: var(--ink);
  line-height: 1.05;
}

.hero h1 { margin-bottom: 0.75rem; }

.page-title {
  font-family: Georgia, "Iowan Old Style", "Times New Roman", serif;
  font-size: clamp(1.9rem, 6vw, 2.5rem);
  font-weight: 400;
  letter-spacing: 0.01em;
  color: var(--ink);
  margin: 0 0 1.5rem;
}

.eyebrow {
  font-size: 0.72rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 0.6rem;
}

.tagline {
  margin: 0 auto;
  max-width: 32rem;
  font-size: clamp(1.05rem, 3.4vw, 1.2rem);
  color: var(--muted);
}

.rule {
  width: 3.5rem;
  height: 1px;
  margin: 2.25rem auto;
  background: var(--hairline);
  border: 0;
}

p { margin: 0 0 1.1rem; }
main a { color: var(--ink); }

h2 {
  font-family: Georgia, "Iowan Old Style", "Times New Roman", serif;
  font-weight: 400;
  font-size: 1.4rem;
  color: var(--ink);
  margin: 2.5rem 0 0.75rem;
}

.lead { font-size: 1.12rem; }

/* ---- App preview ---- */

.app-preview {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 2rem 2.5rem;
  margin: 2.5rem 0 0;
}

.app-preview .copy {
  flex: 1 1 16rem;
  min-width: 14rem;
}

.app-preview .copy h2 { margin-top: 0.9rem; }
.app-preview .copy .soon-pill { margin-bottom: 0; }

/* The device frame is part of the IMAGE now, not drawn here.

   This used to be a fake bezel — a 9px --ink border with a 2.4rem radius and a
   matching background — wrapped around a raw screen capture, and the bezels
   read as wrong. Proper device mockups replaced it (Aug 2026), and those
   already carry a photographic frame, buttons and notch. Keeping the CSS bezel
   would have put a phone inside a phone.

   Slightly wider than the 224px it was, because that 224px was the SCREEN and
   this 250px is the whole handset — so the screen lands at about the same size
   on the page as before. */
.phone {
  flex: 0 0 auto;
  width: 250px;
  line-height: 0;
}

.phone img {
  display: block;
  width: 100%;
  height: auto;
}

/* Two device colours, one per page theme. The same screen is supplied in a
   graphite and a silver handset, which is the pair that matters here: a black
   phone disappears against the dark page and a white one disappears against the
   light one. Both files are cropped to the handset with the surrounding white
   knocked out to transparency, so neither carries a plate of its own.
   NOTE these are the same app screen, not app light/dark mode. */
.phone .shot-dark { display: none; }
:root[data-theme="dark"] .phone .shot-light { display: none; }
:root[data-theme="dark"] .phone .shot-dark { display: block; }

.soon-pill {
  display: inline-block;
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  border: 1px solid var(--hairline);
  border-radius: 999px;
  padding: 0.32rem 0.85rem;
}

.stores {
  margin: 1.25rem 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
}

/* Store buttons. Deliberately typographic rather than the official badge
   artwork: the badges are fixed-height PNGs that go soft on a retina screen
   and carry their own black, which fights the dark page. */
.store-btn {
  display: inline-flex;
  flex-direction: column;
  justify-content: center;
  min-width: 9.5rem;
  padding: 0.5rem 1.05rem;
  border: 1px solid var(--hairline);
  border-radius: 10px;
  text-decoration: none;
  color: var(--ink);
  background: var(--panel);
  transition: border-color 0.15s ease, transform 0.15s ease;
}
.store-btn:hover {
  border-color: var(--ink);
  transform: translateY(-1px);
}
.store-btn-sub {
  font-size: 0.62rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  line-height: 1.4;
}
.store-btn-name {
  font-size: 0.98rem;
  font-weight: 600;
  line-height: 1.25;
}

@media (max-width: 480px) {
  .store-btn { flex: 1 1 100%; }
}

.prayers {
  margin: 2.5rem 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.6rem 1.5rem;
  font-size: 0.75rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}

/* ---- Panels / cards ---- */

.panel {
  background: var(--panel);
  border: 1px solid var(--hairline);
  border-radius: 12px;
  padding: 1.5rem 1.5rem 1.6rem;
  margin: 1.5rem 0;
}

.panel h2 { margin-top: 0; }

.card-links {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 1rem;
  margin: 2.5rem 0 0;
  padding: 0;
  list-style: none;
}

.card-links a {
  display: block;
  text-decoration: none;
  color: var(--text);
  background: var(--panel);
  border: 1px solid var(--hairline);
  border-radius: 12px;
  padding: 1.1rem 1.2rem;
}

.card-links a:hover { border-color: var(--ink); }

.card-links strong {
  display: block;
  color: var(--ink);
  font-weight: 600;
  margin-bottom: 0.2rem;
}

.card-links span { font-size: 0.9rem; color: var(--muted); }

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

.btn {
  display: inline-block;
  text-decoration: none;
  font-size: 0.95rem;
  letter-spacing: 0.02em;
  padding: 0.7rem 1.4rem;
  border-radius: 8px;
  border: 1px solid var(--ink);
  background: var(--ink);
  color: #ffffff;
  cursor: pointer;
}

/* The filled button's label is the reverse of its fill. --ink is near-black in
   light and #ffffff in dark, so the label cannot stay the literal white above.

   :where() is load-bearing, not decoration. Written plainly as
   `:root[data-theme="dark"] .btn` this scores 0,3,0 and beats `.btn.secondary`
   below — which turned the OUTLINED button's label the page colour on a
   transparent background, i.e. an empty box with nothing in it. :where()
   contributes nothing to specificity, so this sits at 0,1,0: exactly what the
   `@media (prefers-color-scheme: dark)` rule it replaced scored, and .secondary
   goes back to winning. */
:where(:root[data-theme="dark"]) .btn { color: var(--page); }

/* Outlined variant. No fill, so the label takes the ink itself — navy in light,
   white in dark. Stated after the rule above as well as outranking it, so the
   intent survives even if someone later rewrites that selector. */
.btn.secondary {
  background: transparent;
  color: var(--ink);
}

/* Buttons sitting side by side, stacking on narrow screens. */
.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
}

/* Small print — processor, cancellation, charity status. */
.fine {
  font-size: 0.85rem;
  color: var(--muted);
}

/* ---- Give: one-off beside monthly ----

   Stripe cannot offer both on one payment link — a link is either a one-off
   price or a subscription, and "customer chooses what to pay" only exists for
   one-off prices. So the choice has to be made here, on the page, before the
   visitor ever reaches Stripe: two panels, one link each.

   Collapses to a single column below roughly 31rem, which is where two 15rem
   panels and the gap stop fitting. */
.give {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1rem;
  margin: 1.5rem 0;
}

/* The panels are siblings in a grid now, so their own vertical margin would
   double the row gap. Column flex is what pins both button rows to the same
   line when one blurb runs longer than the other. */
.give .panel {
  margin: 0;
  display: flex;
  flex-direction: column;
}

.give .panel h2 { font-size: 1.25rem; }

.give-note {
  color: var(--muted);
  font-size: 0.9rem;
  /* Takes the slack, which is what pushes the buttons down to a shared baseline
     rather than leaving them to float under unequal paragraphs. */
  flex: 1 0 auto;
}

.give .btn-row { margin-bottom: 0; }

/* ---- Form ---- */

.field { margin: 0 0 1.1rem; }

.field label {
  display: block;
  font-size: 0.85rem;
  letter-spacing: 0.03em;
  color: var(--muted);
  margin-bottom: 0.4rem;
}

.field input,
.field textarea {
  width: 100%;
  font: inherit;
  color: var(--text);
  background: var(--page);
  border: 1px solid var(--hairline);
  border-radius: 8px;
  padding: 0.7rem 0.8rem;
}

.field input:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--ink);
}

.field textarea { min-height: 8rem; resize: vertical; }

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

.site-footer {
  flex-shrink: 0;
  border-top: 1px solid var(--hairline);
  color: var(--muted);
  font-size: 0.85rem;
  text-align: center;
  padding: 1.75rem 1.5rem;
}

.site-footer a { color: var(--muted); }
.site-footer a:hover { color: var(--ink); }
.site-footer p { margin: 0.25rem 0; }
