/*
 * Sensei — English Tutor app, shared stylesheet, loaded identically by
 * index.html, vocab.html, and dashboard.html (see the
 * <link rel="stylesheet" href="./styles/styles.css"> tag in each page's
 * <head>).
 *
 * Organized as: shared tokens + chrome every page uses (color variables,
 * reset, focus indicators, the nav/header system), then one section per
 * page for the content that's unique to it (the chat interface, the
 * flashcard deck, the dashboard stats). Nothing here is duplicated — a
 * rule that used to be copy-pasted into all three pages' <style> blocks
 * now exists exactly once.
 *
 * The one place this needed more than a straight merge: index.html's
 * header uses a 3-column CSS grid (to center #new-convo-btn independently
 * of the nav width on either side of it), while vocab.html/dashboard.html
 * share a simpler 2-part flex header. Rather than force all three into
 * one compromise layout, the shared `header`/`.header-actions` rules
 * below are the flex version (correct as-is for vocab/dashboard), and
 * index.html's own section further down fully overrides both with the
 * grid version — see the comment there for how that override works.
 *
 * WCAG contrast notes — read before changing any color below:
 *   - --teal is the bright brand accent. It's intentionally NOT used
 *     anywhere text or icons sit directly on top of it, because white
 *     text on --teal only measures ~1.9:1 contrast (WCAG AA requires
 *     4.5:1 for normal text). Use it only for borders, dots, badges, and
 *     other purely decorative accents.
 *   - --teal-solid / --teal-solid-hover are dark enough that white
 *     text/icons on top of them always pass AA (~6:1), regardless of
 *     theme — use these for any solid button or bubble whose foreground
 *     text is white (.bubble.user, .retry-btn, #send-btn, .know-btn,
 *     .continue-btn.primary, .topic-tab.active).
 *   - --teal-text is for teal-colored text/icons/focus rings that sit
 *     directly on the page background (nav active state, focus ring,
 *     input focus border, progress-fill) rather than inside a solid fill.
 *     It's theme-swapped below (dark teal in light mode, bright teal in
 *     dark mode) because a single fixed shade can't clear 4.5:1 against
 *     both a near-white and a near-black background — same reason --text
 *     itself swaps per theme.
 *   - --text-muted's light-mode value is intentionally darker than a
 *     "natural"-looking muted gray would be: the obvious lighter choice
 *     (#78716C) measures ~4.4:1 against --bg, just under the 4.5:1 AA
 *     minimum, and it's used for a lot of small text (nav links, status
 *     labels). #57534E clears it with margin (~7:1) while staying in the
 *     same warm-gray family.
 *   - --surface-hover is used only by vocab.html's .learning-btn:hover; see
 *     that page's own section below for why it needs its own theme-swap.
 */
:root {
  --teal: #14B8A6;
  --teal-solid: #0B6E63;
  --teal-solid-hover: #084F47;
  --teal-text: #0B6E63;
  --bg: #F5F5F4;
  --card-bg: #FFFFFF;
  --surface-muted: #E7E5E4;
  --border: #E5E5E4;
  --text: #292524;
  --text-muted: #57534E;
}
:root[data-theme="dark"] {
  --teal-text: #14B8A6;
  --bg: #1A1A2E;
  --card-bg: #2D2D44;
  --surface-muted: #3D3D5C;
  --border: #3D3D5C;
  --text: #E5E5E5;
  --text-muted: #A8A8BD;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: var(--bg);
  color: var(--text);
}

/* "sr-only" pattern: keeps content in the accessibility tree (readable by
   screen readers, reachable by keyboard) while removing it from visual
   layout entirely. Used by index.html for the page's real <h1> (the
   compact header doesn't have room for a full descriptive heading, but the
   page still needs one for screen-reader users navigating by heading) and
   the message input's <label>. Not currently referenced by vocab.html or
   dashboard.html, but shared here rather than duplicated in case a future
   edit to either needs it. Do not use display:none/visibility:hidden for
   this — those hide content from screen readers too, defeating the
   purpose. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Focus indicators. :focus-visible (not plain :focus) means a mouse click
   won't show the ring, only keyboard/AT focus. Uses --teal-text
   specifically because it's the one token already proven above the ~3:1
   UI-component contrast minimum against both this app's light and dark
   backgrounds. [role="button"] covers vocab.html's flashcard front faces,
   the only role="button" elements in the app. index.html's #message-input
   defines its own focus style instead of using this rule (a border-color
   + soft ring reads more clearly on a pill-shaped input than an outline
   would) — see that page's own section below. */
a:focus-visible,
button:focus-visible,
[role="button"]:focus-visible {
  outline: 2px solid var(--teal-text);
  outline-offset: 2px;
  border-radius: 6px;
}

/* ============================================================
   Header / nav chrome
   Base version here is the simple 2-part flex header used as-is by
   vocab.html and dashboard.html (title on the left, nav + theme toggle +
   hamburger on the right). index.html overrides `header` and
   `.header-actions` with a 3-column grid version in its own section
   further down — see the comment there for why.

   Desktop: inline nav link list. Below the 820px breakpoint (media query
   further down) .nav-links collapses to a hidden dropdown revealed by
   tapping the hamburger; that toggle is wired up by initNavToggle() in
   scripts/scripts.js via the #nav-toggle / #nav-links ids — don't rename
   either id without updating that function. aria-expanded/aria-controls
   on the button plus the JS that keeps them in sync are what make this an
   accessible disclosure widget rather than just a visual effect (WCAG
   4.1.2 Name, Role, Value).

   820px, not a narrower value, is deliberate: it's the same breakpoint
   index.html's #new-convo-btn label shortens at (see
   .new-convo-label-short further down). Those two used to be different
   breakpoints (640px here, 820px there), which meant resizing the window
   changed the header's layout twice in quick succession — first the
   button label shortened, then a bit narrower the nav collapsed. Keeping
   them at one shared value means the whole header settles into its
   "narrow" layout in a single step. vocab.html/dashboard.html don't have
   a competing button to crowd against, so collapsing their nav at 820px
   too is simply a little more conservative than strictly necessary there
   — not a problem, just earlier than the minimum required.
   ============================================================ */
header {
  position: relative; /* positioning context for the mobile nav dropdown's position:absolute below */
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 20px;
  background: var(--card-bg);
  border-bottom: 1px solid var(--border);
}
.page-title { font-weight: 600; font-size: 17px; margin: 0; }
.header-actions { display: flex; align-items: center; gap: 8px; }
.theme-toggle {
  background: none;
  border: none;
  font-size: 18px;
  line-height: 1;
  padding: 6px 8px;
  border-radius: 8px;
  cursor: pointer;
}
.theme-toggle:hover { background: var(--bg); }
.nav-links { display: flex; gap: 4px; }
.nav-links a {
  font-size: 13px;
  color: var(--text-muted);
  text-decoration: none;
  padding: 7px 12px;
  border-radius: 8px;
}
.nav-links a.active { color: var(--teal-text); font-weight: 600; }
.nav-links a:hover { background: var(--bg); }

/* Hamburger button. display:none by default; the 820px media query below
   flips this to display:flex. Always present in the DOM (not
   JS-injected) so it's reachable without JS. */
.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
  background: none;
  border: none;
  border-radius: 8px;
  padding: 8px;
  cursor: pointer;
}
.nav-toggle-bar {
  width: 20px;
  height: 2px;
  background-color: var(--text);
  border-radius: 2px;
}
.nav-toggle:hover { background: var(--bg); }

@media (max-width: 820px) {
  .nav-toggle { display: flex; }

  /* Dropdown panel. Hidden by default; initNavToggle() (scripts/scripts.js)
     toggles the .open class (and the matching aria-expanded on
     #nav-toggle) on click. Positioned absolute + edge-to-edge under the
     sticky-feeling header (top:100%, left:0, right:0) rather than inline,
     so opening it doesn't push page content down. display:none also
     removes these links from the accessibility tree while closed, so
     screen readers don't announce a hidden menu's contents. */
  .nav-links {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    gap: 0;
    background: var(--card-bg);
    border-bottom: 1px solid var(--border);
    padding: 8px 20px;
    z-index: 10;
  }
  .nav-links.open { display: flex; }
  .nav-links a {
    padding: 12px 4px;
    border-bottom: 1px solid var(--border);
  }
  .nav-links a:last-child { border-bottom: none; }
}

/* ============================================================
   Index: chat interface (index.html only)
   ============================================================ */

/* Adds to (doesn't replace) the shared `body` rule above — .chat-page
   (set on index.html's <body>, nowhere else) needs a full-height flex
   column so #chat can grow to fill the space between the header and the
   input bar. */
body.chat-page {
  height: 100vh;
  display: flex;
  flex-direction: column;
}

/* Three-column layout — .tutor-info (branding) on the left, #new-convo-btn
   truly centered, .header-actions (nav + theme toggle + hamburger) on the
   far right. Grid rather than flex specifically because it centers
   #new-convo-btn *in the header as a whole* regardless of how much the
   left/right content differ in width: the two 1fr columns are always
   forced equal, so the auto-sized center column sits in the true middle.
   (A flex row with justify-content:space-between + margin:auto tricks
   can't guarantee that when the left and right groups aren't the same
   width, which they aren't here.) .header-grid is set on index.html's
   <header> only (nowhere else), and fully overrides the shared
   `header`/`.header-actions` rules above just for that page — vocab.html
   and dashboard.html never add this class, so they keep using the shared
   flex version as-is. */
.header-grid {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 12px;
}
.tutor-info { display: flex; align-items: center; gap: 10px; min-width: 0; justify-self: start; }
.tutor-name { font-weight: 600; font-size: 17px; }
.status { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--text-muted); }
.status-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: #22C55E; /* purely decorative — "Online" text right next to it already conveys the same status in words, so this doesn't need its own text-contrast check (WCAG 1.4.1) */
}
.header-grid .header-actions { justify-self: end; min-width: 0; }

.new-convo-btn {
  justify-self: center;
  background: none;
  border: 1px solid var(--border);
  color: var(--text-muted);
  font-size: 13px;
  padding: 7px 12px;
  border-radius: 8px;
  cursor: pointer;
  white-space: nowrap;
}
.new-convo-btn:hover { background: var(--bg); }
/* Adjustable: the width this switches at is tuned to where the button's
   full "New Conversation" label starts crowding the nav links beside it
   — narrower than this and .new-convo-label-short ("New C..") takes over
   to keep the button (and the whole header row) from wrapping. Move it
   if the nav links, branding text, or button label ever change length.
   Both labels are aria-hidden because #new-convo-btn's own aria-label
   (set in the HTML) already gives it a stable accessible name regardless
   of which one is visible — a screen reader always hears
   "New Conversation", never the abbreviation. */
.new-convo-label-short { display: none; }
@media (max-width: 820px) {
  .new-convo-label-full { display: none; }
  .new-convo-label-short { display: inline; }
}

/* Starters */
#starters {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  padding: 16px 20px;
}
.starter-btn {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 12px 14px;
  font-size: 14px;
  text-align: left;
  color: var(--text);
  cursor: pointer;
}
.starter-btn:hover { border-color: var(--teal); color: var(--teal-text); }

/* Chat */
#chat {
  flex: 1;
  overflow-y: auto;
  padding: 16px 20px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.bubble-row { display: flex; }
.bubble-row.user { justify-content: flex-end; }
.bubble-row.tutor { justify-content: flex-start; }
.bubble {
  max-width: 75%;
  padding: 10px 14px;
  border-radius: 16px;
  font-size: 15px;
  line-height: 1.4;
  white-space: pre-wrap;
}
.bubble.user {
  background: var(--teal-solid); /* see the WCAG contrast note at the top of this file — plain --teal would fail under the white text below */
  color: #fff;
  border-bottom-right-radius: 4px;
}
.bubble.tutor {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-bottom-left-radius: 4px;
}
.bubble.error-msg {
  background: var(--surface-muted);
  border: 1px solid var(--border);
  color: var(--text);
}
.retry-btn {
  display: block;
  margin-top: 8px;
  background: var(--teal-solid);
  color: #fff;
  border: none;
  border-radius: 8px;
  padding: 6px 14px;
  font-size: 13px;
  cursor: pointer;
}
.retry-btn:hover { background: var(--teal-solid-hover); }

/* Typing indicator. The bounce animation loops for as long as a reply is
   pending, which can exceed the 5-second threshold WCAG 2.2.2 (Pause,
   Stop, Hide) cares about for auto-playing motion — see the
   prefers-reduced-motion override near the bottom of this section, which
   freezes the dots to a static (non-bouncing) state instead of adding a
   pause control. */
.slow-notice {
  display: none;
  font-size: 12px;
  color: var(--text-muted);
  padding: 10px 14px 0;
}
.typing-dots {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 12px 14px;
}
.typing-dots span {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--text-muted);
  animation: bounce 1.2s infinite ease-in-out;
}
.typing-dots span:nth-child(2) { animation-delay: 0.15s; }
.typing-dots span:nth-child(3) { animation-delay: 0.3s; }
@keyframes bounce {
  0%, 60%, 100% { transform: translateY(0); opacity: 0.5; }
  30% { transform: translateY(-5px); opacity: 1; }
}

/* Input bar */
#input-bar {
  display: flex;
  gap: 8px;
  padding: 14px 20px;
  background: var(--card-bg);
  border-top: 1px solid var(--border);
}
#message-input {
  flex: 1;
  background: var(--card-bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 10px 16px;
  font-size: 15px;
  outline: none;
}
/* Custom focus style (rather than the shared :focus-visible rule above,
   which targets a/button/[role=button] only) — border-color + a soft
   ring reads more clearly on a pill-shaped input than an outline would.
   var(--teal-text) here for the same 3:1-against-both-themes reason as
   the shared focus rule. */
#message-input:focus {
  border-color: var(--teal-text);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--teal-text) 20%, transparent);
}
#send-btn {
  background: var(--teal-solid);
  border: none;
  width: 40px; height: 40px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex-shrink: 0;
}
#send-btn:hover { background: var(--teal-solid-hover); }
#send-btn:disabled { background: var(--text-muted); cursor: not-allowed; }

/* Honors the OS-level "reduce motion" setting (WCAG 2.2.2): stops the
   typing-indicator dots from bouncing indefinitely while a reply is
   pending. The dots themselves stay visible (still communicates "Sensei
   is responding"), they just stop moving. */
@media (prefers-reduced-motion: reduce) {
  .typing-dots span {
    animation: none;
    opacity: 1;
  }
}

/* ============================================================
   Vocab: flashcard deck (vocab.html only)
   --surface-hover is theme-swapped for the same reason --text-muted/
   --teal-text are: the light-mode hover tint would be nearly invisible
   text-on-background if used unchanged against the dark theme's
   already-dark surfaces. Used only by .learning-btn:hover below.
   ============================================================ */
:root { --surface-hover: #D6D3D1; }
:root[data-theme="dark"] { --surface-hover: #4A4A6E; }

/* Topic tabs */
#topic-tabs {
  display: flex;
  gap: 8px;
  padding: 16px 20px 0;
  overflow-x: auto;
}
.topic-tab {
  flex-shrink: 0;
  background: var(--card-bg);
  border: 1px solid var(--border);
  color: var(--text-muted);
  font-size: 14px;
  padding: 8px 16px;
  border-radius: 20px;
  cursor: pointer;
}
.topic-tab.active {
  background: var(--teal-solid); /* see the WCAG note at the top of this file — plain --teal fails under white text */
  border-color: var(--teal-solid);
  color: #fff;
  font-weight: 600;
}

/* Progress bar */
#progress-section { padding: 16px 20px 0; }
#progress-label { font-size: 13px; color: var(--text-muted); margin-bottom: 6px; }
#progress-track {
  height: 8px;
  background: var(--border);
  border-radius: 4px;
  overflow: hidden;
}
/* var(--teal-text) rather than plain --teal: the flat --teal fill only
   measures ~2:1 against this track's --border background (WCAG 1.4.11
   Non-Text Contrast wants 3:1 for a meaningful graphical element like
   this), and fails even worse in dark mode where the track is also
   dark. --teal-text's theme-swap (dark shade in light mode, bright
   shade in dark mode) clears 3:1 against the track in both themes. */
#progress-fill {
  height: 100%;
  background: var(--teal-text);
  border-radius: 4px;
  transition: width 0.3s ease;
  width: 0%;
}

/* Card grid */
#card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 14px;
  padding: 20px;
}

.card-outer {
  height: 230px;
  perspective: 1000px;
  cursor: pointer;
}
.card-inner {
  position: relative;
  width: 100%;
  height: 100%;
  transition: transform 0.5s;
  transform-style: preserve-3d;
}
.card-inner.flipped { transform: rotateY(180deg); }

.card-face {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
  border-radius: 14px;
  background: var(--card-bg);
  border: 1px solid var(--border);
  padding: 14px;
  display: flex;
  flex-direction: column;
}
/* .card-front is promoted to role="button"/tabindex="0" in scripts.js so
   it needs to look focusable/interactive like one; cursor is already
   inherited from .card-outer. */
.card-front {
  align-items: center;
  justify-content: center;
  text-align: center;
  position: relative;
}
.card-front .word-en {
  font-size: 22px;
  font-weight: 600;
}
.status-badge {
  position: absolute;
  top: 10px;
  right: 10px;
  font-size: 16px;
}
.speak-btn {
  margin-top: 8px;
  background: none;
  border: none;
  font-size: 16px;
  line-height: 1;
  padding: 4px;
  cursor: pointer;
}
.speak-btn:hover { transform: scale(1.15); }
.card-front.known { border-color: var(--teal); }
.card-front.learning { border-color: var(--text-muted); }

.card-back {
  transform: rotateY(180deg);
  justify-content: space-between;
}
/* lang="ja" is set on this element by renderGrid() in scripts.js rather
   than here, since the Japanese text itself is inserted dynamically —
   see that function's comment. */
.card-back .word-jp { font-size: 22px; font-weight: 600; }
.card-back .word-example { font-size: 12px; color: var(--text); line-height: 1.4; margin-top: 4px; }
.card-back .word-pron { font-size: 12px; color: var(--text-muted); font-style: italic; margin-top: 4px; }
.card-back-buttons { display: flex; gap: 6px; margin-top: 8px; }
.card-back-buttons button {
  flex: 1;
  border: none;
  border-radius: 8px;
  padding: 7px 4px;
  font-size: 11px;
  cursor: pointer;
}
.know-btn { background: var(--teal-solid); color: #fff; }
.know-btn:hover { background: var(--teal-solid-hover); }
.learning-btn { background: var(--border); color: var(--text); }
.learning-btn:hover { background: var(--surface-hover); }
/* Small text-only control that lets keyboard/AT users flip a card back
   over without marking it known/learning — mouse/touch users can still
   just tap anywhere else on the back face (see the card-back click
   handler in scripts.js), but that gesture has no keyboard equivalent, so
   this button is the accessible path for the same action (WCAG 2.1.1
   Keyboard). */
.flip-back-btn {
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: 11px;
  text-decoration: underline;
  align-self: center;
  margin-top: 6px;
  padding: 2px 4px;
  cursor: pointer;
}

#topic-complete {
  display: none;
  margin: 0 20px 20px;
  background: var(--card-bg);
  border: 1px solid var(--teal);
  border-radius: 12px;
  padding: 16px;
  text-align: center;
  color: var(--teal-text);
  font-weight: 600;
}

/* Honors "reduce motion" (WCAG 2.2.2 for the always-visible progress-fill
   width transition running whenever progress changes; and in the spirit
   of WCAG 2.3.3 for the card flip specifically — a 3D rotateY flip is a
   textbook vestibular-motion trigger, so reduced-motion users get an
   instant swap instead). Card content and progress state are unaffected,
   only the animated transition is removed. */
@media (prefers-reduced-motion: reduce) {
  .card-inner,
  #progress-fill {
    transition: none;
  }
}

/* ============================================================
   Dashboard: stats + progress overview (dashboard.html only)
   ============================================================ */

/* Welcome */
#welcome { padding: 20px 20px 4px; }
#welcome h1 { margin: 0 0 4px; font-size: 22px; }
#welcome .date { font-size: 14px; color: var(--text-muted); }

/* Stat cards */
#stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
  padding: 16px 20px;
}
.stat-card {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 16px 10px;
  text-align: center;
}
.stat-value { font-size: 26px; font-weight: 700; color: var(--teal-text); }
.stat-label { font-size: 12px; color: var(--text-muted); margin-top: 4px; }

/* Continue learning */
#continue-section { padding: 4px 20px 16px; }
#continue-section h2 { font-size: 15px; margin: 0 0 10px; }
.continue-buttons { display: flex; flex-direction: column; gap: 10px; }
.continue-btn {
  display: block;
  text-decoration: none;
  text-align: center;
  padding: 14px;
  border-radius: 12px;
  font-size: 15px;
  font-weight: 600;
}
.continue-btn.primary { background: var(--teal-solid); color: #fff; }
.continue-btn.primary:hover { background: var(--teal-solid-hover); }
.continue-btn.secondary { background: var(--card-bg); color: var(--teal-text); border: 1px solid var(--teal); }
/* var(--bg) rather than a hardcoded light tint: a fixed light color would
   look fine in light mode but never change per theme, producing a jarring
   light flash in dark mode — and dark mode's --teal-text (bright teal)
   against that same light hardcoded color would also fail contrast.
   var(--bg) matches the hover pattern already used elsewhere on this page
   (.theme-toggle:hover, .nav-links a:hover) and is correct in both themes
   automatically. */
.continue-btn.secondary:hover { background: var(--bg); }

/* Progress section */
#progress-section { padding: 4px 20px 20px; }
#progress-section h2 { font-size: 15px; margin: 0 0 12px; }
.topic-row { margin-bottom: 14px; }
.topic-row-label {
  display: flex;
  justify-content: space-between;
  font-size: 13px;
  margin-bottom: 6px;
}
.topic-row-label .count { color: var(--text-muted); }
.topic-row-track {
  height: 10px;
  background: var(--border);
  border-radius: 5px;
  overflow: hidden;
}
/* var(--teal-text) rather than plain --teal — see the matching
   #progress-fill comment in the vocab section above for the WCAG 1.4.11
   contrast reasoning (identical fill-vs-track situation here). */
.topic-row-fill {
  height: 100%;
  background: var(--teal-text);
  border-radius: 5px;
}
