/* ==========================================================================
   components.css — shared controls: buttons, chips, inputs, overlays,
   player bar, skeletons, panels, charts. Fourth load.
   Touch-target contract (test-gated): standalone controls ≥44px; dense
   inline targets expand their hit area via ::after.
   ========================================================================== */

/* ==========================================================================
   1. Buttons
   ========================================================================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--touch-target);
  padding: var(--space-2) var(--space-5);
  border-radius: var(--radius-md);
  border: 1px solid transparent;
  font-size: var(--fs-sm);
  font-weight: 600;
  line-height: 1.2;
  white-space: nowrap;
  cursor: pointer;
  transition:
    background-color var(--dur-base) var(--ease-standard),
    border-color var(--dur-base) var(--ease-standard),
    color var(--dur-base) var(--ease-standard),
    box-shadow var(--dur-base) var(--ease-standard),
    transform var(--dur-fast) var(--ease-standard);
}
.btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
  transform: none;
}

.btn--primary {
  /* (v5.1.0) subtle vertical gradient that only DARKENS toward the base —
     white text keeps its audited 4.5:1 on every palette — plus a 1px inset
     top highlight: the "primary action" reads molded, not flat. */
  background: linear-gradient(
    180deg,
    var(--color-primary),
    color-mix(in srgb, var(--color-primary) 92%, black)
  );
  color: var(--color-on-primary);
  box-shadow:
    var(--shadow-sm),
    inset 0 1px 0 rgba(255, 255, 255, 0.16);
}
.btn--primary:hover:not(:disabled) {
  background: linear-gradient(
    180deg,
    color-mix(in srgb, var(--color-primary) 94%, black),
    color-mix(in srgb, var(--color-primary) 86%, black)
  );
  box-shadow: var(--shadow-md);
  transform: translateY(-1px);
}
.btn--primary:active:not(:disabled) {
  transform: translateY(0);
}

.btn--secondary {
  background: var(--color-surface);
  border-color: var(--color-border-strong);
  color: var(--color-text);
  box-shadow: var(--shadow-sm);
}
.btn--secondary:hover:not(:disabled) {
  background: var(--color-surface-alt);
  border-color: var(--color-text-muted);
}

.btn--ghost {
  background: transparent;
  color: var(--color-primary-text);
}
.btn--ghost:hover:not(:disabled) {
  background: color-mix(in srgb, var(--color-primary) 10%, transparent);
}

.btn--danger {
  background: var(--color-danger);
  color: #ffffff;
}
.btn--danger:hover:not(:disabled) {
  background: color-mix(in srgb, var(--color-danger) 88%, black);
}

.btn--sm {
  min-height: var(--touch-target);
  padding: var(--space-1) var(--space-3);
  font-size: var(--fs-caption);
}

.btn-stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  align-items: stretch;
}

.link-btn {
  background: none;
  border: none;
  padding: var(--space-1) 0;
  min-height: 40px; /* v4.1: standalone controls hold a comfortable target */
  color: var(--color-primary-text);
  font-size: var(--fs-sm);
  font-weight: 600;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: color-mix(in srgb, var(--color-primary-text) 40%, transparent);
  transition: text-decoration-color var(--dur-base) var(--ease-standard);
}
.link-btn:hover {
  text-decoration-color: var(--color-primary-text);
}
.link-btn--sm {
  font-size: var(--fs-caption);
}

/* ==========================================================================
   2. Icon buttons
   ========================================================================== */
.icon-btn {
  position: relative;
  display: inline-grid;
  place-items: center;
  width: var(--touch-target);
  height: var(--touch-target);
  border-radius: var(--radius-md);
  color: var(--color-text-secondary);
  background: transparent;
  touch-action: manipulation; /* v4.1: no double-tap zoom on rapid taps */
  -webkit-tap-highlight-color: transparent;
  transition:
    background-color var(--dur-base) var(--ease-standard),
    color var(--dur-base) var(--ease-standard),
    transform var(--dur-fast) var(--ease-standard),
    box-shadow var(--dur-base) var(--ease-standard);
}
/* v4.1: "has bookmarks" indicator on the Mushaf topbar — the class shipped
   in markup with no rule, so the state was invisible. */
.icon-btn--badged::after {
  content: '';
  position: absolute;
  top: var(--space-1_5);
  inset-inline-end: var(--space-1_5);
  width: 8px;
  height: 8px;
  border-radius: var(--radius-pill);
  background: var(--color-accent-raw);
  box-shadow: 0 0 0 2px var(--color-surface);
}
.icon-btn:hover {
  background: var(--color-surface-alt);
  color: var(--color-text);
}
.icon-btn:active {
  transform: scale(0.94);
}
.icon-btn--sm {
  width: 36px;
  height: 36px;
}
.icon-btn--sm::after {
  content: '';
  position: absolute;
  inset-block: -6px;
  inset-inline: -6px;
}
.icon-btn--active {
  color: var(--color-primary-text);
  background: color-mix(in srgb, var(--color-primary) 12%, transparent);
}
.icon-btn--active-bell {
  color: var(--color-primary-text);
  background: color-mix(in srgb, var(--color-primary) 14%, transparent);
  box-shadow: var(--ring-primary);
}
.icon-btn--playing {
  color: var(--color-primary-text);
  background: color-mix(in srgb, var(--color-primary) 12%, transparent);
}
.icon-btn--play:hover {
  color: var(--color-primary-text);
}

/* The recite-follow chip-eye state. */
.icon-btn--recite-follow {
  color: var(--color-primary-text);
  background: color-mix(in srgb, var(--color-primary) 12%, transparent);
}

/* ==========================================================================
   3. Chips — hit-area expansion contract: relative + ::after ≥44px block
   ========================================================================== */
.chip {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1_5);
  padding: var(--space-1_5) var(--space-3);
  min-height: 40px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text-secondary);
  font-size: var(--fs-sm);
  font-weight: 500;
  line-height: 1.2;
  white-space: nowrap;
  cursor: pointer;
  /* Rapid-tap safety: no double-tap zoom, no text-selection callout, no
     gray tap flash on the filter chips people tap repeatedly. */
  touch-action: manipulation;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  transition:
    background-color var(--dur-base) var(--ease-standard),
    border-color var(--dur-base) var(--ease-standard),
    color var(--dur-base) var(--ease-standard),
    transform var(--dur-fast) var(--ease-standard);
}
.chip::after {
  content: '';
  position: absolute;
  inset-block: -6px;
  inset-inline: -3px;
}
.chip:hover {
  border-color: var(--color-border-strong);
  color: var(--color-text);
}

.chip--sm {
  padding: var(--space-1) var(--space-2);
  font-size: var(--fs-caption);
}
.chip--sm::after {
  inset-block: -6px;
  inset-inline: -2px;
}

.chip__count {
  font-size: var(--fs-caption);
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}
.chip__x {
  display: grid;
  place-items: center;
  position: relative;
  /* (v4.2) the × sits beside the filter chip people tap constantly — a
     bare glyph was a sub-16px target, well under the app's own 36px
     minimum. Same min-size as icon-btn--sm. */
  min-inline-size: 36px;
  min-block-size: 36px;
  margin-inline-start: var(--space-1);
  color: var(--color-text-muted);
}
/* (v5.2) 44px hit-area expansion, same documented .chip pattern: the
   visual stays a compact 36px × but the tap box reaches the token. */
.chip__x::after {
  content: '';
  position: absolute;
  inset-block: -4px;
  inset-inline: -4px;
}
.chip__x:hover {
  color: var(--color-danger-text);
}

.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-2);
}
/* (v5.2, U14) Settings table of contents: sticky section-jump chips so
   the 11-panel settings scroll stays navigable without memorization. */
.settings-toc {
  position: sticky;
  top: var(--topbar-height);
  z-index: var(--z-raised);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  padding-block: var(--space-2);
  background: var(--color-surface);
}
.view--settings .panel {
  scroll-margin-top: calc(var(--topbar-height) + var(--space-4));
}
.chip-row--scroll {
  flex-wrap: nowrap;
  overflow-x: auto;
  padding-bottom: var(--space-2);
  /* (v4.4) an inline-end fade that says "this strip scrolls" — clipped
     chips on the tasbih presets were read as cut-off buttons, not a
     scroller. Mask direction flips with document direction. */
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
  scroll-padding-inline-end: var(--space-2);
  scrollbar-width: none;
}
[dir='rtl'] .chip-row--scroll {
  -webkit-mask-image: linear-gradient(to left, #000 calc(100% - 28px), transparent);
  mask-image: linear-gradient(to left, #000 calc(100% - 28px), transparent);
}
.chip-row--scroll::-webkit-scrollbar {
  display: none;
}

/* Semantic chip variants */
.chip--muted {
  background: var(--color-surface-alt);
  color: var(--color-text-muted);
}
.chip--ok {
  background: var(--color-success-bg);
  border-color: color-mix(in srgb, var(--color-success) 35%, transparent);
  color: var(--color-success-text);
}
.chip--tag {
  background: var(--color-surface-alt);
  color: var(--color-text-secondary);
  font-size: var(--fs-caption);
}
.chip--add {
  border-style: dashed;
  color: var(--color-primary-text);
  border-color: color-mix(in srgb, var(--color-primary) 40%, transparent);
}
.chip--query {
  background: color-mix(in srgb, var(--color-primary) 10%, transparent);
  border-color: color-mix(in srgb, var(--color-primary) 30%, transparent);
  color: var(--color-primary-text);
}
.chip--collection {
  background: var(--color-surface);
  border-color: color-mix(in srgb, var(--color-primary) 30%, transparent);
  color: var(--color-primary-text);
}
.chip--phrase {
  cursor: pointer;
}
.chip--phrase-active {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-on-primary);
}
.chip--phrase-active .chip__count {
  color: color-mix(in srgb, var(--color-on-primary) 90%, transparent);
}
/* Selected FILTER chips (hadith sections, fasting categories, the hifz and
   recite-follow toggles): the views emit .chip--active — before v4.1 this
   class had no rule at all, so selected filters showed zero visual
   feedback next to their aria-pressed state. */
.chip--active {
  background: color-mix(in srgb, var(--color-primary) 12%, var(--color-surface));
  border-color: color-mix(in srgb, var(--color-primary) 45%, transparent);
  color: var(--color-primary-text);
}
.chip--basis-active {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-on-primary);
}

/* Category-tinted chips — tinted ground + strong text (AA both themes). */
.chip--amber,
.chip--blue,
.chip--cyan,
.chip--emerald,
.chip--gold,
.chip--indigo,
.chip--lime,
.chip--ocean,
.chip--orange,
.chip--pink,
.chip--purple,
.chip--red,
.chip--rose,
.chip--sky,
.chip--slate,
.chip--stone,
.chip--teal,
.chip--violet,
.chip--yellow {
  border-color: color-mix(in srgb, var(--chip-cat, var(--cat-emerald)) 28%, transparent);
  background: color-mix(in srgb, var(--chip-cat, var(--cat-emerald)) 10%, var(--color-surface));
  color: var(--chip-cat-text, var(--cat-emerald-text));
}
.chip--amber {
  --chip-cat: var(--cat-amber);
  --chip-cat-text: var(--cat-amber-text);
}
.chip--blue {
  --chip-cat: var(--cat-blue);
  --chip-cat-text: var(--cat-blue-text);
}
.chip--cyan {
  --chip-cat: var(--cat-cyan);
  --chip-cat-text: var(--cat-cyan-text);
}
.chip--emerald {
  --chip-cat: var(--cat-emerald);
  --chip-cat-text: var(--cat-emerald-text);
}
.chip--gold {
  --chip-cat: var(--cat-gold);
  --chip-cat-text: var(--cat-gold-text);
}
.chip--indigo {
  --chip-cat: var(--cat-indigo);
  --chip-cat-text: var(--cat-indigo-text);
}
.chip--lime {
  --chip-cat: var(--cat-lime);
  --chip-cat-text: var(--cat-lime-text);
}
.chip--ocean {
  --chip-cat: var(--cat-ocean);
  --chip-cat-text: var(--cat-ocean-text);
}
.chip--orange {
  --chip-cat: var(--cat-orange);
  --chip-cat-text: var(--cat-orange-text);
}
.chip--pink {
  --chip-cat: var(--cat-pink);
  --chip-cat-text: var(--cat-pink-text);
}
.chip--purple {
  --chip-cat: var(--cat-purple);
  --chip-cat-text: var(--cat-purple-text);
}
.chip--red {
  --chip-cat: var(--cat-red);
  --chip-cat-text: var(--cat-red-text);
}
.chip--rose {
  --chip-cat: var(--cat-rose);
  --chip-cat-text: var(--cat-rose-text);
}
.chip--sky {
  --chip-cat: var(--cat-sky);
  --chip-cat-text: var(--cat-sky-text);
}
.chip--slate {
  --chip-cat: var(--cat-slate);
  --chip-cat-text: var(--cat-slate-text);
}
.chip--stone {
  --chip-cat: var(--cat-stone);
  --chip-cat-text: var(--cat-stone-text);
}
.chip--teal {
  --chip-cat: var(--cat-teal);
  --chip-cat-text: var(--cat-teal-text);
}
.chip--violet {
  --chip-cat: var(--cat-violet);
  --chip-cat-text: var(--cat-violet-text);
}
.chip--yellow {
  --chip-cat: var(--cat-yellow);
  --chip-cat-text: var(--cat-yellow-text);
}

/* Grade chips — solid fills, white text (each gated at 4.5:1). */
.chip--grade {
  font-size: var(--fs-caption);
  font-weight: 600;
  letter-spacing: 0.02em;
  border: none;
  cursor: default;
  color: #ffffff;
  padding: var(--space-1) var(--space-2);
}
.chip--grade-quran {
  background: var(--grade-quran);
}
.chip--grade-sahih {
  background: var(--grade-sahih);
}
.chip--grade-hasan {
  background: var(--grade-hasan);
}
.chip--grade-daif {
  background: var(--grade-daif);
}
.chip--grade-athar {
  background: var(--grade-athar);
}
.chip--grade-custom {
  background: var(--grade-custom);
}
.chip--grade-unknown {
  background: var(--grade-unknown);
}

/* ==========================================================================
   4. Form fields
   ========================================================================== */
.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-1_5);
  margin-bottom: var(--space-4);
}
.field-label {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--color-text-secondary);
}

.input,
.select,
.textarea {
  width: 100%;
  min-height: var(--touch-target);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border-strong);
  background: var(--color-surface);
  color: var(--color-text);
  font-size: var(--fs-sm);
  transition:
    border-color var(--dur-base) var(--ease-standard),
    box-shadow var(--dur-base) var(--ease-standard);
}
.textarea {
  min-height: 96px;
  resize: vertical;
  line-height: var(--lh-normal);
}
.input:hover,
.select:hover,
.textarea:hover {
  border-color: var(--color-text-muted);
}
.input:focus,
.select:focus,
.textarea:focus {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: var(--ring-primary);
}
.input::placeholder,
.textarea::placeholder {
  color: var(--color-text-muted);
}

.select {
  appearance: none;
  -webkit-appearance: none;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--color-text-muted) 50%),
    linear-gradient(135deg, var(--color-text-muted) 50%, transparent 50%);
  background-position:
    calc(100% - 18px) calc(50% - 2px),
    calc(100% - 13px) calc(50% - 2px);
  background-size:
    5px 5px,
    5px 5px;
  background-repeat: no-repeat;
  padding-inline-end: var(--space-7);
}
[dir='rtl'] .select {
  background-position:
    18px calc(50% - 2px),
    13px calc(50% - 2px);
}

.slider {
  width: 100%;
  height: var(--touch-target);
  margin: 0;
  accent-color: var(--color-primary);
  cursor: pointer;
}

/* Switch (checkbox-driven) */
.switch {
  position: relative;
  display: inline-flex;
  align-items: center;
  width: 52px;
  height: 32px;
  flex-shrink: 0;
  cursor: pointer;
}
.switch input {
  position: absolute;
  opacity: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  cursor: pointer;
}
.switch__track {
  position: absolute;
  inset: 0;
  border-radius: var(--radius-pill);
  background: var(--color-border-strong);
  transition: background-color var(--dur-base) var(--ease-standard);
}
.switch__track::after {
  content: '';
  position: absolute;
  top: 3px;
  inset-inline-start: 3px;
  width: 26px;
  height: 26px;
  border-radius: var(--radius-pill);
  background: #ffffff;
  box-shadow: var(--shadow-sm);
  transition: transform var(--dur-base) var(--ease-spring);
}
.switch input:checked + .switch__track {
  background: var(--color-primary);
}
.switch input:checked + .switch__track::after {
  transform: translateX(20px);
}
[dir='rtl'] .switch input:checked + .switch__track::after {
  transform: translateX(-20px);
}
.switch input:focus-visible + .switch__track {
  box-shadow: var(--shadow-focus);
}

.toggle-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 52px;
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--color-border);
  cursor: pointer; /* the whole row is a <label> — tap anywhere toggles */
}
.toggle-row:last-child {
  border-bottom: none;
}
.toggle-row__label {
  flex: 1;
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: -0.005em;
  color: var(--color-text);
}

/* Segmented control */
.segmented {
  display: flex;
  gap: var(--space-1);
  padding: var(--space-1);
  background: var(--color-surface-alt);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: inset 0 1px 2px rgba(28, 32, 28, 0.08);
}
.segmented__btn {
  flex: 1;
  min-height: var(--touch-target);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--color-text-secondary);
  transition:
    background-color var(--dur-base) var(--ease-standard),
    color var(--dur-base) var(--ease-standard),
    box-shadow var(--dur-base) var(--ease-standard);
}
.segmented__btn:hover {
  color: var(--color-text);
}
.segmented__btn--active {
  background: var(--color-surface);
  color: var(--color-primary-text);
  font-weight: 700;
  box-shadow:
    var(--shadow-sm),
    inset 0 0 0 1px color-mix(in srgb, var(--color-primary) 25%, transparent);
}

/* Search bar */
.search-bar {
  position: relative;
  display: flex;
  align-items: center;
}
.search-bar__icon {
  position: absolute;
  inset-inline-start: var(--space-3);
  color: var(--color-text-muted);
  pointer-events: none;
}
.search-bar__input {
  width: 100%;
  min-height: 52px;
  padding: var(--space-2) var(--space-4);
  padding-inline-start: calc(var(--space-8) + var(--space-1));
  border-radius: var(--radius-pill);
  border: 1px solid var(--color-border-strong);
  background: var(--color-surface);
  box-shadow: var(--shadow-sm);
  font-size: var(--fs-base);
  transition:
    border-color var(--dur-base) var(--ease-standard),
    box-shadow var(--dur-base) var(--ease-standard);
}
.search-bar__input:focus {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: var(--ring-primary);
}
.search-bar__input::placeholder {
  color: var(--color-text-muted);
}

/* ==========================================================================
   5. Modal
   ========================================================================== */
#modal-root {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  pointer-events: none;
}

.modal-overlay {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: var(--space-3);
  background: var(--color-overlay);
  pointer-events: auto;
  animation: fadeIn var(--dur-base) var(--ease-standard);
}
@media (min-width: 640px) {
  .modal-overlay {
    align-items: center;
  }
}

/* Background scroll lock while a modal is open — set on <body> by
   ui/modal.js. Without it, a swipe on the overlay scrolls the page behind
   the sheet on iOS. */
body.modal-open {
  overflow: hidden;
}

.modal {
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 560px;
  /* dvh fallback: pre-dvh engines (Safari ≤15.3, Chrome <108) drop the
     dvh line entirely, leaving no height cap at all. */
  max-height: 86vh;
  max-height: 86dvh;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: calc(var(--radius-lg) + 2px);
  box-shadow: var(--shadow-lg);
  animation: sheetIn var(--dur-slow) var(--ease-spring);
}
@media (min-width: 640px) {
  .modal {
    animation: popIn var(--dur-slow) var(--ease-spring);
  }
}

.modal__close {
  position: absolute;
  top: var(--space-2);
  inset-inline-end: var(--space-2);
  /* (v4.3) the z-scale's local-stacking token replaces the one raw
     z-index literal left in the design system. */
  z-index: var(--z-raised);
}

.modal__body {
  position: relative;
  padding: var(--space-6) var(--space-5);
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* ==========================================================================
   6. Toasts
   ========================================================================== */
#toast-root {
  position: fixed;
  bottom: calc(var(--bottomnav-height) + var(--space-5));
  inset-inline: var(--space-4);
  z-index: var(--z-toast);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  pointer-events: none;
}
@media (min-width: 960px) {
  #toast-root {
    bottom: var(--space-5);
  }
}

.toast {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  max-width: 420px;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--color-text) 92%, transparent);
  color: var(--color-bg);
  font-size: var(--fs-sm);
  font-weight: 500;
  box-shadow: var(--shadow-lg);
  pointer-events: auto;
  animation: slideUp var(--dur-slow) var(--ease-spring);
}
.toast--leaving {
  animation: toastOut var(--dur-fast) var(--ease-standard) forwards;
}
@keyframes toastOut {
  to {
    opacity: 0;
    transform: translateY(var(--space-1));
  }
}
.toast-action {
  background: none;
  border: none;
  color: color-mix(in srgb, var(--color-accent-raw) 60%, var(--color-text));
  font-weight: 700;
  font-size: var(--fs-sm);
  cursor: pointer;
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
  flex-shrink: 0;
}
.toast-action:hover {
  text-decoration: underline;
}
/* Inverted toast: mixing the accent with currentColor keeps the action
   readable on the pill in BOTH themes — the pill is dark in light mode and
   light in dark mode, so a fixed white-mix washed out to 1.25:1 at night. */
.toast .toast-action {
  color: color-mix(in srgb, var(--color-accent-raw) 70%, currentColor);
}

/* ==========================================================================
   7. Action sheet + pickers + dialogs
   ========================================================================== */
.action-sheet {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.action-sheet__item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 56px;
  padding: var(--space-3) var(--space-3);
  border-radius: var(--radius-md);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--color-text);
  text-align: start;
  transition: background-color var(--dur-base) var(--ease-standard);
}
.action-sheet__item:hover {
  background: var(--color-surface-alt);
}
.action-sheet__item svg {
  width: 38px;
  height: 38px;
  padding: 9px;
  border-radius: 12px;
  background: color-mix(in srgb, var(--color-primary) 11%, var(--color-surface));
  color: var(--color-primary-text);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--color-primary) 18%, transparent);
  flex-shrink: 0;
}

.collection-picker {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.confirm-dialog,
.prompt-dialog {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

/* ==========================================================================
   8. Progress + streak badge
   ========================================================================== */
.progress-bar {
  height: 10px;
  border-radius: var(--radius-pill);
  background: var(--color-surface-alt);
  box-shadow: inset 0 1px 2px rgba(28, 32, 28, 0.12);
  overflow: hidden;
}
.progress-bar__fill {
  height: 100%;
  width: 100%;
  border-radius: var(--radius-pill);
  background: linear-gradient(90deg, var(--color-primary-deep), var(--color-primary));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
  /* scaleX (vs animating width) keeps progress updates off the layout path —
     the home bar re-renders on every tasbih tap. Origin follows the
     reading direction so the bar always grows from the start edge. */
  transform: scaleX(var(--p, 0));
  transform-origin: 0 50%;
  transition: transform var(--dur-slow) var(--ease-standard);
}
[dir='rtl'] .progress-bar__fill {
  transform-origin: 100% 50%;
}

.streak-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1_5);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--color-accent-raw) 12%, var(--color-surface));
  color: var(--color-text);
  font-size: var(--fs-caption);
  font-weight: 600;
}
.streak-badge svg {
  color: color-mix(in srgb, var(--color-accent-raw) 60%, var(--color-text));
}

/* ==========================================================================
   9. Skeletons (shimmer mirrors the shape it replaces)
   ========================================================================== */
.sk {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-sm);
  background: var(--color-surface-alt);
  /* ui/skeleton.js sets --sk-w/--sk-h inline on every bar; without this
     box the spans were inline, empty and 0×0 — the shimmer never showed. */
  display: block;
  width: var(--sk-w, 100%);
  height: var(--sk-h, 12px);
}
.sk::after {
  content: '';
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, var(--sk-sheen), transparent);
  animation: sk-sweep var(--dur-loop-med) var(--ease-standard) infinite;
}
.sk--chip {
  height: 30px;
  border-radius: var(--radius-pill);
}
.sk--badge {
  height: 22px;
  width: 64px;
  border-radius: var(--radius-pill);
}
.sk--arabic {
  height: var(--fs-lg);
  border-radius: var(--radius-sm);
}

.sk-ayah-card,
.sk-hadith-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-4);
  border-radius: var(--radius-lg);
  border: 1px solid var(--color-border);
  background: var(--color-surface);
}
.sk-ayah-card__top,
.sk-hadith-card__chips {
  display: flex;
  gap: var(--space-2);
}
.sk-hadith-card__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.sk-tile {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.sk-tile__lines {
  display: flex;
  flex-direction: column;
  gap: var(--space-1_5);
}

.sk-block {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.sk-block--cards {
  gap: var(--space-3);
}

.sk-surah-grid,
.sk-reciter-list {
  display: grid;
  gap: var(--space-3);
}
.sk-reciter-row {
  display: flex;
  gap: var(--space-3);
  align-items: center;
}

.sk-mushaf-page {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  align-items: center;
}
.sk--paper {
  width: var(--sk-w, 100%);
  height: 24px;
}

/* ==========================================================================
   10. Empty states + hints
   ========================================================================== */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-8) var(--space-5);
  text-align: center;
}
.empty-state__medallion {
  display: grid;
  place-items: center;
  width: 72px;
  height: 72px;
  border-radius: 22px;
  background: color-mix(in srgb, var(--color-primary) 12%, var(--color-surface));
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--color-primary) 20%, transparent);
  color: var(--color-primary-text);
}
.empty-state__title {
  font-size: 1.05rem;
  font-weight: 800;
  letter-spacing: -0.01em;
}
.empty-state__hint {
  font-size: var(--fs-sm);
  color: var(--color-text-secondary);
  line-height: 1.6;
  max-width: 42ch;
}

.empty-hint {
  padding: var(--space-4) var(--space-5);
  border-radius: var(--radius-md);
  border: 1px dashed var(--color-border-strong);
  background: color-mix(in srgb, var(--color-surface-alt) 50%, var(--color-surface));
  color: var(--color-text-secondary);
  font-size: var(--fs-sm);
  line-height: 1.6;
  text-align: center;
}

/* ==========================================================================
   11. View scaffolding + panels
   ========================================================================== */
.view {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

.view-header {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.view-header--row {
  flex-direction: row;
  align-items: center;
  gap: var(--space-3);
}
.view__title {
  font-size: 1.65rem;
  font-weight: 800;
  letter-spacing: -0.025em;
  line-height: 1.15;
  /* (v5.1.0) optical balance for the big screen titles: the slight
     negative tracking is what makes modern app headings read "designed". */
}
.view__subtitle {
  font-size: var(--fs-sm);
  color: var(--color-text-secondary);
  line-height: 1.5;
}
.view__meta {
  font-size: var(--fs-caption);
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}

.back-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1_5);
  min-height: var(--touch-target);
  padding-inline-start: calc(var(--space-1) * -1);
  color: var(--color-primary-text);
  font-size: var(--fs-sm);
  font-weight: 600;
}
.back-link svg {
  transform: scaleX(1);
}
[dir='rtl'] .back-link svg {
  transform: scaleX(-1);
}
/* (v4.5.2) the topbar universal Back button (APP-FLOW I9) — points
   "backward" in the reading direction, like .back-link above. */
.topbar__back svg {
  transform: scaleX(1);
}
[dir='rtl'] .topbar__back svg {
  transform: scaleX(-1);
}
.back-link:hover {
  text-decoration: none;
  opacity: 0.85;
}

.panel {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-5);
  border-radius: var(--radius-lg);
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  box-shadow: var(--shadow-sm);
}

.panel__header {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: 1.02rem;
  font-weight: 800;
  letter-spacing: -0.01em;
}
.panel__header-side {
  margin-inline-start: auto;
  font-size: var(--fs-caption);
  font-weight: 500;
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}
.panel__subtext {
  font-size: var(--fs-sm);
  color: var(--color-text-muted);
}

/* ==========================================================================
   12. Statistics widgets
   ========================================================================== */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-3);
}
@media (min-width: 560px) {
  .stat-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

.stat-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-4);
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border);
  background:
    radial-gradient(
      120% 130% at 100% 0%,
      color-mix(in srgb, var(--color-primary) 7%, transparent) 0%,
      transparent 60%
    ),
    var(--color-surface);
  box-shadow: var(--shadow-sm);
}
.stat-card__label {
  font-size: var(--fs-caption);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--color-text-secondary);
}
.stat-card__value {
  font-size: var(--fs-xl);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.1;
  color: var(--color-text);
  font-variant-numeric: tabular-nums;
}

.bar-chart {
  display: flex;
  align-items: flex-end;
  gap: var(--space-2);
  height: 120px;
  padding-top: var(--space-5);
}
.bar-chart--lg {
  height: 160px;
}
.bar-chart__col {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1_5);
  flex: 1;
  min-width: 0;
}
.bar-chart__bar {
  width: 100%;
  max-width: 36px;
  border-radius: var(--radius-sm) var(--radius-sm) 2px 2px;
  background: color-mix(in srgb, var(--color-primary) 30%, var(--color-surface));
  /* Height comes from the --bar-h custom property (set inline by the view);
     the transition animates week-over-week changes as data accrues. */
  height: var(--bar-h, 4px);
  transition: height var(--dur-slow) var(--ease-standard);
}
.bar-chart__bar--best {
  background: var(--color-primary);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-primary) 25%, transparent);
}
.bar-chart__value--zero {
  opacity: 0.4;
}
.bar-chart__value {
  font-size: var(--fs-caption);
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
  height: 1.2em;
}
.bar-chart__label {
  font-size: var(--fs-caption);
  color: var(--color-text-muted);
}

/* Heatmap: two 7-column grids (labels row + cells). The view wraps each
   group; flat children previously collapsed the layout into stacked
   full-width squares. */
.heatmap {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.heatmap__dow {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 3px;
  font-size: var(--fs-caption);
  color: var(--color-text-muted);
  text-align: center;
}
.heatmap__grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 3px;
}
.heatmap__cell {
  aspect-ratio: 1;
  border-radius: var(--radius-xs);
  background: var(--color-surface-alt);
  border: 1px solid transparent;
}
.heatmap__cell--empty {
  background: transparent;
  border-color: var(--color-border);
  opacity: 0.5;
}
.heatmap__cell--0 {
  background: var(--color-surface-alt);
}
.heatmap__cell--1 {
  background: var(--heat-1);
}
.heatmap__cell--2 {
  background: var(--heat-2);
}
.heatmap__cell--3 {
  background: var(--heat-3);
}
.heatmap__cell--4 {
  background: var(--heat-4);
}
.heatmap__cell--today {
  border-color: var(--color-primary-text);
  box-shadow: var(--ring-primary);
}
.heatmap__cell {
  display: grid;
  place-items: center;
  font-size: var(--fs-caption);
  color: var(--color-text-secondary);
}
/* Bucket 3 is a mid tint — dark ink in light mode, near-white in dark mode
   (both themes hold AA via --color-text). Bucket 4 is a 92% primary fill,
   chosen so WHITE numerals hold 4.5:1 on every bundled palette (the old
   65%/85% + white measured 2.8–4.06:1 in light mode). */
.heatmap__cell--3 {
  color: var(--color-text);
}
.heatmap__cell--4 {
  color: #ffffff;
}

.heatmap-month-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}
.heatmap-month-nav__label {
  font-size: var(--fs-sm);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* Ranked rows ("most read") */
.ranked-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.ranked-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--touch-target);
  padding: var(--space-2);
  border-radius: var(--radius-md);
  transition: background-color var(--dur-base) var(--ease-standard);
}
.ranked-row:hover {
  background: var(--color-surface-alt);
}
.ranked-row__icon {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-sm);
  flex-shrink: 0;
}
.ranked-row__icon--emerald {
  background: color-mix(in srgb, var(--cat-emerald) 12%, transparent);
  color: var(--cat-emerald-text);
}
.ranked-row__label {
  flex: 1;
  font-size: var(--fs-sm);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ranked-row__value {
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--color-primary-text);
  font-variant-numeric: tabular-nums;
}

/* Year-in-review windows */
.review-window {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-4);
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border);
  background: var(--color-surface);
}
.review-window__title {
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--color-text-secondary);
}

/* ==========================================================================
   13. Player bar (docked console)
   ========================================================================== */
#playerbar {
  position: fixed;
  bottom: calc(var(--bottomnav-height) + var(--space-2));
  inset-inline: var(--space-3);
  z-index: var(--z-player);
}
@media (min-width: 960px) {
  #playerbar {
    bottom: var(--space-4);
    inset-inline: var(--space-4);
    max-width: calc(var(--content-max-width) - var(--space-8));
    margin-inline-start: auto;
  }
}

.player-bar {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-lg);
  background: color-mix(in srgb, var(--color-surface) 94%, transparent);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border: 1px solid var(--color-border);
  box-shadow: var(--shadow-lg);
}

.player-bar__head {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
}

.player-bar__play {
  display: grid;
  place-items: center;
  width: var(--touch-target);
  height: var(--touch-target);
  flex-shrink: 0;
  border-radius: var(--radius-pill);
  background: linear-gradient(145deg, var(--color-primary) 0%, var(--color-primary-deep) 100%);
  color: #ffffff;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.25),
    0 4px 12px rgba(8, 51, 47, 0.3);
  transition:
    transform var(--dur-fast) var(--ease-standard),
    background-color var(--dur-base) var(--ease-standard),
    box-shadow var(--dur-base) var(--ease-standard);
}
.player-bar__play:hover {
  background: linear-gradient(
    145deg,
    color-mix(in srgb, var(--color-primary) 94%, black),
    color-mix(in srgb, var(--color-primary-deep) 94%, black)
  );
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.25),
    0 6px 16px rgba(8, 51, 47, 0.35);
}
.player-bar__play:active {
  transform: scale(0.94);
}

.player-bar__meta {
  display: flex;
  flex-direction: column;
  min-width: 0;
  flex: 1;
}
.player-bar__surah {
  font-size: var(--fs-sm);
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.player-bar__reciter {
  font-size: var(--fs-caption);
  color: var(--color-text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.player-bar__chip {
  display: inline-flex;
  align-items: center;
  position: relative; /* FIX (v5.2.1): the ::after hit-expansion below
    positions against the nearest positioned ancestor — without this it
    anchored to the bar itself, so every chip's invisible hit box stacked
    over its neighbors and taps (e.g. repeat) landed on the wrong chip. */
  gap: var(--space-1);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-pill);
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text-secondary);
  font-size: var(--fs-caption);
  font-weight: 600;
  min-height: 32px;
}
.player-bar__chip::after {
  content: '';
  position: absolute;
  inset-block: -4px;
  inset-inline: -2px;
}
.player-bar__chip--on {
  border-color: color-mix(in srgb, var(--color-primary) 40%, transparent);
  background: color-mix(in srgb, var(--color-primary) 12%, transparent);
  color: var(--color-primary-text);
}

/* (UX-8) the shared console's wide-viewport text labels: icon-only
 * buttons (ayah prev/next, follow, pause) show their short label at
 * desktop widths so touch users aren't left with title-tooltips that
 * don't exist on touch. Hidden on phones — the row stays compact. */
.rec-console-label {
  display: none;
}
@media (min-width: 900px) {
  .rec-console-label {
    display: inline;
    margin-inline-start: 4px;
    white-space: nowrap;
  }
  /* Labeled buttons escape the fixed 44px icon grid (the label would
   * overlap the glyph) while keeping the touch-target floor. */
  .icon-btn:has(> .rec-console-label) {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: auto;
    min-width: var(--touch-target);
    padding-inline: var(--space-2);
  }
}

/* (v5.2.0) Echo-mode "your turn" banner inside the recitation console. */
.player-bar__echo-wait {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-3);
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--color-primary-text);
  background: color-mix(in srgb, var(--color-primary) 10%, transparent);
  border-radius: var(--radius-pill);
}

.player-bar__buffer {
  font-size: var(--fs-caption);
  color: var(--color-text-muted);
}

.player-bar__seek {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.player-bar__track {
  flex: 1;
  height: 32px;
  accent-color: var(--color-primary);
  cursor: pointer;
}
.player-bar__time {
  font-size: var(--fs-caption);
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
  min-width: 4ch;
}
.player-bar__time--dur {
  text-align: end;
}

/* Recitation console variant */
.player-bar--recite .player-bar__pulse {
  width: 10px;
  height: 10px;
  border-radius: var(--radius-pill);
  background: var(--color-accent);
  animation: recite-pulse var(--dur-loop-med) var(--ease-standard) infinite;
  flex-shrink: 0;
}
.player-bar__ayah-counter {
  font-size: var(--fs-sm);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* ==========================================================================
   14. Reciter rows + download manager grid
   ========================================================================== */
.reciter-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--touch-target);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  text-align: start;
  transition: background-color var(--dur-base) var(--ease-standard);
}
.reciter-row:hover {
  background: var(--color-surface-alt);
}
.reciter-row--active {
  background: color-mix(in srgb, var(--color-primary) 10%, transparent);
  box-shadow: var(--ring-inset-primary);
}
.reciter-row__main {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 1;
  min-width: 0;
}
.reciter-row__name {
  font-size: var(--fs-sm);
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.reciter-row__sub {
  font-size: var(--fs-caption);
  color: var(--color-text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.reciter-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.picker-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--touch-target);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  text-align: start;
  transition: background-color var(--dur-base) var(--ease-standard);
}
.picker-row:hover {
  background: var(--color-surface-alt);
}
.picker-row__count {
  margin-inline-start: auto;
  font-size: var(--fs-caption);
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Offline audio download grid (114 cells) */
.dl-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(56px, 1fr));
  gap: var(--space-2);
}
@media (max-width: 480px) {
  .dl-grid {
    grid-template-columns: repeat(6, 1fr);
  }
}
.dl-cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  min-height: var(--touch-target);
  padding: var(--space-1);
  border-radius: var(--radius-sm);
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  font-size: var(--fs-caption);
  color: var(--color-text-secondary);
  transition:
    background-color var(--dur-base) var(--ease-standard),
    border-color var(--dur-base) var(--ease-standard);
}
.dl-cell__btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  width: 100%;
  min-height: var(--touch-target);
  justify-content: center;
}
.dl-cell:hover .dl-cell__btn {
  color: var(--color-primary-text);
}
.dl-cell--done {
  border-color: color-mix(in srgb, var(--color-success) 40%, transparent);
  background: var(--color-success-bg);
  color: var(--color-success-text);
}
.dl-cell--busy {
  opacity: 0.7;
  pointer-events: none;
}
.dl-cell__num {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.dl-cell__bytes {
  font-size: var(--fs-caption);
  color: var(--color-text-muted);
}
.dl-cell__state {
  display: grid;
  place-items: center;
}
.dl-cell__spinner {
  width: 16px;
  height: 16px;
  border-radius: var(--radius-pill);
  border: 2px solid var(--color-border-strong);
  border-top-color: var(--color-primary);
  animation: dl-spin var(--dur-loop-slow) linear infinite;
}

.panel--dl {
  gap: var(--space-4);
}

/* Home panel order rows (Settings → Content). */
.home-panel-row {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  min-height: var(--touch-target);
  padding-block: var(--space-1);
  border-bottom: 1px solid var(--color-border);
}
.home-panel-row:last-child {
  border-bottom: none;
}
.home-panel-row__label {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--fs-sm);
}

/* Offline library rows (Offline view): icon + name/size + status + action. */
.offline-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--touch-target);
  padding-block: var(--space-1);
  border-bottom: 1px solid var(--color-border);
}
.offline-row:last-child {
  border-bottom: none;
}
.offline-row__icon {
  flex: none;
  color: var(--color-text-secondary);
}
.offline-row__text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}
.offline-row__name {
  font-size: var(--fs-sm);
  font-weight: 600;
}
.offline-row__sub {
  font-size: var(--fs-caption);
  color: var(--color-text-muted);
}
.offline-row__status {
  flex: none;
  font-size: var(--fs-caption);
  color: var(--color-text-muted);
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.offline-row__status--done {
  color: var(--color-primary-text);
}

/* Monthly prayer timetable modal: scrollable table, full grid. */
.prayer-month {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.table-scroll {
  overflow-x: auto;
  scrollbar-width: thin;
}
.prayer-month__table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
}
.prayer-month__table th,
.prayer-month__table td {
  border: 1px solid var(--color-border);
  padding: var(--space-1_5) var(--space-2);
  text-align: center;
  white-space: nowrap;
}
.prayer-month__table thead th {
  background: color-mix(in srgb, var(--color-primary) 8%, transparent);
  position: sticky;
  top: 0;
}

/* Hifz translation MCQ: option chips with right/wrong states. */
.panel--mcq {
  gap: var(--space-2);
}
.mcq-options {
  display: flex;
  flex-direction: column;
  gap: var(--space-1_5);
}
.chip--mcq {
  justify-content: flex-start;
  text-align: start;
  white-space: normal;
  min-height: var(--touch-target);
}
.chip--correct {
  border-color: color-mix(in srgb, var(--color-success, #15803d) 60%, transparent);
  background: color-mix(in srgb, var(--color-success, #15803d) 12%, transparent);
}
.chip--wrong {
  border-color: color-mix(in srgb, var(--color-danger, #b91c1c) 60%, transparent);
  background: color-mix(in srgb, var(--color-danger, #b91c1c) 10%, transparent);
  opacity: 0.75;
}

/* Kids mode: big tiles, stars, giant tasbih door. Calm greens + golds,
   same tokens as the rest of the app — simple, never garish. */
body.is-kids #bottomnav {
  display: none;
}
.view--kids {
  gap: var(--space-4);
}
.kids-hello {
  font-size: var(--fs-xl);
  font-weight: 800;
  text-align: center;
}
.kids-section-title {
  font-size: var(--fs-xl);
  font-weight: 800;
}
.panel--kids-stars {
  align-items: center;
  text-align: center;
}
.kids-stars__icon {
  color: var(--cat-gold-text);
}
.kids-stars__total {
  font-size: 2.2rem;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.kids-stars__label {
  font-size: var(--fs-base);
  font-weight: 600;
  color: var(--color-text-secondary);
}
.kids-stars__text {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: var(--space-2);
}
.kids-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: var(--space-3);
}
.kids-tile {
  width: 100%;
  min-height: 150px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  border-radius: var(--radius-lg);
  border: 2px solid color-mix(in srgb, var(--mushaf-gold) 45%, transparent);
  background: color-mix(in srgb, var(--mushaf-gold) 8%, var(--color-surface));
  cursor: pointer;
  padding: var(--space-3);
}
.kids-tile--playing {
  border-color: var(--color-primary);
  background: color-mix(in srgb, var(--color-primary) 12%, var(--color-surface));
}
.kids-tile__play {
  color: var(--color-primary-text);
}
.kids-tile__name-ar {
  font-family: var(--font-arabic);
  font-size: 1.5rem;
  font-weight: 700;
}
.kids-tile__name-en {
  font-size: var(--fs-sm);
  color: var(--color-text-secondary);
}
.kids-tasbih {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  border-radius: var(--radius-lg);
  border: 2px solid var(--color-border);
  background: var(--color-surface);
  padding: var(--space-5);
  color: var(--color-text);
  text-decoration: none;
}
.kids-tasbih__label {
  font-size: var(--fs-xl);
  font-weight: 800;
}
.kids-exit {
  align-self: center;
  position: relative;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1_5);
  min-height: var(--touch-target);
  padding-inline: var(--space-4);
  border-radius: var(--radius-pill);
  border: 1px solid var(--color-border);
  background: transparent;
  color: var(--color-text-muted);
  font-size: var(--fs-sm);
}
/* Hold progress: fills in 25% steps over the 2s press (JS interval —
   a single 2s CSS transition would break the 300ms motion contract). */
.kids-exit__fill {
  position: absolute;
  inset: 0;
  width: 0;
  background: color-mix(in srgb, var(--color-primary) 25%, transparent);
  pointer-events: none;
  transition: width 0.25s linear;
}
.kids-exit__hint {
  text-align: center;
}
/* Kids mode hides the bottom nav — the desktop rail margin must go with
   it, or #main keeps a rail-sized hole on wide screens. */
body.is-kids #main {
  margin-inline-start: 0;
}

/* Grammar flashcards (Roots view): big Arabic prompt, graded answers. */
.panel--grammar {
  gap: var(--space-2);
}
.grammar-word {
  font-family: var(--font-arabic);
  font-size: calc(var(--fs-arabic-card) * 0.9);
  line-height: var(--lh-arabic);
  text-align: center;
}
.grammar-answer {
  font-size: var(--fs-base);
  text-align: center;
}
.grammar-score {
  font-size: var(--fs-base);
  font-weight: 700;
  text-align: center;
}

/* Adhan loudness schedule (Prayer view): day volume + quiet-hours row. */
.adhan-volume {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.adhan-quiet-row {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: var(--space-2);
}
@media (max-width: 560px) {
  .adhan-quiet-row {
    grid-template-columns: 1fr 1fr;
  }
}

/* Recitation queues: saved (surah, from, to) range lists in the Audio view. */
.panel--queue {
  gap: var(--space-3);
}
.queue-row {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--space-2) var(--space-3);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.queue-row__head {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.queue-row__name {
  flex: 1;
  min-width: 0;
  font-weight: 700;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.queue-row__items {
  margin: 0;
  padding-inline-start: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.queue-row__item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--fs-sm);
}
.queue-row__item-label {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ==========================================================================
   15. Settings rows: reminders, sounds, shapes, swatches
   ========================================================================== */
.reminder-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--touch-target);
  padding: var(--space-2) 0;
}
.reminder-row__label {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 1;
  min-width: 0;
  font-size: var(--fs-sm);
}
.reminder-row__time {
  font-size: var(--fs-caption);
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}

.sound-picker-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--touch-target);
}
.sound-picker-row .select {
  flex: 1;
}

.shape-row,
.swatch-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.swatch {
  position: relative;
  width: var(--touch-target);
  height: var(--touch-target);
  border-radius: var(--radius-sm);
  border: 2px solid var(--color-border-strong);
  background: var(--sw-color, var(--color-primary));
  cursor: pointer;
  transition:
    transform var(--dur-fast) var(--ease-standard),
    box-shadow var(--dur-base) var(--ease-standard);
}
.swatch::after {
  content: '';
  position: absolute;
  inset-block: -4px;
  inset-inline: -4px;
}
.swatch:hover {
  transform: scale(1.06);
}
.swatch--active {
  border-color: var(--color-text);
  box-shadow: var(--ring-primary);
}

.shape-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-2);
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  min-width: 64px;
  cursor: pointer;
  transition:
    border-color var(--dur-base) var(--ease-standard),
    background-color var(--dur-base) var(--ease-standard);
}
.shape-btn__swatch {
  width: 28px;
  height: 28px;
  border-radius: var(--sh-radius, var(--radius-sm));
  background: color-mix(in srgb, var(--color-primary) 25%, var(--color-surface));
  border: 1px solid var(--color-border-strong);
}
.shape-btn__label {
  font-size: var(--fs-caption);
  color: var(--color-text-secondary);
}
.shape-btn--active {
  border-color: var(--color-primary);
  background: color-mix(in srgb, var(--color-primary) 8%, transparent);
  /* (v4.4) a 2px-equivalent ring — the 1px border swap read as a
     misaligned/ragged edge at 64px button size in browser audits. */
  box-shadow:
    0 0 0 1px var(--color-primary),
    0 0 0 3px color-mix(in srgb, var(--color-primary) 18%, transparent);
}
.shape-btn--active .shape-btn__label {
  color: var(--color-primary-text);
  font-weight: 600;
}

/* Data health panel */
.data-health {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  font-size: var(--fs-sm);
}

/* ==========================================================================
   16. Editor forms + misc dialogs
   ========================================================================== */
.editor-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.editor-form__actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
  margin-top: var(--space-2);
}

.note-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.note-form__conditional {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding-block-start: var(--space-2);
  border-top: 1px dashed var(--color-border);
  margin-block-start: var(--space-1);
}

/* Calendar day detail + note rows (modal content) */
.day-detail {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.day-detail__hijri {
  font-size: var(--fs-caption);
  color: var(--color-text-muted);
}
.day-note-row {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-3);
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border);
  background: var(--color-surface);
}
.day-note-row__meta {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--fs-caption);
  color: var(--color-text-muted);
}
.day-note-row__body {
  font-size: var(--fs-sm);
}
.day-note-row__actions {
  display: flex;
  gap: var(--space-1);
  margin-inline-start: auto;
}

/* Adhan variant rows (prayer alert panel) */
.adhan-mode-row,
.adhan-variant-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--touch-target);
}
.adhan-variant-row__label {
  display: flex;
  flex-direction: column;
  flex: 1;
  gap: 2px;
  font-size: var(--fs-sm);
}
.adhan-variant-row__status {
  font-size: var(--fs-caption);
  color: var(--color-text-muted);
}
.adhan-mode-chip {
  /* styled via .chip + .chip--phrase-active semantics in the view */
}
.adhan-mode-chip--active {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-on-primary);
  font-weight: 600;
}

/* Utility: has-action affordance */
.has-action {
  cursor: pointer;
}

/* (v4.2) Tasbih target presets: 33 / 100 / 500 / 1000 one-tap chips beside
 * the ± stepper (stepping 33 → 100 used to be 67 taps). */
.target-presets {
  margin-block-start: var(--space-1);
}

/* ==========================================================================
   (v4.6.0) The per-view "⋯" sheet — every tab's options menu. Same visual
   language as the Mushaf More sheet: grouped bordered rows, one action per
   row, icon + label + inline-end control.
   ========================================================================== */
.view-sheet {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
.view-sheet h2 {
  font-size: 1.25rem;
  font-weight: 800;
  letter-spacing: -0.015em;
}
.view-sheet__group {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.view-sheet__group-label {
  padding: var(--space-2) var(--space-4) var(--space-1);
  font-size: var(--fs-caption);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text-muted);
  background: color-mix(in srgb, var(--color-surface-alt) 60%, var(--color-surface));
}
.view-sheet__row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  min-height: 56px;
  padding: var(--space-2) var(--space-4);
  background: none;
  border: none;
  border-block-start: 1px solid var(--color-border);
  color: var(--color-text);
  font-size: var(--fs-sm);
  font-weight: 600;
  text-align: start;
  cursor: pointer;
}
.view-sheet__group-label + .view-sheet__row,
.view-sheet__group .view-sheet__row:first-child {
  border-block-start: none;
}
a.view-sheet__row {
  text-decoration: none;
}
.view-sheet__row:hover {
  background: var(--color-surface-alt);
  text-decoration: none;
}
.view-sheet__row:focus-visible {
  outline: none;
  box-shadow: var(--shadow-focus) inset;
}
.view-sheet__row svg {
  width: 36px;
  height: 36px;
  padding: 8px;
  border-radius: 11px;
  background: color-mix(in srgb, var(--color-primary) 11%, var(--color-surface));
  color: var(--color-primary-text);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--color-primary) 18%, transparent);
  flex-shrink: 0;
}
.view-sheet__label {
  flex: 1;
  min-width: 0;
}
.view-sheet__value {
  font-size: var(--fs-caption);
  color: var(--color-text-muted);
  flex-shrink: 0;
}
.view-sheet__row--toggle .switch {
  flex-shrink: 0;
}
/* The visual-only switch used by click-dispatched toggle rows. */
.switch__track--on {
  background: var(--color-primary);
}
.switch__track--on::after {
  transform: translateX(20px);
}
[dir='rtl'] .switch__track--on::after {
  transform: translateX(-20px);
}
.view-sheet__footnote,
.view-sheet__intro {
  font-size: var(--fs-sm);
  color: var(--color-text-muted);
  line-height: 1.6;
}
.view-sheet__intro {
  color: var(--color-text-secondary);
}

/* The small ⋯ trigger riding in view headers. */
.view-menu-btn {
  flex-shrink: 0;
}
.view-header--row .view-menu-btn {
  margin-inline-start: auto;
}

/* Prayer panels opened as modals breathe like sheets. */
.view-panel-modal {
  gap: var(--space-3);
}
