/* ui/theme.css — shared design tokens + component classes (issue #40).
   Linked from ui/index.html, ui/katha.html, and auth/pages/__init__.py so the
   token source lives in exactly one place, and from the two archive pages so
   the YouTube/audio playback surfaces (styled here, driven by ui/player.js)
   live in exactly one place too. The install-offer card (ui/install.js) is
   paired with its script the same way. No build step: plain CSS, <link>ed as-is. */

:root {
  --parchment: #f3e9d8;
  --paper: #fbf6ea;
  --ink: #2a1c10;
  --ink-soft: #5b4732;
  --muted: #927d61;
  --saffron: #c5631a;
  --saffron-deep: #a14a10;
  --maroon: #6f2410;
  --gold: #a8801f;
  --line: rgba(111, 36, 16, 0.18);
  --shadow: 28px 34px 60px -38px rgba(58, 30, 10, 0.55);
}

* { box-sizing: border-box; }
html { -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; }

@keyframes rise { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

/* --- setting the chrome in Gujarati (issue #74) ---------------------------
   The design's micro-labels are Latin small-caps: uppercased and tracked out
   to 0.2–0.42em. Gujarati has no case, and tracking pulls a conjunct apart
   into pieces that no longer read as one letter — સ્વામિનારાયણ set that way
   comes out as loose fragments. Its display text has the mirror problem: the
   italic faces (Cormorant Garamond) carry no Gujarati, so the browser
   synthesises an oblique of a script that has no italic tradition.

   So when the document says it is in Gujarati, these two groups drop the
   Latin typographic conventions and take the Gujarati face that is already
   loaded on every page. Selecting on html[lang] means one rule covers the
   archive pages, the auth pages and anything added later — and an English
   document is untouched, byte for byte (US7).

   Only chrome is listed. Passage text and katha titles are set by their own
   rules and are not the interface. */
html[lang="gu"] .kicker,
html[lang="gu"] .count,
html[lang="gu"] .divider,
html[lang="gu"] .field label,
html[lang="gu"] label.fld span,
html[lang="gu"] .in-series,
html[lang="gu"] .provenance,
html[lang="gu"] footer,
html[lang="gu"] .backlink,
html[lang="gu"] button.go,
html[lang="gu"] a.backbtn,
html[lang="gu"] .pw-toggle,
html[lang="gu"] #go,
html[lang="gu"] button.playbtn,
html[lang="gu"] .install-card button.install-go {
  font-family: "Noto Serif Gujarati", "Spectral", serif;
  letter-spacing: 0.02em;
  text-transform: none;
}
html[lang="gu"] .title-en,
html[lang="gu"] .hint,
html[lang="gu"] .state,
html[lang="gu"] .card .sub,
html[lang="gu"] .note,
html[lang="gu"] .muted,
html[lang="gu"] .speaker,
html[lang="gu"] .notplay,
html[lang="gu"] .transcript-only-note,
html[lang="gu"] .install-card .install-text span,
html[lang="gu"] select,
html[lang="gu"] #q,
html[lang="gu"] #q::placeholder,
html[lang="gu"] .dock .title {
  font-family: "Noto Serif Gujarati", "Cormorant Garamond", serif;
  font-style: normal;
}

/* --- the language toggle (issue #74) --------------------------------------
   A pill fixed top-left, mirroring the admin link opposite it, in the same
   place on every page — the archive pages build it in ui/lang.js, the auth
   pages render it server-side, and both land on this one style. It always
   shows BOTH languages: a single word in the current language would be
   unfindable by exactly the reader who needs it. */
.langtoggle { position: fixed; top: 18px; left: 20px; z-index: 10;
  display: inline-flex; align-items: center; gap: 8px;
  border: 1px solid var(--saffron); border-radius: 100px; padding: 7px 14px;
  background: rgba(253, 246, 234, 0.82); -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
  box-shadow: 0 6px 18px -12px rgba(58, 30, 10, 0.5); }
.langtoggle .langopt { font-family: "Spectral", serif; font-size: 0.74rem; font-weight: 600;
  letter-spacing: 0.04em; color: var(--muted); background: transparent; border: 0; padding: 0;
  cursor: pointer; text-decoration: none; transition: color 0.15s; }
.langtoggle .langopt:hover { color: var(--saffron-deep); }
.langtoggle .langopt.current { color: var(--maroon); text-decoration: underline;
  text-underline-offset: 4px; text-decoration-color: var(--saffron); cursor: default; }
.langtoggle .langopt[lang="gu"] { font-family: "Noto Serif Gujarati", serif; font-size: 0.8rem; }
.langtoggle .langsep { color: var(--line); font-size: 0.8rem; }
/* On a narrow screen the toggle and the admin link share the top row; keep the
   toggle from crowding the page heading beneath it. */
@media (max-width: 520px) {
  .langtoggle { top: 12px; left: 12px; padding: 6px 11px; }
}

/* --- playback: trigger buttons, inline video, mobile modal, docked audio ---
   Rendered by ui/player.js's renderPlayControl(h, {variant}): "entry" (search
   result cards) uses button.playbtn / .notplay; "timestamp" (read-view
   segments) uses button.ts / span.ts-flat. */
button.playbtn { font-family: "Spectral", serif; font-weight: 600; font-size: 0.76rem; letter-spacing: 0.04em;
  display: inline-flex; align-items: center; gap: 6px; color: var(--saffron-deep); cursor: pointer;
  padding: 6px 15px; border: 1px solid var(--saffron); border-radius: 100px; background: rgba(197, 99, 26, 0.07);
  transition: background 0.15s, color 0.15s, box-shadow 0.15s, transform 0.15s; }
button.playbtn:hover { background: var(--saffron); color: var(--parchment);
  box-shadow: 0 7px 16px -8px rgba(161, 74, 16, 0.6); transform: translateY(-1px); }
button.playbtn .play { font-size: 0.66rem; line-height: 1; }
button.playbtn.active { background: var(--maroon); color: #fbf2df; border-color: var(--maroon); }
.notplay { font-family: "Spectral", serif; font-size: 0.76rem; font-style: italic; color: var(--muted); }

button.ts { font-family: "Spectral", serif; font-weight: 600; font-size: 0.8rem;
  font-variant-numeric: tabular-nums; color: var(--saffron-deep); cursor: pointer;
  padding: 5px 12px; min-width: 62px; text-align: center; border: 1px solid var(--saffron);
  border-radius: 100px; background: rgba(197, 99, 26, 0.07); white-space: nowrap;
  transition: background 0.15s, color 0.15s, box-shadow 0.15s, transform 0.12s; }
button.ts:hover { background: var(--saffron); color: var(--parchment);
  box-shadow: 0 6px 14px -8px rgba(161, 74, 16, 0.6); transform: translateY(-1px); }
button.ts.active { background: var(--maroon); color: #fbf2df; border-color: var(--maroon); }
span.ts-flat { font-family: "Spectral", serif; font-weight: 600; font-size: 0.8rem;
  font-variant-numeric: tabular-nums; color: var(--muted); padding: 5px 12px; min-width: 62px;
  text-align: center; white-space: nowrap; border: 1px dashed var(--line); border-radius: 100px; }

.player-inline { margin-top: 16px; border-radius: 5px; overflow: hidden; border: 1px solid var(--line);
  background: #000; aspect-ratio: 16 / 9; animation: rise 0.4s cubic-bezier(.2,.7,.2,1) both; }
.player-inline iframe, .player-inline > div { width: 100%; height: 100%; display: block; border: 0; }

/* The phone video (issue #83). Pinned to the top of the viewport, NOT laid
   over the page: it replaced a fullscreen modal that covered the transcript —
   on the one screen where a reader most wants to read along while the vakta
   speaks. The page scrolls underneath it, so the read view can follow the
   moment and a search reader keeps their results. */
.yt-pinned { position: fixed; top: 0; left: 0; right: 0; z-index: 60; background: #120a04;
  padding: 0 0 8px; box-shadow: 0 14px 34px -18px rgba(0, 0, 0, 0.75);
  animation: pindown 0.25s cubic-bezier(.2,.7,.2,1) both; }
.yt-pinned .frame { width: 100%; aspect-ratio: 16 / 9; background: #000; overflow: hidden; }
.yt-pinned .frame iframe, .yt-pinned .frame > div { width: 100%; height: 100%; border: 0; display: block; }
.yt-pinned .close { display: block; margin: 8px auto 0; cursor: pointer;
  font-family: "Spectral", serif; font-size: 0.78rem; letter-spacing: 0.06em; color: #fbf2df;
  background: rgba(255,255,255,0.12); border: 1px solid rgba(255,255,255,0.3);
  border-radius: 100px; padding: 7px 16px; }
.yt-pinned .close:hover { background: rgba(255,255,255,0.22); }
@keyframes pindown { from { transform: translateY(-100%); } to { transform: none; } }
/* Room for it, so the pinned frame never covers the first lines of the page.
   56.25vw is the 16/9 frame's own height at full width, plus the close row. */
body.has-pinned-video .wrap { padding-top: calc(56.25vw + 58px); }
/* On a wide screen a full-width 16/9 frame would be half the viewport tall and
   leave no transcript to read along with, so the video is capped and centred —
   and the clearance follows the cap rather than the window. */
@media (min-width: 681px) {
  /* left/right 0 + a width + auto margins, NOT a transform: the pindown
     animation owns transform, and with fill-mode both it would settle on
     `none` and throw the bar back into the corner. */
  .yt-pinned { left: 0; right: 0; width: 560px; margin: 0 auto; border-radius: 0 0 8px 8px; }
  .yt-pinned .frame { max-width: 520px; margin: 0 auto; }
  body.has-pinned-video .wrap { padding-top: 350px; }
}
/* Wide enough to put the video BESIDE the words instead of over them (#84).
   Centred at the top it lands squarely on the 760px transcript column, and
   every line the reader is following slides underneath it — the reader's
   complaint was simply "this window is in the way", and it was.
   The body's padding is what moves the column: .wrap centres itself inside
   whatever room is left, so the two never overlap and nothing has to be
   measured. */
@media (min-width: 1180px) {
  .yt-pinned { top: 20px; right: 20px; left: auto; width: 380px; margin: 0;
    padding: 0 0 6px; border-radius: 8px; }
  .yt-pinned .frame { max-width: none; border-radius: 8px 8px 0 0; }
  body.has-pinned-video { padding-right: 420px; }
  body.has-pinned-video .wrap { padding-top: 40px; }
  /* The admin bar is fixed across the top of the read view and would be the
     one thing the video still covered. */
  body.has-admin-bar .yt-pinned { top: 72px; }
}
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }

.dock { position: fixed; left: 0; right: 0; bottom: 0; z-index: 50; background: var(--paper);
  border-top: 2px solid var(--saffron); box-shadow: 0 -14px 40px -24px rgba(58,30,10,0.6);
  padding: 12px 18px; display: none; }
.dock.open { display: block; animation: dockup 0.25s cubic-bezier(.2,.7,.2,1) both; }
@keyframes dockup { from { transform: translateY(100%); } to { transform: none; } }
.dock-inner { max-width: 820px; margin: 0 auto; display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.dock .title { font-family: "Cormorant Garamond", serif; font-size: 1.05rem; color: var(--ink-soft);
  flex: 1 1 160px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dock button.ctl { cursor: pointer; border: 1px solid var(--line); background: transparent; color: var(--maroon);
  font-family: "Spectral", serif; font-size: 0.76rem; font-weight: 600; border-radius: 100px; padding: 7px 11px; white-space: nowrap; }
.dock button.ctl:hover { background: rgba(197,99,26,0.12); }
.dock button.play-pause { background: var(--maroon); color: #fbf2df; border: 1px solid var(--maroon);
  width: 42px; height: 42px; border-radius: 50%; font-size: 0.95rem; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto; }
.dock .scrub-wrap { flex: 2 1 240px; display: flex; align-items: center; gap: 10px; min-width: 180px; }
.dock .times { font-family: "Spectral", serif; font-size: 0.72rem; color: var(--muted);
  font-variant-numeric: tabular-nums; white-space: nowrap; }
.dock .track { position: relative; flex: 1; display: flex; align-items: center; }
.dock input[type=range].scrub { -webkit-appearance: none; appearance: none; width: 100%; height: 4px;
  background: var(--line); border-radius: 3px; outline: none; margin: 0; }
.dock input[type=range].scrub::-webkit-slider-thumb { -webkit-appearance: none; appearance: none;
  width: 14px; height: 14px; border-radius: 50%; background: var(--saffron); cursor: pointer; }
.dock input[type=range].scrub::-moz-range-thumb { width: 14px; height: 14px; border: 0; border-radius: 50%; background: var(--saffron); cursor: pointer; }
.dock .moment { position: absolute; top: 50%; transform: translate(-50%, -50%); width: 3px; height: 15px;
  background: var(--gold); border-radius: 2px; pointer-events: none; box-shadow: 0 0 0 1px rgba(251,246,234,0.7); }
.dock button.close { cursor: pointer; border: 0; background: transparent; color: var(--muted); font-size: 1.25rem; line-height: 1; padding: 4px 8px; flex: 0 0 auto; }
.dock button.close:hover { color: var(--maroon); }
.dock .authwarn { flex: 1 1 100%; margin-top: 10px; font-family: "Spectral", serif; font-size: 0.84rem;
  color: var(--maroon); display: flex; align-items: center; gap: 14px; }
.dock .authwarn a { color: #fbf2df; background: var(--maroon); text-decoration: none; font-weight: 600;
  padding: 6px 14px; border-radius: 100px; }

/* --- install offer: the home-screen card built by ui/install.js ------------
   Sits below the dock (z-index 50) and the video modal (60), and steps aside
   entirely while something is playing — a reader mid-katha is not installing. */
.install-card { position: fixed; z-index: 40; left: 16px; right: 16px; bottom: 18px;
  max-width: 460px; margin: 0 auto; display: flex; align-items: center; gap: 14px;
  padding: 13px 14px; background: var(--paper); border: 1px solid var(--line);
  border-left: 3px solid var(--saffron); border-radius: 5px;
  box-shadow: 0 22px 48px -22px rgba(58, 30, 10, 0.6);
  animation: rise 0.45s cubic-bezier(.2,.7,.2,1) both; }
.install-card .install-icon { width: 40px; height: 40px; border-radius: 7px; flex: 0 0 auto;
  border: 1px solid var(--line); }
.install-card .install-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.install-card .install-text strong { font-family: "Spectral", serif; font-weight: 600;
  font-size: 0.86rem; color: var(--maroon); }
.install-card .install-text span { font-family: "Cormorant Garamond", serif; font-size: 1rem;
  line-height: 1.35; color: var(--ink-soft); }
.install-card button.install-go { flex: 0 0 auto; cursor: pointer; border: 0; background: var(--maroon);
  color: #fbf2df; font-family: "Spectral", serif; font-weight: 600; letter-spacing: 0.12em;
  text-transform: uppercase; font-size: 0.68rem; padding: 11px 16px; border-radius: 3px;
  transition: background 0.2s, transform 0.1s; }
.install-card button.install-go:hover { background: var(--saffron-deep); }
.install-card button.install-go:active { transform: translateY(1px); }
.install-card button.install-x { flex: 0 0 auto; cursor: pointer; border: 0; background: transparent;
  color: var(--muted); font-size: 0.9rem; line-height: 1; padding: 6px 2px; }
.install-card button.install-x:hover { color: var(--maroon); }
body.has-dock .install-card { display: none; }

/* The dock is identical markup everywhere (built by player.js's buildDock),
   so its clearance is one shared value — was drifted 170px/index.html vs
   190px/katha.html with no actual reason (katha's admin bar sits at the
   *top* of the page, not the bottom). */
body.has-dock .wrap { padding-bottom: 190px; }
