/* GUL — website styles, built on the Gul token set (brand v2: the petal
   is the dome). Motion contract: the sun moves linear 600ms; a petal
   answers a person, eased 760ms on cubic-bezier(.22,1,.36,1). */

:root {
  --pn-void:        #030507;
  --pn-page:        #05080A;
  --pn-surface:     #0A0F0E;
  --pn-card:        #0E1513;
  --pn-line:        #1C2723;
  --pn-line-soft:   #16211E;
  --pn-line-strong: #2A3630;

  --pn-sun:         #E9B366;
  --pn-sun-high:    #FFF7E6;
  --pn-sun-pale:    #F5D6A6;
  --pn-dusk:        #DE8B52;
  --pn-dawn:        #B4693F;

  --pn-leaf:        #7CD9A6;
  --pn-leaf-late:   #4E6558;
  --pn-stem:        #2C4238;

  --pn-wilt:        #4A3A31;
  --pn-wilt-line:   #6B3B30;
  --pn-wilt-text:   #E3C0B4;

  --pn-ink:         #F7F3EA;
  --pn-ink-2:       #F2EDE3;
  --pn-ink-3:       #C9C6BE;
  --pn-muted:       #8E8B82;
  --pn-label:       #6E7B74;
  --pn-faint:       #4E5E58;

  --pn-display: 'Instrument Serif', Georgia, serif;
  --pn-ui:      'DM Sans', system-ui, sans-serif;

  --pn-r-card: 24px;
  --pn-r-panel: 24px;
  --pn-r-well: 16px;
  --pn-r-pill: 999px;

  --pn-ease: cubic-bezier(.22, 1, .36, 1);
  --pn-dur-tap: 180ms;
  --pn-dur-sun: 600ms;
  --pn-dur-grow: 760ms;
  --pn-dur-heal: 1000ms;
  --pn-dur-flare: 620ms;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--pn-page);
  color: var(--pn-ink-2);
  font-family: var(--pn-ui);
  font-size: 13.5px;
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
}
button { font-family: inherit; cursor: pointer; }
a { color: var(--pn-sun); text-decoration: none; }
h2 { font-family: var(--pn-display); font-weight: 400; font-size: 34px; line-height: 1.14; color: var(--pn-ink); margin: 0; }
h3 { font-family: var(--pn-display); font-weight: 400; font-size: 23px; color: var(--pn-ink-2); margin: 26px 0 12px; }

/* ── Nav ─────────────────────────────────────────────────────────── */
.nav {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px clamp(20px, 5vw, 56px);
  background: color-mix(in srgb, var(--pn-page) 82%, transparent);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--pn-line-soft);
}
/* Belt and braces with the viewport line: `manipulation` removes the 300ms
   double-tap-to-zoom wait on every tappable thing, so a tap that notes a
   prayer registers immediately. The aperture overrides this with
   `touch-action: none` because it needs the whole gesture for scrubbing. */
html, body, button, a, .dt-row, .tt-row, .m-cell { touch-action: manipulation; }

/* viewport-fit=cover puts the page under the notch and the home indicator.
   These two lines are what keep the nav and the footer out from under them. */
.nav { padding-top: calc(16px + env(safe-area-inset-top)); }
.foot { padding-bottom: calc(28px + env(safe-area-inset-bottom)); }

.brand { display: flex; align-items: center; gap: 12px; }
.brand-word { font-family: var(--pn-display); font-size: 24px; letter-spacing: .16em; color: var(--pn-ink); }
/* The slogan the experiments card carries, carried here too, in the same
   sun ramp — first light to meridian. The hub and the app should read as
   one thing, and this is the cheapest place to say so. */
.brand-slogan {
  font-size: 10.5px; letter-spacing: .2em; text-transform: uppercase;
  padding-left: 13px;
  border-left: 1px solid var(--pn-line-soft);
  background: linear-gradient(92deg, #D66434, #F2B864 58%, #FDF1D2);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}
.links { display: flex; gap: clamp(14px, 3vw, 34px); }
.links a {
  font-size: 11px; letter-spacing: .22em; text-transform: uppercase;
  color: var(--pn-label); transition: color var(--pn-dur-tap) var(--pn-ease);
}
.links a:hover { color: var(--pn-sun-pale); }
.links a.on { color: var(--pn-ink-2); }

/* ── Today ───────────────────────────────────────────────────────── */
.today {
  display: grid;
  grid-template-columns: minmax(320px, 1.1fr) minmax(300px, 1fr) minmax(280px, .9fr);
  gap: clamp(24px, 4vw, 56px);
  align-items: center;
  padding: clamp(36px, 6vh, 72px) clamp(20px, 5vw, 56px);
  max-width: 1460px; margin: 0 auto;
}

.flower-stage { position: relative; width: 100%; max-width: 460px; aspect-ratio: 1; margin: 0 auto; display: grid; place-items: center; }
.corona {
  position: absolute; width: 290px; height: 290px; border-radius: 50%;
  background: radial-gradient(circle, rgba(233,179,102,.20) 0%, transparent 66%);
  pointer-events: none;
  transition: all var(--pn-dur-sun) linear;
}
@keyframes gul-corona { 0%, 100% { opacity: .24; transform: scale(1); } 50% { opacity: .56; transform: scale(1.13); } }

/* ── The bloom ────────────────────────────────────────────────────────
   Fired once, when a person notes a prayer. Never on a timer, never on
   load. It eases, because it answers someone — the sun's own radius and
   colour keep running linearly underneath and are untouched by this.     */
.flare {
  position: absolute; width: 300px; height: 300px; border-radius: 50%;
  pointer-events: none; opacity: 0;
  background: radial-gradient(circle, rgba(242,237,227,.55) 0%, rgba(233,179,102,.28) 34%, transparent 68%);
}
.flare.on { animation: gul-flare var(--pn-dur-grow, 760ms) var(--pn-ease); }
@keyframes gul-flare {
  0%   { opacity: 0;   transform: scale(.55); }
  38%  { opacity: .95; transform: scale(1.06); }
  100% { opacity: 0;   transform: scale(1.34); }
}

/* The petal that was just opened swells past its resting size and settles —
   the same 5° overshoot the handoff specifies, expressed as scale so it
   cannot fight the transform the flower already sets on each petal. */
#flower .petal.opened { animation: gul-petal-open var(--pn-dur-grow, 760ms) var(--pn-ease); }
@keyframes gul-petal-open {
  0%   { opacity: .4; }
  40%  { opacity: 1; }
  100% { opacity: 1; }
}

#flower { position: relative; width: min(100%, 340px); height: auto; }
#flower .petal { transition: all var(--pn-dur-grow) var(--pn-ease); }
#flower #disc { transition: all var(--pn-dur-sun) linear; }

/* The label ring must share the flower's centre, not the stage's top-left.
   With `inset: 0` plus an explicit width, `right` is dropped and the box
   anchors left — which put every label off by half the difference between
   the stage and the mark, and read as a crooked flower. Centring the box
   is what makes the five names land on their own petal tips. */
.tips {
  position: absolute; top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  pointer-events: none;
}
.tip {
  position: absolute; transform: translate(-50%, -50%);
  font-size: 9.5px; letter-spacing: .16em; text-transform: uppercase; white-space: nowrap;
  transition: color var(--pn-dur-grow) var(--pn-ease);
}

.today-panel { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.date-line { font-size: 14.5px; color: var(--pn-muted); display: flex; gap: 8px; flex-wrap: wrap; }
.date-line .dot { color: var(--pn-faint); }
.place {
  align-self: flex-start; background: none; border: none; padding: 0;
  font-size: 14.5px; color: var(--pn-label);
  transition: color var(--pn-dur-tap) var(--pn-ease);
}
.place:hover { color: var(--pn-sun-pale); }

.now-block { display: flex; flex-direction: column; gap: 3px; padding-top: 6px; }
.kicker { font-size: 13px; color: var(--pn-muted); }
.now-name { font-family: var(--pn-display); font-size: clamp(38px, 4vw, 52px); line-height: 1.05; color: var(--pn-ink); }
.now-time { font-family: var(--pn-display); font-size: 25px; line-height: 1.25; color: var(--pn-ink-2); }
.next-label { font-size: 13px; color: var(--pn-muted); padding-top: 4px; }

.primary {
  margin-top: 6px; width: 100%; max-width: 380px; padding: 15px 0;
  border: none; border-radius: var(--pn-r-pill);
  background: #EAE2D5; color: var(--pn-page);
  font-size: 15px; font-weight: 500;
  transition: all var(--pn-dur-tap) var(--pn-ease);
}
.primary:hover { background: var(--pn-sun-pale); }
.primary.noted { background: transparent; border: 1px solid #2A3630; color: var(--pn-muted); }

/* ── The day table ───────────────────────────────────────────────────
   This replaced a row of five 44px pills. On a phone each pill was only
   as wide as the word inside it, and all five shared one cramped line, so
   noting Maghrib meant aiming a thumb at seven characters. A full-width
   row cannot be missed, and it has room for the time, which the pills
   never had anywhere to put.

   56px is the floor, not the target — rows grow with their content. */
.day-table { display: flex; flex-direction: column; margin-top: 6px; border-top: 1px solid var(--pn-line-soft); }
.dt-row {
  display: flex; align-items: center; gap: 12px;
  width: 100%; min-height: 56px; padding: 10px 12px 10px 10px;
  border: 0; border-bottom: 1px solid var(--pn-line-soft);
  border-left: 2px solid transparent;
  background: transparent; color: inherit; font: inherit; text-align: left;
  cursor: pointer; -webkit-tap-highlight-color: transparent;
  transition: background var(--pn-dur-tap) var(--pn-ease),
              border-left-color var(--pn-dur-tap) var(--pn-ease);
}
.dt-row:active { background: rgba(242,237,227,.05); }
@media (hover: hover) { .dt-row:hover { background: rgba(242,237,227,.03); } }
.dt-row:focus-visible { outline: 2px solid var(--pn-sun); outline-offset: -2px; }

.dt-disc { flex: none; width: 26px; display: flex; align-items: center; justify-content: center; }
/* The disc is the real sun at that prayer's minute, so it moves the way the
   sun moves: linear, 600ms, no easing. The row's own state easing sits
   right below it. Two motion families, kept apart, as everywhere else. */
.dt-disc circle { transition: r var(--pn-dur-sun) linear, fill var(--pn-dur-sun) linear; }

.dt-name { flex: 1; min-width: 0; font-family: var(--pn-display); font-size: 19px; color: var(--pn-ink-2); }
.dt-time {
  font-size: 14px; color: var(--pn-muted); white-space: nowrap;
  font-variant-numeric: tabular-nums;
  transition: color var(--pn-dur-tap) var(--pn-ease);
}

.dt-state { flex: none; display: flex; align-items: center; justify-content: flex-end; gap: 8px; min-width: 76px; }
.dt-ring {
  width: 13px; height: 13px; border-radius: 50%;
  border: 1px solid var(--pn-line-strong); background: transparent;
  transition: all var(--pn-dur-tap) var(--pn-ease);
}
/* The word appears only once there is something to say. Five rows all
   reading "not marked" is the app nagging; an empty ring says the same
   thing without raising its voice. */
.dt-word {
  font-size: 10.5px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--pn-leaf); opacity: 0;
  transition: opacity var(--pn-dur-tap) var(--pn-ease);
}
.dt-row.on .dt-ring { border-color: var(--pn-leaf); background: var(--pn-leaf); }
.dt-row.on .dt-name { color: var(--pn-ink); }
.dt-row.on .dt-word { opacity: 1; }

/* Sun, not green. Green in this app means a prayer was noted and nothing
   else, so the prayer you are currently inside is marked in the sun's own
   colour instead. */
.dt-row.now { border-left-color: var(--pn-sun); }
.dt-row.now .dt-time { color: var(--pn-sun); }

.quiet { margin: 4px 0 0; max-width: 44ch; font-size: 13.5px; line-height: 1.55; color: var(--pn-muted); }
.notice {
  margin: 4px 0 0; max-width: 46ch; font-size: 13px; line-height: 1.55;
  color: var(--pn-wilt-text);
  padding: 12px 14px; border: 1px solid var(--pn-wilt-line); border-radius: var(--pn-r-well);
  background: rgba(74,58,49,.25);
}

/* ── Aperture ────────────────────────────────────────────────────── */
.today-aperture { display: flex; flex-direction: column; align-items: center; gap: 18px; }
.aperture-frame {
  position: relative; width: min(100%, 300px); aspect-ratio: 1;
  border-radius: 50%; overflow: hidden; background: #0C1216;
  box-shadow: 0 0 0 12px var(--pn-page), 0 0 90px rgba(233,179,102,.10);
}
.ap-layer { position: absolute; transition: all var(--pn-dur-sun) linear; }
.ap-readout { text-align: center; display: grid; gap: 6px; }
.ap-phase { font-family: var(--pn-display); font-size: 20px; color: var(--pn-ink-2); }
.ap-meta { font-size: 11px; letter-spacing: .2em; text-transform: uppercase; color: var(--pn-label); }

/* ── Scrubbing the aperture ──────────────────────────────────────────
   Dragging moves the clock, not the sun. The sun still sits exactly
   where it truly is at whatever minute the finger is holding — so the
   window never lies, it is just showing a different hour. While the
   finger is down the layers follow it with no transition at all: that
   motion is the person's, and the person is not on a 600ms delay. On
   release the 600ms linear returns and the sun travels back to now. */
.aperture-frame { cursor: grab; touch-action: none; }
.aperture-frame.scrubbing { cursor: grabbing; }
.aperture-frame.scrubbing .ap-layer { transition: none; }
/* It is a button, so it arrives with the browser's grey chrome and black
   text. Reset that explicitly — without it the label sat pale gold on a
   near-white default background and could not be read. */
.ap-scrub {
  appearance: none; -webkit-appearance: none;
  background: none; border: 0; padding: 4px 2px; margin: 0;
  font: inherit; font-size: 11px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--pn-label); cursor: pointer;
  transition: color var(--pn-dur-tap) var(--pn-ease);
}
.ap-scrub:hover { color: var(--pn-ink-2); }
/* Away from now, it is the one thing on screen asking to be pressed. */
.ap-scrub.away { color: var(--pn-sun); }
.ap-scrub.away:hover { color: var(--pn-sun-pale); }
@media (prefers-reduced-motion: reduce) { .ap-layer { transition-duration: 1ms; } }

/* ── Sheets (timetable / history / settings) ─────────────────────── */
/* Views are tabs, not stacked panels. `hidden` alone loses to the display
   values below, so it is made to win explicitly — otherwise every section
   renders on top of Today and the app reads as one long settings page. */
[hidden] { display: none !important; }

.sheet {
  max-width: 860px; margin: 0 auto;
  padding: clamp(48px, 8vh, 84px) clamp(20px, 5vw, 40px) 0;
}
.sheet:last-of-type { padding-bottom: clamp(48px, 8vh, 84px); }
.sheet-head { display: flex; flex-direction: column; gap: 12px; margin-bottom: 20px; }
.sheet-sub { font-size: 13.5px; color: var(--pn-muted); }

.day-nav { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.day-nav button {
  padding: 11px 15px; border: 1px solid #2A3630; border-radius: var(--pn-r-pill);
  background: transparent; color: var(--pn-ink-2); font-size: 13px; white-space: nowrap;
  transition: all var(--pn-dur-tap) var(--pn-ease);
}
.day-nav button:hover { border-color: var(--pn-sun); color: var(--pn-sun-pale); }
#day-today { border: none; color: var(--pn-label); pointer-events: none; }

.rows { display: flex; flex-direction: column; }
.tt-row { display: flex; align-items: center; gap: 12px; padding: 14px 0; border-bottom: 1px solid #16201C; }
/* Sun, not green — green means a prayer was noted and nothing else, and the
   row you are currently inside is a fact about the sun, not about you. */
.tt-row.now { border-left: 2px solid var(--pn-sun); padding-left: 12px; margin-left: -14px; }
.tt-disc { flex: none; width: 30px; display: flex; align-items: center; justify-content: center; }
.tt-disc svg circle { transition: all var(--pn-dur-sun) linear; }
.tt-main { flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.tt-name { font-family: var(--pn-display); font-size: 19px; color: var(--pn-ink-2); }
.tt-name.info { font-size: 16px; color: var(--pn-muted); }
.tt-sub { font-size: 12px; line-height: 1.4; color: #7F8C85; }
.tt-time { font-size: 14px; color: var(--pn-ink-2); white-space: nowrap; }
.tt-time.info { color: var(--pn-muted); }
.tt-mark {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 9px 11px; min-width: 74px; min-height: 44px;
  border-radius: 13px; border: 1px solid #26383B; background: transparent; color: #8C9A90;
  font-size: 12px; transition: all var(--pn-dur-tap) var(--pn-ease);
}
.tt-mark .glyph { font-size: 10px; color: var(--pn-faint); }
.tt-mark.open { border-color: rgba(124,217,166,.4); background: rgba(124,217,166,.08); color: #DFF3E7; }
.tt-mark.open .glyph { color: var(--pn-leaf); }

.info-card {
  display: flex; gap: 11px; align-items: flex-start;
  padding: 14px 15px; margin: 4px 0 0;
  background: #0E1513; border: 1px solid var(--pn-line); border-radius: var(--pn-r-well);
  font-size: 13px; line-height: 1.5; color: var(--pn-ink-3);
}
.i-dot {
  flex: none; width: 20px; height: 20px; border-radius: 50%;
  border: 1px solid #4A5A52; color: var(--pn-muted);
  font-size: 11.5px; font-style: italic;
  display: flex; align-items: center; justify-content: center;
}

/* ── Consistency ─────────────────────────────────────────────────────
   A report, not an instrument: nothing in here is the sun, so everything
   eases. Green is the one accent, because green already means "noted"
   everywhere else in the app and a second meaning would break that. The
   unfilled part of a bar is line colour, never wilt — an unmarked prayer
   is an absence of a note, not a recorded failure, and colouring it as
   damage would be the app making a claim it cannot make. */
.consist {
  margin: 18px 0 8px; padding: 18px 18px 14px;
  background: var(--pn-card); border: 1px solid var(--pn-line);
  border-radius: var(--pn-r-panel);
}
.cs-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; margin-bottom: 16px;
}
.cs-title { font-family: var(--pn-display); font-size: 23px; color: var(--pn-ink-2); }
.cs-range { display: flex; gap: 6px; }
.cs-range button {
  font: inherit; font-size: 11px; letter-spacing: .1em; text-transform: uppercase;
  padding: 7px 12px; min-height: 36px; border-radius: var(--pn-r-pill); cursor: pointer;
  border: 1px solid var(--pn-line-strong); background: transparent; color: var(--pn-muted);
  transition: color var(--pn-dur-tap) var(--pn-ease),
              border-color var(--pn-dur-tap) var(--pn-ease),
              background var(--pn-dur-tap) var(--pn-ease);
}
.cs-range button:hover { color: var(--pn-ink-2); border-color: var(--pn-label); }
.cs-range button[aria-pressed="true"] {
  background: var(--pn-ink-2); border-color: var(--pn-ink-2); color: var(--pn-page);
}

.cs-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px; background: var(--pn-line);
  border: 1px solid var(--pn-line); border-radius: var(--pn-r-well); overflow: hidden; }
.cs-stats > div { background: var(--pn-surface); padding: 14px 14px 12px; }
.cs-stats b {
  display: block; font-family: var(--pn-display); font-weight: 400;
  font-size: 27px; line-height: 1.1; color: var(--pn-ink-2);
  transition: color var(--pn-dur-grow) var(--pn-ease);
}
.cs-stats b.on { color: var(--pn-leaf); }
.cs-stats span {
  display: block; font-size: 10px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--pn-label); margin-top: 5px;
}

.cs-bars { margin-top: 16px; }
.cs-row {
  display: grid; grid-template-columns: 62px 1fr 52px; align-items: center;
  gap: 12px; padding: 8px 0;
}
.cs-name { font-family: var(--pn-display); font-size: 16px; color: var(--pn-ink-3); }
.cs-track {
  height: 7px; border-radius: var(--pn-r-pill); background: var(--pn-line);
  overflow: hidden;
}
.cs-fill {
  display: block; height: 100%; border-radius: var(--pn-r-pill);
  background: var(--pn-leaf-late);
  transition: width var(--pn-dur-heal) var(--pn-ease),
              background var(--pn-dur-heal) var(--pn-ease);
}
/* The strongest prayer of the period is the only one lit. Lighting them
   all would make the ranking unreadable, which is the whole point of the
   row. */
.cs-row.best .cs-fill { background: var(--pn-leaf); }
.cs-val { font-size: 12px; color: var(--pn-muted); text-align: right; font-variant-numeric: tabular-nums; }
.cs-row.best .cs-val { color: var(--pn-ink-3); }
@media (max-width: 420px) {
  .cs-row { grid-template-columns: 54px 1fr 46px; gap: 9px; }
  .cs-stats b { font-size: 23px; }
}
@media (prefers-reduced-motion: reduce) {
  .cs-fill, .cs-stats b { transition: none; }
}

/* ── Install ─────────────────────────────────────────────────────────
   The card sits in Settings and nowhere else. Gul's rule is that the app
   stays quiet unless it has something true to say, and "you could install
   me" is not worth interrupting someone's prayer times for. It is never
   shown at all once the app is running standalone. */
.inst-card {
  display: flex; align-items: center; gap: 14px;
  padding: 15px 16px; margin-bottom: 12px;
  background: var(--pn-card); border: 1px solid var(--pn-line);
  border-radius: 18px;
}
.inst-icon { flex: none; border-radius: 11px; display: block; }
.inst-text { flex: 1 1 auto; min-width: 0; }
.inst-name { font-size: 14px; color: var(--pn-ink-2); }
.inst-sub { font-size: 12px; color: var(--pn-muted); margin-top: 2px; }
.inst-btn {
  flex: none; font: inherit; font-size: 13px; cursor: pointer;
  padding: 10px 20px; min-height: 44px; border-radius: var(--pn-r-pill);
  background: var(--pn-ink-2); color: var(--pn-page); border: 1px solid var(--pn-ink-2);
  transition: opacity var(--pn-dur-tap) var(--pn-ease);
}
.inst-btn:hover { opacity: .88; }

/* ── The iOS sheet ───────────────────────────────────────────────────
   A bottom sheet on the phone, a centred dialog on a wide screen. It is a
   real dialog — focus trapped, Escape closes, focus returned — because it
   is the one modal in the app and a keyboard user should not be stranded
   in it. */
.inst-scrim {
  position: fixed; inset: 0; z-index: 200;
  display: flex; align-items: flex-end; justify-content: center;
  background: rgba(3, 5, 7, .66);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.inst-scrim[hidden] { display: none; }
.inst-sheet {
  position: relative; width: 100%; max-width: 460px;
  background: var(--pn-surface);
  border: 1px solid var(--pn-line); border-bottom: 0;
  border-radius: 26px 26px 0 0;
  padding: 30px 26px calc(30px + env(safe-area-inset-bottom));
  animation: inst-rise var(--pn-dur-grow) var(--pn-ease);
}
@keyframes inst-rise { from { transform: translateY(14px); opacity: 0 } to { transform: none; opacity: 1 } }
@media (min-width: 620px) {
  .inst-scrim { align-items: center; }
  .inst-sheet { border-radius: 26px; border-bottom: 1px solid var(--pn-line); }
}
.inst-x {
  position: absolute; top: 16px; right: 16px;
  width: 34px; height: 34px; border-radius: 50%; cursor: pointer;
  background: transparent; border: 1px solid var(--pn-line-strong);
  color: var(--pn-muted); font-size: 12px; line-height: 1;
}
.inst-x:hover { color: var(--pn-ink-2); }
.inst-sheet-icon { border-radius: 14px; display: block; margin-bottom: 16px; }
.inst-h {
  font-family: var(--pn-display); font-weight: 400; font-size: 25px;
  line-height: 1.2; color: var(--pn-ink-2); margin: 0;
}
.inst-lede { font-size: 13.5px; color: var(--pn-ink-3); margin: 10px 0 0; }
/* Not red — Gul has no red. An unusual browser is a condition, not a fault. */
.inst-warn {
  font-size: 13px; color: var(--pn-wilt-text); margin: 14px 0 0;
  padding: 12px 14px; border-radius: 12px;
  background: rgba(74, 58, 49, .3); border: 1px solid var(--pn-wilt);
}
.inst-steps { list-style: none; margin: 20px 0 0; padding: 0; }
.inst-steps li {
  display: grid; grid-template-columns: 26px 1fr; gap: 12px; align-items: start;
  padding: 11px 0; border-top: 1px solid var(--pn-line);
  font-size: 14px; line-height: 1.6; color: var(--pn-ink-3);
}
.inst-steps b { color: var(--pn-ink-2); font-weight: 500; }
.inst-num {
  font-family: var(--pn-display); font-size: 16px; color: var(--pn-faint); line-height: 1.5;
}
.inst-share {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 6px; vertical-align: -6px;
  border: 1px solid var(--pn-line-strong); color: var(--pn-sun);
}
.inst-ok { width: 100%; margin-top: 22px; }
.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;
}
@media (prefers-reduced-motion: reduce) {
  .inst-sheet { animation: none; }
  .inst-btn { transition: none; }
}

/* ── The day editor ──────────────────────────────────────────────────
   Same grammar as the install sheet: bottom sheet on a phone, centred
   dialog on a wide screen, focus trapped, Escape closes. The five rows
   inside are literally .dt-row — the component Today uses — so marking a
   prayer feels the same whether it is happening now or being corrected
   three weeks late. */
.day-scrim {
  position: fixed; inset: 0; z-index: 190;
  display: flex; align-items: flex-end; justify-content: center;
  background: rgba(3, 5, 7, .68);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.day-scrim[hidden] { display: none; }
.day-sheet {
  position: relative; width: 100%; max-width: 480px;
  max-height: 88vh; overflow-y: auto; -webkit-overflow-scrolling: touch;
  background: var(--pn-surface);
  border: 1px solid var(--pn-line); border-bottom: 0;
  border-radius: 26px 26px 0 0;
  padding: 28px 22px calc(24px + env(safe-area-inset-bottom));
  animation: inst-rise var(--pn-dur-grow) var(--pn-ease);
}
@media (min-width: 620px) {
  .day-scrim { align-items: center; }
  .day-sheet { border-radius: 26px; border-bottom: 1px solid var(--pn-line); }
}
.day-x {
  position: absolute; top: 16px; right: 16px;
  width: 34px; height: 34px; border-radius: 50%; cursor: pointer;
  background: transparent; border: 1px solid var(--pn-line-strong);
  color: var(--pn-muted); font-size: 12px; line-height: 1;
}
.day-x:hover { color: var(--pn-ink-2); }
.day-sheet-head { padding-right: 44px; margin-bottom: 6px; }
.day-sheet-kicker {
  font-size: 10px; letter-spacing: .2em; text-transform: uppercase;
  color: var(--pn-label);
}
.day-sheet-date {
  font-family: var(--pn-display); font-weight: 400; font-size: 24px;
  line-height: 1.2; color: var(--pn-ink-2); margin: 8px 0 0;
}
.day-sheet .quiet { margin-top: 12px; }
.day-sheet-nav { display: flex; gap: 8px; margin-top: 16px; }
.day-sheet-nav button {
  flex: 1; font: inherit; font-size: 12px; cursor: pointer;
  padding: 11px 10px; min-height: 44px; border-radius: var(--pn-r-pill);
  border: 1px solid var(--pn-line-strong); background: transparent; color: var(--pn-muted);
  transition: color var(--pn-dur-tap) var(--pn-ease), border-color var(--pn-dur-tap) var(--pn-ease);
}
.day-sheet-nav button:hover:not(:disabled) { color: var(--pn-ink-2); border-color: var(--pn-label); }
.day-sheet-nav button:disabled { opacity: .35; cursor: default; }
@media (prefers-reduced-motion: reduce) { .day-sheet { animation: none; } }

/* ── History calendar ────────────────────────────────────────────── */
.month-title { font-family: var(--pn-display); font-size: 23px; color: var(--pn-ink-2); padding: 20px 0 12px; }
.month-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
.m-cell {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 6px 0 8px; border-radius: 10px;
  font: inherit; background: transparent; border: 1px solid transparent;
  cursor: pointer; min-height: 56px;
  transition: background var(--pn-dur-tap) var(--pn-ease),
              border-color var(--pn-dur-tap) var(--pn-ease);
}
.m-cell:hover:not(:disabled) { background: rgba(242,237,227,.045); border-color: var(--pn-line); }
.m-cell:focus-visible { outline: 2px solid var(--pn-sun); outline-offset: 2px; }
.m-cell.today { border-color: rgba(124,217,166,.4); background: rgba(124,217,166,.05); }
/* A day that has not happened is dimmed and inert — there is nothing in it
   to correct, and letting someone bank tomorrow's five would turn every
   number in Consistency into a guess. */
.m-cell.future, .m-cell:disabled { opacity: .38; cursor: default; }
.m-num { font-size: 10px; color: var(--pn-label); }
.m-cell.today .m-num { color: #DFF3E7; }
.m-cell .m-flower path, .m-cell .m-flower circle { transition: all var(--pn-dur-heal) var(--pn-ease); }
.dow { font-size: 9.5px; letter-spacing: .14em; text-transform: uppercase; color: var(--pn-faint); text-align: center; padding-bottom: 4px; }

/* ── Settings ────────────────────────────────────────────────────── */
.place-card {
  padding: 17px; background: #0E1513; border: 1px solid var(--pn-line);
  border-radius: 18px; display: flex; flex-direction: column; gap: 3px; margin-bottom: 12px;
}
.place-name { font-size: 15.5px; color: var(--pn-ink-2); }
.place-meta { font-size: 13px; color: var(--pn-muted); }
.city-row { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
.city-chip {
  padding: 10px 16px; min-height: 44px; border-radius: var(--pn-r-pill);
  border: 1px solid #2A3630; background: transparent; color: var(--pn-ink-2); font-size: 13px;
  transition: all var(--pn-dur-tap) var(--pn-ease);
}
.city-chip.on { border-color: rgba(124,217,166,.4); background: rgba(124,217,166,.08); color: #DFF3E7; }
.outline-btn {
  padding: 13px 22px; min-height: 44px; border-radius: var(--pn-r-pill);
  border: 1px solid #2A3630; background: transparent; color: var(--pn-ink-2); font-size: 14.5px;
  transition: all var(--pn-dur-tap) var(--pn-ease);
}
.outline-btn:hover { border-color: var(--pn-sun); color: var(--pn-sun-pale); }

.field-label { font-size: 13px; color: var(--pn-muted); padding: 18px 0 9px; }
.method-list { display: flex; flex-direction: column; gap: 9px; }
.method {
  padding: 15px 16px; border-radius: var(--pn-r-well); text-align: left;
  border: 1px solid var(--pn-line); background: #0E1513;
  display: flex; flex-direction: column; gap: 4px;
  transition: all var(--pn-dur-tap) var(--pn-ease);
}
.method .m-name { font-size: 15px; color: var(--pn-ink-2); }
.method .m-note { font-size: 12.5px; line-height: 1.45; color: var(--pn-muted); }
.method.on { border-color: rgba(124,217,166,.4); background: rgba(124,217,166,.05); }

.asr-toggle { display: flex; gap: 9px; max-width: 420px; }
.asr-toggle button {
  flex: 1; padding: 13px 0; min-height: 44px; text-align: center;
  border: 1px solid #2A3630; border-radius: 14px; background: transparent;
  font-size: 13.5px; color: var(--pn-muted);
  transition: all var(--pn-dur-tap) var(--pn-ease);
}
.asr-toggle button.on {
  border-color: rgba(124,217,166,.4); background: rgba(124,217,166,.12); color: #DFF3E7;
}

/* ── Footer ──────────────────────────────────────────────────────── */
.foot {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 28px clamp(20px, 5vw, 56px) 40px;
  border-top: 1px solid var(--pn-line-soft);
  font-size: 12.5px; color: var(--pn-muted);
}
.foot-note { color: var(--pn-faint); }

/* ── Responsive ──────────────────────────────────────────────────── */
@media (max-width: 1080px) {
  .today { grid-template-columns: 1fr 1fr; }
  .today-aperture { grid-column: 1 / -1; }
  /* The nav has to hold four tabs and a sign-in; the slogan is the first
     thing that can go, because the wordmark already says who this is. */
  .brand-slogan { display: none; }
}
@media (max-width: 720px) {
  .today { grid-template-columns: 1fr; }
  .now-name { font-size: 42px; }

  /* ── The mobile nav ──────────────────────────────────────────────
     This used to read `.links a:not(:last-child) { display: none }`,
     which on a phone left exactly one tab standing — Settings, because
     it happens to be last — and quietly removed Today, Timetable and
     History from the app. Everything still worked; there was simply no
     way to reach it. Hiding overflow is a reasonable instinct on a
     marketing header and a serious bug on an app whose whole record
     lives behind one of the hidden tabs.

     The fix is the obvious one: give the tabs their own row. The header
     wraps to two lines — wordmark and account on top, four tabs beneath,
     spread across the full width so each is a wide target rather than a
     word. Nothing is hidden at any width. */
  .nav { flex-wrap: wrap; row-gap: 12px; padding-bottom: 0; }
  .brand { order: 1; }
  .auth-btn { order: 2; }
  .links {
    order: 3; width: 100%;
    justify-content: space-between; gap: 4px;
    border-top: 1px solid var(--pn-line-soft);
    margin: 0 calc(-1 * clamp(20px, 5vw, 56px));
    padding: 0 clamp(12px, 3vw, 20px);
  }
  .links a {
    flex: 1; text-align: center;
    padding: 13px 2px; min-height: 46px;
    font-size: 10px; letter-spacing: .14em;
    border-bottom: 2px solid transparent;
  }
  /* The router already marks the active tab with .on — it just had
     nothing to show for it while three of the four were hidden. */
  .links a.on { color: var(--pn-ink-2); border-bottom-color: var(--pn-sun); }
}
@media (max-width: 380px) {
  .links a { font-size: 9px; letter-spacing: .08em; }
  .brand-word { font-size: 21px; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .corona { animation: none !important; }
  .flare, #flower .petal.opened { animation: none !important; }
  #flower .petal, .tt-mark, .dt-row, .dt-ring, .dt-word, .m-cell .m-flower path { transition-duration: 1ms; }
}

/* ── v2: account, search, qibla, sync ────────────────────────────── */
.auth-btn {
  padding: 9px 18px; min-height: 40px; border-radius: var(--pn-r-pill);
  border: 1px solid #2A3630; background: transparent; color: var(--pn-ink-2);
  font-size: 12.5px; white-space: nowrap;
  transition: all var(--pn-dur-tap) var(--pn-ease);
}
.auth-btn:hover { border-color: var(--pn-sun); color: var(--pn-sun-pale); }
.auth-btn.signed { border-color: rgba(124,217,166,.4); color: #DFF3E7; }

.qibla-line { font-size: 12.5px; color: var(--pn-label); padding-top: 6px; letter-spacing: .06em; }
.sync-line { margin: 2px 0 0; font-size: 12px; color: var(--pn-faint); }
.sync-line.on { color: var(--pn-leaf-late); }

.month-bar { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.month-bar .day-nav button { padding: 8px 14px; min-height: 40px; }

.account-actions { margin-top: 12px; display: flex; gap: 8px; flex-wrap: wrap; }
.outline-btn.wide { width: 100%; }

.search-wrap { position: relative; margin-bottom: 12px; max-width: 460px; }
.place-search {
  width: 100%; padding: 13px 18px; min-height: 48px;
  border-radius: var(--pn-r-pill); border: 1px solid #2A3630;
  background: #0E1513; color: var(--pn-ink-2);
  font-family: inherit; font-size: 14px; outline: none;
  transition: border-color var(--pn-dur-tap) var(--pn-ease);
}
.place-search:focus { border-color: var(--pn-sun); }
.place-search::placeholder { color: var(--pn-faint); }
.search-results {
  position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 30;
  display: none; flex-direction: column; gap: 2px;
  background: #0E1513; border: 1px solid var(--pn-line); border-radius: var(--pn-r-well);
  padding: 6px; box-shadow: 0 18px 44px rgba(0,0,0,.5);
}
.search-results.show { display: flex; }
.search-hit {
  display: flex; justify-content: space-between; gap: 10px; align-items: baseline;
  padding: 11px 14px; min-height: 44px; border: none; border-radius: 11px;
  background: transparent; color: var(--pn-ink-2); font-size: 14px; text-align: left;
  transition: background var(--pn-dur-tap) var(--pn-ease);
}
.search-hit:hover { background: #16211E; }
.search-hit .tz { font-size: 11.5px; color: var(--pn-faint); white-space: nowrap; }

.asr-toggle.three { max-width: 560px; }
.asr-toggle.three button { font-size: 12.5px; }

/* ── Auth modal ──────────────────────────────────────────────────── */
.auth-overlay {
  position: fixed; inset: 0; z-index: 60;
  background: rgba(4,7,14,.72); backdrop-filter: blur(8px);
  display: grid; place-items: center; padding: 20px;
}
.auth-card {
  width: min(400px, 100%);
  background: var(--pn-card); border: 1px solid var(--pn-line);
  border-radius: var(--pn-r-card); padding: 34px 30px;
  display: flex; flex-direction: column; gap: 12px; align-items: stretch; text-align: center;
}
.auth-title { font-family: var(--pn-display); font-size: 27px; color: var(--pn-ink); }
.auth-sub { margin: 0; font-size: 13px; line-height: 1.6; color: var(--pn-muted); }
.auth-google[hidden], .auth-or[hidden] { display: none !important; }
.auth-google {
  display: flex; align-items: center; justify-content: center; gap: 11px;
  min-height: 48px; padding: 13px 18px; border-radius: var(--pn-r-pill);
  border: 1px solid #2A3630; background: rgba(242,237,227,.04);
  color: var(--pn-ink); font: inherit; font-size: 14.5px; cursor: pointer;
  transition: background var(--pn-dur-tap) var(--pn-ease),
              border-color var(--pn-dur-tap) var(--pn-ease);
}
.auth-google:hover { background: rgba(242,237,227,.09); border-color: var(--pn-line-2, #3A4A42); }
.auth-google svg { flex: 0 0 auto; }
/* A hairline with the word sitting in it — cheaper than two rules and a
   background, and it survives the card being any width. */
.auth-or {
  display: flex; align-items: center; gap: 12px;
  font-size: 10.5px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--pn-faint); margin: 2px 0;
}
.auth-or::before, .auth-or::after {
  content: ""; flex: 1; height: 1px; background: var(--pn-line-soft);
}

.auth-input {
  padding: 13px 16px; min-height: 48px; border-radius: 14px;
  border: 1px solid #2A3630; background: #0E1513; color: var(--pn-ink-2);
  font-family: inherit; font-size: 14px; outline: none; text-align: left;
  transition: border-color var(--pn-dur-tap) var(--pn-ease);
}
.auth-input:focus { border-color: var(--pn-sun); }
.auth-error { min-height: 18px; font-size: 12.5px; color: var(--pn-wilt-text); }

/* ── The three steps ───────────────────────────────────────────────────
   Each step is a column in the same card, so the card does not jump size
   between them any more than it must. */
.auth-step { display: flex; flex-direction: column; gap: 10px; }
.auth-step[hidden] { display: none; }

/* Labels, because a placeholder disappears the moment someone types and
   then the field has no name at all — for a person or a screen reader. */
.auth-label {
  font-size: 11px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--pn-label); text-align: left; margin-top: 2px;
}
.auth-input + .auth-field-err { margin-top: -4px; }

/* Field errors sit under the field they are about, not in a banner at the
   top of the card where you have to work out which one they mean. */
.auth-field-err {
  min-height: 0; font-size: 12px; line-height: 1.45;
  color: var(--pn-wilt-text); text-align: left;
}
.auth-field-err:empty { display: none; }

/* The password rule is shown before the first submit, never as a rejection. */
.auth-hint {
  font-size: 11.5px; color: var(--pn-muted); text-align: left; margin-top: -4px;
}

.auth-back { opacity: .75; }
.auth-back:hover { opacity: 1; }

/* A busy button must still read as a button, not as a disabled dead end. */
.auth-step .primary:disabled { opacity: .65; cursor: default; }
.auth-card .primary { max-width: none; margin-top: 0; }
.auth-link {
  background: none; border: none; color: var(--pn-label); font-size: 12.5px;
  /* 44px of height even though the text is small. These read as quiet links,
     but Back and Forgot password are load-bearing on a phone — a thumb does
     not care that they are secondary. */
  min-height: 44px; padding: 6px 10px;
  display: flex; align-items: center; justify-content: center;
  transition: color var(--pn-dur-tap) var(--pn-ease);
}
.auth-link:hover { color: var(--pn-sun-pale); }

@media (max-width: 720px) {
  .nav { gap: 10px; }
  .auth-btn { padding: 8px 13px; font-size: 11.5px; }
}

/* the [hidden] attribute must always win over display */
.auth-overlay[hidden] { display: none; }

/* ── The danger zone ───────────────────────────────────────────────────
   Set apart from the account card, and the only place in Gul that uses a
   warm alarm colour. Everywhere else red is banned — a missed prayer is
   never an error — but erasing an account is genuinely destructive, and
   the one place the design system should raise its voice. */
.danger-zone { margin-top: 26px; padding-top: 18px; border-top: 1px solid var(--pn-line); }

.danger-link {
  background: none; border: none; padding: 12px 0; min-height: 44px;
  font-size: 12.5px; letter-spacing: .04em; color: var(--pn-wilt-text);
  opacity: .78; cursor: pointer;
  transition: opacity var(--pn-dur-tap) var(--pn-ease);
}
.danger-link:hover { opacity: 1; text-decoration: underline; }

.danger-confirm {
  margin-top: 6px; padding: 18px; border-radius: 14px;
  background: var(--pn-card); border: 1px solid var(--pn-wilt);
}
.danger-confirm[hidden] { display: none; }

.danger-lede { margin: 0; font-size: 14.5px; line-height: 1.6; color: var(--pn-ink-2); }
.danger-note { margin: 10px 0 0; font-size: 12.5px; line-height: 1.55; color: var(--pn-muted); }
.danger-error { margin-top: 10px; font-size: 12.5px; line-height: 1.5; color: var(--pn-wilt-text); }
.danger-error:empty { display: none; }

.danger-row { display: flex; gap: 10px; margin-top: 16px; flex-wrap: wrap; }
.danger-row > * { flex: 1 1 auto; min-height: 48px; }

/* Deliberately not the primary style. Keeping the account is the default
   action; destroying it should never be the prettiest button on screen. */
.danger-btn {
  border-radius: 999px; padding: 13px 20px; font-size: 13.5px; cursor: pointer;
  color: var(--pn-wilt-text); background: transparent;
  border: 1px solid var(--pn-wilt);
  transition: background var(--pn-dur-tap) var(--pn-ease), color var(--pn-dur-tap) var(--pn-ease);
}
.danger-btn:hover { background: var(--pn-wilt); color: var(--pn-ink-2); }
.danger-btn:disabled { opacity: .6; cursor: default; }
