/* ═══════════════════════════════════════════════════════════════════════════
   LSD PORTAL — SHARED RESPONSIVE LAYER                            Phase 12
   ═══════════════════════════════════════════════════════════════════════════

   WHY THIS FILE EXISTS
   Responsive work was done page-by-page as each phase shipped, so six pages
   ended up with five different breakpoint sets (1024/720/420 · 900/720/480 ·
   880/420 · 720/520 · 860/700/600/480) and wildly uneven quality. index.html
   and manzoori.html are a copy-paste pair differing by ~127 lines; audio.html
   and quran-ikhtebar.html independently reinvented the same two-row-header
   recipe. Editing six inline <style> blocks guarantees they drift again.

   HOW IT COMPOSES
   Linked AFTER each page's inline <style> block, so at equal specificity this
   file wins. The division of labour is deliberate:

       inline <style>   →  APPEARANCE (colors, borders, type, brand look)
       responsive.css   →  LAYOUT at every width

   That split is what makes "responsive only, keep both looks" safe: the two
   token systems (paper-ink-amber on admin, brown-gold here) are never touched.

   MOBILE-FIRST, HONESTLY SCOPED
     · Universal hygiene (touch, text-size-adjust, overscroll, 16px controls)
       is unprefixed — it is correct at every width.
     · The SHELL is authored phone-first: base rules are the phone layout and
       `min-width: 901px` restores the single-row desktop header. This is only
       possible because all five app-page `.header` rules are structurally
       identical (64px tall, 24px gutter, flex, space-between).
     · Page-specific component tiers use `max-width`. Deliberate: those pages'
       desktop CSS lives in untouched inline blocks, and flipping them to
       min-width would mean rewriting all six inline stylesheets — exactly the
       re-skin risk the "responsive only" decision rules out.

   BREAKPOINT LADDER — the single ladder, replacing all five old sets
     base            phone portrait   iPhone SE 375 · 17 402 · 17 Pro Max 440
                                      Pixel 9 Pro 412 · S25 Ultra 412
     min-width: 481  large phone / phone landscape (667–956)
     min-width: 640  foldable unfolded / small tablet
                     (Pixel 9 Pro Fold inner ~674, Galaxy Z Fold inner ~653-700)
     min-width: 901  desktop, single-row header

   901px, not 721px: the header does not overflow at iPad-portrait widths, it
   SQUASHES — clipping the active nav tab behind the FILES link and wrapping
   the quota pill. The breakpoint has to clear the content's real minimum, not
   the point where a scrollbar finally appears. (Inherited from audio.html.)

   Capability queries do the rest, because they ask the right question:
   `pointer: coarse` gives a touch laptop 44px targets while a narrow desktop
   window stays compact — width can never tell you that.

   TEST CONSTRAINT — READ BEFORE ADDING AN OVERLAY
   `test_fullscreen_flex_overlays_can_scroll` is parametrised over every
   frontend/*.css, so it polices this file. Any rule carrying all three of
   `position: fixed`, `display: flex` and `inset: 0` must also have
   `overflow-y: auto` and must NOT have `align-items: center` — a flex item
   taller than its container overflows BOTH ways, putting its top out of
   scroll reach. Use `align-items: flex-start` + `margin: auto` on the child.
   The bottom sheets below sidestep this by pinning left/right/bottom rather
   than using `inset: 0`.
   ═══════════════════════════════════════════════════════════════════════════ */


/* ─── § 1 · LAYOUT TOKENS ─────────────────────────────────────────────────
   Mobile-first: the bare :root values are the phone's. Each tier raises them.
   Everything downstream reads the token, so a gutter change happens once. */

:root {
  --shell-gutter: 14px;
  --header-h: 56px;

  /* WCAG 2.5.5 / Apple HIG minimum. */
  --tap: 44px;

  /* Landscape on a notched iPhone takes ~59px on the notch side, so the
     inset can exceed the gutter — max() keeps whichever is larger. */
  --safe-l: max(var(--shell-gutter), env(safe-area-inset-left, 0px));
  --safe-r: max(var(--shell-gutter), env(safe-area-inset-right, 0px));
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-t: env(safe-area-inset-top, 0px);

  /* Height the iOS soft keyboard is covering. Published by viewport.js from
     window.visualViewport; stays 0px everywhere else, including Android,
     where `interactive-widget=resizes-content` shrinks the layout viewport
     and dvh already does the right thing. */
  --kb-inset: 0px;

  /* Tells the UA to render form controls, scrollbars and the canvas in light
     colors. Without it iOS will happily auto-darken a <select> out from under
     the brand palette. */
  color-scheme: light;
}

@media (min-width: 481px) { :root { --shell-gutter: 16px; } }
@media (min-width: 640px) { :root { --shell-gutter: 20px; } }
@media (min-width: 901px) { :root { --shell-gutter: 24px; --header-h: 64px; } }


/* ─── § 2 · UNIVERSAL HYGIENE ─────────────────────────────────────────────
   Correct at every width, so no media query. */

html {
  /* iOS inflates text when a page rotates to landscape unless told not to.
     100% (not `none`) so user-initiated zoom still works. */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

/* Nothing may exceed the viewport. Note we do NOT set `overflow-x: hidden` on
   body — that hides overflow bugs rather than fixing them, and would make the
   no-horizontal-overflow assertion in the device matrix pass falsely. */
img, svg, video, canvas { max-width: 100%; height: auto; }
pre, code { overflow-x: auto; }

/* A long unbroken token (a URL, an un-spaced Arabic string) is the other way
   a page gains a horizontal scrollbar. */
.msg-bubble, .message-bubble, .lsd-render, .preview, .exam-verse-card {
  overflow-wrap: anywhere;
}

/* Removes the ~300ms delay browsers reserve for double-tap-to-zoom, and stops
   a double tap on a control zooming the page instead of firing twice. */
a, button, summary, label,
[role="button"], input[type="submit"], input[type="button"],
.header-link, .header-btn, .seg-control a, .pick-btn, .drop-zone {
  touch-action: manipulation;
  -webkit-tap-highlight-color: rgba(92, 58, 40, 0.14);
}

/* Long-pressing a button on iOS raises the copy/share callout and starts a
   text selection. Controls only — never links or content, where selecting
   text is the whole point. */
button, summary,
.header-link, .header-btn, .seg-control a,
.mic-btn-large, .stop-btn, .retry-btn, .play-mini, .pick-btn {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

/* Scroll chaining: without `contain`, flinging past the end of any of these
   scrolls the page behind it — and on Android Chrome, fires pull-to-refresh
   mid-chat, discarding whatever was typed. */
.chat-container, .page-body, .messages,
.audio-history, .upload-queue,
.annot-modal, .header-right {
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}

/* Every control keeps a visible focus ring for keyboard and switch-control
   users. `:focus-visible` so a tap does not leave a ring behind. */
a:focus-visible, button:focus-visible,
input:focus-visible, select:focus-visible, textarea:focus-visible,
summary:focus-visible {
  outline: 2px solid var(--gold-600, #A67C3D);
  outline-offset: 2px;
}


/* ─── § 3 · APP SHELL: HEADER + CROSS-PAGE NAV ────────────────────────────
   Phone-first. Base = the two-row header; min-width:901px puts it back on one
   row. Shared by index / manzoori / audio / quran-ikhtebar / files, whose
   .header rules are structurally identical.

   THE BUG THIS FIXES: index.html and manzoori.html had
   `@media (max-width: 420px) { .seg-control { display: none } }` — which left
   a phone user with NO way to reach Chat, Manzoori or Audio. audio.html had
   already spotted this and kept the nav in a scrollable row instead. That
   pattern is now portal-wide, and `.seg-control` is never hidden anywhere.
   Pinned by test_mobile_readiness.py::test_cross_page_nav_is_never_hidden. */

.header {
  height: auto;
  min-height: var(--header-h);
  flex-wrap: wrap;
  align-items: center;
  row-gap: 6px;
  padding: calc(6px + var(--safe-t)) var(--safe-r) 0 var(--safe-l);
}

/* min-width:0 is what lets a long title actually ellipsis instead of forcing
   the flex row wider than the screen — the default `min-width: auto` on a
   flex item refuses to shrink below its content. */
.header-left { flex: 1 1 auto; min-width: 0; }
.header-left > div { min-width: 0; }
.header-title {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The email line is the first thing to go — it is recoverable from /files or
   the admin page, the nav is not. */
.header-subtitle { display: none; }

.header-right {
  order: 3;
  flex: 1 0 100%;
  justify-content: flex-start;
  gap: 6px;
  padding-bottom: 8px;
  /* Even wrapped onto its own row, quota + 3-way nav + FILES + ADMIN + logout
     can exceed a 320px screen. Scroll it sideways in place rather than
     clipping the logout button off the end. */
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}
.header-right::-webkit-scrollbar { display: none; }
/* Scrollable flex children must not shrink, or they compress instead. */
.header-right > * { flex-shrink: 0; }

.seg-control { flex-shrink: 0; }

/* ── Tablet portrait and up: the email line fits again ── */
@media (min-width: 721px) {
  .header-subtitle { display: block; }
}

/* ── Desktop: back to one row ── */
@media (min-width: 901px) {
  .header {
    height: var(--header-h);
    min-height: 0;
    flex-wrap: nowrap;
    row-gap: 0;
    padding: 0 var(--safe-r) 0 var(--safe-l);
  }
  .header-left { flex: 0 1 auto; }
  .header-right {
    order: 0;
    flex: 0 1 auto;
    justify-content: flex-end;
    gap: 8px;
    padding-bottom: 0;
    overflow-x: visible;
  }

  /* Restore desktop footer layout */
  .ik-footer, .ik-footer.is-condensed { padding: 30px 40px 22px; }
  .ik-footer-cols { 
    flex-direction: row-reverse;
    align-items: center;
    justify-content: space-between;
    gap: 48px;
  }
  .ik-footer-brand { 
    max-width: 300px; 
    order: 0;
  }
  .ik-footer-col { 
    gap: 35px; 
    order: 0;
  }
  .ik-footer-bottom {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
  }
}


/* ─── § 4 · TOUCH TARGETS ─────────────────────────────────────────────────
   Keyed on the pointer, not the width. A touch laptop or an iPad Pro at
   1024px gets 44px targets; a narrow desktop window does not get needlessly
   chunky ones. */

@media (pointer: coarse) {
  .header-link, .header-btn { height: var(--tap); min-width: var(--tap); }
  .seg-control a { height: var(--tap); padding: 0 14px; }
  .audio-history-row .play-mini,
  .upload-row .status-icon {
    min-width: var(--tap);
    min-height: var(--tap);
  }
  .audio-history-row { padding: 12px; }
  .word-timing-chip { padding: 6px 10px; font-size: 12px; }
  .ww-add, .na-btn, .grade-submit-row .btn { min-height: var(--tap); }
  /* The composer collapses to 40px when empty, which is under the minimum and
     is the single most-tapped element on the phone. It still grows to its
     140px max as the user types. */
  .input-field { min-height: var(--tap); }
  .stars .star { min-width: var(--tap); min-height: var(--tap); font-size: 24px; }
  .form-pwd-toggle { min-height: var(--tap); min-width: var(--tap); }
  .exam-mistake-group summary { min-height: var(--tap); }
  .submit-btn, .pick-btn, .exam-start-btn { min-height: var(--tap); }
  /* The minutes form. `.mform-remove` is a 32px × that DELETES a line someone
     just typed, which is the worst possible combination of small and
     destructive; `.btn-ghost` carries SAVE DETAILS and both export buttons.
     The checkbox gets its target from the label wrapping it, so the whole
     "Online" control is tappable rather than just the 13px box. */
  .mform-remove, .mform-add, .mform-online, .btn-ghost {
    min-height: var(--tap);
    min-width: var(--tap);
  }

  /* NOT resized: `.logo-mark` stays 38x38. It is a link to /app, and the CHAT
     entry in .seg-control is a >=44px control to the same destination on the
     same screen — which is WCAG 2.5.5's explicit equivalent-control exception.
     Inflating the brand mark to 44px to satisfy a checker that the criterion
     already exempts would be the wrong trade. Recorded here so the next person
     to run the tap-target audit knows it was a decision, not an oversight. */

  /* iOS zooms the whole page when a control smaller than 16px takes focus,
     then leaves it zoomed. This is a floor, not a restyle — desktop keeps its
     designed 13/15px sizes because this block never applies there.
     The class selectors are needed: a bare `textarea` (0,0,1) loses to
     `.input-field` (0,1,0) no matter which file it is in. */
  input, select, textarea,
  .input-field, .form-input, .modal-input, .modal-select,
  .ww-row input, .annot-modal input, .annot-modal select, .annot-modal textarea {
    font-size: 16px;
  }
}

/* Hover affordances must never be the only way to see something. Anything
   that appears purely on :hover gets pinned visible where hover is faked. */
@media (hover: none) {
  .copy-btn, .annot-action-btn, .msg-actions { opacity: 1; }
}


/* ─── § 5-6, 8 · REMOVED ───────────────────────────────────────
   The chat (index/manzoori), audio and files pages were dropped when the
   Ikhtebar was extracted from the portal. Section numbers below are left
   as they were so this file still lines up with the upstream one it was
   taken from — renumbering buys nothing and loses that correspondence. */

/* ─── § 7 · QURAN IKHTEBAR (quran-ikhtebar.html) ──────────────────────────*/

@media (max-width: 900px) {
  .exam-page-grid { max-width: none; padding: 20px; }
}

@media (max-width: 720px) {
  .exam-page-grid {
    padding: 16px var(--safe-r) calc(24px + var(--safe-b)) var(--safe-l);
    gap: 16px;
  }
  .exam-page-title { font-size: 22px; }
  .exam-verse-card { padding: 16px 14px; }
}

/* Keep side-by-side layout even on very small screens, just adjust spacing */

@media (max-width: 480px) {
  .exam-page-title { font-size: 20px; }
  .exam-score-tiles { gap: 8px; }
  .exam-score-tile { padding: 12px; flex-basis: 100px; }
  .exam-score-value { font-size: 22px; }
  .exam-stepper { flex-wrap: wrap; row-gap: 6px; }

  /* Additional attempts page fixes for very small screens */
  .ik-attempts-head h1 { font-size: 22px; }
  .ik-pagination-btns { 
    gap: 4px; 
    justify-content: center; 
  }
  .ik-page-btn { 
    min-width: 32px; 
    height: 32px; 
    padding: 0 8px; 
    font-size: 12px; 
  }
  
  /* Ensure breadcrumb navigation doesn't overflow */
  .ik-breadcrumb { 
    font-size: 13px; 
    overflow-wrap: anywhere; 
  }
  
  /* Ensure attempt items stack better on very small screens */
  .ik-attempt { 
    padding: 12px 14px; 
    gap: 8px 12px; 
  }
  .ik-attempt-score { 
    width: 48px; 
  }
  .ik-attempt-total { 
    font-size: 18px; 
  }

  /* Make sure toolbar segments don't overflow */
  .ik-segment button {
    padding: 0 10px;
    font-size: 12px;
    white-space: nowrap;
  }

  /* Fix header brand alignment on very small screens */
  .header.ik-appbar .ik-brand-name {
    font-size: 26px;
  }
  .header.ik-appbar .ik-brand .logo-mark {
    width: 30px;
    height: 30px;
  }

  /* Fix page section padding */
  .exam-page-grid {
    padding: 12px var(--safe-r) calc(16px + var(--safe-b)) var(--safe-l);
  }

  /* Additional footer adjustments for very small screens */
  .ik-footer-cols {
    min-height: 44px;
  }
  .ik-footer-col {
    gap: 12px;
  }
  .ik-footer-col a {
    font-size: 12px;
  }
  
  /* Ensure footer bottom elements have proper sizing on mobile */
  .ik-footer-bottom span,
  .ik-footer-bottom a {
    font-size: 10.5px;
    flex-shrink: 0;
  }
}

/* The rubric USED to be a 4-column table with a 520px min-width that scrolled
   sideways on a phone, behind an edge-fade meant to advertise the scroll. It
   was the wrong trade: a student contesting a grade had to drag the marks
   into view, and the fade only made a bad affordance discoverable. It is now
   a list of criteria (.exam-rubric-list) that reflows — the criterion column
   is minmax(0, 1fr) and the descriptor spans the full width beneath, so the
   whole block fits a 320px screen with nothing off-canvas.

   Nothing here may reintroduce a width, a min-width or an overflow on the
   rubric. Pinned by test_the_rubric_never_scrolls_sideways. */

/* Stacked, the criterion column absorbs all the slack — which is right on a
   phone and wrong on anything wider, where it leaves a growing void between
   the criterion and its marks and pushes the descriptor onto a line of its
   own below. From 640px there is room to put the descriptor back in that
   void: four columns, the descriptor taking what is left.

   The criterion column is a FIXED 10rem here, not max-content. Each item is
   its own grid, so a content-sized column would resolve differently per row
   and the marks would stop lining up down the block — the one thing the old
   table was actually buying. 10rem holds every criterion in the seeded
   rubric, and a longer one wraps rather than widening anything.

   This is a reflow, NOT the old table: no min-width, so it collapses back to
   the stacked layout below 640px instead of scrolling. */
@media (min-width: 640px) {
  .exam-rubric-item {
    grid-template-columns: 10rem 2.5rem 4.5rem minmax(0, 1fr);
    column-gap: 14px;
  }
  .exam-rubric-desc { grid-column: auto; }
}

/* ── Phase 14: the marked passage on the results screen ──
   Same rule as the rubric above: it reflows and must NEVER scroll sideways,
   or a student reads Quran through a letterbox. Nothing here sets a width. */

@media (max-width: 480px) {
  .exam-passage-block { padding: 12px 10px; }
  .exam-passage-legend { gap: 10px; row-gap: 6px; }
}

/* Marked words are the only tappable thing inside a block of text, so they
   need real target height without opening gaps between the unmarked words
   around them. Vertical padding plus inline-block gets that; the generous
   line-height on .exam-passage is what stops the padded boxes colliding
   between lines. Keyed on the pointer, not the width — a touch laptop needs
   this and a narrow desktop window does not. */
@media (pointer: coarse) {
  .exam-passage-word.marked {
    display: inline-block;
    padding: 6px 4px;
    margin: 0 -2px;
  }
}


/* ─── § 7b · QURAN IKHTEBAR — Claude Design "Ikhtebar UI Polish" LAYOUT ────
   Appearance for these components lives in quran-ikhtebar.html's inline
   <style> (the "Claude Design polish" block); everything here is layout at
   width, same division of labour as the rest of this file. Page-specific
   max-width tiers, per § 7's stated convention. The design's own tiers are
   1024 (desktop as drawn) and 768 (below it the hamburger sheet takes over);
   those are the two used here. */

/* App bar: one row at every width; nav inline ≥768, hamburger + sheet below. */
.header.ik-appbar {
  flex-wrap: nowrap;
  row-gap: 0;
  align-items: center;
  min-height: 0;
  height: auto;
  padding: 12px var(--safe-r) 12px var(--safe-l);
  border-bottom: 2px solid #3F2415;
}
.header.ik-appbar .ik-brand { flex: 0 1 auto; }
.header.ik-appbar .ik-nav { order: 0; flex: 0 1 auto; }
.header.ik-appbar .ik-appbar-right { order: 0; flex: 0 0 auto; overflow: visible; padding-bottom: 0; }

@media (min-width: 768px) {
  .ik-hamburger { display: none !important; }
  .ik-navsheet { display: none !important; }
}

@media (max-width: 767.98px) {
  .header.ik-appbar { gap: 12px; }
  .header.ik-appbar .ik-nav { display: none; }
  .header.ik-appbar .ik-account { display: none; }
  .ik-hamburger { display: flex; }
  .ik-brand-sub { display: none; }
  .header.ik-appbar .ik-brand .logo-mark { width: 32px; height: 32px; }
  .ik-brand-name { font-size: 15px; }

  .exam-page-grid {
    padding: 16px var(--safe-r) calc(24px + var(--safe-b)) var(--safe-l);
    gap: 16px;
  }
}

/* Tablet and below: the 2-col grids stack. */
@media (max-width: 1023.98px) {
  .ik-rules { grid-template-columns: 1fr; }
  .ik-ayah-grid { grid-template-columns: 1fr; }
  /* Side by side the cards read right-to-left (START right, STOP left) like the
     Arabic; once stacked, START has to come first top-to-bottom. */
  .ik-ayah-grid .exam-verse-card.start { order: -1; }
  .ik-scorecards { grid-template-columns: 1fr 1fr; }
  .ik-scorecards .ik-scorecard.total { grid-column: 1 / -1; }
  .audio-recorder { flex-wrap: wrap; }
  .recorder-controls { flex-basis: 100%; order: 3; }
  .ik-toolbar .ik-segment { flex: 1 1 100%; }
  
  /* Fix attempts toolbar layout on smaller tablets */
  .ik-toolbar { 
    flex-direction: column; 
    align-items: stretch; 
    gap: 12px; 
  }
  .ik-toolbar .ik-segment { 
    flex: none; 
    width: 100%; 
    justify-content: center;
  }
}

/* Tablet portrait: improve attempts layout */
@media (max-width: 900px) {
  .ik-attempts-head { 
    flex-direction: column; 
    align-items: stretch; 
    gap: 16px; 
  }
  .ik-attempts-head .exam-start-btn { width: 100%; }
}

/* Phone: single column, full-width controls, stacked recorder. */
@media (max-width: 767.98px) {
  .ik-titlebar { flex-direction: column; align-items: flex-start; gap: 12px; }
  .exam-quota-line { align-self: flex-start; }
  .exam-page-title { font-size: 24px; }

  .ik-attempts-head { flex-direction: column; align-items: stretch; gap: 14px; }
  .ik-results-head { flex-direction: column; align-items: stretch; gap: 14px; }
  .ik-card-foot { flex-direction: column; align-items: stretch; }
  .ik-card-foot .ik-foot-cta { flex-direction: column; align-items: stretch; }
  .ik-attempts-head .exam-start-btn,
  .ik-results-head .exam-start-btn,
  .ik-card-foot .exam-start-btn { width: 100%; }

  /* Fix attempts page header to prevent layout issues */
  .ik-attempts-head h1 { font-size: 24px; }
  
  /* Fix pagination horizontal scrolling on mobile */
  .ik-pagination { 
    flex-direction: column; 
    gap: 10px; 
    align-items: center;
  }
  .ik-pagination-btns { 
    justify-content: center; 
    flex-wrap: wrap; 
    max-width: 100%;
  }

  .ik-scorecards { grid-template-columns: 1fr; }

  .ik-summary { flex-direction: column; align-items: stretch; gap: 16px; }
  .ik-summary-stats { justify-content: space-between; gap: 12px; }
  .ik-summary .ik-btn-secondary { width: 100%; }

  .ik-stepper-top { flex-direction: column; align-items: flex-start; gap: 2px; }

  /* Recording panel — a clean vertical stack. Explicitly undo the tablet-tier
     row-wrap rules above (flex-wrap / flex-basis / order), which otherwise
     leak in here and throw the mic and controls into separate columns. */
  .audio-recorder {
    flex-direction: column; flex-wrap: nowrap;
    align-items: stretch; text-align: center;
    gap: 16px; padding: 22px 16px;
  }
  .audio-recorder .ik-mic-wrap { order: 1; align-self: center; }
  .recorder-controls {
    order: 2;
    flex: 0 0 auto; flex-basis: auto; width: 100%;
    flex-direction: column; align-items: stretch; gap: 12px;
  }
  .recorder-controls .ik-rec-main { align-items: stretch; gap: 10px; }
  .ik-rec-timerrow { justify-content: center; flex-wrap: wrap; gap: 6px 10px; }
  .ik-meter-row { flex-wrap: wrap; justify-content: center; }
  .ik-meter-cap { width: 100%; text-align: center; align-self: center; }
  .ik-rec-actions { width: 100%; }
  .stop-btn { width: 100%; }

  /* No room to the right of the centred mic on a phone — put the coach mark
     above it, arrow pointing down. */
  .ik-guide {
    left: 50%; right: auto; top: auto;
    bottom: calc(100% + 14px);
    transform: translateX(-50%);
    max-width: 82vw;
  }
  .ik-guide::after {
    right: auto; left: 50%; top: 100%;
    margin: 0 0 0 -8px;
    border-right-color: transparent;
    border-top-color: var(--ik-card);
  }
  .ik-guide::before {
    right: auto; left: 50%; top: 100%;
    margin: 0 0 0 -9px;
    border-right-color: transparent;
    border-top-color: var(--ik-border-str);
  }

  .exam-mushaf-frame { padding: 18px 14px; }

  .ik-attempt { flex-wrap: wrap; gap: 10px 14px; }
  .ik-attempt-mid { flex-basis: 100%; order: 3; }
  .ik-attempt-right { margin-inline-start: auto; }

  .ik-toolbar-right { flex-direction: column; align-items: stretch; width: 100%; }
  .ik-search, .ik-sort { width: 100%; }

  .ik-pagination { flex-direction: column; gap: 10px; align-items: center; }
  .ik-pagination-btns { justify-content: center; flex-wrap: wrap; }

  .ik-footer, .ik-footer.is-condensed { padding: 20px var(--safe-r) 16px var(--safe-l); }
  .ik-footer-cols { 
    gap: 16px; 
    flex-direction: row-reverse; 
    align-items: center; 
    justify-content: space-between;
  }
  .ik-footer-brand { 
    flex: 0 0 auto;
  }
  .ik-footer-col { 
    gap: 16px; 
    flex: 1 1 auto;
  }
  .ik-footer-bottom {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
  }

  /* Adjust footer brand size for mobile while keeping right alignment */
  .ik-footer-mark { 
    padding: 4px 6px; 
  }
  .ik-footer-mark img { 
    height: 24px; 
  }
  .ik-footer-brand strong { 
    font-size: 14px; 
  }
  .ik-footer-brand strong:lang(ar) {
    font-size: 20px;
  }
}

/* Touch: keep the new controls at the 44px floor. */
@media (pointer: coarse) {
  .ik-nav a, .ik-segment button, .ik-sort, .ik-page-btn, .ik-discard,
  .ik-account, .exam-replay-icon, .ik-hamburger,
  .ik-btn-secondary, .exam-end-btn { min-height: var(--tap); }
  .ik-search { min-height: var(--tap); }
}

/* ── Error Details Modal Responsive Fixes ──────────────────────────────── */
@media (max-width: 767.98px) {
  .exam-error-detail-modal {
    height: auto !important;
    min-height: auto !important;
    max-height: calc(100vh - 20px);
    max-height: calc(100dvh - 20px);
  }
  .exam-error-detail-body {
    gap: 8px;
    padding: 0;
  }
}

@media (max-width: 480px) {
  .exam-error-detail-modal {
    height: auto !important;
    min-height: auto !important;
    max-height: calc(100vh - 16px);
    max-height: calc(100dvh - 16px);
  }
  .exam-error-detail-body {
    gap: 6px;
  }
}

/* Reduce excessive spacing in error detail content */
.exam-error-detail-body .exam-issue-cat {
  gap: 4px;
  margin: 0;
}

.exam-error-detail-body .exam-passage-detail-word {
  margin: 0;
  padding: 4px 0;
}

.exam-error-detail-body .exam-passage-detail-hint {
  margin: 0;
  padding: 2px 0;
}

.exam-mushaf-detail-head {
  margin: 0 0 8px 0;
  padding: 0;
}


/* ─── § 9 · LOGIN (admin-user / terms / itsonelogin split layout;
   student /login uses page-its-login and owns its layout inline) ───────────
   Phone-first: one column, brand panel demoted to a compact band. The old
   `min-height: 40vh` on the brand half pushed the form below the fold on an
   iPhone SE — you landed on a sign-in page with no sign-in form in sight. */

.page-login { overflow: auto; }

.page-login .auth-layout {
  grid-template-columns: 1fr;
  height: auto;
  min-height: 100svh;
}

.page-login .brand-panel {
  padding: 20px var(--safe-r) 20px var(--safe-l);
  min-height: 0;
}
.page-login .brand-center { min-height: 96px; }
.page-login .brand-arabic { font-size: 52px; letter-spacing: 2px; }
.page-login .brand-art { background-size: 140px 140px; }

.page-login .form-panel {
  padding: 28px var(--safe-r) calc(32px + var(--safe-b)) var(--safe-l);
}
.page-login .form-wrap { max-width: 100%; }
.page-login .form-heading { font-size: 26px; }

/* Student ITS login: full-bleed patterned shell; card centers itself. */
.page-its-login { overflow: auto; }
.page-its-login .its-shell {
  min-height: 100svh;
}

@media (max-width: 480px) {
  .page-its-login .its-card { padding: 32px 22px 26px; border-radius: 14px; }
  .page-its-login .top-brand { font-size: 24px; }
  .page-its-login .card-logo { width: 76px; height: 76px; }
  .page-its-login .card-logo img { width: 58px; }
}

@media (min-width: 481px) {
  .page-login .brand-arabic { font-size: 72px; letter-spacing: 3px; }
  .page-login .brand-center { min-height: 130px; }
}

@media (min-width: 640px) {
  .page-login .brand-panel { padding: 36px 28px; }
  .page-login .brand-arabic { font-size: 92px; letter-spacing: 4px; }
  .page-login .form-panel { padding: 40px 32px; }
}

@media (min-width: 901px) {
  .page-login { overflow: hidden; }
  .page-login .auth-layout {
    grid-template-columns: 1fr 1fr;
    height: 100vh;
    height: 100dvh;
    min-height: 0;
  }
  .page-login .brand-panel { padding: 56px; }
  .page-login .brand-center { min-height: 0; }
  .page-login .brand-art { background-size: 200px 200px; }
  .page-login .form-panel { padding: 56px; }
  .page-login .form-wrap { max-width: 380px; }
  /* Terms page needs a wider reading column than the sign-in form. */
  .page-login .form-wrap.terms-wrap { max-width: 520px; }
  .page-login .form-heading { font-size: 30px; }

  /* Desktop Sign in ↔ Terms: keep the brand panel, cross-fade the form half.
     Requires <meta name="view-transition" content="same-origin"> on both
     pages. Unsupported browsers fall back to the page's own mount animation. */
  @view-transition {
    navigation: auto;
  }
  .page-login .brand-panel {
    view-transition-name: login-brand;
  }
  .page-login .form-panel {
    view-transition-name: login-form;
  }
  ::view-transition-old(login-brand),
  ::view-transition-new(login-brand) {
    animation-duration: 0.01ms;
    animation-timing-function: linear;
  }
  ::view-transition-old(login-form),
  ::view-transition-new(login-form) {
    animation-duration: 0.4s;
    animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
  }
}

@media (min-width: 901px) and (prefers-reduced-motion: reduce) {
  .page-login .brand-panel,
  .page-login .form-panel {
    view-transition-name: none;
  }
}


/* ─── § 10 · SHORT VIEWPORTS (phone in landscape) ─────────────────────────
   ~380px of height once the browser chrome is gone. Vertical space is the
   scarce resource here, not width — which is why this is a height query. */

@media (max-height: 480px) and (orientation: landscape) {
  .header { position: static; }
  .mic-btn-large { width: 56px; height: 56px; }
  .audio-recorder { padding: 14px 12px; gap: 8px; }
  .audio-page-grid, .exam-page-grid { gap: 12px; }
  .page-chat .welcome { min-height: 0; padding: 20px 24px 12px; }
  .page-chat .welcome-arabic { font-size: 40px; }
  .brand-center { min-height: 0; }
  .brand-arabic { font-size: 44px; }
}


/* ─── § 11 · REDUCED MOTION ───────────────────────────────────────────────*/

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  /* The record button's pulse is a live status cue, not decoration — keep a
     static ring so "recording" stays visually distinct from "idle". */
  .mic-btn-large.recording { box-shadow: 0 0 0 4px rgba(196, 148, 74, 0.35); }
  /* Same reasoning for the "your turn" cue after the read-along ends — the
     bounce is gone, but a solid ring still says "tap me". */
  .mic-btn-large.ik-mic-cue { box-shadow: 0 0 0 4px rgba(158, 69, 38, 0.4); }
}
