/* Hittite cuneiform has no reliable glyph coverage in default browser/OS fonts -- mobile
   fallbacks render visibly wrong glyphs (wrong wedge counts), not just an ugly substitute.
   Same three-face Ullikummi setup as flashcards/session.css and interlinear_reading's
   reading.html. .tile (drag_fill.html's tray buttons) isn't wrapped in .cuneiform like every
   other glyph on these pages, so it needs its own selector. */
@font-face {
  font-family: "UllikummiA";
  src: url("/static/custom_interlinear/fonts/UllikummiA.d0baacffa803.ttf") format("truetype");
  font-display: block;
  unicode-range: U+12000-1247F;
}
@font-face {
  font-family: "UllikummiB";
  src: url("/static/custom_interlinear/fonts/UllikummiB.fc248627e709.ttf") format("truetype");
  font-display: block;
  unicode-range: U+12000-1247F;
}
@font-face {
  font-family: "UllikummiC";
  src: url("/static/custom_interlinear/fonts/UllikummiC.a7fc04c5cb6b.ttf") format("truetype");
  font-display: block;
  unicode-range: U+12000-1247F;
}
.tile { font-family: UllikummiA, UllikummiB, UllikummiC, sans-serif; }

#word-list { list-style: none; padding: 0; }
.word { margin-bottom: 1em; }
/* More than 4 words: switch from a single column to a grid so a large (uncapped, spec D6)
   review pool doesn't turn into one long scroll. */
#word-list:has(> .word:nth-child(5)) {
  display: grid;
  /* max-content (not 1fr, its pre-2026-09-14 value) sizes each column to its OWN row's content,
     not stretched to match the widest column in the grid -- a page mixing short and long words
     no longer wastes a full 15em-plus on every short row just because one rare row needs more
     (real report: uniform 1fr columns made the grid look unfinished, all that white space next
     to a scrollbar on the one row that didn't fit). 15em is still the FLOOR (unchanged
     calibration: widest .cuneiform row measured in practice, ~152px for 4 blanks, ~228px for 6,
     with headroom) -- auto-fill still uses it to decide how many columns fit before dropping to
     fewer (down to 1) on a narrow viewport, max-content only governs how much wider than that
     floor a column bothers growing -- growth is still capped by whatever space auto-fill's
     other columns leave available, so a column doesn't reach its own max-content at the expense
     of pushing the grid past the viewport. Confirmed live (2026-09-14) that max-content columns
     don't push the whole grid past the viewport at any tested desktop width (641-1280px). What
     genuinely keeps this safe in the general case is min-width: 0 on .word (below) -- a grid
     item's automatic minimum size otherwise defaults to its content's min-content, which for a
     nowrap row equals its full unwrapped width, and THAT floor really can't shrink to fit
     available space; min-width: 0 removes it, so a column can always shrink as far as it needs
     to. The scrollport below exists for what that shrinking costs a too-narrow column locally
     (its own content no longer fits and must scroll to stay reachable), not to guard against
     the whole grid overflowing the viewport -- min-width: 0 already rules that out. */
  grid-template-columns: repeat(auto-fill, minmax(15em, max-content));
  gap: 0.5em 1.5em;
}
/* Without this, adjacent inline-block buttons/spans in .cuneiform get an implicit line-break
   opportunity between them and wrap onto a second line inside the grid column above, which is
   what looked like blanks not lining up with their own transliteration. nowrap only works
   because that column is now sized to fit the row's content (see the 15em comment above) --
   otherwise this would overflow the column instead of wrapping. */
.cuneiform { font-size: 1.8em; font-family: UllikummiA, UllikummiB, UllikummiC, sans-serif; white-space: nowrap; }
/* A column can still end up narrower than its own row's content in two cases: (a) at desktop
   widths, before 2026-09-14's max-content fix (grid-template-columns comment above) forced
   every column to the width of the WIDEST column in the grid via 1fr -- fixed by that change,
   this scrollport is now a fallback for the corpus's current longest word, not its active fix;
   (b) any row whose content a max-content column still can't grow enough to fit, because
   min-width: 0 (below) lets auto-fill shrink that column to make room for others instead --
   see the grid-template-columns comment above for why that's the right tradeoff (a locally
   scrollable column, not the whole grid overflowing the viewport). Needs a scrollport at EVERY
   viewport width, not just the mobile one below, for either case. Real report that first exposed the missing desktop
   protection: with no overflow-x here, an over-width row's excess painted straight over the
   next grid column's word (2026-09-13, lesson 4 page 39). Mechanism only, unscoped from
   viewport width -- the viewport-tuned column-width/font-size values themselves stay in the
   media query below, same division of responsibility the mobile block below already
   established. min-width: 0 gives the column a real box to scroll within; display: block is
   needed since overflow has no effect on .cuneiform's inline default (see the mobile block's
   own comment for the full reasoning on both). Unlike the mobile block, this one does NOT
   hide the scrollbar: mobile hides it because swipe-to-scroll is a self-evident touch gesture
   (the scroll capability stays, only its visible chrome goes -- see the mobile block's own
   comment), but a desktop mouse/trackpad user has no equivalent implicit affordance for "this
   row scrolls" -- hiding the scrollbar there would leave a truncated-looking row with no visual
   cue that more content, and more click targets on click_identify pages, exist past the edge
   (accessibility review finding, 2026-09-14). The browser's native horizontal scrollbar is the
   visible affordance at every non-mobile width. */
#word-list:has(> .word:nth-child(5)) > .word { min-width: 0; }
#word-list:has(> .word:nth-child(5)) .cuneiform {
  display: block;
  overflow-x: auto;
  overflow-y: hidden;
  box-sizing: border-box;
  padding: 8px;
}
/* Graded rows need more room on the bottom edge specifically: the checkmark sits further past
   .gap's box than either ring does. This padding-bottom REPLACES the 8px above on this one edge
   (same specificity, later in source order -- it doesn't add to it), and only here; left/right/
   top keep the 8px ring padding on graded rows too. 0.75em is the checkmark's own font-size
   (0.55em) plus headroom (measured live: 0.6em left only a ~1px margin before the checkmark's
   line box hit the bottom edge; 0.75em gives ~4px), relative to .cuneiform's own font-size at
   whichever breakpoint is active -- already comfortably past the 8px ring minimum at either
   size, so no separate max() of the two is needed on this edge. Scoped to graded rows only so
   ungraded rows keep the smaller, ring-only padding. */
#word-list:has(> .word:nth-child(5)) .cuneiform:has(.gap[data-verdict]) { padding-bottom: 0.75em; }
/* Mirrors the .cuneiform:has(.gap[data-verdict]) padding-bottom rule above, for
   click_identify's own per-glyph labels, which now grow UPWARD out of .sign-cell instead of
   sideways -- without this, a label can get clipped by this row's overflow-y: hidden. */
#word-list:has(> .word:nth-child(5)) .cuneiform:has(.missed, .wrong-click) { padding-top: 0.75em; }
/* Below 40rem (matches flashcards/session.css's own breakpoint), no phone in portrait reaches
   the ~500px of content width the desktop 15em floor needs for 2 columns -- base.html puts no
   max-width on <main>, so the full device viewport is the content width. Shrinking .cuneiform's
   font-size (and the grid floor/gap with it) is what actually gets 2 columns onto a real phone
   without re-allowing wrap. 1.25em is the smallest this can go: gaps.css's .gap (drag_fill's
   blanks) sizes itself at 1.2em off this same font-size, and 1.2 * 1.25em(20px) = 24px, the
   WCAG 2.5.8 floor -- any smaller and blanks fail that minimum. 10.5em (168px) is calibrated
   the same way the 15em floor above was: off the widest real row (333px at 1.8em, scaled to
   ~255px at 1.25em) with headroom for the normal case -- most rows are far under 255px, so the
   floor still buys 2 columns for the vast majority of pages. Raising the floor to fit the rare
   255px row outright isn't viable (it would need ~266px+ columns, 2x266+16=548px, wider than
   any real phone's content width, which would just kill 2 columns entirely), so that rare row
   instead gets its own tiny horizontal scroll below rather than forcing one column for everyone
   or wrapping (nowrap on .cuneiform is a hard constraint, see above). */
@media (max-width: 40rem) {
  .cuneiform { font-size: 1.25em; }
  #word-list:has(> .word:nth-child(2)) {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(9em, 1fr));
    gap: 0.5em 1em;
  }
  /* Words over 5 signs (views._shuffle_short_first sorts them last) take a full row instead of
     scrolling inside a narrow column; the 9em floor lets short words pair up in 2 columns on a
     ~326px-wide phone. */
  #word-list:has(> .word:nth-child(2)) > .word.wide { grid-column: 1 / -1; }
  /* The scrollport mechanism itself (min-width: 0, overflow-x: auto, the graded-row
     padding-bottom) is unscoped now -- see its comment above this media query -- since the rare
     over-column row it protects against isn't a mobile-only problem. Only the viewport-tuned
     values and the scrollbar-hiding rules stay here: touch swipe is a self-evident scroll
     affordance on its own, so hiding the mobile scrollbar's chrome doesn't cost discoverability
     the way it would on desktop (see the base rule's own comment above). */
  #word-list:has(> .word:nth-child(2)) .cuneiform { scrollbar-width: none; }
  #word-list:has(> .word:nth-child(2)) .cuneiform::-webkit-scrollbar { display: none; }
  /* Pages with 2-4 words get the grid on phones only (desktop keeps the 5+ words trigger), so the
     same min-width: 0 / scrollport / graded-row padding mechanism the 5+ rules above give
     must apply at the lower trigger too. */
  #word-list:has(> .word:nth-child(2)) > .word { min-width: 0; }
  #word-list:has(> .word:nth-child(2)) .cuneiform {
    display: block;
    overflow-x: auto;
    overflow-y: hidden;
    box-sizing: border-box;
    padding: 8px;
  }
  #word-list:has(> .word:nth-child(2)) .cuneiform:has(.gap[data-verdict]) { padding-bottom: 0.75em; }
  #word-list:has(> .word:nth-child(2)) .cuneiform:has(.missed, .wrong-click) { padding-top: 0.75em; }
}
/* drag_fill.html's not-yet-taught signs render inline among .gap blanks (exercises/gaps.css)
   as a bare glyph span -- unstyled, it had no box to match .gap's (height 1.5em, baseline
   align), and the Ullikummi font's tall glyph metrics pushed it above the row instead of
   sitting inline with the blanks around it. Same height/line-height/vertical-align as .gap
   so a word mixing blanks and shown signs reads as one row. */
.cuneiform .cuneiform-sign { display: inline-block; height: 1.5em; line-height: 1.4; vertical-align: baseline; }
.sign-glyph { font: inherit; padding: 0 0.1em; border: none; background: transparent; cursor: pointer; min-width: 24px; min-height: 24px; }
/* Inset rings stay separate without widening tightly packed cuneiform words. */
.sign-glyph[aria-pressed="true"]:not([aria-disabled="true"]) { outline: 2px solid var(--focus); outline-offset: -3px; background: var(--surface-raised); }
.sign-glyph[aria-pressed]:focus-visible { outline: 2px dashed var(--focus); outline-offset: -3px; }
.sign-glyph.hit { font-weight: bold; }
.sign-glyph.hit::after { content: " ✓"; color: var(--success); font-size: 0.6em; vertical-align: super; }
/* Wraps each glyph button so a missed/wrong-click label (exercise 2 only -- exercise 1 has
   no per-glyph label, see click_identify.js) renders ABOVE the glyph without moving where
   the JS inserts it: column-reverse puts the LAST DOM child (the label, inserted via
   button.after()) on top, the FIRST (the button) on the bottom. Purely a layout wrapper --
   an inline-flex atomic box still participates in .cuneiform's white-space: nowrap the same
   way the bare button did. */
.sign-cell { display: inline-flex; flex-direction: column-reverse; align-items: center; vertical-align: bottom; }
/* Same mechanism as .sign-glyph.hit::after's green check (line above), mirrored for a wrong
   click. #a4262c is already used by .missed below -- ~7.25:1 against a white background,
   clears WCAG AA's 4.5:1 for small text, so no new color needed. */
.sign-glyph.wrong::after { content: " ✗"; color: var(--error); font-size: 0.6em; vertical-align: super; }
/* 1rem (not em) so this matches the page's own 16px base text size regardless of .cuneiform's
   1.8em/1.25em glyph scaling -- em here would size relative to the enlarged glyph next to it,
   not the page's actual body text size. font-family: initial for the same reason: without it
   these spans also inherit .cuneiform's UllikummiA/B/C glyph font, rendering this Latin
   feedback text in the glyph font instead of the page's own body font. */
.missed, .wrong-click { font-size: 1rem; margin-left: 0.2em; font-family: initial; }
.missed { color: var(--error); }
/* Exercise 1's missed mark lands on the glyph itself, not the free-flowing transliteration
   text above it (see click_identify.js) -- the reading's word-widths don't line up with the
   fixed-width glyphs, so a text-line mark can't reliably point at the sign it names. Same
   mechanism as .sign-glyph.hit's font-weight/::after: a plain modifier on the button, not a
   recolor of the glyph itself. Two-class selector overrides the bare .missed label rule
   above (font-size/margin/color meant for exercise 2's adjacent span, not a button) --
   but that rule's font-family: initial cascades onto this button too (CSS applies the
   specificity winner per property, not per rule, so this selector's higher specificity
   only beats the bare .missed rule for the properties it actually redeclares). Left
   unrestored, the glyph itself -- not just a label -- rendered in the browser default
   font instead of Ullikummi. font-family: inherit below undoes that. */
.sign-glyph.missed {
  font-family: inherit;
  font-size: inherit;
  margin-left: 0;
  text-decoration: underline;
  text-decoration-color: var(--error);
  text-decoration-thickness: 2px;
}
/* Shared base for both templates that render a .transliteration span
   (click_identify.html and drag_fill.html) -- this must stay unscoped: it's
   the only layout drag_fill.html's transliteration line gets. */
.transliteration { display: block; }
.syllabic { font-style: italic; }
.not-italic { font-style: normal; }
/* Now sits above a nowrap glyph row (click_identify.html) -- letting it wrap to a second
   line would visually misalign with the row beneath it, so it gets the same treatment as
   .cuneiform: nowrap, one calibrated shrink step, then horizontal scroll. Unscoped from the
   #word-list:has(> .word:nth-child(5)) grid trigger below -- unlike .cuneiform, this line
   can overflow its own .word regardless of grid/list layout, since it was never part of
   that scrollport before.
   Scoped with :has(.translit-sign) -- both click_identify.html and drag_fill.html render a
   bare .transliteration span (#word-list/.word are shared by both), but only
   click_identify.html wraps each sign in a .translit-sign child (needed there for the
   per-sign missed/hit marking above); drag_fill.html's is plain text. Same :has() scoping
   idiom this file already uses elsewhere (#word-list:has(> .word:nth-child(5)), etc.) rather
   than a new class, so this ADDITIONAL nowrap/scroll/shrink treatment never reaches
   drag_fill.html -- it only augments the shared base rule above, never replaces it.
   padding-top reserves room for a raised .determinative (base.html: position: relative;
   top: -0.5em) -- without it, overflow-y: hidden clips the determinative whenever it pokes
   above this line's own content box. 0.75em matches this file's own calibration for the
   same "something renders above the line, overflow-y: hidden would clip it" problem (see
   the #word-list:has(...) .cuneiform:has(.missed, .wrong-click) padding-top rule above). */
.transliteration:has(.translit-sign) {
  white-space: nowrap;
  overflow-x: auto;
  overflow-y: hidden;
  max-width: 100%;
  box-sizing: border-box;
  padding-top: 0.75em;
}
@media (max-width: 40rem) {
  /* One calibrated step, not indefinite shrinking (WCAG 1.4.4) -- 0.85em still scales with
     the page's own base font size and browser zoom, it just starts from a smaller base on a
     narrow viewport, same relationship .cuneiform's own 1.8em/1.25em breakpoint pair has. */
  .transliteration:has(.translit-sign) { font-size: 0.85em; }
}
/* Keyboard access to the scroll container (accessibility review finding): tabindex="0" in
   click_identify.html makes it focusable; this is the visible focus indicator, matching the
   outline convention .sign-glyph[aria-pressed="true"] already uses in this same file. */
.transliteration:focus-visible {
  outline: 3px solid var(--focus);
}
.gloss { display: block; color: var(--muted); }

/* Matches features/flashcards/static/flashcards/session.css's #session-complete-modal. */
#group-complete-modal {
  position: relative;
  border: none;
  border-radius: 12px;
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3);
  padding: 2rem;
  max-width: 24rem;
  text-align: center;
  background: var(--canvas);
}
#group-complete-modal::backdrop { background: rgba(0, 0, 0, 0.5); }
#group-complete-modal a { display: inline-block; margin: 0 0.75rem; }
#group-complete-modal h2 { margin-top: 0; }
#close-group-modal {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  min-width: 32px;
  min-height: 32px;
  border: none;
  background: transparent;
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  color: var(--muted);
}
#close-group-modal:hover, #close-group-modal:focus-visible { color: var(--ink); }
