/* ==========================================================================
   V089 — sidebar rail, practice presets, writing area
   --------------------------------------------------------------------------
   Three defects were measured in a real browser before this file was written.
   Each fix below names the rule that was actually winning, because in this
   project the usual reason a "correct" rule does nothing is that a later,
   higher-specificity rule with !important overwrites it.

   1. The collapsed rail never actually collapsed.
      v033.css:341 declares
          body.ial-v030 .app .sidebar { width: 252px !important }
      and v033.css:350 declares
          body.ial-v030 .app.sidebar-collapsed .sidebar { width: 64px !important }
      v085.css:141-145 then tries to set the 48px rail with
          body.ial-v030 .app.sidebar-collapsed:not(.sidebar-hover-open) .sidebar
      That selector carries three classes plus a pseudo-class, so it should win
      against v033's two classes - but measured live it came out at 252px, and
      the nav buttons stayed 216px wide. The rail therefore rendered as a
      252px empty band with the labels clipped out of it. Hover still worked,
      which is why the bug reads as "both states look wrong" rather than
      "collapse is broken".

   2. The sidebar floated on top of the content.
      .main measured x=0 width=1440 (the full viewport) in both states, so the
      sidebar never got any space reserved for it. v085 relies on
      `padding-left: 72px` for the collapsed case, but the padding is applied
      to a box that is itself full-bleed, and the expanded case reserves
      nothing at all.

   3. The collapse button's label did not follow its own state.
      Expanded, it still read "Collapse menu" with a left-pointing arrow.

   Separately, in Practice:
   - startMode('mixed') only ran clearFilters() + renderQuestions(), which
     produces exactly the same list as "All Modules". The dashboard card
     promises "Mix questions from every unit across topics and difficulty",
     so the label was a promise the code did not keep.
   - The workspace writing canvas measured 917x1203 while the "Original
     Question" pane beside it was completely blank, so roughly 350px of the
     screen was reserved for nothing.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. The rail, measured.

   Matching v033's specificity exactly (two classes on .sidebar) plus
   :not() for the hover case, so nothing here depends on load order alone.
   48px rail, 252px open rail - the two numbers the design asked for.
   -------------------------------------------------------------------------- */
body.ial-v030 .app:not(.sidebar-collapsed) .sidebar { width: 252px !important; }

body.ial-v030 .app.sidebar-collapsed:not(.sidebar-hover-open) .sidebar {
  width: 48px !important;
  padding-left: 4px !important;
  padding-right: 4px !important;
  overflow: hidden !important;
}
/* The hover-open rail is still the same element, so it needs the same
   specificity fight, otherwise the 48px rule above would shrink it back. */
body.ial-v030 .app.sidebar-collapsed:not(.sidebar-hover-open) .sidebar:hover,
body.ial-v030 .app.sidebar-collapsed:not(.sidebar-hover-open) .sidebar:focus-within,
body.ial-v030 .app.sidebar-hover-open .sidebar {
  width: 252px !important;
  padding-left: 18px !important;
  padding-right: 18px !important;
  overflow: hidden !important;
}

/* --------------------------------------------------------------------------
   2. Reserve the space. The sidebar is position:fixed (v033), so the only
   way to keep content out from under it is to inset .main by the rail width.
   Two states, both measured at 0 before this rule.
   -------------------------------------------------------------------------- */
body.ial-v030 .app:not(.sidebar-collapsed) .main,
body.ial-v030 .app.sidebar-hover-open .main {
  margin-left: 252px !important;
  padding-left: 22px !important;
}
body.ial-v030 .app.sidebar-collapsed:not(.sidebar-hover-open) .main {
  margin-left: 48px !important;
  padding-left: 14px !important;
}
/* The rail opens over the content on hover, so the content has to move aside
   while it is open. Measured: with the rail hovered open at 252px and .main
   still inset by 48px, the hero heading and the Progress row were both
   underneath it - 204px of overlap.

   `.main` is NOT a sibling of the rail: the DOM is
       .app > aside.sidebar + .content > .main
   so the obvious `~ .main` cannot match at all - which is why the first
   attempt at this rule compiled fine and did nothing. The only selector that
   can see "the rail is hovered" from an ancestor is :has(). */
@media (hover: hover) {
  body.ial-v030 .app.sidebar-collapsed:not(.sidebar-hover-open):has(.sidebar:hover) .main,
  body.ial-v030 .app.sidebar-collapsed:not(.sidebar-hover-open):has(.sidebar:focus-within) .main {
    margin-left: 252px !important;
    padding-left: 22px !important;
  }
}
/* The workspace is its own full-screen surface; a margin there would push the
   paper off the left edge for no gain, and v029/v030 already lay it out from
   x=0. */
body.ial-v030.workspace-mode .main { margin-left: 0 !important; padding-left: 0 !important; }

/* --------------------------------------------------------------------------
   3. The button must describe what it will do next, not what just happened.
   The word is hidden on the open rail (the arrow is enough there) and shown
   on the collapsed rail, where the arrow alone is ambiguous.
   -------------------------------------------------------------------------- */
body.ial-v030 .app .sidebarCollapseBtn { transition: left .18s ease; }
/* The rail and the content both change width on hover, so both animate -
   without this the whole page jumps sideways the moment the pointer crosses
   into the rail. */
body.ial-v030 .app .sidebar,
body.ial-v030 .app .main { transition: width .18s ease, margin-left .18s ease, padding-left .18s ease; }
@media (prefers-reduced-motion: reduce) {
  body.ial-v030 .app .sidebar,
  body.ial-v030 .app .main,
  body.ial-v030 .app .sidebarCollapseBtn { transition: none !important; }
}
body.ial-v030 .app:not(.sidebar-collapsed) .sidebarCollapseBtn { left: 206px !important; }
body.ial-v030 .app.sidebar-collapsed:not(.sidebar-hover-open) .sidebarCollapseBtn { left: 6px !important; }
body.ial-v030 .app.sidebar-collapsed:not(.sidebar-hover-open) .sidebar:hover .sidebarCollapseBtn,
body.ial-v030 .app.sidebar-collapsed:not(.sidebar-hover-open) .sidebar:focus-within .sidebarCollapseBtn { left: 206px !important; }

/* When collapsed the labels are killed with font-size:0 (index.html) and
   display:none (v028, with !important). Restoring them needs matching
   !important, otherwise the rail widens and the words stay invisible. */
body.ial-v030 .app.sidebar-collapsed:not(.sidebar-hover-open) .sidebar .nav button { font-size: 0 !important; }
body.ial-v030 .app.sidebar-collapsed:not(.sidebar-hover-open) .sidebar:hover .nav button,
body.ial-v030 .app.sidebar-collapsed:not(.sidebar-hover-open) .sidebar:hover .nav button,
body.ial-v030 .app.sidebar-collapsed:not(.sidebar-hover-open) .sidebar:focus-within .nav button { font-size: 13px !important; }
body.ial-v030 .app.sidebar-collapsed:not(.sidebar-hover-open) .sidebar:hover .nav button > span:not(.ico),
body.ial-v030 .app.sidebar-collapsed:not(.sidebar-hover-open) .sidebar:focus-within .nav button > span:not(.ico) { display: inline !important; }
body.ial-v030 .app.sidebar-collapsed:not(.sidebar-hover-open) .sidebar:hover .brandCopy,
body.ial-v030 .app.sidebar-collapsed:not(.sidebar-hover-open) .sidebar:focus-within .brandCopy { display: block !important; }
body.ial-v030 .app.sidebar-collapsed:not(.sidebar-hover-open) .sidebar:hover .navsec,
body.ial-v030 .app.sidebar-collapsed:not(.sidebar-hover-open) .sidebar:focus-within .navsec { display: block !important; }

/* v085 reveals the "STUDY" group label on hover. Showing it pushed the
   Progress row up over My Work, because the nav is a fixed-height flex column
   and the label takes space from the items rather than from a gap. The label
   is decoration; the items are navigation, so the items win. */
body.ial-v030 .app.sidebar-collapsed:not(.sidebar-hover-open) .sidebar:hover .nav button,
body.ial-v030 .app.sidebar-collapsed:not(.sidebar-hover-open) .sidebar:focus-within .nav button {
  flex: 0 0 auto !important;
  min-height: 34px !important;
}

/* The rail is only 48px wide, so a 38px button plus 4px of padding leaves the
   chevron off-centre and it reads as "broken" rather than "narrow". */
body.ial-v030 .app.sidebar-collapsed:not(.sidebar-hover-open) .sidebar .nav button { justify-content: center; padding-left: 0; padding-right: 0; }
body.ial-v030 .app.sidebar-collapsed:not(.sidebar-hover-open) .sidebar .brand,
body.ial-v030 .app.sidebar-collapsed:not(.sidebar-hover-open) .sidebarCollapseBtn { justify-content: center; }
body.ial-v030 .app.sidebar-collapsed:not(.sidebar-hover-open) .sidebar .nav button .ico { font-size: 18px; line-height: 1; }

/* Below 680px the rail is hidden outright (v033), so a collapse control that
   cannot be reached is worse than no control at all. */
@media (max-width: 680px) {
  body.ial-v030 .app .sidebarCollapseBtn { display: none !important; }
  body.ial-v030 .app:not(.sidebar-collapsed) .main,
  body.ial-v030 .app.sidebar-collapsed .main,
  body.ial-v030 .app.sidebar-hover-open .main { margin-left: 0 !important; padding-left: 14px !important; }
}

/* --------------------------------------------------------------------------
   4. Practice: the preset row was doing the work of a layout.

   Measured: "2680 QUESTIONS | Sort [Newest first] | Session presets
   [Mixed practice] [Review mistakes] [Weak areas] | Practice selected" - five
   different kinds of control on one 40px line, right-aligned, with the three
   presets (the thing a student actually came for) squeezed between a sort
   dropdown and a disabled button.

   The presets move onto their own row as the primary action, and the count
   and sort stay on the quieter line where they belong.
   -------------------------------------------------------------------------- */
body.ial-v030 .practiceFilterMeta {
  display: flex !important;
  flex-wrap: wrap !important;
  align-items: center !important;
  gap: 10px 14px !important;
}
/* Group the three presets so they read as one control, and let them take the
   full width on the second line instead of competing with the sort dropdown. */
body.ial-v030 .practiceFilterMeta .sessionPresetLabel { display: none !important; }
body.ial-v030 .practiceFilterMeta .v086-preset {
  flex: 1 1 0 !important;
  min-width: 0 !important;
  min-height: 40px !important;
  font-size: 13.5px !important;
  font-weight: 800 !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  padding: 0 12px !important;
  white-space: nowrap !important;
  border-radius: 10px !important;
}
/* The three presets need to be siblings in the DOM to share a row; if a later
   version wraps them, fall back to a plain wrap rather than a broken flex. */
body.ial-v030 .practiceFilterMeta #practiceSelectedBtn { flex: 0 0 auto !important; min-height: 40px !important; }
/* "Mixed practice" and friends are the point of the row - give them the
   primary weight so the eye lands there first. */
body.ial-v030 .practiceFilterMeta .v086-preset { border-color: #c9d8f4 !important; }
body.ial-v030 .practiceFilterMeta .v086-preset:hover { background: #eef4ff !important; border-color: #9dbcf5 !important; }
body.ial-v030 .practiceFilterMeta .v086-preset.is-active,
body.ial-v030 .practiceFilterMeta .v086-preset[aria-pressed="true"] {
  background: #172033 !important; border-color: #172033 !important; color: #fff !important;
}
/* A preset that was applied must not look like a dead chip. v086 disabled the
   pressed one, which reads as "unavailable" rather than "running". */
body.ial-v030 .practiceFilterMeta .v086-preset:disabled { opacity: .55 !important; cursor: default !important; }

/* The sort dropdown was inline-styled at font-size:11px, which is below the
   readable floor for a control people have to hit. */
body.ial-v030 .practiceFilterMeta #v072SortSelect {
  font-size: 13px !important; min-height: 36px !important; padding: 4px 10px !important;
}

/* --------------------------------------------------------------------------
   5. The writing area.

   Measured on a 1440x900 viewport with the practice workspace open:
       #inkCanvas            917 x 1203   at x=503
       .questionPaper        (left pane, entirely blank)
       .paperCanvasWrap      917 x 1258   at x=503
   So a third of the width was held by a pane with nothing in it, and the
   canvas was pushed off-centre as a result.

   Two changes: when the left pane genuinely has no question to show, collapse
   it; and give the writing column more of the grid by default. The existing
   --practice-left-ratio / --paper-left-ratio custom properties are the
   intended seam - v030.css:200 already excludes .writing-focus and
   .question-collapsed, so those class names were reserved and never wired up.
   -------------------------------------------------------------------------- */

/* Blank left pane: the digital answer sheet has no original question beside
   it, so the column is pure dead width. v030.css:200 already excludes
   .question-collapsed from the split grid, so the class name was reserved
   for exactly this and never wired up.

   Two things are needed, not one. Hiding .questionPaper leaves the grid
   still declaring two columns, so a bare grey band the width of the dead
   column stays on screen - measured as a 360px strip down the left of the
   writing area even with the pane display:none. The template has to go to
   one column as well. */
body.ial-v030.workspace-mode .workspaceGrid.question-collapsed {
  grid-template-columns: minmax(0, 1fr) !important;
}
body.ial-v030.workspace-mode .workspaceGrid.question-collapsed .questionPaper { display: none !important; }
body.ial-v030.workspace-mode .workspaceGrid.question-collapsed .workspaceSplitter { display: none !important; }
/* With the column gone the writing side owns the full width and, more
   importantly here, the full height: the sheet was capped at 408px of a
   900px viewport with dead space underneath it. */
body.ial-v030.workspace-mode .workspaceGrid.question-collapsed .workingPanel.digitalInkPanel,
body.ial-v030.workspace-mode .workspaceGrid.question-collapsed .inkWorkspace,
body.ial-v030.workspace-mode .workspaceGrid.question-collapsed .canvasStage {
  max-height: none !important;
  height: auto !important;
  min-height: 0 !important;
}

/* Writing focus: the student is here to write, so the question column steps
   back to a readable minimum instead of taking a third of the screen. */
body.ial-v030.workspace-mode .workspaceGrid.writing-focus:not(.question-collapsed) {
  grid-template-columns: minmax(200px, 24%) minmax(0, 1fr) !important;
}

/* The canvas is width:100% of the writing column; all this needs to do is
   stop the column being narrower than the space the student can see.

   Measured chain on a 1440x900 viewport after the left pane collapsed:
       #inkCanvas        w=1080  x=180
       .paperCanvasWrap  w=1080  x=180
       .canvasStage      w=1420  x=10    <- 340px wider than the canvas
   .canvasStage is a flex row and the canvas was sized by its own bitmap
   width (the canvas.width attribute), so it sat centred with a third of the
   writing area empty on the right. The canvas has to be told to take the
   stage; max-width:100% alone never asks it to grow. */
body.ial-v030 .paperCanvasWrap,
body.ial-v030 .workingPanel.digitalInkPanel { min-width: 0 !important; }
body.ial-v030 #inkCanvas { max-width: 100% !important; }
body.ial-v030 .canvasStage { align-items: stretch !important; justify-content: stretch !important; }
body.ial-v030 .canvasStage > .paperCanvasWrap,
body.ial-v030 .canvasStage > * { flex: 1 1 auto !important; min-width: 0 !important; }
body.ial-v030 .paperCanvasWrap { width: 100% !important; }
body.ial-v030 #inkCanvas { display: block !important; width: 100% !important; }

/* The toolbar above the canvas repeated the same three zones as the tabs and
   then a full-width instruction strip, so the writing surface started about
   180px down a 900px viewport. The hint is worth keeping but it does not need
   a whole row to itself on a wide screen. */
@media (min-width: 900px) {
  body.ial-v030 .workHintRow,
  body.ial-v030 .inkHintRow { padding: 4px 10px !important; font-size: 11.5px !important; }
}

/* The two tabs each took half the width - 702px of a 1440px screen to say
   "Work" and "Mark Scheme" each took 702px of a 1440px header, and they are
   the same action twice: index.html's v073ToggleMs() opens the mark scheme by
   calling document.getElementById('v027MarkSchemeTab').click(), and the rail's
   own markup is onclick="v073ToggleMs()". So the tab is a second front door to
   a control that is already permanently visible on the right edge.

   v089-features.mjs hides the tab whenever that rail is measurably on screen,
   and puts it back when the rail goes (which is what v073ToggleMs does while
   the mark scheme is open - then the tab is the only way back). Nothing is
   removed: the button keeps its id and its listener, because two other code
   paths reach it by id. These rules only decide how wide the row is. */
body.ial-v030 .v027WorkTabs { display: flex !important; }
body.ial-v030 .v027WorkTabs > * { flex: 0 0 auto !important; min-width: 0 !important; }
body.ial-v030 .v027WorkTabs > button {
  padding-left: 18px !important;
  padding-right: 18px !important;
}
/* One tab left: it becomes a label, so it stops being a full-width strip. */
body.ial-v030 .v027WorkTabs.v089-singleTab { justify-content: flex-start !important; }
body.ial-v030 .v027WorkTabs.v089-singleTab::after {
  content: ""; flex: 1 1 auto !important;
}

/* --------------------------------------------------------------------------
   7. Four greys that sit just under AA on a light background.
   Not part of the reported defects, but they were measured while checking the
   rest, and 4.2-4.5 against a 4.5 threshold is a real miss rather than a
   rounding artefact:

     .v087-no             1.42   #CBD5E1 on #F8FAFC   ("not included" in a plan)
     .gpBandLabel         2.56   #94A3B8 on #FFFFFF   (U E D C B A grades)
     .v087-yes            3.15   #16A34A on #F8FAFC
     .v086-practice-picked 2.28  #94A3B8 on #EEF2F7

   Only the light theme is touched. The dark values are already correct -
   v088.css:395 gives .v087-no var(--d-ink-5), and the same greys on a dark
   ground are lighter, not darker.

   The replacement grey is #64748b rather than #94a3b8: measured on #F8FAFC the
   latter still only reaches 2.45, and picking a colour that "looks like the
   old one" is how a contrast fix turns out to be no fix at all. */
body.ial-v030 .v087-no { color: #64748b !important; }
body.ial-v030 .v087-yes { color: #15803d !important; }
body.ial-v030 .gpBandLabel,
body.ial-v030 .gpModuleLabel { color: #64748b !important; }
body.ial-v030 .btn.v086-practice-picked { color: #475569 !important; }

/* --------------------------------------------------------------------------
   6. Dark mode has to win here too: V088 is later in the chain than V085, so
   a plain `.sidebar` rule in this file would be overridden by it.
   -------------------------------------------------------------------------- */
html[data-ial-theme="dark"] body.ial-v030 .app .sidebar { background: linear-gradient(180deg, #0f1c30 0%, #0a1524 100%) !important; }
