/* ============================================================
   Hifzhelper -- detail pages: tajweed picker, timer, shared form bits
   Current as of V3.45.13
   ============================================================ */

.detail-page label {
  display: block; font-size: var(--font-size-base); color: var(--color-ink-soft);
  margin-top: var(--space-md); margin-bottom: 4px;
}
.detail-page select, .detail-page input, .detail-page textarea {
  width: 100%; padding: var(--space-sm);
  border: 1px solid var(--color-table-border); border-radius: var(--radius-sm);
  background: var(--color-surface);
}
.picker-row {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-sm);
}
/* V3.26.1: Juz/position row -- when the position switch hides itself
   entirely (Full/Juz unit has exactly one valid starting marker, so
   there's nothing to choose -- see dhorPage.js's renderDhorPositionOptions),
   this collapses the row to one column so Juz's own field expands to
   fill the space rather than leaving an empty gap beside it. */
.picker-row.picker-row-single {
  grid-template-columns: 1fr;
}
/* 2026-08-03: Juz's <select> had no explicit height (relying on padding +
   line-height, which varies by platform/browser and commonly doesn't
   match a fixed value), while the Position switch has always had an
   explicit 42px -- so their bottom edges didn't line up. Both now share
   one explicit height instead of one side guessing at the other's. */
/* 2026-08-04: was hardcoded to 44px separately from Row 2's own
   --dhor-row2-h (also 44px, coincidentally the same number, but two
   separate values that could easily drift apart again) -- now the same
   single shared variable everywhere. */
#dhor_juz,
#dhor_juz_to {   /* V3.90.1 (user): the To select never had the height rule — From and To now match */
  height: var(--dhor-row2-h);
  box-sizing: border-box;
}
#dhor_position_switch {
  height: var(--dhor-row2-h);
}

/* V3.18.0: header rebuilt as two explicit CSS grids per the confirmed
   spec, replacing V3.12.0's flex row -- row 1 is icon:heading:save at
   10:70:20, row 2 is date:blank at 30:70. save-status + the Save button
   are grouped into one wrapper (.card-header-save-wrap in index.html) so
   they occupy grid column 3 together, stacked, instead of each claiming
   their own auto-placed column. Applies to all 4 detail cards
   identically. The bottom-of-card Save button these cards used to have
   is gone -- this is the only Save control now. */
.card-header-row {
  display: grid;
  grid-template-columns: 10% 70% 20%;
  align-items: center;
  gap: var(--space-sm);
}
/* V3.45.7: Sabaq/Sabaq Dhor/Dhor's own header rows get a 4th column for
   the new timer icon, confirmed in chat -- scoped to just these 3
   cards by id rather than changing the shared .card-header-row rule
   itself, since every other screen (Tadabbur, Juz Tracker, etc.) still
   uses the plain 3-column version and shouldn't be affected. */
/* V3.45.9: simplified back to 3 columns, confirmed in chat -- the
   heading and timer button are no longer 2 separate grid columns
   (that's what caused the timer button to sit a fixed distance from
   the heading regardless of how short the text was, "hanging around"
   rather than reading as one phrase). Now grouped together in
   .card-header-title-group below instead, so the timer button's
   position dynamically follows wherever the heading text actually
   ends. Same 10/70/20 proportions the shared default already uses. */
#card-sabaq .card-header-row,
#card-sabaqDhor .card-header-row,
#card-dhor .card-header-row {
  grid-template-columns: 10% 70% 20%;
}
/* Heading + timer button as one flex unit, confirmed in chat --
   min-width:0 lets the h2's own ellipsis-truncation (the shared
   .card-header-row h2 rule below still applies, unchanged, since it's
   a descendant selector) keep working correctly inside a flex
   context; the timer button doesn't grow/shrink (flex: 0 0 auto),
   sitting immediately after however much space the heading text
   itself actually takes up. */
.card-header-title-group {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  min-width: 0;
}
.card-header-title-group .card-header-timer-btn { flex: 0 0 auto; }
.card-header-timer-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  border: none;
  background: none;
  padding: 0;
  font-size: 10px;
  font-weight: normal;
  text-transform: uppercase;
  color: var(--color-ink-soft);
  cursor: pointer;
}
/* V3.45.8: added a "Timer" text label below the icon, confirmed in
   chat -- matches the icon-on-top/uppercase-label convention
   .card-header-save-btn already uses. Icon shrunk from 24px to 20px.
   V3.45.9: `justify-self: center` (a grid-only property) removed --
   no longer a direct grid child of .card-header-row at all, now a
   flex child of .card-header-title-group instead (see that rule's
   own comment above for why). */
/* V3.50.2 (confirmed in chat): timer icon slightly bigger (20 -> 24px)
   and slightly right of the heading (margin doubles the title-group's
   own 4px gap to 8px) on the three log detail cards. */
.card-header-timer-btn svg { width: 24px; height: 24px; }
.card-header-title-group .card-header-timer-btn { margin-left: var(--space-xs); }
.card-header-row h2 { margin: 0; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.card-header-icon { width: 22px; height: 22px; color: var(--color-ink-soft); justify-self: center; }
.card-header-icon svg { width: 100%; height: 100%; }

/* V3.41: X-to-Home, added to every screen except Home itself (confirmed
   in chat) -- generalizes the same visual language .log-detail-close
   already established (below) into a shared class, rather than a
   second copy of the same rules. Reuses the existing `close` icon
   throughout for consistency. */
.screen-close-btn {
  border: none;
  background: none;
  padding: 4px;
  color: var(--color-ink-soft);
  cursor: pointer;
}
.screen-close-btn svg { width: 22px; height: 22px; }
.screen-close-btn:active { opacity: 0.6; }
/* Slots into a .card-header-row's 3rd (20%) column, same justify-self
   convention .card-header-save-wrap already uses for that column. */
.card-header-row .screen-close-btn { justify-self: center; }
/* For screens with no natural single-title header to slot into
   (Journal's own table header, Settings' 4 independent sections) -- a
   dedicated top-of-screen row instead. */
.screen-top-close-row {
  display: flex;
  justify-content: flex-end;
  margin-bottom: var(--space-sm);
}
/* V3.20.0: icon doubled in size and the whole unit centered (was right-
   aligned, hugging the column's edge and looking cramped live) both
   horizontally (align-items on the wrap) and within its grid cell
   (justify-self/align-self on the wrap itself, since .card-header-row's
   own align-items:center only centers row-height, not column-width). */
.card-header-save-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-self: center;
  align-self: center;
  gap: 2px;
  min-width: 0;
}
/* V3.41: when a screen's card-header-row already has save controls in
   its 3rd column (Tadabbur currently), the new X-to-Home button joins
   them here instead of fighting for the same grid slot -- a plain flex
   row, save-wrap keeps its own existing layout untouched inside it. */
.card-header-right {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  justify-self: center;
}
/* V3.23.0: date field widened -- was a fixed 30% column that truncated
   the rendered date text on narrower screens; now sized to its own
   natural content width instead. History moved into this same row
   (index.html) rather than sitting on its own further down, and
   align-items:stretch makes it match the date field's height exactly
   regardless of exact pixel values on either side. */
.card-date-row {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: stretch;
  /* V3.90.1: the fixed height was the real culprit behind "still
     touching" — when the pill renders taller than 44px (desktop), it
     spilled past the row's edge and OVER the V3.90.0 margin. The row
     now grows with its content; the pill keeps its own height. */
  height: auto;
  min-height: var(--dhor-row2-h);
  margin: var(--space-sm) 0 var(--space-md);
  gap: var(--space-sm);
}
.card-date-row .card-header-date { height: var(--dhor-row2-h); }
/* V3.90.0: the calendar-info label (e.g. the term name) sits on its own
   line ABOVE the pill, full-width, instead of crowding beside it. */
.card-date-row .card-date-info { grid-column: 1 / -1; order: -1; margin: 0 0 2px; }
.card-header-date {
  padding: 4px 6px;
  box-sizing: border-box;
}
/* Custom date display (2026-08-03, confirmed in chat): a native
   <input type="date">'s own displayed text is entirely browser/OS-
   controlled -- no CSS can reformat it, which is why desktop Chrome and
   mobile Safari were showing 2 different formats for the same date.
   wireCustomDateDisplay (js/customDate.js) wraps each date input in
   .custom-date-wrap and shows this visible pill in its place.
   V3.50.1 (confirmed in chat): the tap path is inverted -- the NATIVE
   INPUT sits invisibly ON TOP (z-index below) and is what the user
   actually taps, because showPicker() for date inputs was never
   implemented on iOS (WebKit bug 268114) and a direct tap on a real
   date input is the one thing iOS opens reliably. The pill is purely
   visual, styled to the iOS-native pill look the user preferred from
   Tadabbur's then-unwired bare input (screenshot, 2026-08-14). */
.custom-date-wrap {
  position: relative;
  width: 100%;
  height: 100%;
}
.native-date-hidden {
  position: absolute;
  inset: 0;
  opacity: 0;
  z-index: 2;         /* the real tap target, over the pill */
  cursor: pointer;
}
/* Keyboard affordance: the invisible input has focus, so ring the
   visible pill beside it instead (input is the wrap's first child). */
.native-date-hidden:focus-visible + .custom-date-display {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}
.custom-date-display {
  width: 100%;
  height: 100%;
  box-sizing: border-box;
  display: flex;               /* span now, not a button -- needs its own layout */
  align-items: center;
  justify-content: center;
  padding: 4px 14px;
  border: none;
  border-radius: 999px;
  background: #E9E9EB;         /* the iOS-native date-pill neutral */
  font-family: inherit;
  font-size: 13px;
  cursor: pointer;
  color: var(--color-ink);
}
/* V3.24.0: Row 2 replaces the old date-row + separate Amount/View-Plan
   row with ONE 40:30:30 grid (date : Plan Dhor : History) -- a shared
   --dhor-row2-h custom property (defined on the whole card so both this
   row AND Row 3's switch below can reference it) gives both buttons a
   real fixed height with wrapping (not truncating) labels, scoped here
   rather than changing .history-btn's general sizing, since Sabaq/Sabaq
   Dhor still use that for their own differently-laid-out History
   buttons. */
/* 2026-08-04: unified spacing/sizing system, confirmed in chat -- one
   shared row-height variable for every card instead of each row picking
   its own value (this used to be 40px here, 44px on Juz/Position and
   Duration/Timer, and nothing explicit at all on Sabaq/Sabaq Dhor's date
   row, which is exactly why nothing lined up between cards). Defined on
   .detail-page so all 4 cards share the exact same value. */
.detail-page { --dhor-row2-h: 44px; }
/* 2026-08-04: was a fixed 40:30:30 split -- confirmed in chat, changed
   to auto:1fr:1fr so the date sizes to its own short text (matching
   Sabaq/Sabaq Dhor's date field exactly, which has always been
   auto-sized) instead of being stretched to fill a fixed share of the
   row regardless of its content. Plan and History split whatever's left
   evenly. */
/* V3.50.2 (confirmed in chat): the bespoke .dhor-row2 40:30:30 grid is
   GONE -- Dhor's row 2 now uses the same .card-date-row markup and
   rules Sabaq/Sabaq Dhor always have (date pill left, History right,
   the general .history-btn sizing). Only the Plan button's own styling
   survives from that block, standalone: it moved to the bottom of the
   card, below Notes, at 30% width -- left-aligned by normal flow. The
   --dhor-row2-h custom property stays: .card-date-row, the amount
   switch, and Tadabbur's own date row all still size from it. */
.dhor-row2-btn {
  width: 30%;
  height: var(--dhor-row2-h);
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  white-space: normal;
  word-break: break-word;
  padding: 4px 6px;
  border: none;
  border-radius: var(--radius-sm);
  background: var(--palette-evergreen);
  color: #fff;
  font-size: 12px;
  line-height: 1.15;
  margin-top: var(--space-sm);
}
/* 2026-08-04: was sitting directly under Row 2 with no breathing room.
   V3.50.2 (confirmed in chat): bumped from --space-sm to --space-md --
   the pill sits slightly lower, per the Dhor UI adjustment set. */
#dhorAmountRow {
  margin-top: var(--space-md);
}
/* Row 3: Amount as a 3-way switch (reusing js/uiSwitch.js's shared
   component, same one Setup's Dhor Schedule granularity switch already
   uses), sized to 75% of Row 2's button height specifically -- not an
   independent hardcoded value -- so the two rows visibly relate. */
.switch-track.dhor-amount-switch {
  height: calc(var(--dhor-row2-h) * 0.75);
  margin: 0 auto;
  width: 78%;
}
/* V3.19.0: Save button restyled to match Hifzhelper's own existing
   icon-button convention (.nav-icon-item, css/base.css -- icon on top,
   label below, no border/background) instead of being a special-cased
   bordered button. This becomes the default for in-app icon buttons
   generally, not just Save (confirmed in chat). Label text stays normal
   weight (not bold) -- text-transform handles the caps, the underlying
   string ("Save"/"Saving") is untouched. */
.card-header-save-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  border: none;
  background: none;
  padding: 2px;
  font-size: 10px;
  font-weight: normal;
  text-transform: uppercase;
  color: var(--color-ink);
  cursor: pointer;
}
.card-header-save-btn:active { opacity: 0.6; }
.card-header-save-btn svg { width: 36px; height: 36px; }

/* Tajweed picker (V3.12.0) -- a compact trigger button instead of an
   inline row of toggle buttons, opening a popup with a checkbox per tag
   (multi-select doesn't fit a scroll-wheel or a plain dropdown). */
.tajweed-trigger-btn {
  width: 100%;
  text-align: left;
  padding: var(--space-sm);
  border: 1px solid var(--color-table-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  color: var(--color-ink-soft);
  font-size: 13px;
}
.tajweed-checkbox-list {
  margin-top: var(--space-md);
  max-height: 50vh;
  overflow-y: auto;
}
.tajweed-checkbox-row {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: 6px 0;
  font-size: 14px;
}
.tajweed-checkbox-row input { width: auto; }

/* Sabaq Dhor's checkable quarter-sections (V3.13.0) -- same row shape as
   the tajweed popup's checkbox list, just inline on the card itself
   rather than in a popup (there are at most 4, no need to hide them
   behind a trigger button the way tajweed's larger vocabulary needs). */
/* V3.21.2 fix: this used to be a separate CSS grid PER ROW (each row its
   own .sabaq-dhor-section-row, 80:20 columns computed independently),
   wrapped in a flex .sabaq-dhor-row-wrap to fit the optional Move to
   Dhor button beside it. That's the wrong tool for cross-row alignment
   -- confirmed in chat -- because each row's grid resolves its own 80%/
   20% split against ITS OWN box, so any tiny per-row width difference
   (rounding, or simply not being a perfectly reliable assumption) can
   shift that row's checkbox independently of the others. #sabaqDhor_sections
   is now ITSELF one shared grid; every row contributes exactly 3 direct
   grid children (text, move-button-or-empty-placeholder, checkbox) so
   every checkbox genuinely shares the same column across every row, the
   same way an HTML table's cells would -- not just three separately-
   computed approximations of the same column. */
/* V3.45.11: one shared outer border groups all 3 rows. V3.45.12 keeps
   that group border and restores a separate border around each row's
   field only. The checkbox remains outside its field border but inside
   this outer group, paired with the field by the shared grid row. */
.sabaq-dhor-sections-list {
  display: grid;
  /* V3.45.6: 3rd column changed from auto to a fixed 44px, confirmed in
     chat, matching .checkbox-box's own width exactly -- so this grid's
     checkbox column and the manual-selection row's own checkbox-box
     below it (a separate flex row, not part of this grid) land at the
     identical horizontal position, not just visually close. */
  grid-template-columns: 1fr auto 44px;
  align-items: center;
  column-gap: var(--space-sm);
  row-gap: var(--space-xs);
  flex: 1;
  min-width: 0;
  border: 1px solid var(--color-table-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  padding: var(--space-sm);
}
.sabaq-dhor-row-text {
  min-width: 0;
  font-size: 14px;
  padding: 2px 0;
}
/* V3.45.12: the two generated section labels are <label> elements, so
   they otherwise inherit .detail-page label's 16px top margin and 4px
   bottom margin. That margin was stretching only those grid rows, while
   the manual .verse-ref-field had no equivalent margin. This scoped rule
   resets both margins and gives the field its own border. The adjacent
   checkbox remains a separate child in the shared 44px checkbox column. */
#sabaqDhor_sections > .sabaq-dhor-row-text {
  margin: 0;
  padding: var(--space-sm);
  /* V3.45.9: explicit min-height added, confirmed in chat -- matches
     .checkbox-box's own 44px (the box sitting directly beside it in
     the same row) and .verse-ref-field below, so all 3 long boxes on
     this screen render identical in height regardless of what's
     inside them. min-height rather than a hard height deliberately --
     this row's own text ("Quarter 2 (current): 3:130 - 3:165") can
     wrap to 2 lines on narrower screens, and a fixed height would
     clip that wrapped text; min-height matches on the wide screens
     where the mismatch was actually observed, without risking
     overflow anywhere narrower text wraps. Without this at all,
     .verse-ref-field's own internal ayah-stepper (2 buttons stacked
     vertically) has a taller natural content height than this box's
     own single line of text, even with the same padding value. */
  min-height: 44px;
  display: flex;
  align-items: center;
  border: 1px solid var(--color-table-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
}
.move-to-dhor-btn {
  border: 1px solid var(--palette-evergreen);
  color: var(--palette-evergreen);
  background: none;
  border-radius: var(--radius-sm);
  padding: 4px 8px;
  font-size: 12px;
}
/* V3.45.6: replaces V3.45.5's width/height-only fix on the native
   checkbox itself, confirmed in chat as unreliable across browsers --
   native checkboxes (appearance:auto, the default) don't always
   respect explicit width/height the same way other elements do. This
   sidesteps that entirely: a plain container div/span reliably
   respects explicit CSS dimensions regardless of browser, so the
   checkbox itself stays unstyled and just sits inside one. Same
   bordered-box look as .verse-ref-field again, sized to comfortably
   fit a checkbox with real padding around it -- one shared class used
   everywhere a checkbox needs this treatment, not a scattered rule
   per screen. */
/* V3.45.9: border/background removed, confirmed in chat -- the
   checkbox itself was already "perfect as-is," it was specifically
   this container's own visible border drawing an unwanted box shape
   around it that needed to go. background was already invisible
   either way (matched the surrounding card's own color exactly) --
   removed anyway for cleanliness, not because it was ever the thing
   being seen. Sizing/alignment/centering role (the actual fix for the
   original cross-browser checkbox-sizing problem, V3.45.6) is
   completely unchanged -- the checkbox still sits centered in the
   same 44x44px area, still aligned identically across all 3 rows,
   just with no visible border marking that area's edges anymore. */
.checkbox-box {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  flex: 0 0 auto;
}
/* V3.50.0 (confirmed in chat): Sabaq's from/to fields wrapped in one
   bordered group styled to .sabaq-dhor-sections-list's own pattern --
   deliberately the same tokens (border/background/radius/padding) and
   the same 44px checkbox column (40px at >=768px, mirrored below in
   the same media block that adjusts Sabaq Dhor's own), with the
   checkbox itself in the SAME .checkbox-box class rather than a
   lookalike, so the >=768px scale-1.5 enlargement is inherited
   automatically and mobile keeps the native size (confirmed
   2026-08-12) -- one source of truth, per the V3.45.6-.11 lesson.
   Labels inside the group get their .detail-page label margins reset
   (the V3.45.12 lesson -- those inherited margins stretched grid rows
   in Sabaq Dhor's own group too); .confirm-group-gap restores the
   visual separation above "Sabaq to" deliberately instead. */
.confirm-field-group {
  display: grid;
  /* V3.50.2 (confirmed in chat): 2nd column was a fixed 44px, leaving
     no room to nudge -- now auto, with the box carrying a left margin,
     so the checkbox sits further right with a wider gap from the To
     field. The >=768px override below follows the same change. */
  grid-template-columns: 1fr auto;
  align-items: center;
  column-gap: var(--space-sm);
  row-gap: var(--space-xs);
  border: 1px solid var(--color-table-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  padding: var(--space-sm);
  margin-top: var(--space-md);
}
.confirm-field-group > label { margin: 0; }
.confirm-field-group .checkbox-box { margin-left: var(--space-sm); }
.confirm-field-group > label.confirm-group-gap { margin-top: var(--space-sm); }
/* V3.50.0: Dhor's confirm checkbox rides the Juz/portion picker-row as
   a third column in normal mode (and dhorRawRangeRow's third column in
   plan-range mode -- js/dhorPage.js toggles this class as it relocates
   the one box between modes). picker-row-single's own collapse
   (V3.26.1) composes with it. align-self:end + the 42px height match
   the row's own explicit control height (2026-08-03) so the checkbox
   centres on the control line, not the label line. */
/* V3.51.0 (confirmed in chat): V3.50.2's label removal took away the
   spacing between the amount pill and this row -- restored explicitly. */
#dhorJuzPositionRow { margin-top: var(--space-sm); }
.picker-row.picker-row-with-confirm { grid-template-columns: 1fr 1fr auto; }
.picker-row.picker-row-with-confirm.picker-row-single { grid-template-columns: 1fr auto; }
.picker-row .checkbox-box {
  align-self: end;
  height: 42px;
  /* V3.50.2 (confirmed in chat): nudged right -- widens the gap from
     the 1|2 portion switch (and from the plan-range buttons when the
     box relocates there). */
  margin-left: var(--space-sm);
}
/* V3.51.0: the V3.50.0 'park' relocation is gone -- editing no longer
   uses the confirm checkbox at all (Confirm changes replaced it), so
   the box simply hides in edit mode (rule above). */
/* V3.50.2 (confirmed in chat): Tadabbur's header only -- the icon
   column becomes max-content so the heading sits directly beside the
   icon (the shared 10% column held it at a fixed distance), the middle
   holds the title-group (heading + Save, V3.45.9 pattern), and a small
   fixed spacer reserves the corner where the absolutely-positioned
   X-to-Home floats (V3.45.1), which is what was overlapping Save. */
.tadabbur-header-row { grid-template-columns: max-content 1fr 32px; }
/* V3.45.14: checkbox made genuinely bigger on medium/large screens only,
   confirmed in chat -- transform:scale() on the native input itself
   rather than trying to set its own width/height directly, since a
   native checkbox doesn't reliably respect those across browsers
   (confirmed unreliable in this app's own V3.45.5 history). scale()
   sizes the already-rendered element instead of fighting its internal
   sizing, which doesn't have that same cross-browser problem. Also
   addresses the "reduce space to the right" bonus, confirmed via an
   annotated screenshot as BOTH readings together: .checkbox-box's own
   width shrinks (less residual empty space within its own container,
   directly reducing "the space in the checkbox's box"), and the outer
   group's own right-edge padding trims down too (reducing "the space
   between the 44px box and the group's outer edge"). Height stays 44px
   throughout -- unchanged, for vertical alignment with the other 44px
   elements on this same row. Mobile (<768px) is completely untouched,
   confirmed as in scope.
   V3.45.15: 2 refinements on top of the above, same scope (medium/large
   only) -- scale reduced from 1.8 to 1.5 ("a little smaller," no
   specific value given), and a new left margin added on .checkbox-box
   itself, separating it from the range/picker box beside it. This is a
   different edge than V3.45.14's own right-edge reduction above -- not
   a reversal of it, since that fix targeted the space AFTER the
   checkbox (toward the group's outer edge), while this one is
   specifically about the space BEFORE it. Stacks with the grid's own
   existing column-gap rather than replacing it, adding a bit more
   separation specifically on this one edge. */
@media (min-width: 768px) {
  .checkbox-box input[type="checkbox"] {
    transform: scale(1.5);
  }
  .checkbox-box {
    width: 36px;
    margin-left: var(--space-xs);
  }
  /* 3rd column grown from 36px to 40px here, confirmed necessary --
     .checkbox-box's own 36px width plus its new 4px left margin
     (var(--space-xs)) together need 40px of room; leaving the column
     at exactly 36px (matching width alone, the way it did before this
     margin existed) would have left no space for the margin to
     actually create, risking the box overflowing its own cell instead
     of the intended gap appearing. */
  .sabaq-dhor-sections-list {
    grid-template-columns: 1fr auto 40px;
    padding-right: var(--space-xs);
  }
  /* V3.50.0: same 44->40px checkbox-column adjustment for Sabaq's new
     confirm group, for the same reason (the 36px box + 4px left margin
     above need exactly 40px of room). */
  .confirm-field-group {
    grid-template-columns: 1fr auto;
    padding-right: var(--space-xs);
  }
}
/* V3.45.6: Sabaq Dhor's own manual-selection row, confirmed in chat --
   the picker takes remaining space, the checkbox-box sits fixed-width
   at the end, same as the section rows' own grid below so both align
   at the same horizontal position. */
/* V3.45.10: .sabaq-dhor-manual-row (a separate flex wrapper) and its
   own scoped min-height rule are REMOVED entirely, confirmed in chat --
   "Set Sabaq Dhor" is no longer a separate layout context at all. It's
   now a genuine 4th part of the SAME #sabaqDhor_sections grid
   "Quarter 2"/"Quarter 1" already share (js/sabaqDhorPage.js's
   renderSabaqDhorRows) -- the unified-grid architecture this version
   builds, extending V3.21.2's own "every checkbox genuinely shares the
   same column" principle to include the manual field too. Resolves
   the width/left-alignment mismatches (V3.45.9's own invisible-spacer
   hack is also gone, no longer needed -- an empty <span> in the same
   position "Quarter 2"/"Quarter 1" already use when they have no Move
   button naturally occupies that column now, no faked-width button
   required) by construction rather than by matching values across
   what used to be 2 separate contexts. */
/* V3.45.11: this class and the "Set Sabaq Dhor" heading it labeled
   were REMOVED entirely, confirmed in chat -- redundant once one
   shared border around all 3 rows already made clear they're all part
   of the same "Confirm Sabaq Dhor" action.
   V3.45.14: RE-ADDED for a different purpose -- the manual field
   became a genuine From/To range, "exactly like the Sabaq card,"
   which needs its own 2 labels the same way Sabaq's own "Sabaq
   from"/"Sabaq to" labels already work. margin:0 included this time
   (V3.45.11's version never needed it, having been removed before
   V3.45.12's own margin discovery) -- this is also a <label>, so
   without it, it would inherit the exact same 16px-top/4px-bottom
   margin from .detail-page label that .sabaq-dhor-row-text needed
   its own reset for. */
.sabaq-dhor-sections-header { grid-column: 1 / -1; margin: 0; }
/* V3.45.12: the manual picker keeps the shared .verse-ref-field border
   and background. Only its height is scoped here; its checkbox stays in
   the next grid column, outside the field border and inside the group's
   outer border. */
#sabaqDhor_sections > .verse-ref-field {
  min-height: 44px;
}
/* V3.19.0: rollup control is now a 2-button vertical stepper sitting to
   the left of the section list itself (js/icons.js: rollupMerge/
   rollupSplit), replacing the old full-width row above the list. Each
   button is display:none (not just visually hidden) when its action
   isn't actually eligible right now -- set in JS since it depends on
   comparing computed rows at adjacent rollup levels. */
.sabaq-dhor-sections-row {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}
.sabaq-dhor-rollup-stepper {
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex-shrink: 0;
}
.sabaq-dhor-rollup-btn {
  border: none;
  background: none;
  padding: 4px;
  color: var(--color-ink-soft);
  cursor: pointer;
}
.sabaq-dhor-rollup-btn svg { width: 18px; height: 18px; }

/* V3.45.13: breakpoint-specific Sabaq Dhor refinements. The existing
   768-1179px layout is deliberately untouched because it already renders
   correctly.

   Mobile: when neither roll-up direction is available, JS marks the
   otherwise-empty stepper as .rollup-inactive. Removing only that empty
   gutter, then reducing the checkbox track/gaps/horizontal group padding,
   returns enough width to the field column for the current-quarter text
   to remain on one line. Checkbox height stays 44px and every checkbox
   remains outside its field border but inside the outer group border. */
@media (max-width: 767px) {
  .sabaq-dhor-rollup-stepper.rollup-inactive { display: none; }
  .sabaq-dhor-sections-list {
    grid-template-columns: minmax(0, 1fr) auto 32px;
    column-gap: var(--space-xs);
    padding-inline: var(--space-xs);
  }
  #sabaqDhor_sections .checkbox-box { width: 32px; }
}

/* Large: an auto-sized CSS grid can stretch its implicit auto rows when
   surplus block-axis space reaches the container, leaving a 44px field
   visibly centred inside a much taller row. Size the group from its own
   content, make implicit rows max-content, and pack them at the start.
   Four pixels of vertical outer padding then matches the 4px row gap. */
@media (min-width: 1180px) {
  .sabaq-dhor-sections-list {
    height: max-content;
    grid-auto-rows: max-content;
    align-content: start;
    padding-block: var(--space-xs);
  }
}

/* Combined surah:ayah input field -- V3.18.0 rebuild as an explicit CSS
   grid (chevron:surah:ayah:chevron at 10:50:30:10, per the confirmed
   spec), replacing the flex version entirely rather than patching it.
   The flex version had no min-width guard on the surah label, so a long
   surah name could eat into its neighbours' share depending on exactly
   how much room its flex siblings claimed that render -- the same root
   issue (an unconstrained sibling silently stealing space from one
   that's supposed to have a fixed share) as the V3.14.1 ayah-width bug,
   just showing up via flex-basis instead of a specificity fight. Grid +
   min-width:0 on every text-bearing cell fixes it the same way for
   good: each column keeps exactly its assigned share no matter the
   content length. Left chevron keeps its existing job (opens the surah
   picker). Right chevron is new -- an explicit up/down stepper for the
   ayah value, since it was the native number input's own spinner that
   wasn't showing ("not visible at all") -- this replaces reliance on it
   rather than trying to make it visible. */
.verse-ref-field {
  display: grid;
  grid-template-columns: 10% 50% 30% 10%;
  align-items: center;
  gap: var(--space-xs);
  border: 1px solid var(--color-table-border);
  border-radius: var(--radius-sm);
  padding: var(--space-sm);
  background: var(--color-surface);
}
.verse-ref-chevron {
  border: none;
  background: none;
  font-size: 10px;
  line-height: 1;
  color: var(--color-ink-soft);
  cursor: pointer;
  padding: 4px;
  justify-self: center;
}
.verse-ref-surah-label {
  font-size: 14px;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.verse-ref-ayah-cell {
  display: flex;
  align-items: center;
  gap: 2px;
  min-width: 0;
}
.verse-ref-sep {
  color: var(--color-ink-faint);
  flex-shrink: 0;
}
.verse-ref-field .verse-ref-ayah {
  width: 100%;
  min-width: 0;
  border: none;
  padding: 0;
  text-align: right;
}
.verse-ref-ayah-stepper {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-self: center;
}
.verse-ref-ayah-stepper button {
  border: none;
  background: none;
  padding: 1px 4px;
  font-size: 9px;
  line-height: 1.2;
  color: var(--color-ink-soft);
  cursor: pointer;
}
.surah-picker-list {
  margin-top: var(--space-md);
  max-height: 60vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.surah-picker-row {
  width: 100%;
  text-align: left;
  margin: 0;
}

/* Tajweed pill buttons -- still used inside the popup's own grid style
   isn't needed here (checkboxes instead), but the "+ add" button and the
   Setup/Juz'-grid slide-ins still use this pill look. */
.tajweed-tag {
  display: inline-block;
  padding: 6px 12px;
  margin: 4px 6px 0 0;
  border: 1px solid var(--color-table-border);
  border-radius: 999px;
  font-size: 12px;
  background: var(--color-surface);
  color: var(--color-ink-soft);
}
.tajweed-tag.active {
  background: var(--color-accent);
  color: #fff;
  border-color: var(--color-accent);
}
.tajweed-tag.major.active {
  background: var(--color-error);
  border-color: var(--color-error);
}
.tajweed-tag.tajweed-add {
  border-style: dashed;
  color: var(--color-ink-faint);
}
.tajweed-tag:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.teacher-feedback-box {
  margin-top: var(--space-md);
  padding: var(--space-sm) var(--space-md);
  background: var(--color-page-bg);
  border-radius: var(--radius-sm);
  font-size: 13px;
}
/* V3.18.0: Private checkbox moves up next to the "Notes" label itself,
   replacing the row below the textarea (js/commentPrivacy.js). Scoped
   margin override below -- tadabbur's own private checkbox (a separate,
   standalone use of .cb-private-row under "Reflection", not "Notes")
   keeps its original spacing. */
.notes-header-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: var(--space-md);
  margin-bottom: 4px;
}
.notes-header-row label { margin: 0; }
.cb-private-row {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  margin-top: 8px;
  font-size: 13px;
  color: var(--color-ink-soft);
}
.notes-header-row .cb-private-row { margin-top: 0; }
.cb-private-row input { width: auto; }
.save-btn-text { white-space: nowrap; }

/* Small-wide switch variant (V3.12.0) -- the Notes block's Private/Public
   switch: wider than Setup's tiny inline gender switch, but not a full
   Setup-style field-width track either. */
.switch-track-small-wide {
  height: 34px;
  max-width: 220px;
}
.switch-track-small-wide .switch-option { font-size: 13px; }

/* Timer */
.timer-display {
  font-family: var(--font-mono);
  font-size: 40px;
  text-align: center;
  padding: var(--space-md) 0;
}
.timer-laps {
  max-height: 100px; overflow-y: auto;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--color-ink-soft);
}
.lap-row { padding: 2px 0; }
.timer-controls {
  display: flex; gap: var(--space-sm); margin-top: var(--space-sm);
}
.timer-controls button { flex: 1; }
#dhorTimerSummary, #sabaqDhorTimerSummary {
  font-size: 12px; color: var(--color-ink-soft); text-align: center; margin-top: var(--space-xs);
}

.save-status {
  display: inline-block; opacity: 0; transition: opacity 0.2s;
  color: var(--color-success); font-size: 12px;
  margin-left: auto;
}
/* Scoped rather than changed globally -- .save-status is shared with the
   Setup screens (css/settings.css), which have their own flex wrapper
   and don't need this. Only the new narrow 20%-wide save column here
   needs the smaller size. */
.card-header-save-wrap .save-status { font-size: 10px; }
.save-status.show { opacity: 1; }

.rail-card-date { font-size: 11px; color: var(--color-ink-faint); margin-bottom: 4px; }
.rail-card-body { font-size: 13px; }
.rail-card-laps { font-size: 12px; color: var(--color-ink-faint); margin-top: 2px; }
.rail-card-teacher { font-size: 12px; color: var(--color-ink-faint); margin-top: 2px; }   /* V3.75.0 item 10: the confirming teacher, maktab rows only */

/* History button (V3.18.0) -- compact, dark green (Evergreen), type-
   specific text ("Sabaq History" etc. -- js/dhorPage.js). The last-2-
   entries list below it is removed per the confirmed scope; the button
   alone opens the full popup (up to 50 entries), which still reuses
   .history-entry-row below.
   V3.23.0: moved into the date row (index.html), right-justified with
   edge padding, height matched to the date field via the row's own
   align-items:stretch (above) rather than a hardcoded pixel value --
   robust regardless of the exact rendered height of either side. Width
   deliberately left to size to its own label rather than forced to
   match the date field's width too, since "Sabaq Dhor History" would
   otherwise risk wrapping/truncating on a narrower screen. */
.history-container {
  display: flex;
  justify-content: flex-end;
  padding-right: var(--space-sm);
}
/* V3.86.0 (user, screenshot): NOT pills — a standard button shape.
   The old height:100% + zero vertical padding read as a capsule inside
   the bottom row; normal padding and the app's small radius now. */
.history-btn {
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  padding: 8px 14px;
  border: none;
  border-radius: var(--radius-sm);
  background: var(--palette-evergreen);
  color: #fff;
  font-size: 13px;
  white-space: nowrap;
}
/* V3.21.0: entry rows now hold an edit (pencil) icon button per row,
   opening that entry for editing in the card's own form. */
.history-entry-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  padding: 6px 0;
  border-bottom: 1px solid var(--color-table-border);
}
.history-entry-edit-btn {
  flex-shrink: 0;
  border: none;
  background: none;
  padding: 4px;
  color: var(--color-ink-soft);
  cursor: pointer;
}
.history-entry-edit-btn svg { width: 16px; height: 16px; }
/* V3.45.1: only added to .history-entry-content when a caller passes
   renderRecentEntries' new onRowClick parameter (currently just
   Tadabbur) -- Sabaq/Sabaq Dhor/Dhor's own rows stay non-interactive
   outside their edit icon, exactly as before. */
.history-entry-content-clickable { cursor: pointer; }
.history-full-list {
  margin-top: var(--space-md);
  max-height: 60vh;
  overflow-y: auto;
}

/* ============================================================
   Unified day-log view (V3.6.1) -- 4 cards: Sabaq / Sabaq Dhor / Dhor /
   Tadabbur. Mobile: swipeable rail, 1 card in view. Tablet: swipeable
   rail, 2 in view. Desktop: static 1x4 grid, no swiping -- breakpoints
   match the app-wide tablet/desktop convention already used for
   .login-card/#screen-admin (768/1180), not journal-table.css's older
   720px one.

   V3.12.0: swipe dots moved above the rail (was below) and now show
   text labels (Sabaq/SDhor/Dhor/Tadabbur) instead of plain circles --
   see index.html for the reordered markup, this file just restyles them.
   Cards are explicitly capped at max-width 30% on desktop -- with all 4
   visible, the 4-column grid already computes ~25% each on its own
   (design target: a 13" monitor as the practical maximum width, not an
   ultra-wide external display), the 30% is a stated ceiling rather than
   a value that changes today's math.
   ============================================================ */
/* V3.22.0: dedicated edit "screen" for Sabaq/Sabaq Dhor/Dhor -- not a new
   entry in the screen router (js/app.js), but a full takeover of
   #screen-logDetail that reuses the same card DOM/pickers rather than
   duplicating them: the tabs+dots row and every card except the one
   being edited hide, and within the editing card the normal header/
   History are replaced by this grey top/bottom chrome, confirmed in
   chat specifically so it can't be confused with the normal screen. */
/* Bug fix (2026-08-05, found by the user): #dhorTimerHost was never a
   .log-detail-card -- it's a separate custom element, targeted
   everywhere else in this file by its own id, not this class -- so the
   rule above genuinely could never reach it. That meant the Timer
   stayed visible throughout editing on every one of the other 3 cards,
   despite the actual intent above being "every card except the one
   being edited hides." The rail then had 2 visible elements instead of
   1 (the card being edited, plus the still-visible Timer still holding
   its own spot in the layout), and could land on the wrong one --
   explaining "editing an entry lands on the Timer" regardless of which
   path opened editing, since this same gap sat underneath all of them. */
/* V3.52.0: selectors generalized from .log-detail-card.editing-active
   to .editing-active -- Tadabbur's card is a .screen-content, not a
   .log-detail-card, and editing-active only ever exists during edit,
   so the broader scope is safe by construction. */
.editing-active .card-header-row,
.editing-active .history-container { display: none; }
/* V3.51.1 (confirmed in chat): grey background gone -- the popup reads
   as one clean card; the X is pinned to the popup's own top-right
   corner (absolute, rule below), so the heading row is just the title
   and the date control, with right padding keeping clear of the X. */
.edit-topbar {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: 0 36px var(--space-xs) 0;
  font-size: 15px;
  font-weight: 600;
  margin-bottom: var(--space-xs);
}
.edit-topbar button {
  flex-shrink: 0;
  border: none;
  background: none;
  font-size: 13px;
  color: var(--color-ink-soft);
  cursor: pointer;
}
/* V3.51.0: the card's own date control relocates here while editing --
   the wrap sizes to 100% of its parent, so the slot supplies the box. */
.edit-date-slot { width: 132px; height: var(--dhor-row2-h); flex: 0 0 auto; }
.edit-topbar-text { flex: 0 1 auto; }
.edit-close-btn {
  position: absolute;
  top: var(--space-sm);
  right: var(--space-sm);
  z-index: 1;
}
.edit-close-btn svg { width: 20px; height: 20px; }
/* V3.51.0: read-only portion box, edit mode only, for plan-path
   raw-range Dhor entries the picker can't express. */
.edit-portion-ro {
  border: 1px solid var(--color-table-border);
  border-radius: var(--radius-sm);
  background: var(--color-page-bg);
  color: var(--color-ink-soft);
  padding: 10px 12px;
  font-size: 14px;
  margin-top: var(--space-sm);
}
/* V3.51.0: hidden while editing -- their roles are replaced by the new
   flow (checkboxes -> Confirm changes; Plan/quarter rows aren't part of
   an edit; the manual checkbox likewise). */
.editing-active #dhorViewPlanBtn,
.editing-active #dhorConfirmBox,
.editing-active .confirm-field-group .checkbox-box,
.editing-active .card-date-row,          /* V3.51.1: empty 44px row once its date control relocates */
.editing-active .sabaq-dhor-group-label, /* V3.51.1: "Confirm Sabaq Dhor" -- meaningless in edit */
.editing-active .tadabbur-close-btn,     /* V3.52.0: the X-to-Home would float inside the popup */
.editing-active #sabaqDhor_sections .checkbox-box { display: none; }
/* V3.51.1: the quarter rows themselves are no longer RENDERED while
   editing (js/sabaqDhorPage.js keys the section render off the editing
   id) -- the old CSS-hide of .sabaq-dhor-row-text lost a specificity
   fight against #sabaqDhor_sections > .sabaq-dhor-row-text (1,1,0 vs
   0,3,0) AND would have broken the shared grid's auto-placement for
   the surviving From/To rows anyway. Structure over symptom. */
/* V3.51.0: the edit popup -- other screens visible beneath; the card
   swaps its takeover-era viewport-height formula for popup sizing. */
.edit-popup-modal { z-index: 60; }
.edit-popup-card {
  position: relative;              /* V3.51.1: anchors the pinned X */
  width: min(560px, 94vw);
  max-height: 75vh;                /* V3.51.1: ~75% of the screen (was 88vh) */
  display: flex;
  flex-direction: column;
  overflow: hidden;
  padding: var(--space-sm);
}
/* V3.52.0: two explicit selectors, deliberately -- the log-detail one
   keeps (0,3,0) so it still BEATS the later equal-specificity
   takeover-height rule (.log-detail-card.editing-active) that a
   generic .editing-active selector would lose to on source order; the
   #tadabburCard one covers the screen-content card at (1,2,0). */
.edit-popup-card .log-detail-card.editing-active,
.edit-popup-card #tadabburCard.editing-active {
  height: auto;
  max-height: calc(75vh - (var(--space-sm) * 2));
  flex: 1 1 auto;
  min-height: 0;
  /* V3.51.1: neutralize the RAIL's own sizing, which was rendering the
     card at 30% width inside the popup on desktop (>=1180px
     max-width:30%; >=768px flex-basis 50%) -- the illegible strip. */
  width: 100%;
  max-width: none;
  flex: 1 1 auto;
}
/* V3.51.0 (confirmed in chat): the icon bottombar is gone. Confirm
   changes gates Save -- disabled grey until anything differs from the
   loaded entry, green (ready) when dirty, solid green with reversed
   text once tapped (confirmed); Save greyed until confirmed, then solid
   green. Red Delete below keeps the existing pop-up confirmation. */
/* V3.51.1 (confirmed in chat, merged from the parallel session): grey
   shading removed here too -- buttons sit directly on the card. */
.edit-bottombar {
  margin-top: var(--space-md);
}
.edit-actions-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--space-sm);
}
.edit-confirm-btn, .edit-save-btn, .edit-delete-btn {
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  padding: 10px 14px;
  font: inherit;
  font-size: 14px;
  cursor: pointer;
}
.edit-confirm-btn:disabled, .edit-save-btn:disabled {
  background: var(--color-page-bg);
  border-color: var(--color-table-border);
  color: var(--color-ink-soft);
  cursor: default;
}
.edit-confirm-btn.ready {
  background: #FFFFFF;
  border-color: var(--palette-evergreen);
  color: var(--palette-evergreen);
}
.edit-confirm-btn.confirmed {
  background: var(--palette-evergreen);
  border-color: var(--palette-evergreen);
  color: #FFFFFF;
}
/* V3.51.1 (confirmed in chat): visually DISTINCT from the confirmed
   button beside it -- green fill removed; solid green stays unique to
   "Changes confirmed". */
.edit-save-btn:not(:disabled) {
  background: #FFFFFF;
  border-color: var(--palette-evergreen);
  color: var(--palette-evergreen);
}
.edit-delete-btn {
  display: block;
  width: 100%;
  margin-top: var(--space-md);   /* V3.51.1: more room above Delete */
  background: var(--color-error);
  border-color: var(--color-error);
  color: #FFFFFF;
}

/* Dhor's timer (2026-08-04, confirmed in chat) -- now a permanent rail
   card (index.html's #logDetailRail, in the exact position Tadabbur
   used to occupy) rather than an on-demand full-screen overlay.
   V3.45.7: relocated again, this time OUT of the rail entirely --
   confirmed in chat as needing to be "extremely useful"-level
   accessible (dropdown/Home/per-card entry points) and to stay visible
   across ANY navigation while running, neither of which the rail-card
   version could ever do. Both modes are now genuine position:fixed,
   full-viewport overlays -- "full" mode below no longer inherits any
   sizing from the rail context it used to sit in (flex/scroll-snap-
   align, both meaningless now that there's no rail to belong to). */
#dhorTimerHost {
  position: fixed;
  inset: 0;
  z-index: 260;
  border-radius: 0;
}
/* V3.45.8: maximized (mode="full") state gets its own size and
   position, confirmed in chat -- was inheriting the base rule's full-
   viewport inset:0 unconditionally (both modes identical apart from
   mini's own override), which is also the likely explanation for the
   reported close-icon dead zone (the × sitting right at the very top
   edge, overlapping the device's own status bar). Explicitly resets
   inset to auto before setting top/left -- the base rule's inset:0
   would otherwise still apply its own right/bottom sides even with
   top/left overridden here. Height fixed at 60% of viewport
   (--dhor-row2-h and other viewport-relative formulas elsewhere in
   this file are unrelated -- this is a plain, direct 60vh, not
   derived from any existing pattern). Width follows the app's own
   standard 50%/30% cap at the existing 768px/1180px breakpoints --
   same --width-tablet/--width-desktop tokens every other capped
   screen already uses, not new values invented for this. */
#dhorTimerHost[mode="full"] {
  inset: auto;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  height: 60vh;
  width: 100%;
  border-radius: var(--radius-md);
  overflow: hidden;
}
@media (min-width: 768px) and (max-width: 1179px) {
  #dhorTimerHost[mode="full"] { width: var(--width-tablet); }
}
@media (min-width: 1180px) {
  #dhorTimerHost[mode="full"] { width: var(--width-desktop); }
}
/* 2026-08-05, confirmed in chat: same technique .modal-overlay
   (css/components.css) already uses for History/Plan Dhor's own
   bottom-anchored sheets, applied here for the same underlying reason.
   V3.34.8 anchored only the pill's bottom edge directly
   (position:fixed;bottom:...), which is exactly the single-edge
   calculation iOS Safari's bottom-toolbar bug affects -- worked around
   it with a window.visualViewport recalculation in JS, which also
   applied unconditionally on desktop where the bug doesn't exist,
   visibly regressing a position that was already correct there.
   This version sidesteps the bug's mechanism entirely instead of
   working around it: the host becomes a full-viewport (inset:0),
   invisible (:host([mode="mini"]) is already background:transparent)
   positioning wrapper -- all 4 edges anchored simultaneously, the same
   way .modal-overlay's own inset:0 is, rather than asking the browser
   to calculate one edge (bottom) independently, which is specifically
   the calculation iOS gets wrong. Flexbox (align-items:flex-end) then
   pushes the actual visible pill -- session-timer.js's own .mini div,
   inside the shadow DOM -- to the bottom of that wrapper, the same way
   .modal-card sits at the bottom of .modal-overlay. pointer-events:none
   here (re-enabled on .mini itself, session-timer.js) so this
   full-viewport wrapper doesn't intercept taps anywhere except the
   small area the pill itself actually occupies -- everything behind it
   stays fully interactive. No JS, no visualViewport, no
   MutationObserver -- removed entirely from js/dhorPage.js. */
/* 2026-08-05, confirmed in chat: scope changed from "fix the bottom
   position" to a genuinely draggable pill -- default starting position
   moved to the top of the screen (align-items:flex-start, was flex-end),
   safe-area padding flipped to the top edge accordingly. Once dragged,
   session-timer.js switches .mini itself to explicit position:fixed
   left/top (see its own comment) -- this host rule only governs where
   the pill starts before any drag happens this session. */
#dhorTimerHost[mode="mini"] {
  position: fixed;
  inset: 0;
  flex: none;
  height: auto;
  overflow: visible;
  border-radius: 0;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: calc(20px + env(safe-area-inset-top, 0px)) 20px 0;
  pointer-events: none;
  z-index: 250;
}

#dhorLapRollup {
  margin-top: 6px;
}
#dhorLapRollupToggle {
  background: none;
  border: none;
  padding: 0;
  font-size: 12px;
  color: var(--color-ink-faint);
  cursor: pointer;
  font: inherit;
}
#dhorLapRollupList {
  font-size: 12px;
  color: var(--color-ink-faint);
  margin-top: 4px;
  padding-left: 4px;
}

/* V3.45.8: the Stopwatch column that used to sit here
   (.dhor-stopwatch-col/#dhorStopwatchToggle) is REMOVED entirely,
   confirmed in chat -- redundant with the new timer-icon header
   button (V3.45.7). Duration's own CSS below is unchanged. */
/* 2026-08-04, confirmed in chat: Duration split into 2 plain number
   fields (Minutes/Seconds) instead of one text field holding "mm:ss" --
   a colon in the middle of a single field doesn't play well with the
   native numeric keypad (inputmode="numeric" expects plain digits), so
   each field being purely numeric lets the native keypad work exactly
   as designed for both, with the colon here now just a visual separator
   between them, not something either field actually contains. */
.dhor-duration-split {
  display: flex;
  align-items: center;
  gap: 6px;
}
#dhor_duration_min, #dhor_duration_sec {
  height: var(--dhor-row2-h);
  box-sizing: border-box;
  width: 100%;
  text-align: center;
}
.dhor-duration-colon {
  font-weight: 600;
  color: var(--color-ink-faint);
}

/* V3.44.1: Tadabbur's own card, confirmed in chat -- deliberately a
   different exception from the standard 30/50 rule: 50% specifically,
   at every breakpoint the cap would otherwise narrow it further
   (unlike most screen-content instances, which drop to 30% at
   >=1180px, this one stays at 50% throughout -- more room for long
   reflection text was the explicit reason given). Flex column so the
   textarea below can flex to fill the remaining space after the
   header/date/checkbox/label take their own natural height.
   min-height mirrors .screen's own formula, additionally subtracting
   .screen's own 10px-all-sides padding (20px total top+bottom) since
   this card sits inside that padding -- same technique already used
   elsewhere (--appcontent-vpad) for a parent's padding not otherwise
   being accounted for. */
#tadabburCard {
  display: flex;
  flex-direction: column;
  /* V3.45.2: min-height changed to height, confirmed in chat -- the
     card's own display:flex/flex-direction:column and #tadabbur_text's
     own flex:1 were never the problem (both correct since V3.44.1).
     What was missing: this card never had a DEFINITE size, only a
     minimum, for its internal flex children to actually distribute
     within -- min-height alone doesn't reliably guarantee that the way
     an explicit height does. Deliberately NOT touching #appContent/
     .screen (the app-wide flex-cascade alternative was considered and
     rejected as too risky, since those are shared by every screen) --
     this stays fully scoped to this one card. height still allows
     genuinely long content to push the card taller, same as before,
     since nothing here sets overflow:hidden. */
  height: calc(100vh - var(--auth-band-height, 60px) - (var(--appcontent-vpad) * 2) - 20px);
  height: calc(100dvh - var(--auth-band-height, 60px) - (var(--appcontent-vpad) * 2) - 20px);
  /* V3.45.1: anchor point for .tadabbur-close-btn's absolute
     positioning below, confirmed in chat -- matches .modal-card's own
     position:relative for the same corner-x-button pattern used
     elsewhere in the app. */
  position: relative;
  /* V3.45.1: .card-date-row (below) needs --dhor-row2-h, normally
     defined on .detail-page (line ~177) -- this card doesn't carry
     that class (it would also pull in .detail-page's own unrelated
     label/input/textarea styling, which isn't wanted here), so the
     same 44px value is defined directly on this card instead. */
  --dhor-row2-h: 44px;
}
@media (min-width: 768px) {
  #tadabburCard { width: var(--width-tablet); margin: 0 auto; }
}
@media (min-width: 1180px) {
  /* Deliberately repeats --width-tablet (50%), not --width-desktop
     (30%) -- .screen-content's own >=1180px rule would otherwise drop
     this to 30% like everywhere else; this override keeps it at 50%
     throughout instead. */
  #tadabburCard { width: var(--width-tablet); margin: 0 auto; }
}
/* V3.45.1: close button moves out of the header row's own grid flow
   entirely, confirmed in chat -- pinned to the card's top-right
   corner instead of sitting inline (previously grouped with Save via
   .card-header-right, which is now removed since only Save remains in
   that slot). Values match .modal-card .close-btn's own established
   corner-x pattern exactly, rather than inventing new ones. */
.tadabbur-close-btn {
  position: absolute;
  top: var(--space-md);
  right: var(--space-md);
}
#tadabburCard label { margin-top: var(--space-sm); }
/* V3.44.1: flexes to fill the card's own remaining height, confirmed
   in chat -- grows/shrinks with the card rather than staying a fixed
   rows-based size. min-height:0 is the standard flexbox fix for a
   flex:1 child otherwise refusing to shrink below its content's
   natural size (same pattern .card-scroll already uses elsewhere).
   Font-size increased per "make the input text bigger".
   V3.45.1: NOT YET ROOT-CAUSED -- confirmed via live screenshot that
   this isn't actually growing to fill the card in practice, despite
   this CSS reading correctly on paper. Left as-is rather than
   guessing at an unverified fix; flagged for the user to re-check
   after this delivery, since it may or may not resolve as a side
   effect of the header-row/date-row restructuring done alongside it
   in this same version. */
#tadabbur_text {
  flex: 1;
  min-height: 0;
  font-size: 18px;
  resize: none;
}

/* ---- Log Detail rail (swipeable Sabaq/Sabaq Dhor/Dhor cards) ---- */
.log-detail-rail {
  display: flex;
  gap: var(--space-md);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
}
/* 2026-08-05, confirmed in chat: height was a flat 70vh regardless of
   how much space was actually available above it (the auth band, the
   dots row) -- leaving a real, substantial gap of unused space below
   the card on most phones, and stranding edit-mode's own bottom
   controls partway down the screen instead of near the bottom where a
   thumb naturally reaches. Two calculated standards now, confirmed as
   a pattern to reuse for anything built going forward, not a one-off:
   normal view subtracts both the auth band and the dots row (~36px --
   the .dot button's own padding+font+border, worked out directly,
   plus its row's 8px margin-bottom); .editing-active subtracts only
   the auth band, since the dots row is genuinely hidden then (see
   js/logDetailScreen.js's own enterEditScreenMode), not just visually
   similar to hidden. #dhorTimerHost (below) uses the same "normal"
   calculation -- it's a separate custom element, not a .log-detail-card,
   so it needed its own matching rule, not something this one covers
   automatically. */
.log-detail-card {
  flex: 0 0 100%;
  scroll-snap-align: start;
  background: var(--color-surface);
  border: 1px solid var(--color-table-border);
  border-radius: var(--radius-md);
  /* V3.43: now also subtracts #appContent's own vertical padding
     (--appcontent-vpad, tokens.css), confirmed in chat -- this formula
     predates #appContent having any explicit sizing of its own, so it
     never accounted for that space being unavailable; without this the
     card would run past the visible viewport by exactly that amount. */
  height: calc(100vh - var(--auth-band-height, 60px) - 36px - (var(--appcontent-vpad) * 2));
  display: flex;
  flex-direction: column;
  overflow: hidden; /* .card-scroll below does the actual scrolling */
}
.log-detail-card.editing-active {
  height: calc(100vh - var(--auth-band-height, 60px) - (var(--appcontent-vpad) * 2));
}
.log-detail-card .card-scroll {
  overflow-y: auto;
  padding: var(--space-md);
  flex: 1;
  min-height: 0; /* flexbox gotcha: without this, a flex:1 child with
                    overflow-y:auto won't actually scroll -- it just grows
                    past its container instead of shrinking to fit it. */
}

@media (min-width: 768px) and (max-width: 1179px) {
  .log-detail-card { flex: 0 0 calc(50% - (var(--space-md) / 2)); }
}
@media (min-width: 1180px) {
  .log-detail-rail {
    display: grid;
    /* V3.45.8: was repeat(4, 1fr), left over from the old 4-card layout
       (Timer was the 4th slot) -- confirmed as a real bug, not
       ambiguous. Timer's removal in V3.45.7 was never matched here, so
       the 3 real cards were each being squeezed into 1/4-width columns,
       leaving a permanently empty 4th column and a large unused gap on
       the right at wide screens. */
    grid-template-columns: repeat(3, 1fr);
    overflow: visible;
    scroll-snap-type: none;
  }
  /* V3.89.0: Groups folded into General — the settings rail is back to
     three cards, so the shared repeat(3) rule covers it and the V3.88.0
     four-column override is gone (the V3.45.8 lesson, applied again). */

  /* Dots row is hidden entirely at this breakpoint (all 3 cards already
     visible in the grid, nothing to indicate a position within) -- same
     auth-band-only calculation as .editing-active uses everywhere,
     since there's genuinely nothing to subtract for it here either. */
  /* V3.89.1: max-width was 30% — for a GRID ITEM that percentage
     resolves against its own grid AREA (one column), so Chrome capped
     every card at ~30% of a third of the screen (the user's sliver
     cards), while Safari resolved it against the wider block and looked
     right. The card must simply FILL its column; the 3-column grid
     already caps the layout. */
  .log-detail-card { height: calc(100vh - var(--auth-band-height, 60px) - (var(--appcontent-vpad) * 2)); max-width: none; width: 100%; min-width: 0; }
}

/* Dot indicators -- only meaningful while the rail actually swipes;
   hidden entirely on the desktop grid, where all 3 cards are visible at
   once and there's nothing to indicate a position within. Text labels
   (V3.12.0) instead of plain circles -- same active/inactive states.
   V3.19.0: row is now a 3-col grid (spacer:dots:close) so the dots stay
   centered independently of the xclose button on the right -- only
   .log-detail-dots-inner hides on desktop below, not the whole row,
   since xclose still needs to work there too. */
/* V3.41: this specific close button now goes to Home like every other
   screen's (js/logDetailScreen.js) -- was Journal-only before, kept
   its own dots-row-specific layout here since it needs to sit in a
   3-column spacer:dots:close grid unlike every other screen's simpler
   placement, but shares .screen-close-btn's icon sizing/color/active
   state via the same class now (see above) rather than duplicating
   those rules a second time. */
.log-detail-dots {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  margin-bottom: var(--space-sm);
}
.log-detail-dots-inner {
  grid-column: 2;
  display: flex;
  justify-content: center;
  gap: var(--space-sm);
}
.log-detail-close {
  grid-column: 3;
  justify-self: end;
}
.log-detail-dots .dot {
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 12px;
  background: var(--color-surface);
  border: 1px solid var(--color-table-border);
  color: var(--color-ink-soft);
}
.log-detail-dots .dot.active { background: var(--color-accent); color: #fff; border-color: var(--color-accent); }
@media (min-width: 1180px) {
  .log-detail-dots-inner { display: none; }
}

/* V3.24.0: Plan Dhor modal -- reuses .modal-overlay/.modal-card as its
   base (same as History's popup), plus the shared checkbox-grid pattern
   already proven for Sabaq Dhor (.sabaq-dhor-sections-list) here as
   .plan-dhor-grid, for the same reason it was built as one shared grid
   there: every row needs to align in a genuinely shared column. */
.plan-dhor-card {
  max-width: 480px;
  max-height: 85vh;
  display: flex;
  flex-direction: column;
}
/* 2026-08-04 (confirmed in chat, found via the user's own DevTools
   experiment isolating viewport height as the real variable): every
   child of a flex container can shrink by default unless told not to.
   .plan-dhor-content (below) already has flex:1 + overflow-y:auto --
   the clear intent was always for the list to be the one part that
   scrolls internally when content exceeds the 85vh cap. But without
   flex-shrink:0 here, the title row, switch, and Select All button
   were ALSO shrinking to help make room, proportional to how much
   content-list overflow there was -- which is exactly why "View All"
   (30 rows) squeezed the switch far more than "Dhor Plan" (a handful
   of rows) ever did, and why a shorter browser viewport made it worse:
   85vh of a smaller viewport is a smaller number, tightening the same
   squeeze further. */
.plan-dhor-row1 {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--space-sm);
  flex-shrink: 0;
}
.plan-dhor-title {
  font-size: 16px;
  font-weight: 600;
}
.plan-dhor-row1-icons {
  display: flex;
  gap: var(--space-md);
}
.plan-dhor-row1-icons button {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  border: none;
  background: none;
  padding: 4px;
  font-size: 10px;
  text-transform: uppercase;
  color: var(--color-ink);
  cursor: pointer;
}
.plan-dhor-row1-icons button svg { width: 20px; height: 20px; }
#planDhorTabSwitch { flex-shrink: 0; }
.plan-dhor-select-all {
  align-self: center;
  flex-shrink: 0;
  margin: var(--space-sm) 0;
  border: 1px solid var(--palette-evergreen);
  color: var(--palette-evergreen);
  background: none;
  border-radius: var(--radius-sm);
  padding: 4px 12px;
  font-size: 12px;
  cursor: pointer;
}
.plan-dhor-content {
  overflow-y: auto;
  flex: 1;
}
.plan-dhor-grid {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  column-gap: var(--space-sm);
  row-gap: 4px;
}
.plan-dhor-row-text {
  min-width: 0;
  font-size: 14px;
  padding: 4px 0;
}
.plan-dhor-row-greyed { color: var(--color-ink-faint); }
.plan-dhor-juz-block {
  display: flex;
  align-items: flex-start;
  gap: var(--space-sm);
  padding: 6px 0;
  border-bottom: 1px solid var(--color-table-border);
}
.plan-dhor-juz-rollup {
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex-shrink: 0;
  padding-top: 4px;
}
.plan-dhor-rollup-btn {
  border: none;
  background: none;
  padding: 4px;
  color: var(--color-ink-soft);
  cursor: pointer;
}
.plan-dhor-rollup-btn svg { width: 16px; height: 16px; }
/* display:contents -- this wrapper's own box disappears, so its 2
   children (label, checkbox) become direct participants in the parent
   .plan-dhor-grid's 2-column layout, exactly like V3.21.2's shared-grid
   fix for Sabaq Dhor. Click still bubbles up to this element normally. */
.plan-dhor-tap-row { display: contents; }
.plan-dhor-tap-row .plan-dhor-row-text,
.plan-dhor-tap-row .plan-dhor-unit-cb { cursor: pointer; }

/* V3.24.0: From/To buttons replace Juz/Starting-at when a Plan Dhor
   selection doesn't reduce to one clean quarter/half/juz -- styled to
   look like a plain field (matching the selects they replace) even
   though tapping either reopens Plan Dhor rather than editing inline. */
.dhor-raw-range-btn {
  width: 100%;
  text-align: left;
  border: 1px solid var(--color-table-border);
  background: var(--color-surface);
  border-radius: var(--radius-sm);
  padding: 6px 8px;
  font-size: 14px;
  color: var(--color-ink);
  cursor: pointer;
}

/* V3.24.1: Dhor Plan tab's rolled-up day rows -- a plain button styled
   to look like the same .plan-dhor-row-text label it sits alongside
   (not like a normal button), since it's a row in the same grid, just
   with an expand affordance built into its own text rather than a
   separate checkbox (there's no single meaningful checked state to
   show when completion is genuinely mixed for that day). */
.plan-dhor-expand-btn {
  min-width: 0;
  text-align: left;
  border: none;
  background: none;
  padding: 4px 0;
  font: inherit;
  font-size: 14px;
  color: var(--color-ink);
  cursor: pointer;
}
.plan-dhor-subrow {
  padding-left: var(--space-md);
  color: var(--color-ink-soft);
}
.plan-dhor-unit-cb:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

/* V3.71.0 — read-only maktab day for a student. The JS sweep in
   js/logDetailScreen.js disables the controls; this is only how they LOOK.
   Deliberately not display:none on individual controls — hiding some
   children of the shared card grids is what scrambled auto-placement in the
   V3.45.6-.11 saga, so the layout stays identical and the controls simply
   read as inert. */
.log-detail-readonly [disabled] {
  opacity: 0.45;
  cursor: default;
  pointer-events: none;
}
/* The save wrap and Delete are pure write chrome — nothing to read there, so
   they go entirely rather than sitting greyed out. Whole rows, not
   individual grid children. */
.log-detail-readonly .card-header-save-wrap,
.log-detail-readonly .edit-delete-btn { display: none; }

/* V3.75.0 — .card-header-row-left (V3.74.2) DELETED. It never had any
   effect: base.css's `.screen:has(> .screen-content) .card-header-row`
   outranks a single class, so the Admin header kept the two-column grid
   and its close button fell onto a second row. The Admin layout now lives
   in css/admin.css as an id-scoped rule, which wins by construction. */

/* Note-visibility switch, inside the note box (V3.73.0, resized V3.74.4).
   Reuses .switch-track / .switch-option; the box groups label, switch and
   textarea so the control reads as governing the note.
   No display:none on individual controls -- hiding some children of a
   shared grid is what scrambled auto-placement in the V3.45.6-.11 saga. */
/* V3.75.0 (item 11): margin-top so the box stands off the section above it —
   the same --space-md the PJ's .notes-header-row already carries, so the
   two modes of the card sit their notes at the same height. */
.cb-note-box { border: 1px solid var(--line, #d9d9d9); border-radius: 12px; padding: var(--space-sm, 8px); margin-top: var(--space-md, 16px); }
.cb-note-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-sm, 8px); margin-bottom: var(--space-xs, 4px); }
.cb-note-head label { margin: 0; }
.cb-note-box .cb-teacher-note { border: none; width: 100%; background: transparent; resize: vertical; }

/* V3.74.4 — ONE rule, replacing three stacked generations of it. Each
   earlier attempt appended a new .mk-vis-switch block rather than editing
   the previous, so the file carried three contradictory sets of numbers.

   And the real bug: both earlier attempts set MAX-WIDTH. The track is a
   flex container that sizes to its content -- three short words -- so a
   max-width only ever capped it and never widened anything. 110 -> 187 ->
   240 were all no-ops. It needs an explicit WIDTH.

   flex: 0 0 auto stops the .cb-note-head flex row shrinking it back below
   the width set here, which would undo the fix from the other direction.

   V3.75.0 (item 3) — and the reason the HEIGHT never changed either: the
   base `.switch-track { height: 42px }` lives in css/settings.css, which
   index.html loads AFTER this file. One class against one class, so
   source order decided it and the base rule won every time. The width
   worked only because the base rule sets none. Selector is now two
   classes (.cb-note-box .mk-vis-switch), which outranks the base rule
   wherever it is loaded. Same cascade trap as CONVENTIONS lesson (d). */
.cb-note-box .mk-vis-switch {
  width: 240px;
  flex: 0 0 auto;
  height: 20px;
  margin: 0;
}
.mk-vis-switch .switch-option {
  font-size: 10px;
  padding: 0 4px;
  line-height: 1;      /* the inherited line-height alone can hold the track taller than its height */
  min-width: 0;        /* flex children default to min-content -- a long label would force it wider */
}
.mk-vis-switch .switch-option.active { font-weight: 600; }
.mk-vis-switch .switch-thumb {
  height: 100%;
  top: 0;
  border-radius: 999px;   /* tied to the height, so it is a pill and not a circle */
}

/* V3.74.2 — item 10: Move to Dhor on its own row, spanning the grid rather
   than sharing the portion's middle column. The label carries the portion
   ("Move First Half to Dhor") because the button is PER-ROW: on its own
   line it loses the visual tie to the portion above it, and two movable
   rows would otherwise stack two identical buttons. */
.move-to-dhor-row {
  grid-column: 1 / -1;
  justify-self: start;
  margin: var(--space-xs, 4px) 0 var(--space-sm, 8px);
}

/* V3.78.0 (item 8): the space between groups on the maktab summary. The
   gap alone carries the meaning (no heading rows), so it is deliberately
   much taller than the normal row separation. */
.maktab-group-gap td { border: none; padding: 0; height: 18px; background: transparent; }

/* V3.78.0 (item 9): search-to-student above the summary table. */
/* V3.84.0: the search moved INTO the green Student header cell — the
   full-width .maktab-search-row is gone from the markup; the dropdown
   rules below are shared by the new cell. */
.maktab-search-cell { position: relative; }
.maktab-search-cell-label {
  background: none; border: none; padding: 0; margin: 0; cursor: pointer;
  font: inherit; color: inherit; text-transform: inherit; letter-spacing: inherit;
  display: inline-flex; align-items: center; gap: 4px;
}
/* V3.91.0 (user): the magnifier rides the LEFT of "Student" */
.maktab-search-cell-label::before {
  content: ''; width: 11px; height: 11px; flex: 0 0 auto; opacity: .85;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-3.5-3.5'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-3.5-3.5'/%3E%3C/svg%3E") center / contain no-repeat;
}
.maktab-search-cell input[type="search"] {
  width: 100%; box-sizing: border-box;
  font-size: 12px; padding: 3px 6px; margin: -2px 0;
  border: none; border-radius: var(--radius-sm);
  background: rgba(255,255,255,0.92); color: var(--color-text, #222);
  text-transform: none; letter-spacing: normal; font-weight: 500;
}
.maktab-search-cell .maktab-search-results {
  /* under the CELL, but wide enough to read: spill right of the 25% column */
  min-width: 230px; left: 0; right: auto;
  text-transform: none; letter-spacing: normal; font-weight: 500;
}
.maktab-search-results {
  position: absolute; left: 0; right: 0; top: 100%; z-index: 60;   /* V3.91.0: above the table, always */
  background: var(--color-surface, #fff);
  border: 1px solid var(--color-table-border);
  border-radius: var(--radius-sm);
  box-shadow: 0 4px 12px rgba(0,0,0,0.12);
  max-height: 260px; overflow-y: auto;
}
.maktab-search-result { display: block; width: 100%; text-align: left; background: none; border: none; border-bottom: 1px solid var(--color-table-border); font: inherit; font-size: 14px; padding: 10px 12px; cursor: pointer; color: var(--color-ink); }
.maktab-search-result:last-child { border-bottom: none; }
.maktab-search-empty { font-size: 13px; color: var(--color-ink-faint); padding: 10px 12px; }

/* V3.85.0/V3.85.1: the standalone student-summary page. The header is
   ONE single-row grid sized like the journal itself (the user's
   suggestion): icon | name | attendance | close, sharing the table's
   70% centering on wide screens so nothing floats off to the corners. */
#screen-studentSummary .journal-header-row { margin-top: var(--space-sm); }
.ss-header {
  display: grid;
  /* V3.90.0 (user): the attendance icon sits DIRECTLY AFTER the name —
     "Umme's attendance" — with the X keeping the far corner. */
  grid-template-columns: auto auto auto 1fr;
  align-items: center;
  gap: var(--space-sm);
  margin: var(--space-sm) 0;
}
.ss-header .att-nav-btn { margin-left: 0; }
.ss-header .screen-close-btn { justify-self: end; }
.ss-header h2 { margin: 0; }
.att-nav-btn { background: none; border: none; padding: 4px; cursor: pointer; color: var(--color-ink-soft); }
/* the attendance icon reads at the same visual weight as the title now
   (the first cut's 22px was far too small — user) */
.att-nav-btn svg, .att-nav-btn .icon { width: 30px; height: 30px; display: block; }
.ss-header .screen-close-btn { position: static; margin: 0; }
@media (min-width: 768px){   /* the journal's own breakpoint (journal-table.css) */
  .ss-header { width: 70%; margin-left: auto; margin-right: auto; }
}

/* V3.85.0: the attendance page's two cards */
.att-card {
  background: var(--color-surface, #fff);
  border: 1px solid var(--color-table-border);
  border-radius: var(--radius-md);
  padding: var(--space-md);
  margin: var(--space-sm) 0 var(--space-md);
  box-shadow: 0 1px 3px rgba(0,0,0,0.06);
}
.att-custom-row { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.att-custom-sentence { font-size: 13px; }
/* V3.85.2 (user, 2026-08-28): the attendance cards capped at 50% and
   centered on larger screens — the named figure, applied from the
   app's standard 768px breakpoint. */
@media (min-width: 768px) {
  .att-card { width: 50%; margin-left: auto; margin-right: auto; }
}

/* V3.85.0: both history buttons at the card bottom, below Notes */
.card-history-bottom { display: flex; align-items: center; gap: var(--space-sm); margin: var(--space-sm) 0; }
.notes-kind { font-weight: 700; text-transform: uppercase; font-size: 10px; letter-spacing: .04em; }
.notes-kind-feedback { color: var(--accent, #2f7d5d); }

/* V3.86.0: the Apply check beside the attendance dates */
.att-apply-check {
  flex: 0 0 34px; width: 34px; height: 34px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--color-table-border); border-radius: var(--radius-sm);
  background: var(--color-surface, #fff); color: var(--palette-evergreen);
  font-size: 18px; font-weight: 700; cursor: pointer; padding: 0;
}

/* ============================================================
   V3.87.0: the maktab calendar page + the date markers */
.mcal-card {
  background: var(--color-surface, #fff);
  border: 1px solid var(--color-table-border);
  border-radius: var(--radius-md);
  padding: var(--space-md);
  margin: var(--space-sm) 0 var(--space-md);
}
@media (min-width: 768px) { .mcal-card { width: 50%; margin-left: auto; margin-right: auto; } }
.mcal-month-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--space-sm); font-weight: 700; }
.mcal-weekdays, .mcal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.mcal-weekdays span { text-align: center; font-size: 11px; opacity: .6; padding: 2px 0; }
.mcal-day { position: relative; min-height: 40px; border-radius: var(--radius-sm); padding: 3px 4px; font-size: 13px; }
.mcal-day-muted { opacity: .35; }
.mcal-day-today .mcal-day-num { font-weight: 800; text-decoration: underline; }
.mcal-day-term { background: rgba(47, 125, 93, 0.10); }
.mcal-dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; margin: 2px 1px 0; }
.mcal-dot-islamic { background: var(--palette-evergreen, #2f7d5d); }
.mcal-dot-holiday { background: #b4552d; }
.mcal-term-swatch { display: inline-block; width: 14px; height: 10px; border-radius: 3px; background: rgba(47, 125, 93, 0.25); }
.mcal-legend { display: flex; gap: var(--space-md); margin-top: var(--space-sm); font-size: 12px; align-items: center; flex-wrap: wrap; }
.mcal-list-row { display: flex; gap: var(--space-sm); padding: 6px 0; border-bottom: 1px solid var(--color-table-border); font-size: 14px; }
.mcal-list-row:last-child { border-bottom: none; }
.mcal-list-date { flex: 0 0 auto; opacity: .7; font-variant-numeric: tabular-nums; }
.mcal-list-islamic { color: var(--palette-evergreen, #2f7d5d); font-weight: 600; }
.mcal-list-holiday { color: #b4552d; }
.mcal-list-term span:last-child { font-weight: 700; }

/* the marker riding date cells + day headers, wherever dates appear */
.mcal-mark { display: inline-block; width: 7px; height: 7px; border-radius: 50%; margin-left: 5px; vertical-align: middle; }
.mcal-mark-islamic { background: var(--palette-evergreen, #2f7d5d); }
.mcal-mark-holiday { background: #b4552d; }
.card-date-info { font-size: 11px; opacity: .75; margin-left: 8px; }

/* ============================================================
   V3.88.0: the attendance/haidh layout (user schematic) */
.att-card-title { margin: 0 0 var(--space-sm); font-size: 17px; }
.att-sentence { font-size: 15px; margin-bottom: var(--space-sm); }
.att-custom-label { font-weight: 600; margin-top: var(--space-md); }
#attAbsentBtn { margin: var(--space-sm) 0; }
.att-haidh-subtext { margin: 2px 0 var(--space-sm); font-size: 13px; opacity: .8; }
/* the calendar expands to 90% of the card (user) */
#attHaidhBlock .haidh-cal-weekdays, #attHaidhBlock .haidh-cal-grid { width: 90%; margin-left: auto; margin-right: auto; }
#attHaidhBlock .haidh-cal-nav { width: 90%; margin-left: auto; margin-right: auto; }
/* the range/decision bars use the FULL width; Confirm keeps its size
   but sits on its OWN line, centred (user's circled clipping) */
#attHaidhBlock .haidh-range-bar { width: 100%; box-sizing: border-box; }
.haidh-range-bar-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-sm); }
.haidh-range-confirm-btn { flex-basis: 100%; margin: 6px auto 0; display: block; max-width: max-content; }

/* ============================================================
   V3.90.0 — the queued polish batch (user, 2026-08-29) */
/* the pill-selector TRIAL: one shared class, cascades to every from/to
   row on all cards, PJ and maktab alike */
.verse-ref-field { border-radius: 999px; }
/* air between the note boxes and the history buttons; and above notes */
.card-history-bottom { margin-top: var(--space-md); }
#sabaqCommentBlock, #sabaqDhorCommentBlock, #dhorCommentBlock { margin-top: var(--space-md); }
/* dhor From/To labels above the selector boxes */
.dhor-sel-label { display: block; font-size: 13px; color: var(--color-ink-soft); margin-bottom: 4px; }

/* ============================================================
   V3.91.0 — the queued batch (user, 2026-08-29) */
/* 28: the calendar page header + month nav */
.mcal-header h2 { margin: 0; white-space: normal; }
.mcal-header { margin: var(--space-sm) 0; }
@media (min-width: 768px) { .mcal-header { width: 50%; margin-left: auto; margin-right: auto; } }
.mcal-month-row .secondary { width: auto; flex: 0 0 auto; padding: 6px 14px; }
#mcalMonthLabel { flex: 1 1 auto; text-align: center; white-space: nowrap; }
/* 29a: the selector family takes the palette's light blue */
.verse-ref-field { background: var(--color-accent-soft, #D0DBE7); border-color: transparent; }
#dhor_juz, #dhor_juz_to { background: var(--color-accent-soft, #D0DBE7); border: none; border-radius: 999px; padding-left: 14px; }
.sabaq-dhor-row { background: var(--color-accent-soft, #D0DBE7); border-color: transparent; }
/* 29d: Add-Juz/Plan rides the far right of the date row */
.card-date-row #dhorViewPlanBtn { justify-self: end; }

/* ============================================================
   V3.93.0 — the day-card set + the setup popup (user's annotated
   mocks, 2026-08-30) */
/* (a)+(b): space before the boxed timer */
.card-header-timer-btn {
  margin-left: var(--space-md);
  border: 1.5px solid var(--color-ink, #222);
  border-radius: var(--radius-sm);
  padding: 4px 8px;
  background: transparent;
}
/* (c): the Lines/Pages unit box */
.unit-amount-box { position: relative; display: flex; align-items: center; }
.unit-amount-box input { width: 100%; padding-right: 120px; box-sizing: border-box; }
.unit-pill {
  position: absolute; right: 6px; display: inline-flex;
  border: 1px solid var(--color-table-border); border-radius: 999px; overflow: hidden;
  background: var(--color-surface, #fff);
}
.unit-pill button { border: none; background: transparent; font-size: 11px; padding: 4px 10px; cursor: pointer; color: var(--color-ink-soft); }
.unit-pill button.on { background: var(--color-accent-soft, #D0DBE7); color: var(--color-ink, #222); font-weight: 600; }
/* (d): the Sabaq Dhor suggestion rows as pills */
.sabaq-dhor-row { border-radius: 999px; }
/* (e): the position switch rides the SAME line as the juz select */
/* V3.96.1: center parked the bare switch in the LABEL GAP of the
   labelled From column (the verified cause of every failed alignment
   nudge) — the row bottom-aligns instead, so the switch stands level
   with the select. */
#dhorJuzPositionRow { flex-wrap: nowrap; align-items: flex-end; }
#dhorPositionField { display: inline-flex; align-items: center; }
/* (g): Duration / Mistakes / Tajweed as one row */
.dhor-triple-row { display: flex; gap: var(--space-sm); align-items: flex-end; }
.dhor-triple-row > div { flex: 1 1 0; min-width: 0; }
.dhor-triple-row #dhor_duration_min { width: 100%; box-sizing: border-box; }
/* (h): history symmetry — the pair sits identically on every card */
.card-history-bottom { justify-content: flex-start; }
.card-history-bottom .history-btn, .card-history-bottom .history-container .history-btn {
  min-width: 150px; justify-content: center;
}
/* the setup popup: 3×10 selectable chips; save icon head */
.maktab-setup-head { display: flex; justify-content: flex-end; align-items: center; gap: var(--space-sm); margin-bottom: var(--space-sm); }
.maktab-setup-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.maktab-setup-juz {
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--color-table-border); border-radius: 999px;
  padding: 10px 6px; cursor: pointer; user-select: none;
  background: var(--color-surface, #fff);
}
.maktab-setup-juz input { position: absolute; opacity: 0; pointer-events: none; }
.maktab-setup-juz:has(input:checked) { background: var(--palette-evergreen, #344C3D); color: #fff; border-color: transparent; }
.maktab-setup-juz.partial { border-style: dashed; }

/* ============================================================
   V3.94.0 (user, 2026-08-30) */
/* 40: the Ajzaa popup — title left of the save icon; the X in the LEFT
   corner; pills ~20% smaller with centred text */
.maktab-setup-head { justify-content: space-between; }
.maktab-setup-title { font-size: 17px; margin: 0 0 0 28px; flex: 1 1 auto; }
.maktab-setup-card .maktab-setup-close { left: var(--space-md); right: auto; }
.maktab-setup-juz { padding: 8px 5px; font-size: 13px; text-align: center; }
.maktab-setup-juz span { width: 100%; text-align: center; }
/* 41a: the PILL lands on the element that actually carries the border */
#sabaqDhor_sections .sabaq-dhor-row-text,
.sabaq-dhor-row-wrap .sabaq-dhor-row-text {
  border-radius: 999px;
  background: var(--color-accent-soft, #D0DBE7);
  border-color: transparent;
  padding-left: 16px; padding-right: 16px;
}
/* 41b: the inline 1|2 switch gets real dimensions beside the select */
#dhorPositionField { flex: 0 0 auto; }
/* 41c: the triple row's labels share one line */
.dhor-triple-row { align-items: flex-start; }
.dhor-triple-row > div > label { display: block; margin-top: 0; margin-bottom: 6px; }
/* V3.95.0 (user's boxed mock, replacing the flex-end reading): the
   history pair SPREADS — one to each end — on every card. */
.card-history-bottom { justify-content: space-between; }

/* ============================================================
   V3.95.0 (user, 2026-08-30 09:51 — the red Space markers and the
   dashed alignment lines) */
/* (c) air above the notes, above the history row, above dhor's triple */
#sabaqCommentBlock, #sabaqDhorCommentBlock, #dhorCommentBlock { margin-top: var(--space-lg, 24px); }
.card-history-bottom { margin-top: var(--space-lg, 24px); }
.dhor-triple-row { margin-top: var(--space-md); }
/* (d) the From select and the 1|2 pills share the line at ONE height;
   the three boxes of the triple row align and match height */
/* V3.96.1: the forced track sizes are GONE (both of them — 34px and
   44px debris from three failed attempts). The component's contract is
   restored instead: renderSwitch computes the thumb as PERCENTAGES of
   the track assuming N equal slots, so the options become equal flex
   slots and one width serves 2-way and 4-way alike. */
#dhorPositionField .switch-track { width: 140px; }
#dhor_position_switch .switch-option { flex: 1 1 0; min-width: 0; padding-left: 0; padding-right: 0; text-align: center; }
.dhor-triple-row input,
.dhor-triple-row .tajweed-trigger-btn { height: var(--dhor-row2-h); box-sizing: border-box; }
.dhor-triple-row .tajweed-trigger-btn { width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
