/* ==========================================================================
   Choghadiya — style.css                                        (FE-01, t_0413dd6c)
   Tokens are the contract for this file: docs/03-ux.md
     §4.1 colour   §4.3 type scale   §4.4 spacing & radii   §4.5 component classes
     §5 responsive bands            §4.6 motion            §10 rendering fixes
   Constraints: no third-party @import, no webfonts (NFR-PR1, 03-ux §4.3);
   no inline styles / <style> blocks in shipped files (SEC-03, style-src 'self').
   Light theme is the default; the dark theme applies via
   @media (prefers-color-scheme: dark) AND via the [data-theme="dark"] hook
   (03-ux §4.1 — v1 has no manual switch, it follows the OS).
   ========================================================================== */

:root {
  /* ---- 03-ux §4.1 — colour tokens (light = default) ---- */
  --bg:               #FAF7F2;
  --surface:          #FFFFFF;
  --surface-2:        #F1ECE3;
  --text:             #1A1A1A;
  --text-muted:       #5C5C5C;
  --border:           #E2DACE;
  --brand:            #9A3412;
  --brand-contrast:   #FFFFFF;
  --day-accent:       #7A2C0E;
  --night-accent:     #1F3A6E;
  /* §4.1 lists each quality tier as an fg/bg PAIR; each half gets its own token so the
     two colours can be consumed independently. Names are the §4.1 token name + -fg/-bg,
     values are the §4.1 values verbatim. */
  --qual-auspicious-fg:   #0F5132;  --qual-auspicious-bg:   #E3F1E6;
  --qual-amrit-fg:        #0B3D62;  --qual-amrit-bg:        #E1EEF9;
  --qual-neutral-fg:      #6B3A00;  --qual-neutral-bg:      #FDF0DC;
  --qual-inauspicious-fg: #8A1B1B;  --qual-inauspicious-bg: #FCE9E7;
  --current-bg:       #FFE8D6;
  --current-fg:       #7A2C0E;
  /* 03-ux §4.7 — the v2.3.0 "selected (not current)" row state. Named separately from
     --brand so the two states can never be confused in code; §4.8 verifies --text /
     --text-muted on --selected-bg and the ring on --bg. */
  --selected-bg:      #EFE6D9;
  --selected-border:  #9A3412;
  --focus:            #9A3412;
  --danger:           #8A1B1B;

  /* ---- 03-ux §4.3 — type scale (base 16 px; Devanagari sizes up one step) ---- */
  --font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans Devanagari", "Nirmala UI", sans-serif;
  --fs-2xl: 28px; --lh-2xl: 1.25; --fs-2xl-hi: 32px; --lh-2xl-hi: 1.35;  /* page title (HI 32/1.35) */
  --fs-xl:  20px; --lh-xl:  1.3;                                          /* section heading, date label */
  --fs-lg:  18px; --lh-lg:  1.4;                                          /* slot name when HI */
  --fs-base:16px; --lh-base:1.5;                                          /* slot name EN, times, controls */
  --fs-sm:  14px; --lh-sm:  1.5;                                          /* quality word, day/night marker */
  --fs-xs:  12px; --lh-xs:  1.4;                                          /* small print, footer, privacy */

  /* ---- 03-ux §4.4 — spacing (4 px grid) & radii ---- */
  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px;
  --sp-5: 20px; --sp-6: 24px; --sp-8: 32px; --sp-12: 48px;
  --r-sm: 6px; --r-md: 10px; --r-lg: 16px; --r-full: 999px;

  /* ---- elevation (03-ux §4.4 — one shadow token only) ---- */
  --shadow: 0 1px 2px rgba(0, 0, 0, .06), 0 4px 12px rgba(0, 0, 0, .05);

  /* ---- 03-ux §5 — breakpoints. DOCUMENTATION ONLY: custom properties cannot be used
     inside media queries, so the literals 360/420/600/900/1200 px below are the
     enforcement and these three exist so the intent is greppable. ---- */
  --bp-sm: 600px; --bp-md: 900px; --bp-lg: 1200px;
}

/* Dark theme, hook 1 of 2 — follow the OS. The [data-theme="light"] escape hatch keeps a
   future manual switch possible without touching any other rule. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg:         #121212;
    --surface:    #1E1E1E;
    --surface-2:  #262626;
    --text:       #ECECEC;
    --text-muted: #ADADAD;
    --border:     #333333;
    --brand:          #F0A868;
    --brand-contrast: #1A0F08;
    --day-accent:   #FFB59A;
    --night-accent: #A9C6FF;
    --qual-auspicious-fg:   #9FE7B4;  --qual-auspicious-bg:   #12331F;
    --qual-amrit-fg:        #A9D6FF;  --qual-amrit-bg:        #0E2A44;
    --qual-neutral-fg:      #FFD9A3;  --qual-neutral-bg:      #3A2A12;
    --qual-inauspicious-fg: #FFB4AB;  --qual-inauspicious-bg: #3B1A1A;
    --current-bg: #4A2A10;
    --current-fg: #FFD9A3;
    --selected-bg:     #2A2A2A;
    --selected-border: #F0A868;
    --focus:      #8FB4FF;
    --danger:     #FFB4AB;
    --shadow: 0 1px 2px rgba(0, 0, 0, .4);
  }
}

/* Dark theme, hook 2 of 2 — explicit override (identical values). */
[data-theme="dark"] {
  --bg:         #121212;
  --surface:    #1E1E1E;
  --surface-2:  #262626;
  --text:       #ECECEC;
  --text-muted: #ADADAD;
  --border:     #333333;
  --brand:          #F0A868;
  --brand-contrast: #1A0F08;
  --day-accent:   #FFB59A;
  --night-accent: #A9C6FF;
  --qual-auspicious-fg:   #9FE7B4;  --qual-auspicious-bg:   #12331F;
  --qual-amrit-fg:        #A9D6FF;  --qual-amrit-bg:        #0E2A44;
  --qual-neutral-fg:      #FFD9A3;  --qual-neutral-bg:      #3A2A12;
  --qual-inauspicious-fg: #FFB4AB;  --qual-inauspicious-bg: #3B1A1A;
  --current-bg: #4A2A10;
  --current-fg: #FFD9A3;
  --selected-bg:     #2A2A2A;
  --selected-border: #F0A868;
  --focus:      #8FB4FF;
  --danger:     #FFB4AB;
  --shadow: 0 1px 2px rgba(0, 0, 0, .4);
}

/* ==========================================================================
   Base
   ========================================================================== */

* { box-sizing: border-box }

/* 03-ux §10 fix 2 (an acceptance criterion): a component's own `display` rule
   out-specifies the UA's `[hidden]{display:none}`, so any element with BOTH a display
   rule and a JS-driven `hidden` toggle renders when it should not (caught on the
   "आज / Today" reset pill in the UX wireframe). !important is required here. */
[hidden] { display: none !important }

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-family);
  font-size: var(--fs-base);
  line-height: var(--lh-base);
  overflow-wrap: break-word;
}

/* Visible focus ring on EVERY interactive element, never outline:none — and never
   removed for mouse users either (03-ux §7.2, US-18 AC2). */
:focus,
:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px }

/* Visually hidden but available to assistive tech (labels, live regions). */
.sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Reading column: 640 px centred, widening to 960 px only where the two-column
   slot area earns it (03-ux §5). 320 px floor: nothing may overflow. */
.wrap {
  max-width: 640px;
  margin: 0 auto;
  padding: 0 var(--sp-4) var(--sp-8);
}
@media (min-width: 900px) { .wrap { max-width: 960px } }

/* ==========================================================================
   Header (sticky, 56 px) — 03-ux §3 S1, §5
   ========================================================================== */

header.app {
  position: sticky;
  top: 0;
  z-index: 5;
  min-height: 56px;
  padding: var(--sp-2) 0;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
}
.hrow { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) }
.brand { display: flex; align-items: baseline; gap: var(--sp-2); flex: 1 1 auto; min-width: 0 }
.brand-glyph { font-size: var(--fs-xl); line-height: 1 }
.brand h1 {
  margin: 0;
  font-size: var(--fs-2xl);
  line-height: var(--lh-2xl);
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Devanagari gets the extra step inside the same type-scale step (03-ux §4.3). */
:lang(hi) .brand h1 { font-size: var(--fs-2xl-hi); line-height: var(--lh-2xl-hi) }
/* Subtitle is hidden below 360 px (03-ux §6, app.subtitle). */
.brand-sub { display: none; font-size: var(--fs-xs); color: var(--text-muted) }
@media (min-width: 360px) { .brand-sub { display: block } }

/* Segmented settings control — language + time-format toggles (v2.3.0 CR1, 03-ux
   §3.10a / §7.1: `.segmented`). Each option min 44 × 44 (NFR-A5); the active option
   carries aria-pressed + the --brand fill (never colour alone — the pressed state is
   also announced). Replaces the v1.0.1 `.lang-toggle` (same visual language). */
.segmented {
  display: inline-flex;
  flex: 0 0 auto;
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  overflow: hidden;
}
.segmented button {
  min-width: 44px;
  min-height: 44px;
  padding: 0 var(--sp-3);
  border: 0;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: var(--fs-sm);
  cursor: pointer;
}
.segmented button + button { border-left: 1px solid var(--border) }
.segmented button[aria-pressed="true"] {
  background: var(--brand);
  color: var(--brand-contrast);
  font-weight: 600;
}

/* Location field — .loc-field wraps the .loc-chip button and the trailing ✕ clear
   button (03-ux §4.5 "Location chip"; 03-ux F2 step 7 clear affordance, FE-03).
   .loc-chip is pill-shaped, min 44 px tall, ellipsised city name at 320 px; the
   clear button is a separate 44×44 round target (a <button> cannot nest). */
.loc-field {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  flex: 1 1 100%;
  min-width: 0;
}
.loc-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-1);
  flex: 1 1 auto;
  min-width: 0;
  min-height: 44px;
  padding: 0 var(--sp-3);
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: var(--fs-sm);
  cursor: pointer;
}
.loc-chip .name {
  flex: 1 1 auto;
  min-width: 0;
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* ✕ clear affordance: 44×44 target, aria-labelled from `loc.clear` (US-5, US-18 AC4).
   Shown only when a location is set (JS toggles [hidden]) — the FE-01
   `[hidden]{display:none !important}` reset out-specifies this display rule. */
.loc-clear {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  background: var(--surface);
  color: var(--text-muted);
  font: inherit;
  font-size: var(--fs-base);
  cursor: pointer;
}
@media (min-width: 600px) {
  .loc-field { flex: 0 1 auto }
  .loc-chip { flex: 0 1 auto }
  .loc-chip .name { flex: 0 1 auto; text-align: start }
}

/* ==========================================================================
   Date bar — .datebar, grid auto 1fr auto, 48 px (03-ux §4.5)
   ========================================================================== */

.datebar {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: var(--sp-2);
  min-height: 48px;
  padding: var(--sp-2) 0;
}
.datebar .nav {
  width: 44px;
  height: 44px;
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: var(--fs-lg);
  line-height: 1;
  cursor: pointer;
}
.datebar .label { min-width: 0; text-align: center }
/* Grid placement (03-ux §3.10c). DOM order is the focus order — ‹ → picker → Today →
   › (v2.3.2: Today moved before ›). Below 600 px the pill sits on its own centred row
   (2); at ≥600 px it is inline in column 3, BETWEEN the date and ›, so › keeps its
   place at the bar's right edge when the pill appears. Items are placed explicitly. */
.datebar .nav,
.datebar .label { grid-row: 1 }
.datebar .today-pill {
  grid-row: 2;
  grid-column: 1 / -1;
  justify-self: center;
  margin-top: 0;   /* the row gap already spaces it; the old 4 px offset is redundant */
}
@media (min-width: 600px) {
  .datebar { grid-template-columns: auto 1fr auto auto }
  .datebar .today-pill { grid-row: 1; grid-column: 3; justify-self: end }
  .datebar #next-day { grid-column: 4 }
}
.datebar .d {
  margin: 0;
  font-size: var(--fs-xl);
  line-height: var(--lh-xl);
  font-weight: 600;
  overflow-wrap: anywhere;
}
@media (max-width: 419px) {
  /* 03-ux §3.10c geometry: the 20 px Hindi date needs 198 px but ≤419 px only affords
     ~184 px, so the label steps down to --fs-base instead of wrapping inside the pinned
     bar (a second line costs more vertical space than the 4 px of type). Declared AFTER
     the base rule on purpose: same specificity, so source order wins. The column gap is
     tightened to 4 px — with a 15 px classic scrollbar (desktop Chrome at 320 px) the
     field is 169 px, not the 184 px of a mobile viewport, and the caret + gap would
     otherwise push the longest Hindi dates onto a second line. */
  .datebar { gap: var(--sp-1) }
  /* `nowrap` is the fit guarantee: a desktop Chrome viewport at 320 px loses ~15 px to
     the classic scrollbar, so the field is 169–177 px instead of the 184 px a mobile
     viewport affords, and the longest Hindi dates (मंगलवार/शुक्रवार + दिसंबर) need
     166–169 px on top of the caret's 7 px + gap. Wrapping inside the pinned bar costs a
     second line (row 48 px instead of 44 px); one text line that overlaps the 4 px gap
     before the caret by < 1 px costs nothing and stays inside the date bar (no page
     scroll). On a real mobile viewport nothing overflows at all. */
  .datebar .d { font-size: var(--fs-base); line-height: var(--lh-base); white-space: nowrap }
}
/* Calendar picker (CR4, 03-ux §3.10c; themed popup v2.3.2): the visible date label IS
   the trigger — a <button> with the date text + caret — and #calendar opens below it.
   `.label` is the popup's positioning context. */
.datebar .label { position: relative }
.datebar .picker-field {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-1);
  /* Shrink-wrapped to the date text + caret and centred, so the popup (centred on the
     same column) sits directly under the date. */
  width: fit-content;
  max-width: 100%;
  margin-inline: auto;
  min-width: 0;                 /* load-bearing: without it the field's intrinsic
                                   width pushes › onto its own row at 320 px */
  min-height: 44px;             /* NFR-A5 — the whole label area is tappable */
  padding: 0 var(--sp-1);
  border: 0;
  border-radius: var(--r-sm);
  background: none;
  color: var(--text);
  font: inherit;
  cursor: pointer;
}
.datebar .picker-field:hover .d { text-decoration: underline; text-underline-offset: 4px }
.datebar .picker-field:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}
.datebar .picker-field .caret {
  flex: 0 0 auto;
  color: var(--text-muted);
  font-size: var(--fs-xs);
}
.datebar .picker-field[aria-expanded="true"] .caret { transform: rotate(180deg) }
/* No location yet (S4): the picker is inert, so it must not look tappable. */
.datebar .picker-field:disabled { cursor: default }
.datebar .picker-field:disabled .caret { opacity: .5 }
.datebar .picker-field:disabled:hover .d { text-decoration: none }

/* The popup — page tokens only, so it follows light/dark (both hooks) automatically. */
.calendar {
  position: absolute;
  top: calc(100% + var(--sp-1));
  left: 50%;
  transform: translateX(-50%);
  z-index: 6;                   /* above the panes; the sticky header is z 5 */
  width: min(22rem, calc(100vw - 2 * var(--sp-2)));
  padding: var(--sp-3);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow), 0 8px 24px rgba(0, 0, 0, .12);
  text-align: center;
}
.cal-title {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-base);
  line-height: var(--lh-base);
  font-weight: 600;
  color: var(--brand);
}
.cal-grid {
  width: 100%;
  border-collapse: separate;
  border-spacing: 2px;
  table-layout: fixed;
}
.cal-grid th {
  padding: 0 0 var(--sp-1);
  font-size: var(--fs-xs);
  line-height: var(--lh-xs);
  font-weight: 600;
  color: var(--text-muted);
}
.cal-grid td { padding: 0 }
.cal-day {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 44px;             /* NFR-A5 */
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--r-md);
  background: none;
  color: var(--text);
  font: inherit;
  font-size: var(--fs-base);
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}
.cal-day .m {                   /* month tag on the 1st and on the window's first day */
  font-size: 10px;
  line-height: 1;
  color: var(--text-muted);
}
.cal-day:hover { background: var(--surface-2) }
.cal-day:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px }
/* Today (the location's civil date): a ring — a shape cue, never colour alone. */
.cal-day[aria-current="date"] { border-color: var(--brand); font-weight: 600 }
/* The viewed date: filled brand. */
.cal-day[aria-pressed="true"] {
  background: var(--brand);
  border-color: var(--brand);
  color: var(--brand-contrast);
  font-weight: 600;
}
.cal-day[aria-pressed="true"] .m { color: inherit }
/* Outside the ±10 window: visible for orientation but not selectable. */
.cal-day:disabled {
  color: var(--text-muted);
  opacity: .45;
  cursor: default;
  background: none;
}
@media (prefers-reduced-motion: no-preference) {
  .calendar:not([hidden]) { animation: cal-in .12s ease-out }
  .datebar .picker-field .caret { transition: transform .12s ease-out }
}
@keyframes cal-in {
  from { opacity: 0; transform: translate(-50%, -4px) }
  to   { opacity: 1; transform: translate(-50%, 0) }
}
/* Range edges (03-ux §3.10c "Edge clamping"): a disabled ‹ / › is perceivable without
   trial — muted text AND a dashed border (a shape cue, never colour alone, NFR-A2). */
.datebar .nav:disabled {
  color: var(--text-muted);
  border-style: dashed;
  background: var(--surface-2);
  cursor: default;
}
/* .today-pill — .today-pill, appears only when viewed date ≠ today (03-ux §4.5).
   Kept at 44 px tall so it meets NFR-A5 like every other control. */
.today-pill {
  display: inline-block;
  min-width: 44px;
  min-height: 44px;
  margin-top: var(--sp-1);
  padding: 0 var(--sp-4);
  border: 1px solid var(--brand);
  border-radius: var(--r-full);
  background: var(--brand);
  color: var(--brand-contrast);
  font: inherit;
  font-size: var(--fs-sm);
  cursor: pointer;
}

/* ==========================================================================
   Slot area — day/night panes. Two columns only at ≥ 900 px (03-ux §5)
   ========================================================================== */

.panes { display: grid; gap: var(--sp-6) }
@media (min-width: 900px) {
  .panes { grid-template-columns: 1fr 1fr; align-items: start; gap: var(--sp-8) }
}

.pane {
  margin: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.pane > h2 {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-2);
  margin: 0;
  padding: var(--sp-3) var(--sp-4);
  font-size: var(--fs-xl);
  line-height: var(--lh-xl);
  font-weight: 600;
}
.pane.day > h2 { color: var(--day-accent); border-bottom: 1px solid var(--border) }
.pane.night > h2 { color: var(--night-accent); border-bottom: 1px solid var(--border) }
.pane > h2 .edge { font-size: var(--fs-xs); font-weight: 400; color: var(--text-muted); white-space: nowrap }
.smallprint {
  margin: 0;
  padding: var(--sp-2) var(--sp-4);
  border-top: 1px solid var(--border);
  font-size: var(--fs-xs);
  line-height: var(--lh-xs);
  color: var(--text-muted);
}
.smallprint:empty { display: none }

/* ==========================================================================
   Slot list — .slot-list: <ol>, no markers, panel on --surface with --r-lg and
   --border dividers (03-ux §4.5)
   ========================================================================== */

.slot-list {
  list-style: none;
  margin: 0;
  padding: 0;
  background: var(--surface);
  border-radius: var(--r-lg);
}
.slot-list > li + li { border-top: 1px solid var(--border) }
.slot-list[aria-busy="true"] { opacity: .85 }

/* ==========================================================================
   Slot row — .slot, one <button>, whole row is the tap/keyboard target.
   Grid is exactly `minmax(0, 1fr) auto auto` (03-ux §4.5 / §10 fix 1).
   Child classes this file defines for the three zones (FE-02 fills the rows):
     .slot-name  zone 2 — slot name, both scripts in the active language
     .slot .time zone 3 — 24-hour range, viewed location's tz
     .slot-meta  zone 4 — optional .badge-now + .quality chip (word + glyph)
   The v1.0.1 `.meaning` inline disclosure line is GONE (v2.3.0 CR6, 03-ux §3.9): the
   S9 detail panel carries meaning / good-for / bad-for, and the row is now a SELECTION
   control (`aria-pressed` + `aria-controls="choghadiya-panel"`) instead of a
   disclosure (`aria-expanded`). The current-slot row is `.slot[aria-current="true"]`.
   ========================================================================== */

.slot {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  gap: var(--sp-2);
  align-items: center;
  width: 100%;
  min-height: 56px;
  padding: var(--sp-2) var(--sp-4);
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: start;
  cursor: pointer;
}
.slot:hover { background: var(--surface-2) }
.slot-name {
  display: block;
  min-width: 0;
  font-size: var(--fs-lg);
  line-height: var(--lh-lg);
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.slot .time {
  font-size: var(--fs-base);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.slot-meta {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
}
/* Selected slot row — .slot[aria-pressed="true"] (v2.3.0 CR6, 03-ux §4.7/§4.9).
   --selected-bg fill + a 2 px ALL-ROUND inset ring in --selected-border, so the
   selected state is shape-distinct from the current state (which is a --current-bg
   fill + a 2 px LEFT bar, §4.5). A row that is BOTH keeps the current fill and both
   cues via the combined rule below; the live state also stays announced by
   `aria-current` + the "अभी / Now" badge, so nothing here is colour-only. Hover uses
   --surface-2, i.e. hover ≠ selected. */
.slot[aria-pressed="true"] {
  background: var(--selected-bg);
  box-shadow: inset 0 0 0 2px var(--selected-border);
}

/* Current slot — .slot[aria-current="true"]: --current-bg fill, 2 px inset left border
   in --current-fg (03-ux §4.5, US-14). The badge is the non-colour cue. */
.slot[aria-current="true"] {
  background: var(--current-bg);
  box-shadow: inset 2px 0 0 0 var(--current-fg);
}

/* An explicitly selected row that is ALSO the live row inherits the current fill but
   keeps BOTH cues: the selection ring and the 2 px left current bar. */
.slot[aria-current="true"][aria-pressed="true"] {
  box-shadow: inset 2px 0 0 0 var(--current-fg), inset 0 0 0 2px var(--selected-border);
}

/* Quality chip — .quality: pill, fs-sm, tinted bg per tier, leading glyph.
   Tier modifier classes are the Slot.tier values from 04-architecture §4.1, so FE-02 can
   emit `class="quality {slot.tier}"` straight from the schedule data. */
.quality {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: 2px var(--sp-2);
  border-radius: var(--r-full);
  font-size: var(--fs-sm);
  line-height: var(--lh-sm);
  font-weight: 600;
  white-space: nowrap;
}
.quality.auspicious     { color: var(--qual-auspicious-fg);   background: var(--qual-auspicious-bg) }
.quality.mostAuspicious { color: var(--qual-amrit-fg);        background: var(--qual-amrit-bg) }
.quality.neutral        { color: var(--qual-neutral-fg);      background: var(--qual-neutral-bg) }
.quality.inauspicious   { color: var(--qual-inauspicious-fg); background: var(--qual-inauspicious-bg) }

/* Now badge — .badge-now: pill, 12 px, on --current-bg (03-ux §4.5, US-14). */
.badge-now {
  padding: 2px var(--sp-2);
  border-radius: var(--r-full);
  background: var(--current-bg);
  color: var(--current-fg);
  font-size: var(--fs-xs);
  line-height: var(--lh-xs);
  font-weight: 700;
  white-space: nowrap;
}

/* ==========================================================================
   03-ux §10 fix 1 — two-zone collapse band. The English tier words
   ("✓✓ Most auspicious") overflow the three-zone grid at 360–430 px, so the row
   collapses at ≤ 419 px, NOT at 360 px: name on line 1, quality chip right-aligned
   on line 1, time on line 2.
   ========================================================================== */

@media (max-width: 419px) {
  .slot { grid-template-columns: minmax(0, 1fr) auto }
  .slot-name { grid-area: 1 / 1 }
  .slot-meta { grid-area: 1 / 2; justify-self: end }
  .slot .time { grid-area: 2 / 1 / 3 / 3 }
}

/* ==========================================================================
   Inline notice (.notice) & inline error (.error) — 03-ux §4.5, §3 S5/S6/S7
   ========================================================================== */

.notice {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  margin: var(--sp-3) 0 var(--sp-4);
  padding: var(--sp-3);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface-2);
  font-size: var(--fs-xs);
  line-height: var(--lh-xs);
  color: var(--text);
}
.notice button {
  min-height: 44px;
  margin-left: auto;
  padding: 0 var(--sp-4);
  border: 0;
  border-radius: var(--r-md);
  background: var(--brand);
  color: var(--brand-contrast);
  font: inherit;
  font-size: var(--fs-sm);
  cursor: pointer;
}
/* Inline error inside the sheet — S6 (geocode failure, role="alert" + Retry) and
   S7 (no results). The glyph + text carry the message, so state is never colour-only
   (03-ux §7.4); the Retry button is a ≥ 44 px target (NFR-A5). */
.error {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3);
  margin: var(--sp-2) 0 0;
  font-size: var(--fs-xs);
  color: var(--danger);
}
.err-glyph { flex: 0 0 auto; font-size: var(--fs-sm); line-height: 1 }
.error .retry {
  min-height: 44px;
  margin-left: auto;
  padding: 0 var(--sp-4);
  border: 1px solid var(--danger);
  border-radius: var(--r-md);
  background: transparent;
  color: var(--danger);
  font: inherit;
  font-size: var(--fs-sm);
  cursor: pointer;
}

/* ==========================================================================
   Block-level degradation states
   ========================================================================== */

/* S1 empty state — no location has ever been chosen (03-ux §3 S1 "Empty", US-8 AC1).
   The date bar and the S5 notice + city field above stay in place; only the two
   lists are replaced by this one calm line. */
.empty-state {
  margin: var(--sp-6) 0;
  padding: var(--sp-6) var(--sp-4);
  border: 1px dashed var(--border);
  border-radius: var(--r-lg);
  background: var(--surface);
  color: var(--text-muted);
  font-size: var(--fs-base);
  text-align: center;
}

/* S3 not-defined (polar / no sunrise-sunset) — replaces both lists, the date bar above
   stays live so the user can step to an adjacent date (03-ux §3 S3, US-9). Both
   languages are shown at once here on purpose. */
.not-defined {
  margin: var(--sp-4) 0;
  padding: var(--sp-6) var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--surface);
  text-align: center;
}
.not-defined .nd-glyph { margin: 0 0 var(--sp-2); font-size: var(--fs-xl); line-height: 1; color: var(--text-muted) }
.not-defined .nd-title { margin: 0; font-size: var(--fs-lg); font-weight: 600; color: var(--text) }
.not-defined .nd-reason { margin: var(--sp-1) 0 0; font-size: var(--fs-sm); color: var(--text-muted) }
.not-defined p[lang="en"].nd-title { margin-top: var(--sp-4) }
.nd-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--sp-3);
  margin: var(--sp-5) 0 0;
}
.nd-nav {
  min-height: 44px;
  padding: 0 var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface-2);
  color: var(--text);
  font: inherit;
  font-size: var(--fs-sm);
  cursor: pointer;
}

/* ==========================================================================
   Loading skeleton — .skeleton: 56 px, --surface-2, animated only when the user has
   not asked for reduced motion (03-ux §3 S4, §4.5)
   ========================================================================== */

.skeleton {
  height: 56px;
  background: linear-gradient(90deg, var(--surface-2), var(--surface), var(--surface-2));
  background-size: 200% 100%;
}
@media (prefers-reduced-motion: no-preference) {
  .skeleton { animation: shimmer 1.2s linear infinite }
  @keyframes shimmer {
    from { background-position: 200% 0 }
    to   { background-position: -200% 0 }
  }
}

/* ==========================================================================
   City search sheet — dialog.sheet: backdrop, --surface panel, --r-lg top corners on
   mobile (bottom sheet under 600 px), centred card above (03-ux §4.5, §5)
   ========================================================================== */

dialog.sheet {
  width: calc(100% - var(--sp-8));
  max-width: 520px;
  max-height: 90vh;
  margin: auto auto 0;
  padding: 0;
  overflow: auto;
  border: 0;
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow);
}
dialog.sheet::backdrop { background: rgba(0, 0, 0, .4) }
@media (min-width: 600px) {
  dialog.sheet { margin: auto; border-radius: var(--r-lg) }
}

.sheet-head {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-4);
  border-bottom: 1px solid var(--border);
}
.sheet-head h2 {
  flex: 1;
  margin: 0;
  font-size: var(--fs-xl);
  line-height: var(--lh-xl);
  font-weight: 600;
  overflow-wrap: anywhere;
}
.sheet-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  background: var(--surface-2);
  color: var(--text);
  font: inherit;
  font-size: var(--fs-base);
  cursor: pointer;
}
.sheet-body { padding: var(--sp-4) }
/* v2.3.0 CR2 — "use my current location" (03-ux §3.10b / F8): full-width, ≥44 px,
   --brand fill, leading decorative 📍 (aria-hidden in the markup). Requesting →
   the button is disabled + aria-busy and the label swaps to geo.loading (app.js);
   the label stays at full contrast so it never drops below the §4.8 ratios. The
   global :focus-visible ring (above) gives it a visible focus state. */
.loc-current {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  width: 100%;
  min-height: 44px;
  margin: 0 0 var(--sp-3);
  padding: 0 var(--sp-4);
  border: 0;
  border-radius: var(--r-md);
  background: var(--brand);
  color: var(--brand-contrast);
  font: inherit;
  font-size: var(--fs-base);
  font-weight: 600;
  text-align: center;
  cursor: pointer;
}
.loc-current:disabled { cursor: default }
/* F8 step 4 — the sheet-LOCAL denial line, directly above the city field:
   role="status", glyph ℹ + text, --text (NOT --danger: the typed path still works,
   this is not an error). Never colour-only. */
.sheet-note {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin: 0 0 var(--sp-3);
  font-size: var(--fs-xs);
  line-height: var(--lh-xs);
  color: var(--text);
}
.sheet-note > [aria-hidden] { flex: 0 0 auto }
.field-row { display: flex; gap: var(--sp-2) }
.field-row input {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 44px;
  padding: 0 var(--sp-3);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface-2);
  color: var(--text);
  font: inherit;
  font-size: var(--fs-base);
}
.field-row button {
  min-height: 44px;
  padding: 0 var(--sp-4);
  border: 0;
  border-radius: var(--r-md);
  background: var(--brand);
  color: var(--brand-contrast);
  font: inherit;
  font-size: var(--fs-base);
  cursor: pointer;
}
.results { list-style: none; margin: var(--sp-3) 0 0; padding: 0 }
.results:empty { display: none }
.results > li + li { border-top: 1px solid var(--border) }
.results button {
  display: block;
  width: 100%;
  min-height: 56px;
  padding: var(--sp-2) var(--sp-3);
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: start;
  cursor: pointer;
}
.results button:hover { background: var(--surface-2) }
.results .r1 { display: block; font-weight: 600 }
.results .r2 { display: block; font-size: var(--fs-xs); color: var(--text-muted) }

/* ==========================================================================
   Footer — contentinfo landmark (03-ux §1.1, US-6/US-17)
   ========================================================================== */

footer.app {
  display: grid;
  gap: var(--sp-2);
  margin-top: var(--sp-8);
  padding: var(--sp-4) 0;
  border-top: 1px solid var(--border);
  font-size: var(--fs-xs);
  line-height: var(--lh-xs);
  color: var(--text-muted);
}
footer.app p { margin: 0 }

/* Attribution credit links (v2.3.0 F8). app.js renderAttribution() builds the three
   licence hyperlinks in #footer-credit with createElement('a'); before v2.3.0 the page
   had NO <a> elements, so style.css never needed a link rule and these anchors fell
   back to the user-agent link colour (#0000EE). That colour fails WCAG AA on the dark
   theme (1.99:1 against --bg #121212 — caught by the axe gate, serious color-contrast,
   post-wave tree). Inherit the footer's --text-muted, which is contrast-verified in both
   themes (§4.1/§4.9); the anchors keep the default underline, so they stay
   distinguishable from the surrounding text (WCAG 1.4.1). One rule, no new token. */
footer.app a { color: inherit }

/* ==========================================================================
   S8 inauspicious-periods block (v2.3.0 CR5, 03-ux §3.8, §4.9) — FE-5
   One --surface panel, --r-lg, --sp-4 padding; an <h2> heading on the same type step
   as दिन/रात; `.period` rows are --surface-2 cards with name + range on line 1 and
   the explanation on line 2. At >=900 px the rows form a two-column grid (the rule
   line and disclaimer below the grid stay full width). The block is ONE shared
   "avoid" class — --qual-inauspicious text on --surface / --surface-2 — never
   colour-coded per period, never animated, and nothing here is tappable (§3.8).
   ========================================================================== */

.periods {
  margin: var(--sp-6) 0 0;
  padding: var(--sp-4);
  background: var(--surface);
  border-radius: var(--r-lg);
}
.periods > h2 {
  margin: 0 0 var(--sp-3);
  font-size: var(--fs-xl);
  line-height: var(--lh-xl);
  font-weight: 600;
  color: var(--qual-inauspicious-fg);
}
.periods__list {
  display: grid;
  gap: var(--sp-2);
}
.period {
  padding: var(--sp-3) var(--sp-4);
  background: var(--surface-2);
  border-radius: var(--r-md);
}
.period__head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  column-gap: var(--sp-2);
}
.period__name {
  font-size: var(--fs-base);
  font-weight: 600;
  color: var(--qual-inauspicious-fg);
}
.period__range,
.period__na {
  font-size: var(--fs-base);
  font-weight: 400;
  color: var(--text-muted);
  white-space: nowrap;
}
.period__na { font-size: var(--fs-sm) }
.period__date {
  margin: var(--sp-1) 0 0;
  font-size: var(--fs-xs);
  line-height: var(--lh-xs);
  color: var(--text-muted);
  text-align: end;
}
.period__desc {
  margin: var(--sp-1) 0 0;
  font-size: var(--fs-sm);
  line-height: var(--lh-sm);
  color: var(--text-muted);
  overflow-wrap: anywhere;
}
.periods__note {
  margin: var(--sp-3) 0 0;
  font-size: var(--fs-sm);
  line-height: var(--lh-sm);
  color: var(--text-muted);
}
.periods__disclaimer {
  margin: var(--sp-2) 0 0;
  font-size: var(--fs-xs);
  line-height: var(--lh-xs);
  color: var(--text-muted);
}

/* >=900 px: the period rows become a two-column grid; the rule line and disclaimer
   below the grid are full width, i.e. they span both columns (03-ux §3.8). */
@media (min-width: 900px) {
  .periods__list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--sp-3);
  }
}

/* <=419 px (the same band as the slot-row two-zone collapse): the range wraps under
   the name rather than competing for the row's width (03-ux §4.9). */
@media (max-width: 419px) {
  .period__head { grid-template-columns: minmax(0, 1fr) }
  .period__range,
  .period__na { white-space: normal }
}

/* ==========================================================================
   S9 choghadiya detail panel (v2.3.0 CR6, 03-ux §3.9, §4.9) — FE-6
   One --surface card, --r-lg, --sp-4 padding, below the S8 periods block. The panel
   is a labelled <section aria-labelledby>, is NOT an aria-live region and contains no
   focusable control (the slot rows are the only way in/out). Field labels are real
   text above each value, separated by --border rules. The overlap warning is the
   shared inauspicious "avoid" class (--qual-inauspicious-fg on --surface, 9.32/9.82
   per §4.8) with a 2 px inline-start bar, and its ⚠ glyph is decorative — the
   dictionary sentence carries the meaning, so it is never colour-only. No new
   transition: the panel content swap is instantaneous (§4.6).
   ========================================================================== */

.panel {
  margin: var(--sp-6) 0 0;
  padding: var(--sp-4);
  background: var(--surface);
  border-radius: var(--r-lg);
}
.panel__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--sp-2);
}
.panel__head h2 {
  margin: 0;
  font-size: var(--fs-xl);
  line-height: var(--lh-xl);
  font-weight: 600;
}
.panel__badge {
  padding: 2px var(--sp-2);
  border-radius: var(--r-full);
  background: var(--current-bg);
  color: var(--current-fg);
  font-size: var(--fs-xs);
  line-height: var(--lh-xs);
  font-weight: 700;
  white-space: nowrap;
}
.panel__prompt {
  margin: var(--sp-3) 0 0;
  font-size: var(--fs-sm);
  line-height: var(--lh-sm);
  color: var(--text-muted);
}
.panel__slot {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-3);
  margin: var(--sp-3) 0 0;
}
.panel__slot-name {
  font-size: var(--fs-lg);
  line-height: var(--lh-lg);
  font-weight: 600;
}
.panel__slot-range {
  font-size: var(--fs-base);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.panel__warn {
  margin: var(--sp-3) 0 0;
  padding: var(--sp-2) var(--sp-3);
  border-inline-start: 2px solid var(--qual-inauspicious-fg);
  border-radius: var(--r-sm);
  background: var(--qual-inauspicious-bg);
  color: var(--qual-inauspicious-fg);
  font-size: var(--fs-sm);
  line-height: var(--lh-sm);
  font-weight: 600;
  overflow-wrap: anywhere;
}
.panel__note,
.panel__tier {
  margin: var(--sp-2) 0 0;
  font-size: var(--fs-sm);
  line-height: var(--lh-sm);
  color: var(--text-muted);
  overflow-wrap: anywhere;
}
.panel__fields {
  margin: var(--sp-4) 0 0;
}
.panel__field + .panel__field {
  margin-top: var(--sp-3);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--border);
}
.panel__label {
  font-size: var(--fs-xs);
  line-height: var(--lh-xs);
  font-weight: 600;
  color: var(--text-muted);
}
.panel__value {
  margin: var(--sp-1) 0 0;
  font-size: var(--fs-base);
  line-height: var(--lh-base);
  color: var(--text);
  /* Long unbroken words (a pasted URL-like city name is not possible here, but the
     Hindi copy contains em-dash-joined clauses) wrap rather than push the page wide:
     the panel must not introduce horizontal scroll at 320 px. */
  overflow-wrap: anywhere;
}
.panel__value--sm {
  font-size: var(--fs-sm);
  line-height: var(--lh-sm);
}

/* <=419 px (the slot-row two-zone band): the range drops under the name rather than
   competing for the row's width (03-ux §3.9/§5). Nothing else changes — the field
   labels and values are already a single column. */
@media (max-width: 419px) {
  .panel__slot-range { white-space: normal }
}

/* ==========================================================================
   Motion — 03-ux §4.6: exactly two transitions, both opted in only when the user has
   not asked for reduced motion. Nothing animates that is required to understand state.
   ========================================================================== */

@media (prefers-reduced-motion: no-preference) {
  dialog.sheet { transition: transform 200ms ease-out, opacity 200ms ease-out }
  .slot { transition: background-color 150ms ease-out }
}

/* ==========================================================================
   v2.3.3 — about.html (static explainer for search engines / LLMs). Page tokens only,
   so it follows light/dark like the app. index.html's footer links to it.
   ========================================================================== */

.brand-link { color: inherit; text-decoration: none }
.brand-name { font-size: var(--fs-2xl-hi); line-height: var(--lh-2xl-hi); font-weight: 700 }
.prose { max-width: 46rem; margin-inline: auto; padding-top: var(--sp-4) }
.prose article + article { margin-top: var(--sp-12); padding-top: var(--sp-8); border-top: 1px solid var(--border) }
.prose h1 { margin: 0 0 var(--sp-3); font-size: var(--fs-2xl); line-height: var(--lh-2xl); color: var(--brand) }
.prose :lang(hi) h1 { font-size: var(--fs-2xl-hi); line-height: var(--lh-2xl-hi) }
.prose h2 { margin: var(--sp-8) 0 var(--sp-3); font-size: var(--fs-xl); line-height: var(--lh-xl) }
.prose h3 { margin: var(--sp-5) 0 var(--sp-1); font-size: var(--fs-base); line-height: var(--lh-base) }
.prose p, .prose li { line-height: 1.65 }
.prose p { margin: 0 0 var(--sp-3) }
.prose ol, .prose ul { padding-inline-start: var(--sp-6) }
.prose a { color: var(--brand) }
.prose .disclaimer { margin-top: var(--sp-8); font-size: var(--fs-sm); color: var(--text-muted) }
.cta { text-align: center }
.prose .cta-btn {
  display: inline-flex;
  align-items: center;
  min-height: 44px;             /* NFR-A5 */
  padding: 0 var(--sp-5);
  border-radius: var(--r-full);
  background: var(--brand);
  color: var(--brand-contrast);
  font-weight: 600;
  text-align: center;
  text-decoration: none;
}
.prose .cta-btn:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px }
.table-wrap { overflow-x: auto }
.about-table { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); line-height: var(--lh-sm) }
.about-table th, .about-table td {
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--border);
  text-align: start;
  vertical-align: top;
}
.about-table thead th { color: var(--text-muted); font-weight: 600 }
.about-table tbody th { white-space: nowrap }
.about-table .latin { display: block; margin-top: var(--sp-1); font-weight: 400; color: var(--text-muted) }
.about-table .good { display: block; margin-top: var(--sp-1); color: var(--text-muted) }
.tier { display: inline-block; padding: 0 var(--sp-2); border-radius: var(--r-full); font-weight: 600 }
.tier.q-amrit   { color: var(--qual-amrit-fg);        background: var(--qual-amrit-bg) }
.tier.q-good    { color: var(--qual-auspicious-fg);   background: var(--qual-auspicious-bg) }
.tier.q-neutral { color: var(--qual-neutral-fg);      background: var(--qual-neutral-bg) }
.tier.q-bad     { color: var(--qual-inauspicious-fg); background: var(--qual-inauspicious-bg) }
/* ≤419 px: let the table fit rather than scroll (a scrolling region would need to be
   keyboard-focusable) — names may wrap and long words break. */
@media (max-width: 419px) {
  .about-table th, .about-table td { padding: var(--sp-2) }
  .about-table tbody th { white-space: normal }
  .about-table td:last-child { overflow-wrap: anywhere }
  .prose .cta-btn { padding-block: var(--sp-2); border-radius: var(--r-lg) }
}
