/* Swarasense — static content-page stylesheet (content SEO pages, Task 1).
   The generated /ragas/<slug>/, /tanpura/, /learn/ etc. pages are plain static
   HTML served straight from packages/web/public/, outside the Vite/PWA bundle
   that the SPA's own src/ui/theme/tokens.css ships in (hashed, bundle-internal).
   A <link rel="stylesheet"> here can only reach a file that also lives in
   public/, so this file stands alone rather than depending on the app bundle.

   SOURCE OF TRUTH: src/ui/theme/tokens.css. The custom-property VALUES below
   are copied from that file (the "Kalamkari Indigo" palette) — keep them in
   sync by hand if tokens.css changes. Every rule past the token block below
   reads colour via var(--token), exactly like styles.css does for the SPA;
   there is no literal hex anywhere in the element styling.

   Theme resolution: the no-FOUC inline script in skeleton.ts's renderPage()
   sets [data-theme] on <html> before first paint (same swarasense.theme
   localStorage key + logic as the SPA), so the [data-theme] blocks below are
   what actually paints for a returning visitor; the plain :root fallback only
   covers the reader-mode/no-JS/first-ever-visit flash. */

:root {
  --bg: #f1ebdf;
  --bg-2: #ede5d6;
  --bg-gradient-top: #ede5d6;
  --surface: #fbf7ee;
  --surface-2: #e6dcc9;
  --hair: #dbd0bd;
  --hair-strong: #8b744c;
  --fg: #1c2431;
  --muted: #58626f;
  --faint: #7c8595;
  --accent: #a4422c;
  --accent-deep: #803422;
  --accent-ink: #ffffff;
  --accent-contrast: #ffffff;
  --gamaka: #494077;
  --gamaka-ink: #39325c;
  --focus-ring: #2f5fdd;
  --shadow-sm: 0 3px 12px rgba(14, 18, 26, 0.08);
  --shadow-lg: 0 12px 34px rgba(14, 18, 26, 0.16);
  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #141a24;
    --bg-2: #1c2430;
    --bg-gradient-top: #2b2a35;
    --surface: #1d2634;
    --surface-2: #273243;
    --hair: #303c4c;
    --hair-strong: #6a81a1;
    --fg: #eae4d6;
    --muted: #a7afbd;
    --faint: #6d7686;
    --accent: #d6735d;
    --accent-deep: #aa422b;
    --accent-ink: #12171f;
    --accent-contrast: #12171f;
    --gamaka: #a59fd1;
    --gamaka-ink: #a59fd1;
    --focus-ring: #8ab4ff;
    --shadow-sm: 0 3px 12px rgba(0, 0, 0, 0.3);
    --shadow-lg: 0 12px 34px rgba(0, 0, 0, 0.45);
    color-scheme: dark;
  }
}

:root[data-theme='dusk-light'] {
  --bg: #f1ebdf;
  --bg-2: #ede5d6;
  --bg-gradient-top: #ede5d6;
  --surface: #fbf7ee;
  --surface-2: #e6dcc9;
  --hair: #dbd0bd;
  --hair-strong: #8b744c;
  --fg: #1c2431;
  --muted: #58626f;
  --faint: #7c8595;
  --accent: #a4422c;
  --accent-deep: #803422;
  --accent-ink: #ffffff;
  --accent-contrast: #ffffff;
  --gamaka: #494077;
  --gamaka-ink: #39325c;
  --focus-ring: #2f5fdd;
  --shadow-sm: 0 3px 12px rgba(14, 18, 26, 0.08);
  --shadow-lg: 0 12px 34px rgba(14, 18, 26, 0.16);
  color-scheme: light;
}

:root[data-theme='dusk-dark'] {
  --bg: #141a24;
  --bg-2: #1c2430;
  --bg-gradient-top: #2b2a35;
  --surface: #1d2634;
  --surface-2: #273243;
  --hair: #303c4c;
  --hair-strong: #6a81a1;
  --fg: #eae4d6;
  --muted: #a7afbd;
  --faint: #6d7686;
  --accent: #d6735d;
  --accent-deep: #aa422b;
  --accent-ink: #12171f;
  --accent-contrast: #12171f;
  --gamaka: #a59fd1;
  --gamaka-ink: #a59fd1;
  --focus-ring: #8ab4ff;
  --shadow-sm: 0 3px 12px rgba(0, 0, 0, 0.3);
  --shadow-lg: 0 12px 34px rgba(0, 0, 0, 0.45);
  color-scheme: dark;
}

:root {
  --font-ui: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --font-mono: ui-monospace, 'SF Mono', 'JetBrains Mono', Menlo, monospace;
  --font-serif: 'Iowan Old Style', Georgia, serif;
  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 20px;
  --r-pill: 999px;
  --s-1: 0.25rem;
  --s-2: 0.5rem;
  --s-3: 0.75rem;
  --s-4: 1rem;
  --s-5: 1.5rem;
  --s-6: 2rem;
}

/* ----------------------------------------------------------------- layout */
* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  min-height: 100%;
}

body {
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-ui);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

a {
  /* Fix (contrast blocker): every hyperlink's text sits on the page
     background (`body`'s `--bg`), not on a solid accent fill — `--accent-ink`
     is reserved for the latter (on-accent-fill text/icons). `--accent`
     (madder) is what actually reads against the ground. */
  color: var(--accent);
}

a:focus-visible,
button:focus-visible,
select:focus-visible,
input:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}

/* -------------------------------------------------------------- site chrome */
/* UI reimagine (Task 2, shared navbar): mirrors `src/ui/styles.css`'s own
   `.navbar`/`.navbar-inner`/`.wordmark`/`.navbar-nav`/`.navbar-link`/
   `.navbar-actions`/`.seg` rules byte-for-byte in class names + behaviour
   (kept in sync by hand across the two files, same convention this file
   already uses for the token layer above) — replaces the pre-reimagine
   `.site-header`/`.site-nav` (wordmark + Ragas/Tanpura/Learn), so a visitor
   sees the SAME navbar on every generated content page and on the SPA
   itself: Practice·Ragas·Ear training·Learn, with the current page's link
   underlined in the accent. `scripts/gen-content/skeleton.ts`'s
   `renderHeader(activeNav)` emits this markup; the theme control's click
   wiring (there's no bundled JS on these static pages) is a small inline
   `<script>` `renderHeader()` also emits, doing the same
   localStorage-write + `data-theme` update `src/ui/theme/theme.ts`'s
   `setThemePreference` does in the SPA. */
.navbar {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--surface);
  border-bottom: 1px solid var(--hair);
}
.navbar-inner {
  max-width: 1080px;
  margin: 0 auto;
  padding: var(--s-3) clamp(0.75rem, 2vw, 1.25rem);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-4);
}
.wordmark {
  font-family: var(--font-serif);
  font-weight: 700;
  font-size: 1.25rem;
  letter-spacing: -0.01em;
  white-space: nowrap;
}
.wordmark,
.wordmark:visited {
  color: inherit;
  text-decoration: none;
}
.wordmark b {
  /* Fix (contrast blocker): accent-coloured TEXT on the page background, not
     ink on a solid accent fill — see the top-level `a` rule's comment. */
  color: var(--accent);
  font-weight: 700;
}
.navbar-nav {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  flex: 1 1 auto;
  min-width: 0;
  overflow-x: auto;
}
.navbar-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 0.3rem;
  white-space: nowrap;
  color: var(--muted);
  text-decoration: none;
  font-size: 0.92rem;
  font-weight: 600;
  border-bottom: 2px solid transparent;
}
.navbar-link:hover {
  color: var(--fg);
}
.navbar-link[aria-current='page'] {
  color: var(--fg);
  border-bottom-color: var(--accent);
}
.navbar-actions {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  flex: 0 0 auto;
  margin-left: auto;
}

/* The Auto/Dark/Light theme control — same segmented-pill treatment as the
   SPA's `.seg` (`src/ui/styles.css`), reused here for the navbar's on-page
   theme switcher (the static pages otherwise only ever resolve theme from
   `prefers-color-scheme`/a previously-set `localStorage` value, with no way
   to change it without visiting the SPA first). */
.seg {
  display: inline-flex;
  background: var(--surface-2);
  border: 1px solid var(--hair-strong);
  border-radius: var(--r-pill);
  padding: 3px;
}
.seg button {
  border: none;
  background: none;
  color: var(--faint);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  padding: 0.45rem 0.7rem;
  min-height: 44px;
  border-radius: var(--r-pill);
  cursor: pointer;
  font-family: inherit;
}
.seg button.on {
  background: var(--accent);
  color: var(--accent-contrast);
}

@media (max-width: 760px) {
  .navbar-nav {
    order: 3;
    flex-basis: 100%;
  }
}

.site-footer {
  border-top: 1px solid var(--hair);
  margin-top: var(--s-6);
  padding: var(--s-5) var(--s-4);
  color: var(--faint);
  font-size: 0.85rem;
  text-align: center;
}
/* Connected-Swarasense (W6): one shared footer with proper navigation, matched
   in styles.css. */
.site-footer-nav {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--s-2) var(--s-4);
  margin-bottom: var(--s-3);
}
.site-footer-nav a {
  color: var(--muted);
  text-decoration: none;
  font-weight: 600;
}
.site-footer-nav a:hover {
  color: var(--accent);
}
.site-footer-tagline {
  margin: 0;
}

/* ------------------------------------------------------------- content body */
.content {
  max-width: 720px;
  margin: 0 auto;
  padding: var(--s-6) var(--s-4) var(--s-6);
}

.content h1 {
  font-size: clamp(1.75rem, 4vw, 2.5rem);
  margin: 0 0 var(--s-2);
}

.content h2 {
  font-size: 1.25rem;
  margin: var(--s-6) 0 var(--s-3);
  border-bottom: 1px solid var(--hair);
  padding-bottom: var(--s-2);
}

.content .subtitle {
  color: var(--muted);
  margin: 0 0 var(--s-4);
}

/* NOT scoped under .content: renderPage() (skeleton.ts) inserts the
   breadcrumb <nav> as a sibling of the caller's bodyHtml (i.e. of
   <main class="content">), not nested inside it — so these must be
   top-level rules to actually match the DOM. Already uniquely named
   (.breadcrumbs), so there's no scope leak from dropping the prefix. */
.breadcrumbs {
  font-size: 0.85rem;
  color: var(--faint);
  margin-bottom: var(--s-4);
}

.breadcrumbs a {
  color: var(--faint);
}

.content .classification {
  color: var(--muted);
  margin: 0 0 var(--s-4);
}

/* ------------------------------------------------------- raga-scale widget */
/* Coherent-IA Task 2: the playable arohana/avarohana widget
   `scripts/gen-content/raga-page.ts` emits into `[data-raga-scale]` and
   `src/content/raga-scale-widget.ts` hydrates (tap a swara to hear it, "Play
   scale ▶" a row). Mirrors `src/ui/styles.css`'s `.raga-rail-*` rules
   (byte-for-byte where the shape matches — the SAME in-app rail widget,
   just on a static page) so the two read as the same component. No coloured
   accent side-rail (a flat hairline-bordered card, same as `.lean-note`
   above) — tokens only, works unstyled-but-functional even before JS
   hydrates (every chip is a real, visible `<button>`). */
.raga-scale-widget {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
  background: var(--surface);
  border: 1px solid var(--hair);
  border-radius: var(--r-md);
  padding: var(--s-4);
  margin: 0 0 var(--s-5);
}

.raga-scale-row {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}

.raga-scale-row-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-3);
}

.raga-scale-row-label {
  font-family: var(--font-serif);
  font-weight: 600;
  color: var(--fg);
}

.raga-scale-play {
  border: none;
  background: none;
  padding: 0 0.3rem;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  color: var(--accent);
  font-family: inherit;
  font-size: 0.92rem;
  font-weight: 600;
  cursor: pointer;
  border-radius: var(--r-sm);
}

.raga-scale-play:hover {
  color: var(--accent-deep);
}

.raga-scale-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
}

/* ≥44px tappable target in both dimensions (WCAG 2.5.5/2.5.8) — same floor
   as `.raga-rail-chip` (src/ui/styles.css). */
.scale-swara {
  min-width: 44px;
  min-height: 44px;
  padding: 0.3rem var(--s-2);
  border-radius: var(--r-md);
  border: 1px solid var(--hair-strong);
  background: var(--surface-2);
  color: var(--fg);
  font-family: var(--font-serif);
  font-size: 1.1rem;
  font-weight: 600;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition:
    background-color 120ms ease,
    transform 120ms ease;
}

.scale-swara:hover {
  border-color: var(--accent);
}

/* The "lit while it sounds" state — a chip tap, or a step of "Play scale
   ▶"'s sweep (`raga-scale-widget.ts`'s `sweepChips`/`litChip`). Colour AND a
   filled background together, matching `.raga-rail-chip.is-playing`'s
   identical treatment; the reduced-motion block below collapses the
   transition, but the highlight itself still shows (real information, not
   decoration). */
.scale-swara.is-playing {
  background: linear-gradient(180deg, var(--accent), var(--accent-deep));
  border-color: transparent;
  color: var(--accent-contrast);
  transform: scale(1.06);
}

.raga-scale-sa {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  font-size: 0.85rem;
  color: var(--muted);
}

/* Connected-Swarasense (W1/W2): the shared Sa control (content/sa-control.ts),
   mounted on raga pages + the tanpura page, bound to profile.sa. */
.sa-control {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  flex-wrap: wrap;
}
.sa-control-label {
  font-size: 0.85rem;
  color: var(--muted);
}
.sa-control-pitch,
.sa-control-octave {
  min-height: 44px;
  border-radius: var(--r-sm);
  border: 1px solid var(--hair-strong);
  background: var(--surface-2);
  color: var(--fg);
  padding: 0 var(--s-2);
  font-family: inherit;
  font-size: 0.85rem;
}

.content .cta {
  display: inline-block;
  background: var(--accent);
  color: var(--accent-contrast);
  text-decoration: none;
  font-weight: 600;
  padding: var(--s-3) var(--s-5);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
  margin: var(--s-2) 0 var(--s-5);
}

.content .character {
  font-style: italic;
  color: var(--fg);
}

.content .gamaka-table {
  width: 100%;
  border-collapse: collapse;
  margin: var(--s-3) 0 var(--s-5);
  font-size: 0.9rem;
}

.content .gamaka-table th,
.content .gamaka-table td {
  text-align: left;
  padding: var(--s-2) var(--s-3);
  border-bottom: 1px solid var(--hair);
  vertical-align: top;
}

.content .gamaka-table th {
  color: var(--gamaka-ink);
  font-weight: 600;
}

.content ul.pitfalls li,
.content ul.sources li {
  margin-bottom: var(--s-2);
}

/* A quiet aside, not a highlighted alert: no coloured accent rail (that reads
   as a generic AI-UI callout tell) — just a calm inset note, full hairline
   border all round + a muted surface tint. */
.content .lean-note {
  background: var(--surface-2);
  border: 1px solid var(--hair);
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-sm);
  color: var(--muted);
}

/* ----------------------------------------------------------- ragas index */
/* The /ragas/ browse-all hub: a plain responsive grid of links, each a flat
   hairline-bordered tile (no coloured side-rail/accent-bar per tile — that
   reads as a generic AI-UI tell). Same tokens as every other surface. */
.content .raga-index {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: var(--s-3);
  list-style: none;
  margin: var(--s-5) 0 0;
  padding: 0;
}

.content .raga-index li {
  /* Grid items default to min-width: auto (their content's min-content
     size), which for a long single-token raga name is the width of the
     whole word — wide enough to overflow a 160px track. min-width: 0 lets
     the track win so overflow-wrap below can actually take effect. */
  min-width: 0;
}

.content .raga-index a {
  display: block;
  min-width: 0;
  padding: var(--s-3) var(--s-3);
  border: 1px solid var(--hair);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--fg);
  text-decoration: none;
  overflow-wrap: break-word;
  hyphens: auto;
}

.content .raga-index a:hover {
  border-color: var(--hair-strong);
  /* Fix (contrast blocker): text on the tile's `--surface` background, not
     on-accent-fill — see the top-level `a` rule's comment. */
  color: var(--accent);
}

/* --------------------------------------------------------------- glossary */
/* The /learn/ glossary's <dl>: each term/definition pair reads as a stacked
   pair rather than the browser's default hanging-indent <dd>, with a
   hairline rule between pairs (matching .content h2's rule, not a coloured
   accent rail) so a long list of terms stays easy to scan. */
.content .glossary {
  margin: var(--s-5) 0 0;
}

.content .glossary dt {
  font-weight: 600;
  color: var(--fg);
  margin: 0;
  padding-top: var(--s-4);
  border-top: 1px solid var(--hair);
}

.content .glossary dt:first-child {
  padding-top: 0;
  border-top: none;
}

.content .glossary dd {
  margin: var(--s-1) 0 0;
  color: var(--muted);
}

/* ------------------------------------------------------- guide-links list */
/* Coherent-IA Task 3: the /learn/ page's "Guides & how-tos" section
   (`glossary-page.ts`'s `renderGuidesSection`) — the re-link fix for the 3
   guide pages Task 1's footer trim orphaned. Same stacked, hairline-divided
   treatment as `.glossary dt`/`dd` above (a plain link title + a muted
   description line), not a card grid — this is a short list of 3 items, not
   a browse-all index like `.raga-index`. */
.content .guide-links {
  list-style: none;
  margin: var(--s-5) 0 0;
  padding: 0;
}

.content .guide-links li {
  padding-top: var(--s-4);
  border-top: 1px solid var(--hair);
}

.content .guide-links li:first-child {
  padding-top: 0;
  border-top: none;
}

.content .guide-links a {
  font-weight: 600;
}

.content .guide-links p {
  margin: var(--s-1) 0 0;
  color: var(--muted);
}

/* -------------------------------------------------------- tanpura widget */
/* Coherent-IA Task 3: the online-tanpura player at the top of `/tanpura/`
   (`scripts/gen-content/tanpura-page.ts`'s `renderTanpuraWidget`, hydrated
   by `src/content/tanpura-widget.ts`) — same flat, hairline-bordered card
   treatment as `.raga-scale-widget` (no coloured accent side-rail), so the
   two content-page widgets read as one family. Functional-looking even
   before JS hydrates: real `<select>`s + a real `<button>`, centred as the
   page's primary action. */
.tanpura-widget {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s-4);
  background: var(--surface);
  border: 1px solid var(--hair);
  border-radius: var(--r-md);
  padding: var(--s-5) var(--s-4);
  margin: 0 0 var(--s-5);
  text-align: center;
}

.tanpura-widget-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--s-4);
}

.tanpura-widget-field {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--s-1);
  font-size: 0.85rem;
  color: var(--muted);
}

.tanpura-pitch-select,
.tanpura-octave-select {
  min-height: 44px;
  min-width: 88px;
  border-radius: var(--r-sm);
  border: 1px solid var(--hair-strong);
  background: var(--surface-2);
  color: var(--fg);
  padding: 0 var(--s-2);
  font-family: inherit;
  font-size: 0.95rem;
}

/* The big Play/Stop toggle — the page's one primary action. Larger than the
   plain `.btn` pill (`src/ui/styles.css`) since this widget IS the page's
   headline feature, not a secondary control; same "fill on .on" language as
   `.btn.primary`/`.scale-swara.is-playing` for the playing state. */
.tanpura-play-btn {
  min-width: 160px;
  min-height: 56px;
  padding: var(--s-3) var(--s-6);
  border-radius: var(--r-pill);
  border: 1px solid var(--hair-strong);
  background: var(--surface-2);
  color: var(--fg);
  font-family: inherit;
  font-weight: 700;
  font-size: 1.1rem;
  cursor: pointer;
  transition:
    background-color 120ms ease,
    border-color 120ms ease;
}

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

.tanpura-play-btn.on {
  background: linear-gradient(180deg, var(--accent), var(--accent-deep));
  border-color: transparent;
  color: var(--accent-contrast);
}

.tanpura-widget-volume {
  width: 100%;
  max-width: 220px;
  align-items: center;
}

.tanpura-volume-range {
  width: 100%;
  min-height: 44px;
  accent-color: var(--accent);
}

.tanpura-widget-status {
  min-height: 1.2em;
  margin: 0;
  font-size: 0.85rem;
  color: var(--muted);
}

.tanpura-widget-noscript {
  margin: 0;
  color: var(--muted);
  font-size: 0.9rem;
}

/* ----------------------------------------------------------------- guides */
/* The how-to guides' numbered step list: a plain, legible ordered list —
   custom counters (not the default in-content number glyph) so the number
   and step title share one visual weight, still no coloured accent rail. */
.content .guide-steps {
  list-style: none;
  counter-reset: guide-step;
  margin: var(--s-5) 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
}

.content .guide-steps li {
  counter-increment: guide-step;
  display: flex;
  gap: var(--s-3);
  padding-bottom: var(--s-4);
  border-bottom: 1px solid var(--hair);
}

.content .guide-steps li:last-child {
  padding-bottom: 0;
  border-bottom: none;
}

.content .guide-steps li::before {
  content: counter(guide-step);
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 50%;
  background: var(--surface-2);
  /* Fix (contrast blocker): the step-number glyph on `--surface-2`, not
     on-accent-fill — see the top-level `a` rule's comment. */
  color: var(--accent);
  font-weight: 600;
  font-size: 0.9rem;
}

.content .guide-steps strong {
  color: var(--fg);
}

/* --------------------------------------------------------------- motion */
/* Coherent-IA Task 2: the raga-scale widget is the first interactive/
   transitioned element these static content pages ship (`.scale-swara.is-
   playing`'s background/transform transition above) — mirrors
   `src/ui/styles.css`'s own page-wide reduced-motion rule. The widget's JS
   (`raga-scale-widget.ts`'s `sweepChips`) already degrades "Play scale ▶"
   to a single static highlight (no per-chip stagger) under this same media
   query; this CSS-side rule additionally ensures the highlight itself never
   *animates* into place (no transition), matching that intent for anyone
   who reaches this file directly. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
