/* ------------------------------------------------------------------------- *
 * Word Buddy — the conversational guide overlay.
 *
 * Everything is scoped under #wb-* so the whole feature can be removed by
 * deleting three lines from master.blade.php and these files.
 *
 * Two rules shape the layout and must not be undone:
 *   1. No backdrop and no scroll lock. The learner must be able to reach every
 *      part of the page underneath — on a quiz that means all four answers.
 *   2. z-index stays below Bootstrap's modal layer (1050+), so the Sentences
 *      and Meaning modals still open over the panel.
 * ------------------------------------------------------------------------- */

:root {
  --wb-purple: #6b4c9a;
  --wb-purple-dark: #563d7d;
  --wb-ink: #212529;
  --wb-muted: #6c757d;
  --wb-line: #e6e2ee;
  --wb-bg: #ffffff;
  --wb-surface: #f7f5fb;
  --wb-z: 1035;
}

/* --- Launcher ------------------------------------------------------------ */

/* Bottom-left everywhere. That also keeps it clear of the quiz's Next button,
   which sits bottom-right. */
#wb-launcher {
  position: fixed;
  left: 16px;
  bottom: 16px;
  z-index: var(--wb-z);
  display: inline-flex;
  align-items: center;
  gap: 10px;
  max-width: calc(100vw - 32px);
  padding: 13px 21px 13px 17px;
  border: none;
  border-radius: 999px;
  background: var(--wb-purple);
  color: #fff;
  font-weight: 700;
  font-size: 15.5px;
  line-height: 1.25;
  text-align: left;
  box-shadow: 0 5px 18px rgba(0, 0, 0, .28);
  cursor: pointer;
}

#wb-launcher:hover { background: var(--wb-purple-dark); }
#wb-launcher:focus-visible { outline: 3px solid #ffc107; outline-offset: 2px; }
#wb-launcher[hidden] { display: none; }

/* No extra body padding on quiz pages. It was tried, to guarantee clearance
   under the launcher, and it backfired: it let the page scroll 80px past its
   content, which pushed the first answer up underneath ColWords' own sticky
   mobile navbar. The footer already leaves every option clear of the launcher
   at full scroll, so the padding bought nothing. word-buddy.js still pads the
   body while the sheet is open, which is the case that genuinely needs it. */

#wb-launcher .wb-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: #ffc107;
  flex: 0 0 auto;
  align-self: center;
}

/* Two lines: the invitation, then what Buddy actually is. The subtitle is what
   tells a first-time visitor this guides ColWords rather than replacing it. */
.wb-launcher-text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1px;
  min-width: 0;
}

.wb-launcher-text strong {
  font-size: 15.5px;
  font-weight: 700;
  line-height: 1.2;
}

.wb-launcher-text small {
  font-size: 11.5px;
  font-weight: 500;
  line-height: 1.2;
  opacity: .85;
}

/* --- Panel --------------------------------------------------------------- */

/* Opens from the same corner as the launcher it replaces, so the panel appears
   where the learner just clicked rather than jumping across the screen. */
#wb-panel {
  position: fixed;
  left: 16px;
  bottom: 16px;
  z-index: var(--wb-z);
  display: flex;
  flex-direction: column;
  width: 380px;
  max-width: calc(100vw - 32px);
  max-height: min(70vh, 560px);
  background: var(--wb-bg);
  border: 1px solid var(--wb-line);
  border-radius: 14px;
  box-shadow: 0 10px 40px rgba(0, 0, 0, .28);
  overflow: hidden;
  font-size: 14px;
  color: var(--wb-ink);
}

#wb-panel[hidden] { display: none; }

#wb-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  background: var(--wb-purple);
  color: #fff;
  flex: 0 0 auto;
}

#wb-head strong { font-size: 15px; }

#wb-head .wb-sub {
  font-size: 11px;
  opacity: .85;
  font-weight: 400;
}

#wb-close {
  margin-left: auto;
  border: none;
  background: transparent;
  color: #fff;
  font-size: 22px;
  line-height: 1;
  padding: 0 4px;
  cursor: pointer;
}

#wb-close:focus-visible { outline: 2px solid #ffc107; }

#wb-settings-toggle {
  margin-left: auto;
  border: none;
  background: transparent;
  color: #fff;
  font-size: 17px;
  line-height: 1;
  padding: 0 4px;
  cursor: pointer;
  opacity: .85;
}

#wb-settings-toggle:hover { opacity: 1; }
#wb-settings-toggle:focus-visible { outline: 2px solid #ffc107; }

/* #wb-close keeps its own margin only when the gear is absent. */
#wb-settings-toggle + #wb-close { margin-left: 0; }

/* --- Voice ---------------------------------------------------------------- *
 *
 * The status bar is the consent surface: while the microphone is live it is
 * visible and animated, so a learner can never be recorded without seeing it.
 */

#wb-listen {
  border: none;
  background: transparent;
  color: #fff;
  font-size: 15px;
  line-height: 1;
  padding: 0 4px;
  cursor: pointer;
  opacity: .55;
}

#wb-listen.wb-on { opacity: 1; }
#wb-listen:hover { opacity: 1; }
#wb-listen:focus-visible { outline: 2px solid #ffc107; }
#wb-listen[hidden] { display: none; }

#wb-talk,
#wb-mic {
  flex: 0 0 auto;
  border: 1px solid var(--wb-line);
  border-radius: 999px;
  background: #fff;
  font-size: 15px;
  line-height: 1;
  padding: 8px 11px;
  cursor: pointer;
}

#wb-talk:hover,
#wb-mic:hover { border-color: var(--wb-purple); }
#wb-talk:focus-visible,
#wb-mic:focus-visible { outline: 2px solid var(--wb-purple); outline-offset: 1px; }
#wb-talk[hidden],
#wb-mic[hidden] { display: none; }

#wb-mic.wb-mic-live {
  background: #e8323c;
  border-color: #e8323c;
}

/* A live conversation is a state the learner should never be unsure about. */
#wb-talk.wb-on {
  background: var(--wb-purple);
  border-color: var(--wb-purple);
}

#wb-voice-state {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 12px;
  background: #efe9f7;
  border-bottom: 1px solid var(--wb-line);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--wb-purple-dark);
  flex: 0 0 auto;
}

#wb-voice-state[hidden] { display: none; }
#wb-voice-state.wb-voice-error { background: #fff6d9; color: #6b5300; font-weight: 500; }
#wb-voice-state.wb-voice-listening { background: #fdeaec; color: #96222a; }

#wb-voice-label { flex: 1 1 auto; }

#wb-voice-stop {
  flex: 0 0 auto;
  border: 1px solid currentColor;
  border-radius: 999px;
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: 11.5px;
  padding: 3px 10px;
  cursor: pointer;
}

#wb-voice-stop[hidden] { display: none; }

/* Five bars that only move while the microphone is actually open. */
#wb-voice-wave {
  display: none;
  align-items: flex-end;
  gap: 2px;
  height: 14px;
  flex: 0 0 auto;
}

#wb-voice-wave i {
  display: block;
  width: 3px;
  height: 4px;
  border-radius: 2px;
  background: currentColor;
}

.wb-voice-listening #wb-voice-wave,
.wb-voice-speaking #wb-voice-wave { display: flex; }

@media (prefers-reduced-motion: no-preference) {
  .wb-voice-listening #wb-voice-wave i,
  .wb-voice-speaking #wb-voice-wave i {
    animation: wb-wave .9s ease-in-out infinite;
  }

  #wb-voice-wave i:nth-child(2) { animation-delay: .12s; }
  #wb-voice-wave i:nth-child(3) { animation-delay: .24s; }
  #wb-voice-wave i:nth-child(4) { animation-delay: .36s; }
  #wb-voice-wave i:nth-child(5) { animation-delay: .48s; }

  @keyframes wb-wave {
    0%, 100% { height: 4px; }
    50%      { height: 14px; }
  }
}

/* --- Practice settings --------------------------------------------------- */

#wb-settings {
  flex: 0 0 auto;
  padding: 10px 12px;
  background: #efe9f7;
  border-bottom: 1px solid var(--wb-line);
  font-size: 12.5px;
}

#wb-settings[hidden] { display: none; }

#wb-settings label {
  display: block;
  margin-bottom: 3px;
  font-weight: 700;
  color: var(--wb-purple-dark);
}

#wb-settings select {
  width: 100%;
  margin-bottom: 9px;
  padding: 6px 8px;
  border: 1px solid var(--wb-line);
  border-radius: 7px;
  background: #fff;
  font-size: 13px;
  font-family: inherit;
  color: var(--wb-ink);
}

#wb-settings select:focus { outline: none; border-color: var(--wb-purple); }

#wb-settings-note {
  margin: 0;
  font-size: 11.5px;
  color: var(--wb-muted);
}

/* --- A marked sentence --------------------------------------------------- */

.wb-mark {
  border-left: 3px solid #d4a72c;
}

.wb-mark.wb-mark-pass { border-left-color: #2e9e5b; }

.wb-score {
  margin-bottom: 5px;
  font-weight: 700;
  color: #8a6d00;
}

.wb-mark-pass .wb-score { color: #1f7a44; }

.wb-improved {
  margin: 7px 0 0;
  padding: 7px 9px;
  background: var(--wb-surface);
  border-radius: 8px;
  font-style: italic;
}

/* A practice invitation arrived while the panel was shut. */
#wb-launcher.wb-nudge .wb-dot {
  background: #fff;
  box-shadow: 0 0 0 3px rgba(255, 193, 7, .55);
}

#wb-log {
  flex: 1 1 auto;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 12px;
  background: var(--wb-surface);
}

/* --- Messages ------------------------------------------------------------ */

.wb-msg {
  max-width: 88%;
  margin-bottom: 10px;
  padding: 9px 12px;
  border-radius: 12px;
  line-height: 1.45;
  word-wrap: break-word;
  overflow-wrap: anywhere;
}

.wb-msg p { margin: 0 0 .5em; }
.wb-msg p:last-child { margin-bottom: 0; }
.wb-msg ul { margin: .35em 0 0; padding-left: 1.15em; }
.wb-msg li { margin-bottom: .2em; }

.wb-buddy {
  background: #fff;
  border: 1px solid var(--wb-line);
  border-bottom-left-radius: 4px;
}

.wb-learner {
  margin-left: auto;
  background: var(--wb-purple);
  color: #fff;
  border-bottom-right-radius: 4px;
}

.wb-note {
  max-width: 100%;
  margin-bottom: 10px;
  padding: 8px 10px;
  border-radius: 8px;
  background: #fff6d9;
  border: 1px solid #ffe08a;
  color: #6b5300;
  font-size: 12.5px;
}

.wb-typing { color: var(--wb-muted); font-style: italic; }

/* --- Suggestions and chips ----------------------------------------------- */

#wb-suggest, #wb-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 0 12px 8px;
  flex: 0 0 auto;
  background: var(--wb-surface);
}

#wb-suggest:empty, #wb-chips:empty { display: none; }

.wb-chip, .wb-go {
  border: 1px solid var(--wb-purple);
  border-radius: 999px;
  padding: 5px 11px;
  font-size: 12.5px;
  line-height: 1.2;
  cursor: pointer;
  text-decoration: none;
}

.wb-chip { background: #fff; color: var(--wb-purple); }
.wb-chip:hover { background: #efe9f7; }

.wb-go { background: var(--wb-purple); color: #fff; font-weight: 600; }
.wb-go:hover { background: var(--wb-purple-dark); color: #fff; }

/* --- Composer ------------------------------------------------------------ */

#wb-form {
  display: flex;
  gap: 8px;
  padding: 10px 12px;
  border-top: 1px solid var(--wb-line);
  background: #fff;
  flex: 0 0 auto;
}

#wb-input {
  flex: 1 1 auto;
  min-width: 0;
  border: 1px solid var(--wb-line);
  border-radius: 999px;
  padding: 8px 13px;
  font-size: 14px;
  font-family: inherit;
  resize: none;
  max-height: 84px;
}

#wb-input:focus { outline: none; border-color: var(--wb-purple); }
#wb-input:disabled { background: #f1f1f1; }

#wb-send {
  flex: 0 0 auto;
  border: none;
  border-radius: 999px;
  padding: 8px 16px;
  background: var(--wb-purple);
  color: #fff;
  font-weight: 700;
  font-size: 14px;
  cursor: pointer;
}

#wb-send:disabled { background: #b6a8ce; cursor: default; }

/* --- Phone: a bottom sheet, deliberately not a modal --------------------- *
 *
 * No backdrop, no focus trap, no body scroll lock — so the page underneath
 * keeps scrolling and every quiz answer can still be scrolled above the sheet
 * and tapped. word-buddy.js pads the body by the sheet's height to guarantee
 * the last option can clear it.
 */

@media (max-width: 767.98px) {
  #wb-panel {
    right: 0;
    left: 0;
    bottom: 0;
    width: auto;
    max-width: none;
    border-radius: 14px 14px 0 0;
    border-left: none;
    border-right: none;
    border-bottom: none;
    max-height: 60vh;
  }

  /* Smaller again during a quiz: the answers matter more than the chat. */
  body.wb-quiz #wb-panel { max-height: min(45vh, 300px); }

  /* The label is long, so on a phone it is allowed to run to two lines rather
     than being truncated or pushed off-screen. */
  #wb-launcher {
    left: 12px;
    bottom: 12px;
    max-width: calc(100vw - 24px);
    padding: 10px 16px 10px 13px;
    font-size: 14px;
  }

  .wb-launcher-text strong { font-size: 14px; }
  .wb-launcher-text small  { font-size: 11px; }
}

@media (prefers-reduced-motion: no-preference) {
  #wb-panel { animation: wb-rise .16s ease-out; }
  @keyframes wb-rise {
    from { transform: translateY(8px); opacity: 0; }
    to   { transform: translateY(0);   opacity: 1; }
  }
}

/* --- Light sweep --------------------------------------------------------- *
 *
 * A slow diagonal reflection that slides across a surface. Drop .wb-shine on
 * any element that has its own background; it is purely additive and never
 * touches the host's colour, padding, radius, or hover/focus/active states.
 *
 * Tunable per element — override any of these on the host:
 *
 *   --wb-shine-sweep     how long one pass takes                    (1s)
 *   --wb-shine-rest      the quiet between passes                   (9s)
 *   --wb-shine-width     band width, as a share of the host's width (56%)
 *   --wb-shine-opacity   peak brightness at the band's centre       (.22)
 *   --wb-shine-tint      the light's colour, as "r, g, b"           (lavender)
 *   --wb-shine-skew      lean off vertical; positive tilts the top
 *                        edge to the right                          (19deg)
 *
 * e.g.  <button class="wb-shine" style="--wb-shine-opacity:.12">
 *
 * A quick pass followed by a long quiet reads as glass catching the light. A
 * slow or frequent one reads as a notification demanding to be dealt with —
 * which is the opposite of the point.
 */
.wb-shine {
  --wb-shine-sweep: 1s;
  --wb-shine-rest: 9s;
  --wb-shine-width: 56%;
  --wb-shine-opacity: .22;
  --wb-shine-tint: 240, 234, 255;
  --wb-shine-skew: 19deg;

  position: relative;
  overflow: hidden;   /* clips the band to the host's own border-radius */
  isolation: isolate; /* keeps the band's negative stack level inside the host */
}

.wb-shine::after {
  content: "";
  position: absolute;
  left: 0;
  /* Taller than the host so the skewed ends still cover the full height. */
  top: -50%;
  bottom: -50%;
  width: var(--wb-shine-width);

  /* Above the background, below the label and icon. A negative stack level
     paints over the host's own background but under its in-flow content, so
     text and icons stay crisp instead of washing out. This is why the host
     needs `isolation: isolate` — without it the band would slide behind. */
  z-index: -1;
  pointer-events: none;

  /* Feathered to fully transparent at both edges: no hard lines anywhere. The
     tint is a lavender-white rather than pure white, so over the purple it
     reads as reflected light rather than a grey wash. */
  background: linear-gradient(
    90deg,
    rgba(var(--wb-shine-tint), 0) 0%,
    rgba(var(--wb-shine-tint), calc(var(--wb-shine-opacity) * .45)) 30%,
    rgba(var(--wb-shine-tint), var(--wb-shine-opacity)) 50%,
    rgba(var(--wb-shine-tint), calc(var(--wb-shine-opacity) * .45)) 70%,
    rgba(var(--wb-shine-tint), 0) 100%
  );

  transform: translateX(-150%) skewX(calc(-1 * var(--wb-shine-skew)));
  animation: wb-shine-sweep calc(var(--wb-shine-sweep) + var(--wb-shine-rest)) ease-in-out infinite;
}

/* Transform only — no left, no background-position — so the band is composited
   on the GPU and never triggers layout or paint.

   The 10% split is a literal because CSS cannot compute keyframe offsets from a
   custom property. It is the 1s sweep of the default 10s loop; if you change the
   sweep-to-rest ratio, change this number to match. */
@keyframes wb-shine-sweep {
  0%   { transform: translateX(-150%) skewX(calc(-1 * var(--wb-shine-skew))); }
  10%  { transform: translateX(250%)  skewX(calc(-1 * var(--wb-shine-skew))); }
  100% { transform: translateX(250%)  skewX(calc(-1 * var(--wb-shine-skew))); }
}

/* Nothing to shine for while the learner is already talking to Buddy. Pausing
   rather than hiding means the compositor stops doing the work too. */
body.wb-open .wb-shine::after { animation-play-state: paused; }

/* One deliberate sweep, on demand. Removing this class restarts the idle
   animation from 0%, and its sweep is at the very start of the cycle — so the
   restart *is* the single pass, with the usual quiet after it. That avoids the
   double flash you get from layering a separate one-shot animation on top. */
.wb-shine.wb-shine-reset::after { animation: none; }

@media (prefers-reduced-motion: reduce) {
  .wb-shine::after { display: none; }
}
