/* Product layer — auth, paywall, locked state. Kept separate from the
   learning UI in styles.css so the two can evolve independently. */

/* ---------- brand header (home) ---------- */

header.brand {
  display: flex; align-items: center; gap: 13px;
  padding: 18px 0 16px;
  position: sticky; top: 0; z-index: 20;
  background: linear-gradient(var(--bg) 72%, transparent);
}

/* Full-colour brand badge — drawn as a background image rather than masked,
   because the mark carries its own yellow/red/navy. */
.logo-mark {
  width: 42px; height: 42px; flex: none;
  background: url(brand/logo-192.png) center / contain no-repeat;
}

header.brand .who { flex: 1; min-width: 0; }
header.brand .who b {
  display: block; font-size: 17px; font-weight: 650;
  letter-spacing: -0.012em; line-height: 1.25;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
header.brand .stats {
  display: flex; flex-wrap: wrap; gap: 4px 10px;
  font-size: 12.5px; color: var(--ink-faint);
  font-variant-numeric: tabular-nums; margin-top: 2px;
}
header.brand .stats .s { white-space: nowrap; }
header.brand .stats .flame { color: var(--accent); }

/* Fixed-width tag column so every unit title starts on the same line,
   however long the Kannada phrase is. */
.unit .kn-tag {
  width: 94px; min-width: 94px;
  font-size: 14px; line-height: 1.3;
}

.unit.locked { opacity: 0.62; }
.unit.locked .kn-tag { color: var(--ink-faint); }

.pill.lock {
  background: transparent;
  border: 1px solid var(--line);
  color: var(--ink-faint);
  font-size: 13px;
}

/* "or" divider on the sign-in card */
.or {
  display: flex; align-items: center; gap: 12px;
  color: var(--ink-faint); font-size: 12.5px; margin: 4px 0 14px;
}
.or::before, .or::after {
  content: ''; flex: 1; height: 1px; background: var(--line);
}

/* plan cards on the paywall */
.choice.plan {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: baseline;
  gap: 4px 12px;
  padding: 17px 18px;
}
.choice.plan b { font-size: 16.5px; font-weight: 600; }
.choice.plan .price {
  font-size: 21px; font-weight: 650; color: var(--accent);
  font-variant-numeric: tabular-nums; grid-row: 1 / span 2;
  grid-column: 2; align-self: center;
}
.choice.plan .sub { grid-column: 1; margin-top: 0; }
.choice.plan:active { background: var(--surface-2); }

/* sign-in form */
label.faint { display: block; margin-bottom: 2px; }
input.search[inputmode=numeric] {
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.08em;
}

code {
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: 6px; padding: 1px 6px; font-size: 13px;
}

.setting .btn.slim { flex: none; }

/* ============================================================
   Brand palette, taken from the logo: yellow field, red ring,
   navy wordmark. Navy carries primary actions, red carries
   highlights and active state.
   ============================================================ */

:root {
  --brand: #FFCF31;
  --brand-ink: #1B2A6B;
  --brand-red: #D8342A;
  --brand-orange: #E8873D;
  --accent: #1B2A6B;
  --accent-soft: #eef0fa;
}


nav.tabs a.on { color: var(--brand-red); }
.streak { color: var(--brand-red); background: #fff3d6; border-color: #f0e2b8; }

/* ---------- dashboard home ---------- */

.dash-head { display: flex; align-items: center; gap: 13px; padding: 16px 0 14px; }
/* A button now, so it needs the button chrome taken back off. */
.dash-head .logo-mark {
  width: 46px; height: 46px; padding: 0; border: 0; background-color: transparent;
  cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.dash-head .logo-mark:active { opacity: .7; }
.dash-head .t { flex: 1; min-width: 0; }
.dash-head .t b { display: block; font-size: 16.5px; font-weight: 700; letter-spacing: -0.01em; }
.dash-head .t span { font-size: 12.5px; color: var(--ink-faint); }
/* Badge and help, stacked in one column on the right. Stacking buys the help
   link the badge's width, which is the difference between a glyph nobody is
   sure about and a label that says what it opens. */
.dash-right { flex: none; display: flex; flex-direction: column; align-items: stretch; gap: 5px; }
/* The help link moved out of this column on 3 Oct: stacked under the badge it
   made the right-hand side two rows tall, and the greeting then centred
   against the stack instead of sitting level with the badge. It lives under
   the fact line now, right-aligned and quiet. */
/* "How to use" stays on the right where it has always been; the cards link,
   when there is one, is pushed to the left by its own auto margin rather than
   by space-between — so the row with only one link in it is unchanged. */
.howto-row {
  margin: -2px 0 12px;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
}
.howto-row [data-go="#/cards"] { margin-right: auto; }
/* A line waiting on the ones above it. Dimmed rather than hidden: the
   exchange is still there to be read, it is just not your turn in it yet. */
.bubble.waiting { opacity: .45; }
.bubble.waiting [data-play], .bubble.waiting [data-reveal] { pointer-events: none; }
/* The module number, quieter than the title it labels and on its own line so
   a long title still wraps cleanly under it. */
.sec-head .mod-n {
  display: block; font-style: normal; font-size: 11px; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase; color: var(--ink-faint);
  margin-bottom: 1px;
}
/* The way out, before the reading rather than only after it. */
.howto-top { display: flex; align-items: center; gap: 10px; }
.howto-top .howto-lang { flex: 1; }
.howto-close {
  flex: none; width: 34px; height: 34px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--surface);
  color: var(--ink-faint); font-size: 15px; line-height: 1;
}
.howto-close:active { background: var(--surface-2); color: var(--ink); }
/* Quiet by design — it is for the first week, and for the one day in the third
   month when something stops making sense. It should not compete with the
   badge above it for either. */
.howto-link {
  /* inline-flex, not flex: it sits in a right-aligned paragraph now rather
     than stretching to a column's width. */
  display: inline-flex; align-items: center; justify-content: center; gap: 4px;
  padding: 5px 8px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--line); color: var(--ink-faint);
  font: inherit; font-size: 11px; font-weight: 650; line-height: 1.1;
  white-space: nowrap; cursor: pointer;
}
.howto-link span { font-size: 12px; }
.howto-link:active { background: var(--surface-2); color: var(--ink); }

/* ---------- how to use this app ---------- */

/* The page says hello before it says anything else, in Kannada, with the
   learner's own name in it — and the line is a speaker, so the first thing
   that happens on this screen is the thing the screen is about. */
/* English or Hindi, not both — this page is the one screen that is all prose,
   and saying every paragraph twice doubled it. Right-aligned and small: it is
   a setting, not the first thing to read. */
.howto-lang { display: flex; justify-content: flex-end; gap: 6px; margin: -4px 0 10px; }
.howto-lang button {
  padding: 5px 12px; border-radius: 999px; font: inherit; font-size: 12.5px; font-weight: 600;
  background: var(--surface); border: 1px solid var(--line); color: var(--ink-faint);
  cursor: pointer;
}
.howto-lang button.on {
  background: var(--accent); border-color: var(--accent); color: var(--on-accent);
}

.howto-hero { text-align: center; margin: 2px 0 0; }
.howto-hello {
  display: flex; align-items: center; gap: 12px; width: 100%;
  margin-top: 8px; padding: 14px 15px; text-align: left; cursor: pointer;
  background: var(--accent-soft); border: 1px solid transparent; border-radius: 16px;
  font: inherit; color: inherit;
}
.howto-hello:active { background: var(--surface-2); }
.howto-hello .ico { flex: none; font-size: 22px; line-height: 1; }
.howto-hello .t { min-width: 0; }
.howto-hello b {
  display: block; font-size: 19px; font-weight: 700; letter-spacing: -0.01em;
  line-height: 1.25; color: var(--accent);
}
.howto-hello .t > span { display: block; margin-top: 3px; font-size: 12.5px; color: var(--ink-dim); }

.howto { display: flex; flex-direction: column; gap: 10px; }
.howto-card {
  display: flex; align-items: flex-start; gap: 12px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 14px;
  padding: 14px 15px;
}
/* A fixed column so every heading starts on the same line, however wide the
   glyph — ✓ and 🔊 are nothing like the same width. */
.howto-card .e { flex: none; width: 26px; font-size: 20px; line-height: 1.2; text-align: center; }
/* A flex child's floor is its content, not zero, so the worked example — a
   real row with two fixed-width buttons on the end of it — made the text
   column wider than the card and hung out over the edge of it. */
.howto-card > div { min-width: 0; }
.howto-card b { display: block; font-size: 15px; font-weight: 650; line-height: 1.3; }
.howto-card p { margin: 5px 0 0; font-size: 13.5px; line-height: 1.5; color: var(--ink-dim); }
/* The Hindi under each line sits closer than a paragraph break, so the pair
   reads as one sentence said twice rather than as two points. */
.howto-card .c-hi { display: block; margin-top: 3px; color: var(--ink-faint); }
.howto-card b .c-hi { font-size: .92em; font-weight: 600; }

/* The four tabs, one per row — a definition list because that is what it is:
   the name along the bottom of the screen, and what tapping it gets you. */
.howto-tabs dl { margin: 10px 0 0; }
.howto-tabs dt {
  display: flex; align-items: center; gap: 7px;
  margin-top: 11px; font-size: 13.5px; font-weight: 700; color: var(--ink);
}
.howto-tabs dt:first-child { margin-top: 0; }
.howto-tabs dt span { font-size: 15px; color: var(--accent); width: 17px; text-align: center; }
.howto-tabs dd { margin: 3px 0 0 24px; font-size: 13px; line-height: 1.5; color: var(--ink-dim); }

/* What the card has just described, shown rather than described further: a
   real row with real audio, and the step bar as it looks mid-lesson. */
.howto-cap { margin: 11px 0 6px; font-size: 12px; color: var(--ink-faint); }
.howto-demo {
  background: var(--surface-2); border-radius: 12px; padding: 2px 8px;
}
.howto-demo .pb-item.open { background: transparent; }
/* Between two cards rather than inside one, so it has the page to itself —
   the real bar's width, which is what makes it a picture of the real bar. */
.howto-figure { margin: 2px 0; }
.howto-bar { margin: 0; }
.howto-figure .howto-cap { margin: 8px 0 0; text-align: center; }
/* No arrow over "you are here": the real bar earns that mark by being the
   page you are on, and this one is a picture of somebody else's lesson. */
.howto-bar .seg.at span::before { content: none; }

/* The daily fact: a quiet full-width line under the header, above everything
   that asks anything of you. */
.fact { font-size: 12.5px; line-height: 1.45; color: var(--ink-faint); margin: 0 0 12px; }
.fact b { color: var(--ink-dim); font-weight: 700; }
.fact b::after { content: ' · '; color: var(--ink-faint); font-weight: 400; }

.sec-head {
  display: flex; align-items: baseline; gap: 8px;
  font-size: 11.5px; font-weight: 800; letter-spacing: .09em; text-transform: uppercase;
  color: var(--ink-faint); margin: 20px 0 9px;
}
.sec-head:first-of-type { margin-top: 4px; }
.sec-head span {
  margin-left: auto; font-size: 11px; letter-spacing: 0; text-transform: none;
  font-weight: 600; color: var(--ink-faint); font-variant-numeric: tabular-nums;
}

.tiles { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.tile {
  background: var(--surface); border: 1px solid var(--line); border-radius: 14px;
  padding: 13px; position: relative; text-align: left; min-height: 96px;
}
.tile .e { font-size: 23px; display: block; margin-bottom: 6px; line-height: 1; }
.tile b { font-size: 13.5px; font-weight: 650; display: block; line-height: 1.25; }
.tile span { font-size: 11.5px; color: var(--ink-faint); }
.tile .bar { margin-top: 7px; }
.tile .bar > i { background: var(--brand-orange); }
/* A finished topic turns green. The bar is the only thing on the tile that
   says how far along you are, and a full in-progress bar reads as unfinished rather
   than as an achievement — the same shape meaning "nearly there" and "done"
   depending on a width you have to measure by eye. */
.tile .bar.done > i { background: var(--good); }
.tile.lock { opacity: .6; }
.tile .pill-pro {
  position: absolute; top: 10px; right: 10px; font-size: 9.5px; font-weight: 800;
  background: #fff3d0; color: #9a7413; border-radius: 999px; padding: 2px 7px; letter-spacing: .04em;
}
.tile:active { background: var(--surface-2); }

.dash-foot { text-align: center; margin: 20px 0 4px; }

/* ---------- update banner ---------- */

.update-bar {
  position: fixed; left: 12px; right: 12px; bottom: 70px; z-index: 40;
  background: var(--brand-ink); color: #fff; border-radius: 12px;
  padding: 12px 14px; display: flex; align-items: center; gap: 12px;
  font-size: 13.5px; box-shadow: 0 8px 24px rgba(0,0,0,.25);
}
.update-bar button {
  margin-left: auto; background: var(--brand); color: var(--brand-ink);
  border: none; border-radius: 8px; padding: 7px 13px; font-weight: 700; font-size: 13px;
}

/* ---------- expandable list row ----------
   Tap plays it and opens the rest: the Hindi hook, the literal reading, the
   speed control. One row open at a time. */
.pb-item.open { background: var(--surface-2); border-radius: 12px; }
.pb-item.open .pb-head { padding-left: 12px; padding-right: 12px; }
.pb-more { padding: 2px 12px 12px; }
.pb-more .hi, .pb-more .lit { font-size: 13px; color: var(--ink-dim); margin-bottom: 6px; }
/* A cognate is good news — "you already know this one" — so it reads as a note
   rather than as another translation. */
.pb-more .hi.same { color: var(--accent); }
/* In a list row the Devanagari trails the romanisation on the same line: it is
   the same word said twice, not a second field. */
/* The two spellings share the top line — the same word written twice, one in
   letters the reader sounds out and one in letters they already read. The
   meaning keeps the line below to itself. */
.pb-main .t .l1 { display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap; }
.pb-main .t .l1 b { display: inline; }
.pb-main .t .dev { font-size: 15px; color: var(--accent); font-weight: 500; }
/* The meaning line carries both languages, so a row stands on its own without
   being opened. */
.pb-main .t .him { font-style: normal; color: var(--ink-faint); }
.pb-more .btn.slim { width: 100%; }
/* The beats now hang off the row rather than off its disclosure, because the
   control that reveals them moved up into the head. Indented to the text
   column so they line up under the word they are a breakdown of. */
.pb-item > .chunks { margin: 0 0 11px; padding: 0 12px; }
.pb-item.open > .chunks { padding: 0 24px 0 12px; }
/* Narrower than the turtle: it is the second of two round buttons on a row
   that also has to hold a Kannada line and its meaning. */
.pb-head .brk { min-width: 40px; min-height: 40px; font-size: 15px; }

/* The "what does this mean?" card deliberately shows no word. Without a label
   it is a blank box, which reads as a failure rather than as the exercise. */
.listen-card { text-align: center; }
.listen-btn {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  width: 100%; min-height: 62px; cursor: pointer;
  background: var(--accent-soft); border: 1px solid var(--line);
  border-radius: 14px; color: var(--brand-ink); font-size: 17px; font-weight: 700;
}
.listen-btn .ico { font-size: 26px; }
.listen-btn:active { background: var(--surface-2); }
.listen-hint { font-size: 12.5px; color: var(--ink-faint); margin: 8px 0 2px; }

/* ---------- donate ---------- */
.donate-row { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 8px; margin-bottom: 8px; }
.donate-amt { display: block; text-align: center; text-decoration: none; }
#donate-sheet .btn { width: 100%; }
/* A quiet secondary action: offered, never pressed upon. */
.linky {
  display: block; width: 100%; margin: 14px 0 0; padding: 6px;
  background: none; border: 0; cursor: pointer;
  font-size: 13.5px; color: var(--ink-faint);
  text-decoration: underline; text-underline-offset: 3px;
}
.linky:active { color: var(--ink); }

/* Amount chips: the choice is visible rather than hidden in a default. */
.donate-step { margin: 16px 0 6px; font-weight: 700; color: var(--ink-dim); }
.chip {
  background: var(--surface); border: 1px solid var(--line); color: var(--ink);
  border-radius: 999px; padding: 10px 6px; font-size: 14px; font-weight: 600;
  min-height: 42px; cursor: pointer;
}
.chip.on { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.donate-app { display: block; text-align: center; text-decoration: none; margin-bottom: 8px; }

/* ---------- feedback ---------- */
.foot-links { display: flex; flex-direction: column; gap: 2px; }
.fb-q { border: 0; padding: 0; margin: 0 0 18px; }
.fb-q legend { font-size: 14px; font-weight: 650; color: var(--ink); padding: 0 0 8px; }
.fb-scale { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 8px; }
/* The whole chip is the target, not a 20px circle — this is read by people
   with older eyes and larger thumbs. */
.fb-dot input { position: absolute; opacity: 0; pointer-events: none; }
.fb-dot span {
  display: block; text-align: center; cursor: pointer;
  background: var(--surface); border: 1px solid var(--line); border-radius: 12px;
  padding: 13px 0; font-size: 16px; font-weight: 650; color: var(--ink);
}
.fb-dot input:checked + span {
  background: var(--accent); color: var(--on-accent); border-color: var(--accent);
}
.fb-dot input:focus-visible + span { outline: 2px solid var(--ring); outline-offset: 2px; }
.fb-ends {
  display: flex; justify-content: space-between;
  font-size: 11.5px; color: var(--ink-faint); margin-top: 6px;
}
#fb-text {
  width: 100%; background: var(--surface); border: 1px solid var(--line);
  border-radius: 12px; padding: 12px 14px; font: inherit; font-size: 15px;
  color: var(--ink); resize: vertical;
}
#fb-send { width: 100%; }

/* ---------- analytics (owner only) ---------- */
.astats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-bottom: 10px; }
.astat {
  background: var(--surface); border: 1px solid var(--line); border-radius: 13px;
  padding: 12px 8px; text-align: center;
}
.astat b {
  display: block; font-size: 20px; font-weight: 800; color: var(--brand-ink);
  font-variant-numeric: tabular-nums; line-height: 1.15;
}
.astat span { font-size: 11px; color: var(--ink-faint); line-height: 1.3; display: block; margin-top: 3px; }
:root[data-theme="dark"] .astat b { color: var(--accent); }

.alist { list-style: none; margin: 0 0 8px; padding: 0; }
.alist li {
  display: flex; align-items: center; gap: 12px;
  border-bottom: 1px solid var(--line); padding: 11px 2px;
}
.at { flex: 1; min-width: 0; }
.at b { display: block; font-size: 15px; font-weight: 650; }
.at span { font-size: 12.5px; color: var(--ink-faint); }
.an { flex: none; text-align: right; font-size: 13.5px; font-weight: 700; }
.an span { display: block; font-size: 11px; font-weight: 400; color: var(--ink-faint); }

.afb {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 12px; padding: 12px 14px; margin-bottom: 8px;
}
.afb-h { font-size: 11.5px; color: var(--ink-faint); }
.afb-s { font-size: 12.5px; color: var(--ink-dim); margin-top: 3px; }
.afb p { margin: 6px 0 0; font-size: 14.5px; }

/* Five tabs only for the owner. Labels tighten rather than truncate — a tab
   reading "Setti…" looks broken, and this bar is the one thing always on screen. */
nav.tabs.five a { font-size: 10px; }
nav.tabs.five a .i { font-size: 17px; }

/* ---------- topic flow (module 1 / topic 1.1) ---------- */

/* Six segments, each labelled — filled behind you, orange where you are,
   grey ahead. The label under each one is what makes "which step" legible
   without a "2/6" to decode; the colour is what makes "how far" legible
   without reading any of them. */
.step-bar { display: flex; gap: 4px; margin: -2px 0 16px; }
.step-bar .seg {
  flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 4px;
}
.step-bar i {
  display: block; width: 100%; height: 4px; border-radius: 2px; background: var(--surface-2);
}
.step-bar i.done { background: var(--good); }
.step-bar i.now { background: var(--brand-orange); }
.step-bar span {
  font-size: 8.5px; color: var(--ink-faint); text-align: center; line-height: 1.15;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}
.step-bar span.done { color: var(--good); }
.step-bar span.now { color: var(--brand-orange); font-weight: 700; }
/* Which step you are ON, said separately from whether it is finished — on a
   fully green lesson the bars alone cannot answer "where am I". */
.step-bar .seg.at span { color: var(--brand-orange); font-weight: 800; }
.step-bar .seg.at span::before { content: '▾'; display: block; line-height: 1; font-size: 9px; }

.gate-hint { text-align: center; margin: 10px 0 0; }

/* Two people talking, above the lesson overview. */
.lesson-art { display: block; width: 168px; max-width: 70%; height: auto; margin: 0 auto 4px; }

/* A turn the learner owes before they may see it: a task card, not a
   covered-up answer. */
.bubble.you.try { background: var(--surface); border-style: dashed; border-color: var(--brand-orange); }
.try-say { margin: 2px 0 6px; font-size: 12.5px; color: var(--ink-faint); }
.try-en { margin: 0 0 12px; font-size: 18px; font-weight: 650; color: var(--ink); }
.try-reveal { width: 100%; }

/* Three controls per option now (hear, hear-slow, choose), so the two audio
   buttons give up width to keep the answer itself readable. */
.choice-wrap .hear { width: 44px; font-size: 17px; }

/* An option that has not been heard yet.
 *
 * `disabled` alone was not enough: the row still looked like something to
 * press, so it got pressed, and an answer was chosen before anything had been
 * listened to. The speaker is the only live control until it is used, and it
 * says so by being the only part of the row at full strength.
 *
 * Deliberately faded rather than hidden -- knowing there are four options and
 * that you have heard two of them is part of the task. */
.choice-wrap.unheard .choice { opacity: .45; border-style: dashed; cursor: default; }
.choice-wrap.unheard .hear {
  border-color: var(--accent); color: var(--accent); font-weight: 700;
}
/* Narrower than the speaker: two round buttons of equal weight beside a long
   option read as a choice between them, and the choice is the option. */
.choice-wrap .hear.slow { width: 40px; font-size: 15px; }

/* Before the question has been played, the option speakers are not useful
   yet -- so they say so rather than responding and changing nothing. */
.choice-wrap.locked .hear { opacity: .3; border-color: var(--line); color: var(--ink-faint);
  font-weight: 400; animation: none; cursor: default; }
.choice-wrap.unheard .hear.slow { border-color: var(--line); color: var(--ink-faint); font-weight: 400; }
@media (prefers-reduced-motion: no-preference) {
  /* One pulse on arrival, pointing at the thing to press. It stops after
     three, because a control that never settles reads as an error. */
  .choice-wrap.unheard .hear:not(.slow) { animation: hearpulse 1.6s ease-out 3; }
  @keyframes hearpulse {
    0%, 100% { transform: scale(1); }
    12%      { transform: scale(1.12); }
    24%      { transform: scale(1); }
  }
}
.choice .l1 { display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap; }
.choice .l1 .dev { font-size: 15px; color: var(--accent); font-weight: 500; }

.qprev { width: auto; margin: 0 0 10px; }

.lesson-hero { text-align: center; padding: 6px 0 0; }
.lesson-hero .e { font-size: 40px; display: block; margin-bottom: 10px; }
.lesson-points {
  text-align: left; background: var(--surface); border: 1px solid var(--line);
  border-radius: 14px; padding: 16px; margin-top: 18px;
}
.lesson-points b { font-size: 14.5px; }
.lesson-points ul { margin: 10px 0 0; padding-left: 18px; }
.lesson-points li { font-size: 14px; color: var(--ink-dim); margin-bottom: 6px; }

/* A slim fill under the quiz's existing "N/total" counter — reuses the same
   fill colour as a topic tile's own progress bar. */
.qbar { height: 4px; background: var(--surface-2); border-radius: 2px; overflow: hidden; }
.qbar > i { display: block; height: 100%; background: var(--brand-orange); border-radius: 2px; transition: width .3s; }

/* A test runs as two announced parts (see inParts in app.js): one card before
   each, and a banner on every question so the part is still visible once the
   card has been read and dismissed. */
.part-card {
  background: var(--accent-soft); border: 1px solid var(--line);
  border-radius: 16px; padding: 22px 18px; margin: 6px 0 16px; text-align: center;
}
.part-kicker {
  font-size: 12.5px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--accent);
}
.part-card h2 { margin: 8px 0 0; font-size: 20px; line-height: 1.3; }
.part-how { margin: 10px 0 0; font-size: 14.5px; color: var(--ink-dim); line-height: 1.5; }
.part-card .c-hi, .part-tag .c-hi { display: block; }
.part-tag {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  font-size: 12.5px; color: var(--ink-faint); margin-bottom: 6px;
}
.part-tag b { color: var(--accent); }

.pat.try-it { border-left-color: var(--good); }

/* Alternating turns. `them` is always visible; `you` starts blurred behind a
   reveal overlay so the learner tries the line before checking it. */
.convo { display: flex; flex-direction: column; gap: 10px; }
.bubble {
  position: relative; border-radius: 14px; padding: 10px 12px;
  border: 1px solid var(--line); background: var(--surface);
}
.bubble.them { margin-right: 15%; }
.bubble.you { margin-left: 15%; background: var(--accent-soft); }
.bubble .who {
  display: block; font-size: 10.5px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-faint); margin-bottom: 2px;
}
.bubble-row { display: flex; align-items: center; gap: 6px; }
.bubble .pb-main { padding: 3px 2px; flex: 1; min-width: 0; }
.bubble .convo-tick { flex: none; }
.bubble.blank .preview { font-size: 13px; color: var(--ink-dim); margin: 8px 0 10px; min-height: 1em; }
.bubble .pb-main.ref { opacity: .8; }

/* ---------- sounds first ---------- */
.snd-tiles { grid-template-columns: 1fr 1fr; }
.snd-tile { min-height: 84px; }
.snd-t-letter {
  display: block; font-size: 28px; line-height: 1; margin-bottom: 6px;
  color: var(--brand-ink); font-weight: 700;
}
:root[data-theme="dark"] .snd-t-letter { color: var(--accent); }
.snd-tile.done { border-color: var(--good); }
.snd-tile .pill.done { position: absolute; top: 10px; right: 10px; }

.snd-hero { text-align: center; padding: 6px 0 4px; }
.snd-letter {
  font-size: 76px; line-height: 1.05; color: var(--brand-ink); font-weight: 700;
}
:root[data-theme="dark"] .snd-letter { color: var(--accent); }
.snd-hindi { font-size: 15px; color: var(--ink-dim); margin-top: 2px; }
.snd-hindi b { font-size: 19px; color: var(--ink); }
.snd-who { font-size: 14.5px; line-height: 1.5; margin: 10px 0 14px; }

/* The letters carrying the sound. Underlined as well as coloured, so it still
   reads when the colour does not — on a dim screen, or to a colour-blind eye. */
.rf {
  font-style: normal; color: var(--brand-red);
  text-decoration: underline; text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}
:root[data-theme="dark"] .rf { color: #ff8a7a; }

/* Support and feedback, above the fold rather than below a list nobody
   finishes. A quiet row: two underlined links, no card, no colour. */
.give {
  display: flex; gap: 18px; justify-content: center;
  margin: -4px 0 16px;
}
.give .linky { width: auto; margin: 0; padding: 4px 0; }

/* End-of-page links. Quiet, centred, and genuinely at the end — this sat
   between the progress card and the first lesson once, which is the one place
   on the screen it had no business being. */
.give-end { margin: 22px 0 4px; }
.no-hit { text-align: center; padding: 24px 0 8px; }
.no-hit .linky { margin-top: 2px; }

/* Say-it-yourself pairs. No audio: a Kannada voice cannot read Devanagari, and
   the point is to hear the sound in your own mouth, in a word you already own. */
.aloud { padding: 14px 16px; }
.aloud-h { margin: 0 0 10px; font-size: 12.5px; color: var(--ink-faint); }
.aloud-row {
  display: flex; align-items: baseline; gap: 12px;
  padding: 7px 0; border-top: 1px solid var(--line);
}
.aloud-say { font-size: 19px; font-weight: 700; min-width: 54px; }
.aloud-hi { font-size: 20px; color: var(--brand-ink); min-width: 74px; }
:root[data-theme="dark"] .aloud-hi { color: var(--accent); }
.aloud-en { font-size: 12.5px; color: var(--ink-faint); flex: 1; }

/* The letter is a button: people tap the big glyph, so it had better do
   something. It plays the letter alone — the sound with nothing around it. */
button.snd-letter {
  background: none; border: 0; cursor: pointer; padding: 0;
  display: block; margin: 0 auto;
}
.snd-tap { font-size: 12px; color: var(--ink-faint); margin-top: 2px; }

/* The two letters alone, side by side — the one comparison the whole lesson is
   about, so they get equal weight and sit as a pair rather than a list. */
.pair-row { display: flex; gap: 10px; }
.pair-side {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 12px 6px; border: 1px solid var(--line); border-radius: 12px;
  background: var(--card); cursor: pointer; font: inherit; text-align: center;
}
.pair-side:active { background: var(--line); }
.pair-letter { font-size: 40px; line-height: 1.1; color: var(--brand-ink); font-weight: 700; }
:root[data-theme="dark"] .pair-letter { color: var(--accent); }
.pair-ro { font-size: 16px; font-weight: 700; }
.pair-tag {
  font-size: 11px; letter-spacing: .04em; text-transform: uppercase;
  color: var(--ink-faint); margin-top: 3px;
}


/* The build id, top of the Learn screen. Quiet enough to ignore and specific
   enough to answer "did my change reach the phone?" without opening Settings. */
.buildline {
  margin: -6px 0 10px; font-size: 11px; color: var(--ink-faint);
  letter-spacing: .02em; text-align: right;
}
.buildline b { color: var(--accent); font-weight: 600; cursor: pointer; }


/* ---------- tutor ---------- */

/* A voice, not a banner: quiet, indented like speech, and never occupying the
   space the lesson itself needs. Off entirely unless Settings turns it on. */
.tutor-say {
  display: flex; align-items: flex-start; gap: 9px;
  background: var(--accent-soft); border: 1px solid var(--line);
  border-radius: 14px; padding: 10px 13px; margin: 0 0 14px;
}
.tutor-face { font-size: 19px; line-height: 1.2; flex: none; }
.tutor-text { font-size: 14px; line-height: 1.4; color: var(--ink-dim); }
/* Finishing something is worth a warmer colour than a running remark. */
.tutor-say.step, .tutor-say.done {
  background: color-mix(in srgb, var(--good) 12%, var(--surface));
  border-color: color-mix(in srgb, var(--good) 35%, var(--line));
}
.tutor-say.done .tutor-text { font-weight: 650; color: var(--ink); }
.tutor-say.wrong {
  background: var(--surface-2);
}

/* ---------- bilingual instructions ---------- */

/* English above, Hindi under it, so a reader who needs the Hindi is not
   reading past an English sentence to find it. The two are separate elements
   rather than one string so a Hindi-only mode can hide the English outright. */
.c-hi { display: block; margin-top: 2px; }
/* Inside a button both lines sit centred, the Hindi a touch smaller — the
   button is one action, not two. */
.btn .c-hi { font-size: .88em; opacity: .85; }
.gate-hint .c-hi, .faint .c-hi { color: var(--ink-faint); }
.try-hi { display: block; font-size: .8em; color: var(--ink-dim); margin-top: 3px; font-weight: 500; }
.listen-hint .c-hi, .counter .c-hi { display: block; }

/* The letters are tappable too — say so, and tick them like every other row. */
.heard-mark { display: block; font-size: 12px; margin-top: 4px; line-height: 1; }
button.snd-letter .heard-mark { font-size: 14px; margin-top: 2px; }
/* An option that cannot be chosen yet, because its recording is unplayed. */
.snd-choice:disabled { opacity: .45; }
.choice-wrap .snd-choice { text-align: center; color: var(--ink-faint); }
.choice-wrap .snd-choice.ready { color: var(--ink); font-weight: 600; }

/* Where you are and who is talking. A conversation only teaches if it is
   clear who says these words to whom. */
.scene {
  background: var(--surface); border: 1px solid var(--line);
  border-left: 3px solid var(--brand); border-radius: 12px;
  padding: 11px 13px; margin: 0 0 12px;
}
.scene-k {
  display: block; font-size: 10.5px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-faint); margin-bottom: 3px;
}
.scene p { margin: 0; font-size: 14.5px; line-height: 1.45; color: var(--ink); }

/* Where one small exchange ends and the next begins. */
.beat { display: flex; align-items: center; gap: 10px; margin: 18px 2px 10px; }
.beat:first-child { margin-top: 2px; }
.beat::before, .beat::after { content: ''; flex: 1; height: 1px; background: var(--line); }
.beat span {
  font-size: 10.5px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--ink-faint); text-align: center;
}
.beat .c-hi { display: block; text-transform: none; letter-spacing: 0; font-weight: 600; }

/* ---------- opposite pairs ---------- */

/* The pair is the unit of teaching, so it is the unit on screen: two halves
   of one row, with the arrow between them saying what they are to each other. */
.opp-pair {
  display: flex; align-items: stretch; gap: 8px; margin-bottom: 9px;
}
.opp-half {
  flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 13px;
  padding: 11px 12px; text-align: left; cursor: pointer;
}
.opp-half:active { background: var(--surface-2); }
.opp-half.done { border-color: color-mix(in srgb, var(--good) 40%, var(--line)); }
/* The half stopped being one big button when it grew a turtle and a
   breakdown, so the tap target is now the text block and the controls sit
   under it. Under, not beside: a half is half a phone wide, and a 46px
   turtle taken off the side of "Ninna hesaru yenu?" wraps it to four lines. */
.opp-main {
  display: flex; flex-direction: column; gap: 2px; width: 100%;
  background: none; border: 0; padding: 0; margin: 0;
  font: inherit; color: inherit; text-align: left; cursor: pointer;
}
/* Both controls as icons on one line: half a phone is not wide enough for a
   turtle AND a spelled-out "Break it down", and the pair of them stacked took
   two lines off every card before a word of Kannada. */
.opp-acts { display: flex; align-items: center; gap: 6px; margin-top: 8px; }
/* Smaller than the one on a full-width row, which would be a third of a half. */
.opp-acts .pb-slow { min-width: 40px; min-height: 34px; font-size: 15px; }
/* The beats get the whole width of the half and still have to fit four of
   them — he-gid-dee-raa is wider than this card at the size a full-width row
   uses, and it ran off the edge, question mark and all. Smaller here, and
   free to break mid-word rather than overflow: a wrapped word is still
   readable, and a word half off the card is not. */
.opp-half .chunks { margin: 9px 0 0; gap: 3px; }
.opp-half .chunks .cw { flex-wrap: wrap; }
.opp-half .chunks .beat { padding: 3px 6px; font-size: 14.5px; }
.opp-ro { font-size: 16px; font-weight: 650; line-height: 1.2; }
/* The one word that differs between two halves of a sentence pair. Underline
   rather than colour: the retroflex capitals already own colour here, and two
   colours in one word would be competing for the same glance. */
.pair-diff {
  text-decoration-thickness: 2px; text-underline-offset: 3px;
  text-decoration-color: var(--accent);
}
.opp-en { font-size: 12.5px; color: var(--ink-dim); }
.opp-hi { font-size: 12.5px; color: var(--ink-faint); }
.opp-half .heard-mark { margin-top: 4px; }
.opp-half.done .heard-mark { color: var(--good); }
.opp-vs {
  flex: none; align-self: center; font-size: 15px; color: var(--ink-faint);
}

/* Age band chips on the setup screen. */
.band-row { display: flex; flex-wrap: wrap; gap: 7px; margin: 4px 0 0; }
.band-row .chip { flex: 1 1 30%; min-width: 88px; padding: 10px 8px; font-size: 13.5px; }
.band-row .chip .c-hi { display: block; font-size: .85em; opacity: .8; }

/* ---- pronunciation beats: na-mas-kaa-ra ---- */

/* Wraps rather than scrolls. A five-beat phrase at xl text does not fit a
   phone on one line, and a line that scrolls sideways inside a card that does
   not is a thing nobody finds. */
.chunks {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px 4px;
  margin: 10px 0;
}
/* `hidden` is a UA rule, and ANY author `display` beats it — so the line above
   quietly cancelled the attribute the markup sets and the beats were never
   hidden at all. It looked correct everywhere it was nested inside something
   else already hidden, which was everywhere until a pair half put it on the
   card itself: four syllables of a word nobody had asked to take apart. */
.chunks[hidden] { display: none; }
.chunks .cw { display: inline-flex; align-items: center; }
/* Two different things are called "beat": a conversation's divider (.beat,
   with margins and drawn rules either side) and a breakdown's syllable
   (.chunks .beat). The divider's margin and rules leaked onto the syllables,
   sitting them 13px below their own "?" (13 Oct, on "Hegiddeera?"). */
.chunks .beat { margin: 0; }
.chunks .beat::before, .chunks .beat::after { content: none; }
.chunks .pt { align-self: center; }
.chunks .cw.plain { color: var(--ink-faint); padding: 4px 2px; }

/* A beat is a button, but it should read as part of a word, not as four
   controls in a row — so the border only arrives when it is doing something. */
.chunks .beat {
  font: inherit;
  font-weight: 600;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  padding: 4px 7px;
  border: 1px solid transparent;
  border-radius: 7px;
  background: var(--surface-2);
  color: inherit;
  cursor: pointer;
  transition: background .12s, color .12s, border-color .12s;
}
.chunks .beat .bd { font-size: .82em; font-weight: 500; opacity: .75; }
.chunks .beat:active { background: var(--line); }

/* The beat being spoken. Colour AND weight, never colour alone — this is the
   one moment the screen is telling a learner where they are in a word, and
   some of them are reading it at arm's length in daylight. */
.chunks .beat.on {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
}
.chunks .beat.on .bd { opacity: .95; }

.chunks .dash { opacity: .45; padding: 0 1px; }
.chunks .wdot { opacity: .5; padding: 0 5px; font-weight: 600; }
.chunks .pt { opacity: .6; }

/* Two controls side by side in an opened row, wrapping on a narrow screen
   rather than squeezing each other. */
/* Side by side, not stacked. `.pb-more .btn.slim` forces full width, which
   predates there being two of them — inside this row they share it. */
.row-acts { display: flex; flex-wrap: wrap; gap: 8px; }
.row-acts .btn.slim { width: auto; flex: 1 1 auto; }
.phrase .brk { margin-top: 10px; }

@media (prefers-reduced-motion: reduce) {
  .chunks .beat { transition: none; }
}

/* The lesson's promise, above the inventory of what is in it. Tinted so it
   reads as a claim rather than as another list — it is the one thing on the
   page arguing for starting. */
.lesson-outcome {
  margin-top: 14px;
  padding: 12px 14px;
  border-left: 3px solid var(--accent);
  border-radius: 0 10px 10px 0;
  background: var(--surface-2);
}
.lesson-outcome b { font-size: 13px; letter-spacing: .02em; color: var(--ink-dim); }
.lesson-outcome p { margin: 5px 0 0; font-size: 15px; line-height: 1.5; }

/* Group headings on the Words step. Quiet — they separate two kinds of word,
   they are not a second title competing with the step's own. */
.words-head {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .03em;
  text-transform: uppercase;
  color: var(--ink-dim);
  margin: 18px 0 8px;
}
.words-head:first-of-type { margin-top: 6px; }
.words-head span {
  display: block;
  font-size: 12.5px;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-faint);
  margin-top: 2px;
}

/* "optional" beside a Try-it heading. A quiet aside, not a second heading —
   it is telling you that you may skip, which should not shout. */
.try-it b .opt {
  margin-left: 7px;
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: .02em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* ---- listen question: options shut until the clip has played ---- */

/* Visibly waiting, not broken. Not so faint they cannot be read, because
   reading the options while the Kannada plays is half of what the question
   is asking you to do. */
.choice[disabled] { opacity: .55; }
/* A judged option is not a waiting one: once it is red or green, that colour
   is the message and must not be dimmed along with the rest. */
.choice.wrong[disabled], .choice.right[disabled] { opacity: 1; }

.listen-first {
  margin: 2px 0 10px;
  font-size: 13.5px;
  color: var(--ink-faint);
  text-align: center;
}

/* ---- the Finish step ---- */

.finish-card { text-align: center; padding: 18px 16px 4px; }
.finish-card .big { font-size: 40px; line-height: 1; }
.finish-card h2 { font-size: 19px; margin: 10px 0 0; }

.fin-ask { margin-top: 16px; }
.fin-ask > b { font-size: 15px; }

/* One row per option rather than five across: at xl text five labels do not
   fit a phone, and a rating scale that wraps mid-word is unreadable. Each row
   is a full-width tap target, which is also the easier thing to hit. */
.rate { display: flex; flex-direction: column; gap: 2px; margin: 10px 0 12px; }
.rate-opt {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border-radius: 9px;
  cursor: pointer;
}
.rate-opt:has(input:checked) { background: var(--surface-2); font-weight: 600; }
.rate-opt input { width: 19px; height: 19px; accent-color: var(--accent); flex: none; }

.fin-comment {
  width: 100%;
  font: inherit;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface);
  color: inherit;
  resize: vertical;
  box-sizing: border-box;
}

.fin-mission { margin-top: 14px; border-left: 3px solid var(--accent); }
.fin-mission b { font-size: 13px; letter-spacing: .02em; text-transform: uppercase; color: var(--ink-dim); }
.fin-mission p { margin: 6px 0 0; font-size: 15px; line-height: 1.55; }

/* A segment you can jump to. Only some are: finished steps and the one you
   are on, plus Start — a bar that let you skip to an unvisited step would
   walk straight past the gate that step is built around. */
.step-bar .seg[data-go] { cursor: pointer; }
.step-bar .seg[data-go]:active i { filter: brightness(.92); }
.step-bar .seg[data-go] span { text-decoration: underline; text-decoration-color: transparent; }
.step-bar .seg[data-go]:active span { text-decoration-color: currentColor; }

/* The whole word, while it is being said after its own beats. Its beats are
   lit together, and the word gets a quiet ground so it reads as one thing
   rather than as several that happen to be highlighted at once. */
.chunks .cw.said {
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  border-radius: 9px;
}

/* ---------------- scratch cards ---------------- */

/* A won card, waiting to be opened, on the home screen. It is a strip rather
   than a hero: it is a nice thing, not the thing the learner came for, and a
   full card at the top of home pushes the lessons below the fold. */
.card-tray {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
  border: 1px solid var(--ring);
  background: linear-gradient(100deg,
    color-mix(in srgb, var(--ring) 10%, var(--surface)), var(--surface) 62%);
  border-radius: 14px;
  padding: 12px 14px;
  margin-bottom: 14px;
}
.card-tray .tray-foil {
  flex: none;
  width: 34px; height: 46px;
  border-radius: 5px;
  background: linear-gradient(145deg, #8d9299, #eef1f4 40%, #a8adb4 70%, #d7dbe0);
  box-shadow: 0 1px 3px rgba(0,0,0,.28);
}
.card-tray.rare .tray-foil { background: linear-gradient(145deg, #9c7318, #f0d98b 40%, #b98f24 70%, #e6c25c); }
.card-tray b { display: block; font-size: 15px; }
.card-tray span { font-size: 13px; color: var(--ink-dim); }
.card-tray .tray-go { margin-left: auto; font-size: 20px; color: var(--ink-faint); flex: none; }

/* The scratch screen. Centred, and short enough that the card does not need
   scrolling — the foil swallows vertical drags (touch-action: none, below),
   so a card you have to scroll to see is a card you cannot scroll past. */
.scr-screen { text-align: center; padding: 4px 0 24px; }
.scr-screen .scr-lead { margin: 2px 0 16px; color: var(--ink-dim); font-size: 15px; }
.scr-screen .scr-kicker {
  font-size: 12px; letter-spacing: .09em; text-transform: uppercase;
  color: var(--ring); font-weight: 700; margin: 0;
}

.scr-holder { display: flex; justify-content: center; }
.scr-card {
  position: relative;
  width: min(100%, 320px);
  border-radius: 16px;
  overflow: hidden;
  box-shadow: 0 10px 30px rgba(0,0,0,.26), 0 2px 6px rgba(0,0,0,.18);
  /* Tilted, and straightening as it opens. A card square to the screen is a
     panel in the layout; four degrees off makes it an object someone put
     there, which is most of what "surprise" costs here. */
  transform: rotate(-3.5deg);
  transition: transform .5s cubic-bezier(.22,1.2,.36,1);
}
.scr-card.open { transform: rotate(0deg); }
.scr-art { display: block; width: 100%; height: auto; }

.scr-foil {
  position: absolute;
  top: 0; left: 0;
  width: 100%;
  /* The scratch has to win the gesture. Without this the first drag scrolls
     the page and nothing is scratched, which reads as the card being dead. */
  touch-action: none;
  cursor: grab;
  transition: opacity .45s ease;
}
.scr-card.open .scr-foil { opacity: 0; }

/* One pass of light across the picture as it opens, then never again. */
.scr-sheen { position: absolute; inset: 0; pointer-events: none; opacity: 0; }
.scr-card.open .scr-sheen {
  background: linear-gradient(104deg, transparent 38%, rgba(255,255,255,.55) 50%, transparent 62%);
  animation: scr-sweep .75s ease-out .12s 1 both;
}
@keyframes scr-sweep {
  from { opacity: 1; transform: translateX(-62%); }
  to   { opacity: 0; transform: translateX(62%); }
}

/* Dropped onto the table rather than drawn on the screen. */
.scr-card.arrive { animation: scr-drop .52s cubic-bezier(.18,.9,.3,1.1) both; }
@keyframes scr-drop {
  from { opacity: 0; transform: translateY(-16px) rotate(-11deg) scale(.93); }
  to   { opacity: 1; transform: translateY(0) rotate(-3.5deg) scale(1); }
}

.scr-acts { display: flex; flex-direction: column; gap: 8px; margin-top: 18px; }
.scr-acts .btn { width: 100%; }
.scr-note { font-size: 13px; color: var(--ink-faint); margin: 12px 0 0; }

/* Everything above is decoration over a picture that is already there. With
   motion turned down the card simply is where it is, un-tilted, and the foil
   goes without a fade — the reveal still happens, it just does not perform. */
@media (prefers-reduced-motion: reduce) {
  .scr-card, .scr-card.arrive { transform: none; animation: none; transition: none; }
  .scr-foil { transition: none; }
  .scr-card.open .scr-sheen { animation: none; }
}

/* The collection. Three across on a phone: the artwork is portrait and tall,
   so two would push the second row off the screen and four would make each
   one unreadable. */
.card-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  margin-bottom: 18px;
}
.cg-item {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 1086 / 1448;   /* the artwork's own, so nothing is cropped */
  padding: 0;
  border: 0;
  border-radius: 10px;
  overflow: hidden;
  background: var(--surface-2);
  box-shadow: 0 2px 6px rgba(0,0,0,.18);
  cursor: pointer;
}
/* Cropped from the TOP, not the middle. The deck is not all one shape — some
   artwork is 3:4 and some 1:2 — so a tile always crops something. Taking it
   off the bottom keeps the photograph and the name, which is what makes a
   thumbnail recognisable; centring it cut the title in half and left a band
   of body text that reads as nothing at this size. */
.cg-item img {
  width: 100%; height: 100%; display: block;
  object-fit: cover;
  object-position: top;
}

/* A slot still to be filled. Foil, like the unscratched card — the same
   surface, so the grid reads as "these are all cards, some are covered"
   rather than as a mix of pictures and empty boxes. */
.cg-item.locked {
  cursor: default;
  background: linear-gradient(145deg, #8d9299, #d7dbe0 40%, #a8adb4 70%, #eef1f4);
  color: rgba(0,0,0,.34);
  font-size: 22px;
  font-weight: 700;
}
.cg-item.locked.rare { background: linear-gradient(145deg, #9c7318, #e6c25c 40%, #b98f24 70%, #f0d98b); }

/* One card, full size, in a sheet. */
.cg-full { display: block; width: 100%; height: auto; border-radius: 12px; }

/* ---------- sign-in (redesigned 12 Oct, from Bhaskar's mock-up) ----------
   A picture of the city behind a serif headline, then a taste of Kannada with
   the app's own tools, then one card with the ways in. The hero image is
   brand/hero.jpg when it exists; until then a warm sky-and-sunlight gradient. */
.login { max-width: 480px; margin: 0 auto; padding-bottom: 0; }
.login-hero { position: relative; margin: -12px -16px 0;
  /* The hero is pulled up 12px to meet the top edge, so its own top padding
     has to cover that, plus a notch's safe area -- at 10px the logo's circle
     was clipped at the top (13 Oct). */
  padding: calc(22px + env(safe-area-inset-top, 0px)) 20px 34px;
  /* A wash over the sky's top-left so the navy headline reads on the light;
     the building and the flowers stay clear below it. */
  background: linear-gradient(90deg, rgba(255,250,236,.55) 0%, rgba(255,250,236,0) 72%),
    linear-gradient(180deg, rgba(255,250,236,.72) 0%, rgba(255,250,236,.45) 38%, rgba(255,250,236,0) 62%),
    url("brand/hero.jpg") center 58% / cover no-repeat,
    linear-gradient(180deg, #fbe7b5 0%, #fdf1d6 45%, #f6e7c4 100%);
  border-radius: 0 0 50% 50% / 0 0 26px 26px; color: #12204f; overflow: hidden; }
.login-logo { width: 54px; height: 54px; display: block; margin: 0 auto 6px; border-radius: 50%;
  box-shadow: 0 6px 18px rgba(0,0,0,.14); }
.login-hero h1 { font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  font-size: 27px; line-height: 1.06; margin: 0 0 6px; color: #12204f; letter-spacing: -.01em; font-weight: 700; }
.login-hero .brush { white-space: nowrap; padding: 0 2px;
  /* A painted stroke under the last word, drawn as the span's own background
     so nothing can stack in front of it. */
  background: linear-gradient(176deg, transparent 0 74%, #F2B51C 74% 90%, transparent 90%) no-repeat;
  background-size: 108% 100%; background-position: -2px 0; }
.login-sub { font-size: 14px; line-height: 1.38; margin: 0; color: #1f1d29; max-width: 250px;
  text-shadow: 0 0 10px rgba(255,250,236,.95), 0 0 2px rgba(255,250,236,.9); }
.login-script { font-family: "Bradley Hand", "Segoe Script", "Snell Roundhand", cursive; font-size: 15px;
  color: #6b5034; margin: 4px 0 0 4px; transform: rotate(-6deg); display: inline-block; }
.login-k { font-size: 12px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
  color: var(--ink-dim); margin: 0; }
.login-hear { margin: 10px 0 10px; }
.hear-head { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; margin-bottom: 6px; white-space: nowrap; }
.hear-hint { font-size: 12.5px; color: var(--ink-faint); text-align: right; }
.hear-row { background: var(--surface); border: 1px solid var(--line); border-radius: 12px; padding: 5px 8px 5px 10px;
  margin-bottom: 5px; }
.hear-main { display: flex; align-items: center; gap: 12px; }
.hear-play { width: 30px; height: 30px; border-radius: 50%; border: 0; background: #D32F2F; color: #fff;
  font-size: 15px; flex: none; padding-left: 3px; }
.hear-t { flex: 1; min-width: 0; display: flex; flex-direction: column; font-size: 15px; line-height: 1.2; }
.hear-t span { font-size: 13px; color: var(--ink-dim); }
.hear-tools { display: flex; gap: 2px; flex: none; }
.hear-tools button { display: flex; flex-direction: column; align-items: center; gap: 2px; border: 0; background: none;
  padding: 2px 2px; color: var(--ink-dim); min-width: 38px; }
.hear-tools i { width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center; font-style: normal;
  font-size: 16px; background: var(--surface-2); border: 1px solid var(--line); }
.hear-tools .hi-ic { font-size: 15px; font-weight: 700; color: #12204f; }
.hear-tools small { font-size: 10px; white-space: nowrap; }
.hear-row .chunks { margin-top: 10px; }
.hear-hi { font-size: 13.5px; color: #12204f; margin-top: 1px; }
.login-card { padding: 12px 16px 16px; }
.login-card h2 { font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  font-size: 22px; text-align: center; margin: 0; color: #12204f; }
.login-cardsub { text-align: center; color: var(--ink-dim); font-size: 14px; margin: 2px 0 12px; }
.login-card label { font-size: 14px; }
.login-g { display: flex; justify-content: center; min-height: 44px; margin-bottom: 4px; }
.ifield { position: relative; margin: 6px 0 12px; }
.ifield .search { margin: 0; padding-left: 42px; font-size: 16px; }
.ifield .ii { position: absolute; left: 14px; top: 50%; transform: translateY(-50%); font-size: 17px; color: var(--ink-faint); }
.ifield .eye { position: absolute; right: 8px; top: 50%; transform: translateY(-50%); border: 0; background: none;
  font-size: 18px; padding: 6px; color: var(--ink-dim); }
.pin-in { letter-spacing: .5em; }
.pin-head { display: flex; justify-content: space-between; align-items: baseline; }
.pin-head .linky { font-size: 15px; }
.btn-yellow { background: #FFCF31 !important; color: #12204f !important; font-size: 16px; padding: 13px 18px; }
.login-card .btn { font-size: 16px; }
/* Four boxes for the PIN: a digit shows as it is typed, then becomes a dot
   (12 Oct -- the eye toggle did not work on phones). Masked with
   text-security per box, so the value itself is never rewritten. */
.pin-boxes { display: flex; gap: 10px; margin: 6px 0 12px; }
.pin-boxes input { width: 100%; min-width: 0; height: 50px; text-align: center; font-size: 22px; font-weight: 600;
  border: 1px solid var(--line); border-radius: 12px; background: var(--surface); color: var(--ink); padding: 0; }
.pin-boxes input:focus { outline: 2px solid #F2B51C; border-color: #F2B51C; }
.pin-boxes input.masked { -webkit-text-security: disc; text-security: disc; }
.login-or { display: flex; align-items: center; gap: 14px; margin: 12px 4px; color: var(--ink-dim);
  font-size: 15px; font-weight: 600; text-transform: uppercase; letter-spacing: .1em; }
.login-or::before, .login-or::after { content: ''; flex: 1; height: 1.5px; background: var(--line); }
.login-note { text-align: center; font-size: 12.5px; color: var(--ink-faint); margin: 10px 8px 0; line-height: 1.4; }
.skyline { display: block; width: calc(100% + 32px); margin: 12px -16px 0; height: 56px; color: #e2bf6a; }
/* The tab bar's own display rule beat the hidden attribute, so the tabs
   stayed on the sign-in page; hidden has to win. */
#tabs[hidden] { display: none !important; }

/* Footer links with their icons, and the app marks on "Share this app". */
.foot-l { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; width: auto !important; }
/* Whole links wrap, never the words inside one: "Share this app with
   friends" broke over five lines in a four-across row (13 Oct). */
.give.give-end { display: flex !important; flex-wrap: wrap; justify-content: center; gap: 10px 20px; }
.foot-l svg { flex: none; opacity: .85; }
.share-app-btn { display: flex; align-items: center; justify-content: center; gap: 10px; flex-wrap: wrap; }
.app-marks { display: inline-flex; gap: 4px; }
.app-marks i { width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center; }

/* The policy pages inside the app (viewLegal) -- the same file as /privacy,
   restyled to sit in the shell. */
.legal-nav { display: flex; gap: 8px; flex-wrap: wrap; margin: 0 0 12px; }
.legal-nav .chip { text-decoration: none; }
.legal-nav .chip.on { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.legal-doc { font-size: 15px; line-height: 1.6; }
.legal-doc h2 { font-size: 17px; margin: 22px 0 6px; }
.legal-doc .updated { color: var(--ink-dim); font-size: 13px; margin: 0 0 12px; }
.legal-doc table { border-collapse: collapse; width: 100%; font-size: 14px; }
.legal-doc th, .legal-doc td { text-align: left; border-bottom: 1px solid var(--line); padding: 8px 4px; vertical-align: top; }
.legal-doc ul { padding-left: 20px; }
.legal-doc a { color: var(--accent); }

/* Add to home screen (install.js): one dismissible line on Home. */
.install-card { display: flex; align-items: center; gap: 8px; background: var(--surface);
  border: 1px solid var(--line); border-radius: 14px; padding: 10px 12px; margin-bottom: 12px; }
.install-go { flex: 1; display: flex; align-items: center; gap: 12px; background: none; border: none;
  padding: 0; text-align: left; color: inherit; font: inherit; }
.install-go > span:first-child { font-size: 22px; }
.install-go b { display: block; font-size: 15px; }
.install-go span span { display: block; font-size: 12.5px; color: var(--ink-dim); }
.install-x { background: none; border: none; color: var(--ink-dim); font-size: 16px; padding: 6px; }
.install-steps { padding-left: 22px; line-height: 1.7; }
.install-steps li { margin-bottom: 6px; }

/* A discount (pricing.js): the offer line above the plan, the old price struck. */
.choice.plan .offer { grid-column: 1; font-size: 12px; font-weight: 800; letter-spacing: .06em;
  text-transform: uppercase; color: var(--good, #2e7d32); }
.choice.plan .price s { font-size: 15px; font-weight: 500; color: var(--ink-dim); margin-right: 4px; }
.choice.plan:has(.offer) .price { grid-row: 1 / span 3; }

/* The unlock page (viewPaywall): outcomes and benefits, then the price. */
.pw-hero { background: linear-gradient(135deg, var(--navy, #12204f), #2a3f8f); color: #fff;
  border-radius: 18px; padding: 20px 18px; margin-bottom: 18px; }
.pw-kicker { font-size: 11px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; opacity: .8; }
.pw-hero h2 { font-family: "Iowan Old Style", Palatino, Georgia, serif; font-size: 26px; line-height: 1.15; margin: 8px 0 8px; color: #fff; }
.pw-hero p { margin: 0; font-size: 14.5px; line-height: 1.5; opacity: .92; }
.pw-list { padding: 6px 14px; }
.pw-row { display: flex; gap: 12px; padding: 12px 0; border-bottom: 1px solid var(--line); }
.pw-row:last-child { border-bottom: none; }
.pw-ico { flex: none; width: 34px; height: 34px; border-radius: 10px; background: var(--surface-2);
  display: flex; align-items: center; justify-content: center; font-size: 18px; font-weight: 700; color: var(--accent); }
.pw-row b { display: block; font-size: 15px; }
.pw-row p { margin: 2px 0 0; font-size: 13.5px; line-height: 1.45; color: var(--ink-dim); }
.pw-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.pw-chips .chip { font-size: 13px; }
.pw-price { text-align: center; background: var(--surface); border: 2px solid var(--accent);
  border-radius: 18px; padding: 18px 16px 14px; margin: 22px 0 12px; }
.pw-offer { display: inline-block; background: var(--good, #2e7d32); color: #fff; font-size: 12px; font-weight: 800;
  letter-spacing: .06em; text-transform: uppercase; border-radius: 999px; padding: 4px 12px; margin-bottom: 8px; }
.pw-amt { display: flex; align-items: baseline; justify-content: center; gap: 10px; }
.pw-amt s { font-size: 18px; color: var(--ink-dim); }
.pw-amt b { font-size: 40px; font-weight: 800; color: var(--ink); letter-spacing: -0.02em; }
.pw-terms { font-size: 13px; color: var(--ink-dim); margin: 2px 0 14px; }
.pw-buy { width: 100%; font-size: 17px; }
.pw-trust { display: flex; flex-direction: column; gap: 4px; font-size: 13px; color: var(--ink-dim); margin: 12px 0 6px; }

.pw-quick { display: flex; align-items: center; justify-content: space-between; width: 100%; margin-top: 14px;
  background: #fff; color: var(--navy, #12204f); border: none; border-radius: 12px; padding: 11px 14px; font: inherit; font-size: 15px; }
.pw-quick s { opacity: .55; font-size: 13px; }
.pw-quick-go { font-weight: 800; }
.pw-quick > span { white-space: nowrap; text-align: left; }
