/*
 * Design tokens and the learner surface. FE-G-02.
 *
 * The :root block is copied wholesale from docs/nneola-design-guide.html, which
 * says to do exactly that. One definition of the palette, in both schemes.
 *
 * NOTHING ON A STUDY SURFACE ANIMATES. Guide §4, and it is not a taste rule:
 * §7.5 takes t0 at paint and grades promotion against it, so a transition on
 * item appearance makes "when did this become visible" ambiguous and the
 * fluency engine's whole premise with it. There is no `transition` or
 * `animation` property anywhere in this file, and a browser test asserts it.
 *
 * No web font, for the same reason — a font swapping after first paint reflows
 * the text and moves the moment of legibility.
 */

:root{
  --paper:      #FAF8F5;
  --surface:    #FFFFFF;
  --border:     #E3DED6;
  --border-str: #CFC7BB;
  --ink:        #1C1B19;
  --ink-muted:  #6B655C;

  --indigo:     #2B3A67;
  --indigo-600: #47548A;
  --indigo-400: #7A85A8;
  --indigo-200: #B8C0D4;
  --indigo-050: #E8EBF3;

  --gold:       #C88A2E;
  --gold-deep:  #5C3F0C;
  --gold-mid:   #8A6118;
  --gold-tint:  #FBF0DC;
  --gold-line:  #E8CFA0;

  --teal:       #0E7C6B;
  --teal-deep:  #04342C;
  --teal-tint:  #E2F2EF;

  --amber:      #B4690E;
  --amber-deep: #412402;
  --amber-tint: #FAEEDC;

  --radius: 10px;
  --radius-lg: 14px;
}

@media (prefers-color-scheme: dark){
  :root{
    --paper:      #1A1917;
    --surface:    #232120;
    --border:     #35322E;
    --border-str: #4A463F;
    --ink:        #F0EDE7;
    --ink-muted:  #A39D93;

    --indigo:     #8E9BC4;
    --indigo-600: #6E7BA6;
    --indigo-400: #545F85;
    --indigo-200: #3B4462;
    --indigo-050: #262B3D;

    --gold:       #D9A253;
    --gold-deep:  #F0DBB4;
    --gold-mid:   #C89A5A;
    --gold-tint:  #33280F;
    --gold-line:  #57451D;

    --teal:       #4FBFA7;
    --teal-deep:  #C3E8DE;
    --teal-tint:  #10322B;

    --amber:      #D89544;
    --amber-deep: #F3DBBB;
    --amber-tint: #33230C;
  }
}

/* ---- iOS behaviours to disable. Guide §3; each breaks something specific. --- */

/* Below 16px, iOS zooms the viewport when an input takes focus. */
input, select, textarea { font-size: 16px; }
/* Stops pull-to-refresh reloading the page mid-session and losing the buffer. */
html, body { overscroll-behavior-y: contain; }
/* Stops a double-tap being read as zoom, and a long-press raising the callout. */
.rating-row, .card { touch-action: manipulation; }
.card-face { -webkit-user-select: none; user-select: none; }
/* The grey tap flash reads as lag on a timed screen. */
* { -webkit-tap-highlight-color: transparent; }

*, *::before, *::after { box-sizing: border-box; }

/* An explicit `display` beats the user-agent rule for [hidden], so `display:
   grid` on .rating-row left the rating buttons visible before she had revealed
   the answer -- she could grade a card without ever seeing the back. This is
   the one !important in the file and it is earning it. */
[hidden] { display: none !important; }

body{
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  /* System stack only. Guide §6, and §4 for why. */
  font: 400 18px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
        Helvetica, Arial, sans-serif;
  -webkit-text-size-adjust: 100%;
}

/* Guide §3: capped at 520px and centred. A rating button 900px wide on an iPad
   is worse than one 300px wide — her thumb has further to travel and the screen
   reads as empty rather than generous. */
.wrap{
  max-width: 520px;
  margin: 0 auto;
  padding: 24px 20px max(24px, env(safe-area-inset-bottom));
  padding-top: max(24px, env(safe-area-inset-top));
  min-height: 100vh;
  /* `dvh` after `vh`, so a browser that knows it wins and one that does not
     keeps what it had.

     `100vh` on a phone is the viewport WITHOUT the browser's own bar, and the
     bar is showing — about 110px of a 390x844 screen. So a column sized to
     100vh is taller than what she can see, and the bottom of it sits below the
     fold. On the sprint that bottom is the 0 key and Delete. */
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}

/* THE SPRINT AND THE DRILL FIT THE DEVICE, AND NEVER SCROLL.
 *
 * She is answering against a clock. A screen that scrolls is one where the key
 * she wants is somewhere she has to find first, and §7.5 is measuring the time
 * between the problem appearing and her first keystroke — a scroll goes into
 * that number as though it were thinking.
 *
 * `height` rather than `min-height`: this is a claim about the device, and a
 * minimum would let a tall problem push the keypad off again. */
.wrap-fixed{
  height: 100dvh;
  min-height: 0;
  overflow: hidden;
}

.greeting{ font-size: 24px; font-weight: 500; margin: 8px 0 24px; }

/* ---- Home ---------------------------------------------------------------- */

.destination{
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  min-height: 64px;               /* guide §7: learner primary button */
  padding: 16px 20px;
  margin-bottom: 12px;
  background: var(--surface);
  border: 0.5px solid var(--border);
  border-radius: var(--radius-lg);
  color: var(--ink);
  text-decoration: none;
}
.destination-name{ font-size: 18px; font-weight: 500; }
.destination-count{ font-size: 16px; color: var(--ink-muted); }
.destination-waiting{ opacity: 0.55; }

/* Her sign-out. Deliberately unlike a destination: no card, no border, no
   full-width tap target. She is choosing between three things to do, and the
   exit is not a fourth — it should be findable and never mistaken for the
   thing she came here for.

   Still 44px tall. Guide §7 sets that floor for anything she taps, and a
   control small enough to be missed is a control she presses twice. */
.signout{ margin-top: 32px; text-align: center; }
.signout button{
  min-height: 44px;
  padding: 0 20px;
  font: inherit;
  font-size: 16px;
  background: none;
  border: 0;
  color: var(--ink-muted);
  text-decoration: underline;
  cursor: pointer;
}
.signout button:focus-visible{
  outline: none;
  box-shadow: 0 0 0 3px var(--indigo-200);
  border-radius: var(--radius);
}

/* ---- Recall -------------------------------------------------------------- */

.counter{
  /* Reserved space, always. Guide §4: no layout shift after paint — the counter
     appearing on the first item would move the card down under her thumb. */
  min-height: 22px;
  margin: 0 0 16px;
  text-align: right;
  font-size: 15px;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

.card{
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 20px;
  padding: 28px 24px;
  background: var(--surface);
  border: 0.5px solid var(--border);
  border-radius: var(--radius-lg);
  text-align: center;
}
.card-face{ font-size: 28px; font-weight: 500; }
.card-back{
  font-size: 20px;
  font-weight: 400;
  color: var(--ink);
  border-top: 0.5px solid var(--border);
  padding-top: 20px;
}

.reveal{
  min-height: 60px;
  margin-top: 16px;
  background: var(--surface);
  color: var(--ink);
  border: 0.5px solid var(--border-str);
  border-radius: var(--radius);
  font: 500 17px/1 inherit;
  font-family: inherit;
}

/* Guide §8: one hue at four weights, never a traffic light. Again is darkest
   because it needs the most attention and returns soonest, not because it is
   worst. NO RED ANYWHERE — she rates a card Again perhaps thirty times a
   session, and a red button tells her she failed thirty times before breakfast. */
.rating-row{
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
  margin-top: 16px;
}
.rating{
  min-height: 64px;
  border: none;
  border-radius: var(--radius);
  font: 500 17px/1.2 inherit;
  font-family: inherit;
}
.rating-again{ background: var(--indigo);     color: #fff; }
.rating-hard { background: var(--indigo-400); color: #fff; }
.rating-good { background: var(--indigo-200); color: var(--ink); }
.rating-easy { background: var(--indigo-050); color: var(--ink); }

.done{ margin-top: auto; }
.done-line{ font-size: 18px; margin: 0 0 20px; }

/* ---- Her sign-in --------------------------------------------------------
   Guide §2, one decision per screen. Two fields and one button, and nothing
   else on the page: no product name, no marketing, no link to a parent screen
   she has no business on.

   16px minimum on the inputs, which is not a style choice — iOS Safari zooms
   the whole page when it focuses an input below 16px, and the zoom does not
   come back out. */
.signin-field{ display: block; margin-bottom: 20px; }
.signin-field > span{
  display: block;
  font-size: 16px;
  color: var(--ink-muted);
  margin-bottom: 6px;
}
.signin-field input{
  display: block;
  width: 100%;
  box-sizing: border-box;
  min-height: 56px;
  padding: 12px 16px;
  font: inherit;
  font-size: 18px;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--border-str);
  border-radius: var(--radius);
}
.signin-pin input{
  font-size: 28px;
  letter-spacing: 0.35em;
  text-align: center;
}
.signin-submit{
  display: block;
  width: 100%;
  min-height: 64px;               /* guide §7: learner primary button */
  font: inherit;
  font-size: 18px;
  font-weight: 500;
  color: #fff;
  background: var(--indigo);
  border: 0;
  border-radius: var(--radius);
}
/* Guide §11: say what happened and what to do, in her words. Amber rather than
   red — a mistyped password is not an emergency. */
.signin-error{
  margin: 0 0 20px;
  padding: 12px 16px;
  font-size: 16px;
  color: var(--amber-deep);
  background: var(--amber-tint);
  border-radius: var(--radius);
}
.signin-alt{ margin-top: 24px; font-size: 16px; }
.signin-alt a{ color: var(--indigo-600); }

:focus-visible{ outline: none; box-shadow: 0 0 0 3px var(--indigo-200); }

@media (min-width: 700px){
  .card-face{ font-size: 34px; }
  .card-back{ font-size: 22px; }
  .rating{ min-height: 72px; }
  .reveal{ min-height: 64px; }
}

/* ---- Verbal drill -------------------------------------------------------
   FE-G-04, spec §8.3 and §8.4. Three item formats, one surface.

   EVERY HEIGHT HERE IS RESERVED RATHER THAN GROWN. Guide §4 forbids a layout
   shift after paint on anything carrying an item, and it is a measurement rule:
   `t0` is taken at paint and §7.5 grades a threshold against it. The bridge
   sentence and the Next button both arrive after she answers, so the block that
   holds them is a fixed height from first paint and they appear inside it. The
   naive version of this screen inserts them and pushes the choices up under her
   thumb between one item and the next.

   Nothing in this section declares a transition or an animation, including on
   the answer tints — guide §10: "Answer feedback: instant colour change, no
   transition." */

/* The stem and the choices, filling the space above the reserved block so the
   choices sit at the bottom of it. Guide §3: never a primary action in the top
   third — she is holding the phone one-handed in a car. */
.drill{
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}

.drill-ask{
  min-height: 24px;                /* reserved: it changes wording per format */
  margin: 0 0 12px;
  text-align: center;
  font-size: 16px;
  color: var(--ink-muted);
}

.drill-stem{
  margin: 0 0 24px;
  text-align: center;
  font-size: 28px;
  font-weight: 500;
  color: var(--ink);
}

/* Guide §8: "Twelve relationship choices in mode A need to fit without
   scrolling on a phone — use two columns at 56px each." Six rows of 56 with
   10px gaps is 386px, which clears a 390x844 phone with the stem above and the
   bridge block below. */
.relationship-grid{
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;                       /* guide §7: gap between adjacent targets */
}

/* Mode B's five candidate pairs and the synonym drill's five words. §8.3 and
   §8.4 both give five and one correct; only the text differs. */
.choice-list{
  display: grid;
  gap: 10px;
}

.choice{
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  min-height: 56px;                /* guide §7: drill choice row, phone */
  padding: 8px 12px;
  text-align: left;
  background: var(--surface);
  color: var(--ink);
  border: 0.5px solid var(--border-str);
  border-radius: var(--radius);
  font: 400 15px/1.2 inherit;
  font-family: inherit;
  touch-action: manipulation;
}
.choice-option{ font-size: 17px; }
.choice-text{ flex: 1; }

/* Guide §12: "Feedback never carried by colour alone. Correct and incorrect
   each carry a glyph." Both marks are legible in greyscale. */
.choice-mark{
  flex: none;
  min-width: 18px;
  text-align: right;
  font-size: 18px;
  font-weight: 500;
}

/* Teal and amber, never green against red, and no red anywhere on a learner
   screen. Guide §5 and §13. */
.choice-correct{
  background: var(--teal-tint);
  color: var(--teal-deep);
  border-color: var(--teal);
}
.choice-wrong{
  background: var(--amber-tint);
  color: var(--amber-deep);
  border-color: var(--amber);
}

/* The reserved block. Fixed height, not min-height: the Next button is
   `display: none` until she answers, and a min-height would let the block
   shrink around its absence and move everything above it. */
.after{
  height: 128px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  margin-top: 16px;
}

/* §8.3: "Always show the bridge sentence after answering, correct or not." It
   is the technique being taught, and it is the part most often dropped.

   A fixed height with its own scroll rather than a growing box. Two lines holds
   every bridge sentence the spec writes — "A puppy is a young dog" — and a
   generated one that runs longer scrolls inside its reserved space rather than
   moving the drill above it. */
.bridge{
  height: 56px;
  overflow-y: auto;
  margin: 0 0 12px;
  font-size: 16px;
  color: var(--ink);
}

.next{
  min-height: 60px;                /* guide §7: learner primary button, phone */
  background: var(--indigo);
  color: #fff;
  border: 0;
  border-radius: var(--radius);
  font: 500 17px/1 inherit;
  font-family: inherit;
  touch-action: manipulation;
}

/* §8.7: "If the analogy bank runs dry for her weakest type, say so on the
   results screen rather than silently substituting." Plain, muted, and short —
   FE-F-01 carries the whole bank for whoever can act on it. */
.gaps{
  margin: 0 0 20px;
  padding: 0;
  list-style: none;
  font-size: 16px;
  color: var(--ink-muted);
}
.gaps li{ margin-bottom: 4px; }

@media (min-width: 700px){
  .drill-stem{ font-size: 34px; }
  .choice{ min-height: 60px; }     /* guide §7: drill choice row, iPad */
  .relationship-grid, .choice-list{ gap: 12px; }
  .next{ min-height: 64px; }
}

/* ---- Math sprint --------------------------------------------------------
   FE-G-03, spec §7.5, §7.8 and §7.9. One problem, a numeric keypad, no submit
   key.

   THE KEYPAD GEOMETRY HERE IS A MEASUREMENT, NOT A COMFORT. A mis-tap under
   time pressure produces a correction, which sets `had_correction`, which
   excludes the trial from the execution baseline (E-AC-26). Guide §7 fixes the
   numbers — 72px keys on a phone, 88px on an iPad, 10px and 12px gaps — and a
   keypad that shaved them would quietly starve the baseline BE-E-03's guard
   depends on, while every test of the guard kept passing.

   Nothing in this section declares a transition or an animation, including on
   the answer tints. Guide §10: "Answer feedback: instant colour change, no
   transition." The countdown bar is the one thing here that moves and it is
   moved by sprint.js, from a frame callback — see that file on why it is not a
   90-second CSS transition. */

/* Guide §8 said "pinned to the top edge, 4px, --indigo on --indigo-050", and at
   4px on a phone it was a hairline nobody noticed. 10px, on a track dark enough
   to read against it.

   THE FILL STAYS INDIGO, AND THAT IS NOT AN OVERSIGHT.

   The other two colours on this screen are spoken for: --teal is a right answer
   and --amber is a wrong one, both landing on the problem area thirty times in
   ninety seconds. A countdown in either would put an answer colour permanently
   on screen and make it mean two things. Red is not available at all — guide
   §13 keeps it off every learner screen.

   So the prominence comes from height and from the track, which moves from
   --indigo-050 (#E8EBF3, all but white) to --indigo-200. What is left and what
   is gone are now different shades rather than nearly the same one.

   Worth knowing what this trades: the bar carries no number because guide §13
   says a nine-year-old shown "38 seconds left" races it, and a bar was meant to
   be "a shape she can ignore". A bigger, higher-contrast bar is harder to
   ignore, which is the point of the change and also its cost.

   Fixed rather than in flow, so the bar cannot take a pixel of height away from
   the keypad in landscape. */
.countdown{
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 10px;
  background: var(--indigo-200);
  z-index: 1;
}
/* `transform-origin: left` with scaleX driven from JS. A scale is what a linear
   width change is made of, and it is composited rather than laid out, so the
   bar emptying cannot reflow the problem above it. */
.countdown-fill{
  display: block;
  height: 100%;
  background: var(--indigo);
  transform-origin: left center;
  transform: scaleX(1);
}

/* The problem in the upper half, the keypad in the lower. Guide §3: "Never put
   a primary action in the top third" — she is holding a borrowed phone
   one-handed in a car. */
.sprint{
  /* `0 1 auto`, not `1`. It used to take all the spare height and centre the
     problem in it, which is what left the keypad with a fixed 288px at the
     bottom of a screen it did not fit on. The problem is a line of text and
     wants exactly its own height; the space belongs to the keys. */
  flex: 0 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

/* The tint target. Guide §8 puts the feedback colour on "the problem area",
   which is this block and not the digits alone — a tint behind two characters
   is a highlighter pen, not an answer. */
.sprint-face{
  padding: 24px 20px;
  border: 0.5px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  text-align: center;
}

.sprint-problem{
  margin: 0 0 16px;
  font-size: 40px;
  font-weight: 500;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  -webkit-user-select: none;
  user-select: none;
}

/* Guide §3: "The sprint keypad input must be >= 16px" or iOS zooms the viewport
   on focus and does not come back out — which would put the keypad half off the
   screen, and that is E-AC-26's mis-tap problem arriving by another route. Well
   above the floor here because it is the thing she is looking at. */
.sprint-answer{
  display: block;
  width: 100%;
  margin: 0;
  padding: 8px 0;
  font-family: inherit;
  font-size: 36px;
  font-weight: 500;
  line-height: 1.2;
  text-align: center;
  letter-spacing: 0.08em;
  color: var(--ink);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--border-str);
  border-radius: 0;
  font-variant-numeric: tabular-nums;
}

/* Reserved from first paint. Guide §4 forbids a layout shift after paint on
   anything carrying an item, and the right answer arrives only when she gets
   one wrong — the naive version of this screen inserts it and pushes the keypad
   up under her thumb between one problem and the next. */
.sprint-feedback{
  height: 30px;
  margin: 10px 0 0;
  font-size: 22px;
  font-weight: 500;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.sprint-mark{
  display: block;
  height: 26px;
  font-size: 22px;
  font-weight: 500;
  line-height: 26px;
}

/* Teal and amber, never green against red, and no red anywhere on a learner
   screen. Guide §5 and §13 — a wrong answer in a fluency sprint is the ordinary
   case, since she is meant to be at the edge of what she can retrieve, and a red
   flash thirty times in ninety seconds is a different message from the one
   intended. */
.sprint-correct{
  background: var(--teal-tint);
  border-color: var(--teal);
  color: var(--teal-deep);
}
.sprint-wrong{
  background: var(--amber-tint);
  border-color: var(--amber);
  color: var(--amber-deep);
}
.sprint-correct .sprint-problem, .sprint-correct .sprint-mark{ color: var(--teal-deep); }
.sprint-wrong .sprint-problem,
.sprint-wrong .sprint-mark,
.sprint-wrong .sprint-feedback{ color: var(--amber-deep); }

/* Guide §8: "0-9 in a 3x4 grid with the zero spanning two columns, plus a
   delete key. No submit key" — §7.8 auto-submits on the digit count, and a
   submit button beside it would give her two ways to finish an answer that stop
   `t2` at different moments. */
/* The keypad takes the space that is left, rather than a fixed height.
 *
 * It used to be four rows of 72px whatever the screen was, with the problem
 * area centred in everything above it. On a phone that put the last row at the
 * edge of the fold; on a tall screen it left a band of nothing under her thumb.
 *
 * Growing it is also the answer to "the keyboard should be more prominent" —
 * the keys are the thing she is aiming at eighty times in ninety seconds, and
 * they should be the biggest thing on the screen rather than the leftovers.
 *
 * `1fr` rows with a 72px floor: it fills what is available and never goes under
 * guide §7's minimum on a short screen. */
.keypad{
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: minmax(72px, 1fr);
  flex: 1 1 auto;
  min-height: 0;
  gap: 10px;                       /* guide §7: gap between adjacent targets */
  margin-top: 16px;
  touch-action: manipulation;      /* stops a double-tap being read as zoom */
  -webkit-user-select: none;
  user-select: none;
}
.keypad-key{
  min-height: 72px;                /* guide §7: keypad key, phone */
  height: 100%;
  background: var(--surface);
  color: var(--ink);
  border: 0.5px solid var(--border-str);
  border-radius: var(--radius);
  font: 500 26px/1 inherit;
  font-family: inherit;
  font-variant-numeric: tabular-nums;
  touch-action: manipulation;
}
.keypad-wide{ grid-column: span 2; }
/* A word rather than U+232B: guide §11 bans emoji, and the glyph is neither a
   word she has been taught nor safely outside the range the emoji scan rejects.
   Quieter than the digits — it is a correction key, and §7.5 is explicit that a
   correction is not a mistake. */
.keypad-delete{
  font-size: 17px;
  color: var(--ink-muted);
}

@media (min-width: 700px){
  .sprint-problem{ font-size: 48px; }
  .keypad{ gap: 12px; }            /* guide §7: gap between adjacent targets */
  .keypad-key{ min-height: 88px; } /* guide §7: keypad key, iPad */
}

/* ---- Appended by FE-L-01. Do not reorder anything above this line. ---------
 *
 * The fluency state ramp and the parent red, both defined in
 * docs/nneola-design-guide.html §5 and both missing from the :root block above —
 * FE-G-02 copied the learner surface's half of the palette, which is the half a
 * study screen uses.
 *
 * Guide §9 is why the dashboard needs them: "Charts use the state ramp and
 * nothing else. No multi-hue categorical palettes." A chart that defined its own
 * four colours would be a second palette, and the guide's whole argument for the
 * ramp is that there is only one.
 *
 * Appended as a second :root rather than edited into the first, per the house
 * rule on shared files: two lanes appending merge cleanly, one lane reflowing
 * conflicts with everything. Values are verbatim from the guide.
 */

:root{
  /* Red. Parent screens only — destructive actions and hard failures. Never on
     a learner screen: guide §13, and §12's reason, which is that she rates a
     card "Again" thirty times a session. */
  --red:        #A8322A;
  --red-tint:   #FCEBEB;

  /* The ramp reads as "how much does this need", not "how well did she do".
     `--state-fluent` is the gold §5 reserves for promotion and nothing else. */
  --state-new:         #D6D1C7;
  --state-learning:    #B8C0D4;
  --state-fluent:      #C88A2E;
  --state-maintaining: #2B3A67;
}

@media (prefers-color-scheme: dark){
  :root{
    --red:        #D9736A;
    --red-tint:   #331916;

    --state-new:         #3D3A35;
    --state-learning:    #545F85;
    --state-fluent:      #D9A253;
    --state-maintaining: #8E9BC4;
  }
}
