/* Classes that exist because a style attribute cannot.
 *
 * docs/TODO.md item 39. The app generated 135 `style="..."` attributes as it
 * painted, and that was the only reason `src/_headers` still had to allow
 * 'unsafe-inline' in style-src — the last escape hatch in a policy that had
 * closed every other one. A style attribute parsed out of markup is covered
 * by that directive; a property set through the CSSOM (`el.style.width=...`)
 * is not, so the handful of genuinely dynamic values move into JavaScript
 * rather than in here.
 *
 * Nothing here is a general-purpose utility framework. Each class replaces a
 * repetition that was already in the app, and several of them normalise a
 * number that differed between screens for no reason anyone recorded: the
 * centred block at the top of a screen had five different top paddings, and
 * the row that holds a secondary button under a primary one had five
 * different margins. Where the difference was arbitrary it is now one value.
 *
 * Linked after the component sheets and before motion.css and desktop.css, so
 * these win over a component's own rule the way the attribute they replace
 * did, and still lose to the two override layers.
 */

/* ---- The block at the top of a screen: mascot, title, a line of text ---- */
.hero{text-align:center;padding-top:14px;}

/* ---- A button under a button, and the gap above it ---- */
.stack{margin-top:10px;}
.stack-sm{margin-top:8px;}
.stack-md{margin-top:14px;}
.stack-lg{margin-top:24px;}

/* ---- Small corrections to a component's own spacing ---- */
.flush{margin-top:0;}
.roomy{margin-bottom:16px;}
.field-gap{margin-bottom:6px;}
.centred{text-align:center;}
.ranged{text-align:left;}
.gone{display:none;}
.tight-row{gap:8px;}
.grow{flex:1;min-width:0;}

/* ---- Buttons that are not full width ---- */
.btn.inline-btn{width:auto;padding:9px 14px;min-height:36px;font-size:12.5px;}
.btn.apply-btn{width:auto;padding:8px 12px;font-size:12.5px;}
.btn.small-btn{padding:6px 10px;font-size:12px;}
.btn.tiny-btn{padding:4px 8px;font-size:11px;}
/* Colour by role, never by literal. Both of these were written out as the
   variable in an attribute, which is the same colour and a worse home. */
.btn.ghost.danger{color:var(--coral-text);border-color:var(--coral);}
.btn.ghost.on-ad{color:var(--ad-soft);border-color:var(--ad-line);}

/* ---- Headings and body text that a component class does not cover ---- */
.pl-title.sm{font-size:19px;}
.lesson-title{font-size:19px;margin:2px 0 14px;}
.sim-title{font-size:18px;margin:2px 0 12px;}
.screen-title{font-size:18px;margin:6px 0 16px;}
.panel-title{font-size:17px;margin:0 0 8px;}
.done-title{margin:0 0 6px;font-size:19px;}
.done-sub{color:var(--ink-soft);font-size:13.5px;margin:0;line-height:1.5;}
.done-meta{font-size:12px;color:var(--ink-soft);margin-top:8px;
 font-family:'IBM Plex Mono',monospace;}
.done-meta.tall{line-height:1.6;}
.soft-note{font-size:13.5px;color:var(--ink-soft);line-height:1.5;margin:0 0 14px;}
.soft-note.close{margin:0 0 6px;}
.soft-note.wide{margin:0 0 18px;}
.soft-note.long{line-height:1.55;margin:0 0 22px;}
.small-note{font-size:12px;color:var(--ink-soft);line-height:1.5;}
.small-note.plain{margin:0;}
.tiny-note{font-size:11px;color:var(--ink-soft);margin-top:6px;}
.said-note{font-size:11.5px;color:var(--ink-soft);margin-top:16px;line-height:1.5;}
.body-note{font-size:12.5px;color:var(--ink-soft);line-height:1.55;margin:0;}
/* Both were #9AA3C0 written into the markup — a hardcoded colour in a
   product whose contrast is audited. It is a token now, and it is the
   PANEL's soft ink rather than the page's: these sit on the dark
   predict-and-measure surface, where the page's own --ink-soft reads at
   3.03 against 4.5 needed. */
.sim-note{font-size:12.5px;color:var(--sim-soft);margin-top:9px;line-height:1.45;}
.sim-power{font-size:12.5px;color:var(--sim-soft);margin-top:9px;}
.ok-msg{font-size:12px;color:var(--teal-text);margin-top:8px;text-align:center;}
.sandbox-title{font-size:17px;margin:6px 0 4px;}
.sandbox-sub{font-size:13px;color:var(--ink-soft);margin:0 0 14px;}

/* The rule above the explanation of a first wrong answer. */
.fb-split{margin-top:9px;padding-top:9px;border-top:1px solid var(--line);}

/* The last section of Settings, which has nothing under it to divide from. */
.set-sec.last{border-bottom:none;}

/* The blue ring on the test intro. The other two rings are painted by their
   own classes; this one was a gradient in an attribute. */
.done-ring.to-test{background:linear-gradient(135deg,var(--blue),var(--blue2));}

/* The resistor colour bands in the Module 6 lesson. Ten swatches, each of
   which was a variable written into a style attribute. */
.teach .colours td i.band-black{background:var(--band-black);}
.teach .colours td i.band-brown{background:var(--band-brown);}
.teach .colours td i.band-red{background:var(--band-red);}
.teach .colours td i.band-orange{background:var(--band-orange);}
.teach .colours td i.band-yellow{background:var(--band-yellow);}
.teach .colours td i.band-green{background:var(--band-green);}
.teach .colours td i.band-blue{background:var(--band-blue);}
.teach .colours td i.band-violet{background:var(--band-violet);}
.teach .colours td i.band-grey{background:var(--band-grey);}
.teach .colours td i.band-white{background:var(--band-white);}

/* ---- Corrections to a component, kept next to the component's name ---- */
.set-hint.near{margin-top:6px;}
.set-hint.near-8{margin-top:8px;}
.set-hint.far{margin-top:16px;}
.set-hint.gapped{margin:0 0 8px;}
.set-hint.under-14{margin-bottom:14px;}
.set-row.spaced{margin-top:14px;}
.pf-sub.near{margin-top:2px;}
.opt.spaced{margin-bottom:8px;}
.analogy.roomy{margin-bottom:16px;}
.analogy.roomier{margin-bottom:18px;}
.menu-title{font-size:19px;margin:0 0 8px;}
.tiny-plain{font-size:12px;color:var(--ink-soft);margin:0;}
/* The line under the "watch an ad" card on the path. Not named ad-
   anything: that prefix tells the contrast audit a rule sits on the ad
   panel, and this one sits on the page. */
.topup-note{margin:-6px 20px 14px;font-size:11px;color:var(--ink-soft);}

/* The one figure with a fixed frame — two wire crossings, drawn at a size
   that does not depend on what is in it. */
.dia.crossing svg{max-width:250px;}
/* A plot is the other fixed-frame figure. Its axes carry tick labels at a
   fixed font size, so letting it grow to the full column width makes the
   numbers small relative to the drawing rather than larger. */
.dia.plot svg{max-width:340px;}

/* ---- Markup that carried a style attribute for want of a class ---- */
/* Every progress bar starts empty and is filled from JavaScript. The daily
   goal bar changes colour when the goal is met, which is a state and so a
   class rather than a value written into the markup. */
.lv-fill,.pl-fill,.l-fill,.mod-prog-fill,.goal-bar i{width:0;}
.goal-bar i{background:var(--amber);}
.goal-bar i.hit{background:var(--teal);}

/* ---- hover, which the app had almost none of ---------------------------

   Four rules in the whole of src/styles/ responded to a mouse, three of them
   in the sandbox. On a phone that is invisible; on a laptop it is most of
   what tells you a thing is a control before you click it — a path node, an
   answer, a tab and the primary button all sat there inert, and the app read
   as a picture of itself.

   BEHIND (hover:hover) AND (pointer:fine), which is the whole reason this is
   safe to add. A touch browser reports a hover state after a tap and keeps it
   until you touch something else, so an unguarded :hover leaves the last
   thing you pressed looking pressed — on Android that is the tab you just
   left, permanently highlighted. The query asks for a pointer that can hover
   and is precise, which is a mouse or a trackpad and not a finger.

   Every colour is a token. :not(:active) where a component already has an
   active state to get out of the way of — the node's press is a scale down,
   and hover is a scale up, and without the guard the later rule wins and
   pressing a node makes it bigger.

   Nothing here changes layout. A hover that moves a control moves it out from
   under the pointer that is about to click it. */
@media (hover:hover) and (pointer:fine){
  .btn:not(.ghost):not(:disabled):hover{ background:var(--blue-deep); }
  .btn.amber:not(:disabled):hover{ background:var(--amber); color:var(--on-amber); }
  .btn.ghost:not(:disabled):hover{ background:var(--surface-2); border-color:var(--ink-soft); }
  .btn:disabled{ cursor:default; }

  /* An answer that is still answerable. A marked one keeps its verdict —
     hovering the option you just got right must not repaint it. */
  .opt:not(.disabled):not(.correct):not(.wrong):hover{
    border-color:var(--blue); background:var(--surface-2);
  }

  .nav-btn:not(.active):hover{ background:var(--surface-2); color:var(--ink); }
  .seg-btn:not(.on):hover{ color:var(--ink); }
  .small:hover{ background:var(--surface-2); }
  .sb-tab:not(.on):hover{ border-color:var(--amber); }
  .mod-toggle:hover,.cap-caret:hover{ color:var(--ink); }
  details.danger summary:hover{ color:var(--ink); }

  /* The path. Same idiom the press already uses — the hexagon is the thing
     that moves — and only for a node that can actually be opened. */
  .node-wrap.unlocked:hover:not(:active) .node,
  .node-wrap.mastered:hover:not(:active) .node{ transform:scale(1.06); }
}
