/* _core/_css/theme-quest.css
   The kraft "carnet / passport" skin — warm paper, airmail accents. Applied by
   adding class "wq-mode-quest". Also carries the look of Quest-only widgets;
   each widget's structure lives in its JS module, its skin lives here. */

.wq-mode-quest {
  --wq-paper:      #f6ecd8;
  --wq-paper-dark: #ecdcbb;
  --wq-line:       #d8c69f;
  --wq-ink:        #3b2f22;
  --wq-ink-soft:   #6b5a44;
  --wq-red:        #c94f4f;
  --wq-blue:       #3d6e8c;
  --wq-green:      #5c8a67;
  --wq-gold:       #d69a3c;
  --wq-pink:       #d98a9c;
  --wq-font:       'Trebuchet MS', 'Segoe UI', sans-serif;

  background: var(--wq-paper);
  color: var(--wq-ink);
  font-family: var(--wq-font);
}

/* ---------- Paper plane widget ---------- */
.wq-pp-sky {
  border-radius: 12px; overflow: hidden;
  border: 1px solid var(--wq-line, #d8c69f);
  background: linear-gradient(180deg, #eaf3fb, #f6ecd8);
  touch-action: pinch-zoom; user-select: none;
}
.wq-pp-phrase {
  position: absolute; top: 8px; left: 10px;
  font-family: ui-monospace, 'Courier New', monospace;
  font-size: .6rem; letter-spacing: .05em; color: var(--wq-ink-soft, #6b5a44);
}
.wq-pp-plane {
  position: absolute; left: 8%; top: 50%;
  transform: translate(-50%, -50%) rotate(8deg);
  font-size: 2rem; line-height: 1; cursor: grab;
  transition: left .5s cubic-bezier(.34,1.4,.5,1), top .5s cubic-bezier(.34,1.4,.5,1);
}
.wq-pp-plane.grab { cursor: grabbing; transition: none; }
.wq-pp-plane.done { cursor: default; }
.wq-pp-target {
  position: absolute; right: 7%; top: 50%; transform: translate(50%, -50%);
  width: 64px; height: 64px; border-radius: 50%;
  border: 3px dashed var(--wq-red, #c94f4f);
  display: grid; place-items: center; text-align: center;
  color: var(--wq-red, #c94f4f);
  font-family: var(--wq-font, sans-serif); font-weight: 800; font-size: .62rem;
  background: rgba(201, 79, 79, .05);
  transition: transform .3s, background .3s, border-color .3s, color .3s;
}
.wq-pp-target.lit {
  border-color: var(--wq-green, #5c8a67); color: var(--wq-green, #5c8a67);
  background: rgba(92, 138, 103, .14);
  transform: translate(50%, -50%) scale(1.08);
}
.wq-pp-stamp {
  position: absolute; right: 7%; top: 50%;
  transform: translate(50%, -50%) rotate(-13deg) scale(.4); opacity: 0;
  width: 74px; height: 74px; border-radius: 50%;
  border: 3px solid var(--wq-green, #5c8a67); color: var(--wq-green, #5c8a67);
  display: grid; place-items: center; text-align: center;
  font-family: var(--wq-font, sans-serif); font-weight: 800; font-size: .55rem; line-height: 1.15;
  background: rgba(255, 253, 246, .85);
  transition: transform .45s cubic-bezier(.2,1.5,.4,1), opacity .3s;
}
.wq-pp-stamp.show { opacity: 1; transform: translate(50%, -50%) rotate(-13deg) scale(1); }
.wq-pp-particle {
  position: absolute; pointer-events: none; font-size: 1rem; z-index: 6;
  animation: wqPfly .9s ease-out forwards;
}
@keyframes wqPfly { to { transform: translate(var(--dx), var(--dy)) rotate(300deg); opacity: 0; } }

@media (prefers-reduced-motion: reduce) {
  .wq-pp-plane, .wq-pp-stamp { transition: none; }
  .wq-pp-particle { display: none; }
}

/* Generic "authoring" treatment: shows a widget's real player markup in the
   editor (true WYSIWYG) with a non-intrusive outline so it's still obviously
   a movable/selectable authoring zone. outline doesn't affect box size. */
.wq-editor-preview {
  outline: 2px dashed var(--wq-line, #d8c69f); outline-offset: 2px;
  cursor: move; user-select: none;
}
.wq-editor-preview > *:not(.wq-resize-handle) { pointer-events: none; }

/* ---------- Fill-the-gap widget (quest-input.js) ---------- */
.wq-quest-input { display: flex; }
.wq-qi-field {
  width: 100%; height: 100%; border: 2px solid var(--wq-line, #d8c69f); border-radius: 8px;
  background: #fffdf6; font-family: var(--wq-font, sans-serif); font-size: 1rem;
  color: var(--wq-ink, #3b2f22); text-align: center; padding: 0 6px; outline: none;
}
.wq-qi-field:focus { border-color: var(--wq-blue, #3d6e8c); }
.wq-qi-field.is-correct { border-color: var(--wq-green, #5c8a67); background: rgba(92,138,103,.12); color: var(--wq-green, #5c8a67); }
.wq-qi-field.is-wrong { border-color: var(--wq-red, #c94f4f); background: rgba(201,79,79,.12); color: var(--wq-red, #c94f4f); }

/* ---------- Multi-choice widget (quest-choice.js) ---------- */
.wq-quest-choice { display: flex; flex-wrap: wrap; align-content: flex-start; gap: 6px; }
.wq-qc-opt {
  font-family: var(--wq-font, sans-serif); font-weight: 700; font-size: .82rem;
  background: var(--wq-gold, #d69a3c); color: #fffdf6; border: none; border-radius: 999px;
  padding: .45rem .9rem; cursor: pointer; box-shadow: 0 4px 8px -3px rgba(0,0,0,.35);
}
.wq-qc-opt:disabled { cursor: default; opacity: .85; }
.wq-qc-opt.is-correct { background: var(--wq-green, #5c8a67); }
.wq-qc-opt.is-wrong { background: var(--wq-red, #c94f4f); }

/* ---------- Circle-word widget (quest-select-text.js) ---------- */
.wq-quest-select.wq-shape-rect { border-radius: 8px; }
.wq-quest-select {
  border: 3px solid transparent; border-radius: 999px; cursor: pointer;
  transition: border-color .15s, background .15s;
}
.wq-quest-select:hover { border-color: var(--wq-pink, #d98a9c); }
.wq-quest-select.locked { cursor: default; }
.wq-quest-select.is-correct { border-color: var(--wq-green, #5c8a67); background: rgba(92,138,103,.16); }
.wq-quest-select.is-wrong { border-color: var(--wq-red, #c94f4f); background: rgba(201,79,79,.16); }
/* Editor-only: distinguish which zones are the right answer while authoring
   (the player's own zone is intentionally invisible until picked). */
.wq-quest-select.wq-author-correct { border-color: var(--wq-green, #5c8a67); background: rgba(92,138,103,.08); }
.wq-quest-select.wq-author-distractor { border-color: var(--wq-line, #d8c69f); }

/* ---------- Connect-the-dots widget (quest-silk-dot.js + silk-engine.js) ---------- */
/* shape (border-radius/transform), color, and outline (border) are all set
   inline per-instance by applyDotStyle() in quest-silk-dot.js — true WYSIWYG. */
.wq-quest-dot { aspect-ratio: 1 / 1; box-shadow: 0 2px 6px rgba(0,0,0,.3); cursor: grab; touch-action: pinch-zoom; }
.wq-quest-dot.is-correct { outline: 3px solid var(--wq-green, #5c8a67); }
.wq-quest-dot.is-wrong { outline: 3px solid var(--wq-red, #c94f4f); }
.wq-quest-dot.is-locked { cursor: not-allowed; }
.wq-quest-dot.is-locked-grey { cursor: not-allowed; filter: grayscale(1); outline-color: #9a9488 !important; }

/* Same "locked/done" language reused by choice-style widgets (True/False,
   multi-choice) via quest-feedback.js's wireSingleChoice(). */
.choice-opt.is-locked { cursor: not-allowed; }
.choice-opt.is-locked-grey .sck-img { filter: grayscale(1); }
.wq-choice-lock-badge {
  position: absolute; top: -7px; right: -7px; pointer-events: none;
}
.wq-choice-lock-badge::after {
  content: '✓'; position: absolute; top: 0; left: 0;
  width: 18px; height: 18px; border-radius: 50%; background: var(--wq-green, #5c8a67);
  color: #fff; font-size: 12px; font-weight: 800; line-height: 18px; text-align: center;
  box-shadow: 0 1px 3px rgba(0,0,0,.4), 0 0 0 2px #fffdf6;
}

/* Discreet review dot — independent of lock/grey/clickable style, opt-in via
   resultIcon config. Sits opposite corner from the lock badge so both can
   coexist without overlapping. */
.wq-choice-result-badge { position: absolute; top: -6px; left: -6px; pointer-events: none; }
.wq-choice-result-badge::after {
  content: ''; position: absolute; top: 0; left: 0;
  width: 13px; height: 13px; border-radius: 50%;
  box-shadow: 0 1px 2px rgba(0,0,0,.35), 0 0 0 2px #fffdf6;
}
.wq-choice-result-badge.is-ok::after { background: var(--wq-green, #5c8a67); }
.wq-choice-result-badge.is-bad::after { background: var(--wq-red, #c94f4f); }
.wq-silk-lock-badge {
  position: absolute; pointer-events: none; z-index: 4;
}
.wq-silk-lock-badge::after {
  content: '✓'; position: absolute; top: 50%; left: 50%;
  width: 18px; height: 18px; margin: -9px 0 0 -9px;
  border-radius: 50%; background: var(--wq-green, #5c8a67);
  color: #fff; font-size: 12px; font-weight: 800; line-height: 18px; text-align: center;
  box-shadow: 0 1px 3px rgba(0,0,0,.4), 0 0 0 2px #fffdf6;
}
.wq-silk-result-badge { position: absolute; pointer-events: none; z-index: 4; }
.wq-silk-result-badge::after {
  content: ''; position: absolute; top: -6px; left: -6px;
  width: 13px; height: 13px; border-radius: 50%;
  box-shadow: 0 1px 2px rgba(0,0,0,.35), 0 0 0 2px #fffdf6;
}
.wq-silk-result-badge.is-ok::after { background: var(--wq-green, #5c8a67); }
.wq-silk-result-badge.is-bad::after { background: var(--wq-red, #c94f4f); }
.wq-silk-canvas { z-index: 3; }

/* ---------- Icon button widget (quest-icon-button.js) ---------- */
.wq-icon-btn-edit, .wq-icon-btn-play {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  background: #fffdf6; border: 1px solid var(--wq-line, #d8c69f); border-radius: 14px;
  padding: 6px 4px; box-shadow: 0 8px 16px -12px rgba(59,47,34,.4);
  font-family: var(--wq-font, sans-serif);
}
.wq-icon-btn-edit { cursor: move; user-select: none; }
.wq-icon-btn-play {
  cursor: pointer; transition: transform .18s cubic-bezier(.34,1.56,.64,1), box-shadow .18s ease;
}
.wq-icon-btn-play:hover { transform: translateY(-3px) scale(1.03); box-shadow: 0 14px 22px -12px rgba(59,47,34,.5); }
.wq-icon-btn-play:active { transform: translateY(-1px) scale(.98); }
.wq-icon-btn-play:disabled { cursor: default; }
.wq-icon-btn-ic {
  width: 34%; aspect-ratio: 1 / 1; min-width: 22px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 1.3rem; color: #fffdf6; box-shadow: inset 0 -4px 0 rgba(0,0,0,.12);
  flex: 0 0 auto;
}
.wq-icon-btn-lbl { font-weight: 700; font-size: .7rem; text-align: center; color: var(--wq-ink, #3b2f22); line-height: 1.2; }
.wq-icon-btn-tag { font-size: .5rem; letter-spacing: .4px; color: var(--wq-ink-soft, #6b5a44); text-transform: uppercase; }
.wq-icon-btn-play.is-correct { border-color: var(--wq-green, #5c8a67); box-shadow: 0 0 0 3px rgba(92,138,103,.25); }
.wq-icon-btn-play.is-wrong { border-color: var(--wq-red, #c94f4f); box-shadow: 0 0 0 3px rgba(201,79,79,.25); }

/* ---------- Button widget (quest-button.js) ----------
   Design is entirely CSS custom properties, set inline per instance by
   buildButtonNode() in the JS file — shape/animation/hover-fx logic lives
   here once, not duplicated between editor and player render paths. */
.wq-btn-play {
  width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; gap: .5em;
  cursor: pointer; user-select: none; box-sizing: border-box; text-align: center;
  appearance: none; -webkit-appearance: none; outline: none;
  background: var(--btn-bg, #6366f1); color: var(--btn-fg, #fff);
  font-family: var(--btn-font-family, inherit); font-weight: var(--btn-font-weight, 800);
  font-size: calc(1rem * var(--btn-font-scale, 1));
  border-width: var(--btn-border-w, 0); border-style: var(--btn-border-style, solid); border-color: var(--btn-border-color, #fff);
  padding: var(--btn-pad-y, .6em) var(--btn-pad-x, 1.1em);
  transition: transform .15s cubic-bezier(.34,1.56,.64,1), box-shadow .15s ease, filter .15s ease;
  box-shadow: 0 8px 18px -10px rgba(0,0,0,.4);
}
.wq-btn-play:active { transform: scale(.96); }
.wq-btn-play:disabled { cursor: default; }
.wq-btn-play.is-correct { outline: 3px solid var(--wq-green, #5c8a67); outline-offset: 2px; }
.wq-btn-play.is-wrong { outline: 3px solid var(--wq-red, #c94f4f); outline-offset: 2px; }
.wq-btn-play.wq-btn-glow { box-shadow: 0 0 16px var(--btn-glow-color, #fff), 0 8px 18px -10px rgba(0,0,0,.4); }
.wq-btn-play.wq-btn-bg-none { box-shadow: none; }
.wq-btn-play.wq-btn-bg-none.wq-btn-glow { box-shadow: 0 0 16px var(--btn-glow-color, #fff); }

/* Shape */
.wq-btn-shape-rounded { border-radius: var(--btn-radius-custom, 14px); }
.wq-btn-shape-pill { border-radius: 999px; }
.wq-btn-shape-square { border-radius: 0; }
.wq-btn-shape-circle { border-radius: 50%; aspect-ratio: 1 / 1; padding: 0; }

/* Content layout: icon/image + label, position-aware */
.wq-btn-media { display: inline-flex; align-items: center; justify-content: center; font-size: 1.15em; line-height: 1; flex: 0 0 auto; }
.wq-btn-media img { width: 1.6em; height: 1.6em; object-fit: contain; display: block; }
.wq-btn-lbl { line-height: 1.2; }
.wq-btn-content-left { flex-direction: row; }
.wq-btn-content-right { flex-direction: row-reverse; }
.wq-btn-content-top { flex-direction: column; }
.wq-btn-icon-only .wq-btn-media { font-size: 1.5em; }

/* Image content mode: the picked image IS the button, filling the whole
   interior instead of sitting as a small 1.6em glyph beside label text —
   Style/Border/shape still apply around it as an optional frame. */
.wq-btn-image-mode .wq-btn-media { width: 100%; height: 100%; flex: 1 1 auto; }
.wq-btn-image-mode .wq-btn-media img { width: 100%; height: 100%; object-fit: contain; }

/* Idle animation presets — intensity read from --btn-anim-* vars set inline */
@keyframes wqBtnFloat { 50% { transform: translateY(calc(-1 * var(--btn-anim-float, 8px))); } }
@keyframes wqBtnPulse { 50% { transform: scale(calc(1 + var(--btn-anim-pulse, 0.06))); } }
@keyframes wqBtnFade { 50% { opacity: var(--btn-anim-fade, 0.6); } }
.wq-btn-anim-float { animation: wqBtnFloat 2.2s ease-in-out infinite; }
.wq-btn-anim-pulse { animation: wqBtnPulse 1.5s ease-in-out infinite; }
.wq-btn-anim-fadeInOut { animation: wqBtnFade 2s ease-in-out infinite; }

/* Hover FX */
.wq-btn-hover-lift:hover { transform: translateY(-4px); box-shadow: 0 14px 24px -10px rgba(0,0,0,.45); }
.wq-btn-hover-scale:hover { transform: scale(1.07); }
.wq-btn-hover-glow:hover { box-shadow: 0 0 0 4px var(--btn-glow-color, rgba(255,255,255,.4)), 0 0 20px var(--btn-glow-color, rgba(255,255,255,.5)); }
.wq-btn-hover-colorShift:hover { filter: brightness(1.15) saturate(1.2); }
/* Transparent background: the "lift" box-shadow drew a visible rectangle
   behind a transparent PNG on hover (the shadow follows the element's own
   box, not the image's alpha shape) — drop it for a fond:none button, keep
   just the movement. "Grossit"/"Éclaircit" don't add a shadow, unaffected;
   "Lueur" keeps its glow since that's its whole point. */
.wq-btn-play.wq-btn-bg-none.wq-btn-hover-lift:hover { box-shadow: none; }

@media (prefers-reduced-motion: reduce) {
  .wq-btn-anim-float, .wq-btn-anim-pulse, .wq-btn-anim-fadeInOut { animation: none; }
  .wq-btn-hover-lift:hover, .wq-btn-hover-scale:hover { transform: none; }
}

/* ---------- Shape overlay widget (quest-shape.js) ----------
   Click-through by default (pointer-events set inline per instance by
   buildShapeNode()) — this is meant to sit ON TOP of other elements as a
   highlight ring without blocking clicks to whatever's underneath. */
.wq-shape {
  width: 100%; height: 100%; box-sizing: border-box; display: block;
  background: var(--shape-fill, transparent);
  border-width: var(--shape-border-w, 3px); border-style: var(--shape-border-style, solid); border-color: var(--shape-border-color, #6366f1);
  border-radius: var(--shape-radius, 12px);
  padding: 0; margin: 0; cursor: default;
}
.wq-shape-interactive { cursor: pointer; }
.wq-shape-interactive.is-correct { outline: 3px solid var(--wq-green, #5c8a67); outline-offset: 2px; }
.wq-shape-interactive.is-wrong { outline: 3px solid var(--wq-red, #c94f4f); outline-offset: 2px; }
.wq-shape-circle { border-radius: 50%; aspect-ratio: 1 / 1; }
.wq-shape-square { aspect-ratio: 1 / 1; }

@keyframes wqShapeFloat { 50% { transform: translateY(calc(-1 * var(--shape-anim-float, 8px))); } }
@keyframes wqShapePulse { 50% { transform: scale(calc(1 + var(--shape-anim-pulse, 0.06))); } }
@keyframes wqShapeFade { 50% { opacity: var(--shape-anim-fade, 0.6); } }
@keyframes wqShapeRingPulse {
  0% { box-shadow: 0 0 0 0 var(--shape-ring-color, #6366f1); opacity: 1; }
  100% { box-shadow: 0 0 0 16px transparent; opacity: 0; }
}
.wq-shape-anim-float { animation: wqShapeFloat 2.2s ease-in-out infinite; }
.wq-shape-anim-pulse { animation: wqShapePulse 1.5s ease-in-out infinite; }
.wq-shape-anim-fadeInOut { animation: wqShapeFade 2s ease-in-out infinite; }
.wq-shape-anim-ringPulse { position: relative; }
.wq-shape-anim-ringPulse::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit;
  animation: wqShapeRingPulse 1.8s ease-out infinite;
  pointer-events: none;
}

/* Outline-specific animation — orthogonal to the whole-shape motion above
   (that one moves/scales/fades the whole box; this one only animates the
   border treatment), so both can run at once without clashing. Uses ::before
   (ringPulse above already claims ::after) so the two layers never collide. */
.wq-shape-outline-marchingAnts { border-style: none; position: relative; }
.wq-shape-ants-svg { display: block; }
.wq-shape-ants-line { stroke-dasharray: 10 6; animation: wqShapeAntsMarch var(--shape-outline-dur, .5s) linear infinite; }
@keyframes wqShapeAntsMarch { to { stroke-dashoffset: -16; } }

.wq-shape-outline-glowPulse { animation: wqShapeGlowPulse 1.6s ease-in-out infinite; }
@keyframes wqShapeGlowPulse {
  0%, 100% { box-shadow: 0 0 0 0 transparent; }
  50% { box-shadow: 0 0 var(--shape-glow-blur, 14px) var(--shape-glow-spread, 3px) var(--shape-border-color, #6366f1); }
}

.wq-shape-outline-colorCycle { animation: wqShapeColorCycle var(--shape-outline-dur, 3s) linear infinite; }
@keyframes wqShapeColorCycle { to { filter: hue-rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .wq-shape-anim-float, .wq-shape-anim-pulse, .wq-shape-anim-fadeInOut { animation: none; }
  .wq-shape-anim-ringPulse::after { animation: none; content: none; }
  .wq-shape-ants-line { animation: none; stroke-dasharray: none; }
  .wq-shape-outline-glowPulse, .wq-shape-outline-colorCycle { animation: none; }
}

/* ---------- Drag / drop widget (quest-drag-drop.js) ---------- */
.wq-quest-drag-edit, .wq-quest-drop-edit {
  border: 2px dashed var(--wq-green, #5c8a67); border-radius: 10px;
  background: rgba(92,138,103,.06); cursor: move;
  display: flex; align-items: center; justify-content: center;
  font-size: 1.4rem; color: var(--wq-ink-soft, #6b5a44);
}
.wq-quest-drop-edit { border-style: dotted; background: rgba(92,138,103,.03); }
.wq-quest-drag {
  cursor: grab; touch-action: pinch-zoom; display: flex; align-items: center; justify-content: center;
  font-size: 1.6rem; border-radius: 8px; transition: box-shadow .15s;
  z-index: 5;
}
.wq-quest-drag.dragging { cursor: grabbing; z-index: 50; box-shadow: 0 10px 20px -8px rgba(0,0,0,.4); transition: none; }
.wq-quest-drag.is-correct { box-shadow: 0 0 0 3px var(--wq-green, #5c8a67); }
.wq-quest-drag.is-wrong { box-shadow: 0 0 0 3px var(--wq-red, #c94f4f); }
.wq-quest-drag.is-locked { cursor: not-allowed; }
.wq-quest-drag.is-locked-grey { box-shadow: 0 0 0 3px #9a9488; cursor: not-allowed; filter: grayscale(1); opacity: .7; }
.wq-quest-drop {
  border: 2px dashed var(--wq-line, #d8c69f); border-radius: 10px; background: rgba(0,0,0,.03);
}
.wq-quest-drop.is-correct { border-color: var(--wq-green, #5c8a67) !important; background-color: rgba(92,138,103,.14) !important; }
.wq-quest-drop.is-wrong { border-color: var(--wq-red, #c94f4f) !important; background-color: rgba(201,79,79,.14) !important; }
.wq-quest-drop.is-locked-grey { border-color: #9a9488 !important; background-color: rgba(154,148,136,.14) !important; filter: grayscale(1); }
/* The zone that would receive the piece lights up while dragging.
   !important because SheetDDKit writes the authored look INLINE, and an
   inline style beats a plain class rule. */
.wq-quest-drop.is-hover {
  border-style: solid !important; border-color: var(--wq-green, #5c8a67) !important;
  background-color: rgba(92,138,103,.18) !important;
  box-shadow: 0 0 0 4px rgba(92,138,103,.22) !important;
}
/* "Here is where it belonged": target zone of a misplaced piece. */
.wq-quest-drop.shows-answer {
  border-style: dashed !important; border-color: var(--wq-green, #5c8a67) !important;
  box-shadow: 0 0 0 3px rgba(92,138,103,.28) !important;
}
.wq-answer-strip {
  position: absolute; left: 50%; top: 100%; transform: translateX(-50%);
  margin-top: 6px; display: flex; gap: 4px; flex-wrap: wrap;
  justify-content: center; pointer-events: none; z-index: 60;
  width: max-content; max-width: 220%;
}
.wq-answer-strip.above { top: auto; bottom: 100%; margin: 0 0 6px; }
.wq-answer-chip {
  display: inline-flex; align-items: center; gap: 5px;
  background: var(--wq-paper, #fffdf6);
  border: 1.5px solid var(--wq-green, #5c8a67); border-radius: 999px;
  padding: calc(2px * var(--ans-scale, 1)) calc(9px * var(--ans-scale, 1));
  font-size: calc(.72rem * var(--ans-scale, 1)); font-weight: 800;
  color: var(--wq-green, #5c8a67); white-space: nowrap;
  box-shadow: 0 2px 6px rgba(0,0,0,.14);
}
.wq-answer-chip img { height: calc(22px * var(--ans-scale, 1)); width: auto; border-radius: 4px; display: block; }
.wq-quest-drop { position: absolute; }

/* Tap-to-place: the picked piece pulses, and every zone advertises itself
   as a destination until one is chosen. */
.wq-quest-drag.is-picked {
  z-index: 60;
  outline: 3px dashed var(--wq-green, #5c8a67); outline-offset: 3px;
  box-shadow: 0 8px 18px rgba(92,138,103,.4) !important;
  animation: wqPickPulse 1.1s ease-in-out infinite;
}
@keyframes wqPickPulse { 0%,100% { transform: scale(1); } 50% { transform: scale(1.06); } }
.wq-quest-drop.is-drop-hint {
  cursor: pointer;
  border-color: var(--wq-green, #5c8a67) !important;
  background-color: rgba(92,138,103,.12) !important;
  box-shadow: 0 0 0 3px rgba(92,138,103,.16) !important;
}
@media (prefers-reduced-motion: reduce) { .wq-quest-drag.is-picked { animation: none; } }

/* Text pieces / zone labels (ported from Sheet mode) */
.wq-quest-drag .el-label, .wq-quest-drop .el-label,
.wq-quest-drag-edit .el-label, .wq-quest-drop-edit .el-label {
  font-size: .95rem; font-weight: 700; line-height: 1.15;
  overflow: hidden; text-overflow: ellipsis;
}
.wq-quest-drop, .wq-quest-drop-edit { display: flex; align-items: center; justify-content: center; }
/* A text piece needs a body to be draggable-looking — in Quest's own palette,
   not Sheet's. Authors who customise the look override this inline. */
.wq-quest-drag.has-label {
  background: var(--wq-paper, #fffdf6);
  border: 2px solid var(--wq-green, #5c8a67);
  border-radius: 10px;
  box-shadow: 0 2px 6px rgba(0,0,0,.12);
}

/* ---------- Decorations (quest-decorations.js) — never graded ---------- */
/* Sizing note: these roots are absolutely-positioned, so %-paddings would
   resolve against the PAGE width, not the element — which crushed the inner
   face at small sizes. container-type:size makes each deco its own size
   container, and every inner metric uses cq units, so paddings, emoji and
   captions all scale in proportion to the element itself. Identical rules in
   editor and player = true WYSIWYG. */
/* cq units resolve against the nearest ANCESTOR container, never the element
   itself — so the roots carry container-type only, and all inner boxes are
   absolutely inset in cqmin instead of padding on the root. */
.wq-deco-stamp, .wq-deco-frame { container-type: size; }

.wq-deco-stamp {
  background-image: radial-gradient(circle, transparent 60%, rgba(236,220,187,.9) 61%);
  background-size: 9px 9px;
  background-position: -4px -4px;
}
.wq-deco-stamp-face {
  position: absolute; inset: 6cqmin; box-sizing: border-box;
  border: 2px dashed rgba(59,47,34,.35); border-radius: 3px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2cqmin;
  color: #fffdf6; font-family: var(--wq-font, sans-serif); font-weight: 800;
}
.wq-deco-stamp-content { font-size: 38cqmin; line-height: 1; }
.wq-deco-stamp-cap { font-size: 9cqmin; letter-spacing: .4px; text-transform: uppercase; opacity: .9; }

.wq-deco-frame {
  background: linear-gradient(135deg, #e9d9a8, #a9803f);
  border-radius: 6px; box-shadow: 0 12px 20px -10px rgba(0,0,0,.4);
}
.wq-deco-frame-mat {
  position: absolute; inset: 5cqmin; box-sizing: border-box; background: #fdfaf2; padding: 4cqmin;
  border-radius: 2px; display: flex; flex-direction: column;
}
.wq-deco-frame-inner {
  flex: 1; min-height: 0; background: #eaf3fb; border-radius: 2px;
  display: flex; align-items: center; justify-content: center; font-size: 34cqmin;
}
.wq-deco-frame-cap {
  text-align: center; font-size: 8cqmin; color: #6b4b1f; font-weight: 700;
  font-family: var(--wq-font, sans-serif); padding-top: 2cqmin; flex: 0 0 auto;
}

.wq-deco-tape {
  border-radius: 1px;
  box-shadow: 0 2px 4px rgba(0,0,0,.15);
}

/* ---------- Pointer widget (quest-pointer.js) ---------- */
.wq-pointer {
  width: 100%; height: 100%; display: flex; align-items: center; justify-content: center;
  color: var(--ptr-color, #c94f4f); font-size: calc(3rem * var(--ptr-size, 1));
  line-height: 1;
}
@keyframes wqPointerBounce { 50% { transform: translateY(calc(-1 * var(--ptr-anim-bounce, 12px))); } }
@keyframes wqPointerPulse { 50% { transform: scale(calc(1 + var(--ptr-anim-pulse, 0.08))); } }
@keyframes wqPointerWiggle { 25% { transform: rotate(var(--ptr-anim-wiggle, 9deg)); } 75% { transform: rotate(calc(-1 * var(--ptr-anim-wiggle, 9deg))); } }
@keyframes wqPointerFloat { 50% { transform: translateY(calc(-1 * var(--ptr-anim-float, 9px))); } }
/* Ping-pong (29/08/2026 request): horizontal back-and-forth, half the
   distance each side so the resting position stays centered — matches how
   bounce/float are centered on their own axis instead of drifting. */
@keyframes wqPointerPingPong {
  0%, 100% { transform: translateX(calc(-1 * var(--ptr-anim-pingpong, 12px))); }
  50% { transform: translateX(var(--ptr-anim-pingpong, 12px)); }
}
.wq-pointer-anim-bounce { animation: wqPointerBounce .8s ease-in-out infinite; }
.wq-pointer-anim-pulse { animation: wqPointerPulse 1.4s ease-in-out infinite; }
.wq-pointer-anim-wiggle { animation: wqPointerWiggle 1.2s ease-in-out infinite; }
.wq-pointer-anim-float { animation: wqPointerFloat 2.2s ease-in-out infinite; }
.wq-pointer-anim-pingpong { animation: wqPointerPingPong 1.1s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) {
  .wq-pointer-anim-bounce, .wq-pointer-anim-pulse, .wq-pointer-anim-wiggle, .wq-pointer-anim-float, .wq-pointer-anim-pingpong { animation: none; }
}

/* ---------- Doodle — student drawing zone (sheet-doodle.js) ---------- */
.wq-doodle { touch-action: pinch-zoom; }

/* Background presets */
.wq-doodle.wq-bg-white { background: #fff; border-radius: 8px; box-shadow: inset 0 0 0 1px rgba(0,0,0,.08); }
.wq-doodle.wq-bg-note {
  background-color: #fffdf3;
  background-image: repeating-linear-gradient(180deg, transparent 0 26px, rgba(61,110,140,.28) 26px 27px);
  border-radius: 8px;
  box-shadow: inset 0 0 0 1px rgba(214,154,60,.4), 0 3px 10px -6px rgba(15,23,42,.3);
}
.wq-doodle.wq-bg-frame { border: 2px dashed rgba(61,110,140,.5); border-radius: 8px; background: transparent; }
/* Quadrillé — grille fine régulière, pour les maths posées / schémas. */
.wq-doodle.wq-bg-grid {
  background-color: #fffdf3;
  background-image:
    repeating-linear-gradient(0deg, transparent 0 24px, rgba(61,110,140,.22) 24px 25px),
    repeating-linear-gradient(90deg, transparent 0 24px, rgba(61,110,140,.22) 24px 25px);
  border-radius: 8px;
  box-shadow: inset 0 0 0 1px rgba(214,154,60,.4), 0 3px 10px -6px rgba(15,23,42,.3);
}
/* Séyès — réglure française à double ligne (interligne + ligne de base plus
   marquée), pour l'apprentissage de l'écriture. Deux répétitions superposées :
   un trait fin tous les ~8px, un trait un peu plus marqué tous les 32px. */
.wq-doodle.wq-bg-seyes {
  background-color: #fffdf3;
  background-image:
    repeating-linear-gradient(0deg, transparent 0 7px, rgba(61,110,140,.16) 7px 8px),
    repeating-linear-gradient(0deg, transparent 0 31px, rgba(61,110,140,.4) 31px 32px),
    repeating-linear-gradient(90deg, transparent 0 31px, rgba(201,79,79,.22) 31px 32px);
  border-radius: 8px;
  box-shadow: inset 0 0 0 1px rgba(214,154,60,.4), 0 3px 10px -6px rgba(15,23,42,.3);
}
.wq-doodle.wq-editor-preview { outline: 1px dashed rgba(61,110,140,.45); }
.wq-doodle.wq-editor-preview:not(.wq-bg-white):not(.wq-bg-note):not(.wq-bg-frame) { background: rgba(61,110,140,.05); }
.wq-doodle-hint {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-size: .8rem; font-weight: 700; color: rgba(61,110,140,.65); pointer-events: none; text-align: center;
}

/* Player: the wrapper never blocks the page by itself — only the canvas
   (when armed) and the toolbar receive events. Overlay mode relies on this. */
.wq-doodle-play { pointer-events: none; }
.wq-doodle-play .wq-doodle-canvas, .wq-doodle-play .wq-doodle-bar { pointer-events: auto; }

.wq-doodle-canvas { position: absolute; inset: 0; width: 100%; height: 100%; cursor: crosshair; touch-action: pinch-zoom; }
.wq-doodle-bgimg { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; border-radius: inherit; }

/* Collapsible toolbar, ancrée dans un des 4 coins (barPosition, défaut
   top-left = comportement d'avant, inchangé). Boutons agrandis (34px→52px le
   bouton ✏️, etc.) — cible tactile bien trop petite pour un doigt d'enfant à
   34px (le minimum recommandé pour un enfant est plus proche de 48-56px que
   les ~44px adultes). */
.wq-doodle-bar {
  position: absolute; display: flex; gap: 4px; align-items: center;
  background: #fff; border: 1px solid #d8dee9; border-radius: 16px; padding: 5px;
  box-shadow: 0 6px 14px rgba(15,23,42,.2); z-index: 8;
  max-width: calc(100% - 12px); flex-wrap: wrap;
}
.wq-doodle-bar.orient-vertical { flex-direction: column; max-height: calc(100% - 12px); max-width: none; }
.wq-doodle-bar.pos-top-left { top: 6px; left: 6px; }
.wq-doodle-bar.pos-top-right { top: 6px; right: 6px; }
.wq-doodle-bar.pos-bottom-left { bottom: 6px; left: 6px; }
.wq-doodle-bar.pos-bottom-right { bottom: 6px; right: 6px; }
/* Poignée de déplacement libre — un clic normal ne fait rien d'autre (le
   déplacement se fait par glisser, voir sheet-doodle.js), juste un repère
   visuel + cible tactile dédiée pour ne pas gêner les boutons voisins. */
.wq-doodle-draghandle {
  width: 26px; height: 26px; flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
  color: #94a3b8; font-size: 16px; cursor: grab; touch-action: none; user-select: none;
}
.wq-doodle-draghandle:active { cursor: grabbing; color: #3d6e8c; }
/* Groupes de boutons par fonction (couleurs | épaisseurs | actions | œil),
   séparés par un liseré fin — la barre orientée verticalement tourne le
   séparateur avec elle. */
.wq-doodle-group {
  display: inline-flex; gap: 7px; align-items: center; flex-wrap: wrap;
  padding-inline-start: 7px; border-inline-start: 1px solid #e2e8f0;
}
.wq-doodle-bar.orient-vertical .wq-doodle-group {
  padding-inline-start: 0; border-inline-start: none;
  padding-block-start: 7px; border-block-start: 1px solid #e2e8f0; flex-direction: row;
}
.wq-doodle-toggle {
  width: 52px; height: 52px; border-radius: 50%; border: none; background: #3d6e8c; color: #fff;
  font-size: 24px; cursor: pointer; display: flex; align-items: center; justify-content: center; flex: 0 0 auto;
}
.wq-doodle-toggle.active { background: #d69a3c; }
.wq-doodle-dot { width: 34px; height: 34px; border-radius: 50%; border: 2px solid transparent; cursor: pointer; padding: 0; }
.wq-doodle-dot.active { border-color: #1e293b; box-shadow: 0 0 0 2px #fff inset; }
.wq-doodle-stamp {
  width: 34px; height: 34px; border-radius: 10px; border: 2px solid transparent; background: #f1f5f9;
  cursor: pointer; font-size: 18px; display: flex; align-items: center; justify-content: center; padding: 0;
}
.wq-doodle-stamp.active { border-color: #d69a3c; background: #fff7e6; }
.wq-doodle-shape {
  width: 34px; height: 34px; border-radius: 10px; border: 2px solid transparent; background: #f1f5f9;
  cursor: pointer; font-size: 16px; display: flex; align-items: center; justify-content: center; padding: 0;
}
.wq-doodle-shape.active { border-color: #d69a3c; background: #fff7e6; }
.wq-doodle-texture {
  width: 34px; height: 34px; border-radius: 10px; border: 2px solid transparent; background: #f1f5f9;
  cursor: pointer; font-size: 16px; display: flex; align-items: center; justify-content: center; padding: 0;
}
.wq-doodle-texture.active { border-color: #3d6e8c; background: #e6f0f7; }
.wq-doodle-size {
  width: 36px; height: 36px; border-radius: 50%; background: #f1f5f9; border: 1px solid #d8dee9;
  cursor: pointer; display: flex; align-items: center; justify-content: center; padding: 0;
}
.wq-doodle-size.active { border-color: #1e293b; }
.wq-doodle-size i { border-radius: 50%; background: #1e293b; display: block; }
/* Tailles de boutons (barSize) — "large" = valeurs livrées ci-dessus
   (défaut, inchangé) ; medium/small les réduisent proportionnellement. */
.wq-doodle-bar.size-medium .wq-doodle-toggle { width: 46px; height: 46px; font-size: 21px; }
.wq-doodle-bar.size-medium .wq-doodle-dot { width: 30px; height: 30px; }
.wq-doodle-bar.size-medium .wq-doodle-size { width: 32px; height: 32px; }
.wq-doodle-bar.size-medium .wq-doodle-stamp { width: 30px; height: 30px; font-size: 16px; }
.wq-doodle-bar.size-medium .wq-doodle-shape { width: 30px; height: 30px; font-size: 14px; }
.wq-doodle-bar.size-medium .wq-doodle-texture { width: 30px; height: 30px; font-size: 14px; }
.wq-doodle-bar.size-medium .wq-doodle-btn { width: 36px; height: 36px; font-size: 16px; }
.wq-doodle-bar.size-small .wq-doodle-toggle { width: 40px; height: 40px; font-size: 18px; }
.wq-doodle-bar.size-small .wq-doodle-dot { width: 26px; height: 26px; }
.wq-doodle-bar.size-small .wq-doodle-size { width: 28px; height: 28px; }
.wq-doodle-bar.size-small .wq-doodle-stamp { width: 26px; height: 26px; font-size: 14px; }
.wq-doodle-bar.size-small .wq-doodle-shape { width: 26px; height: 26px; font-size: 12px; }
.wq-doodle-bar.size-small .wq-doodle-texture { width: 26px; height: 26px; font-size: 12px; }
.wq-doodle-bar.size-small .wq-doodle-btn { width: 32px; height: 32px; font-size: 14px; }
.wq-doodle-btn {
  border: none; background: #f1f5f9; border-radius: 10px; width: 40px; height: 40px;
  cursor: pointer; font-size: 18px; line-height: 1; display: flex; align-items: center; justify-content: center;
}
.wq-doodle-btn.active { background: #d69a3c; color: #fff; }
.wq-doodle-btn:disabled { opacity: .35; cursor: not-allowed; }
/* Bouton œil — cligne (opacité qui pulse) tant que le mode "focus dessin"
   (chrome de la page caché) est actif, repère visuel qu'un état invisible
   ailleurs sur la page est en cours. */
.wq-doodle-eye.is-blinking { animation: wqDoodleEyeBlink 2.2s ease-in-out infinite; }
@keyframes wqDoodleEyeBlink { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }
@media (prefers-reduced-motion: reduce) {
  .wq-doodle-eye.is-blinking { animation: none; opacity: .6; }
}

/* ---------- Dessin pleine page (quest-canvas-draw.js) ----------
   Structurally full-canvas: unlike every other .wq-el, this one is NOT a
   placed/resizable rect — it always covers the whole page, no matter what
   el.x_pos/y_pos/width/height the data model carries (the editor's
   mountZone() applies those via canvas-engine.js's applyRect() regardless of
   widget type, so this overrides that effect with !important rather than
   trying to opt out of it). */
.wq-cvdraw {
  left: 0 !important; top: 0 !important; width: 100% !important; height: 100% !important;
  touch-action: pinch-zoom;
}
.wq-cvdraw > .wq-resize-handle { display: none; } /* nothing to resize — it's already full-page */

/* pointer-events:none sur tout le cadre — ce widget étant volontairement
   plein écran (voir .wq-cvdraw ci-dessus), le laisser capter les clics sur
   toute sa surface bloquerait la sélection de N'IMPORTE QUEL autre élément
   de la page dans l'éditeur. Seule la pastille (.wq-cvdraw-select-badge,
   coin bas-droite) reste cliquable — assez pour le sélectionner et ouvrir
   son panneau, sans gêner le reste. */
.wq-cvdraw-editor { outline: 1px dashed rgba(61,110,140,.45); background: rgba(61,110,140,.05); z-index: 60; pointer-events: none; }
.wq-cvdraw-hint {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-size: .8rem; font-weight: 700; color: rgba(61,110,140,.65); pointer-events: none; text-align: center;
}
.wq-cvdraw-select-badge {
  position: absolute; bottom: 10px; right: 10px; pointer-events: auto; cursor: pointer;
  background: #3d6e8c; color: #fff; font-size: .72rem; font-weight: 800;
  padding: 6px 12px; border-radius: 999px; box-shadow: 0 4px 10px rgba(15,23,42,.3);
}
.wq-cvdraw-select-badge:hover { filter: brightness(1.1); }

/* Player: above the page content (like doodle's overlay mode) so it can be
   drawn on top of anything, but the wrapper itself never blocks clicks —
   only the canvas (when armed) and the toolbar receive events. */
.wq-cvdraw-play { pointer-events: none; z-index: 60; }
.wq-cvdraw-play .wq-cvdraw-canvas, .wq-cvdraw-play .wq-cvdraw-bar { pointer-events: auto; }

.wq-cvdraw-canvas { position: absolute; inset: 0; width: 100%; height: 100%; cursor: crosshair; touch-action: pinch-zoom; }

/* Même système que la barre du Doodle (sheet-doodle.js) : coins de départ,
   orientation, groupes séparés par fonction, tailles, poignée déplaçable,
   bouton œil clignotant — voir les commentaires équivalents sur .wq-doodle-*
   plus haut dans ce fichier pour le détail de chaque mécanique. */
.wq-cvdraw-bar {
  position: absolute; display: flex; gap: 4px; align-items: center;
  background: #fff; border: 1px solid #d8dee9; border-radius: 16px; padding: 5px;
  box-shadow: 0 6px 14px rgba(15,23,42,.2); z-index: 8;
  max-width: calc(100% - 12px); flex-wrap: wrap;
}
.wq-cvdraw-bar.orient-vertical { flex-direction: column; max-height: calc(100% - 12px); max-width: none; }
.wq-cvdraw-bar.pos-top-left { top: 6px; left: 6px; }
.wq-cvdraw-bar.pos-top-right { top: 6px; right: 6px; }
.wq-cvdraw-bar.pos-bottom-left { bottom: 6px; left: 6px; }
.wq-cvdraw-bar.pos-bottom-right { bottom: 6px; right: 6px; }
.wq-cvdraw-draghandle {
  width: 26px; height: 26px; flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
  color: #94a3b8; font-size: 16px; cursor: grab; touch-action: none; user-select: none;
}
.wq-cvdraw-draghandle:active { cursor: grabbing; color: #3d6e8c; }
.wq-cvdraw-group {
  display: inline-flex; gap: 7px; align-items: center; flex-wrap: wrap;
  padding-inline-start: 7px; border-inline-start: 1px solid #e2e8f0;
}
.wq-cvdraw-bar.orient-vertical .wq-cvdraw-group {
  padding-inline-start: 0; border-inline-start: none;
  padding-block-start: 7px; border-block-start: 1px solid #e2e8f0; flex-direction: row;
}
.wq-cvdraw-toggle {
  width: 52px; height: 52px; border-radius: 50%; border: none; background: #3d6e8c; color: #fff;
  font-size: 24px; cursor: pointer; display: flex; align-items: center; justify-content: center; flex: 0 0 auto;
}
.wq-cvdraw-toggle.active { background: #d69a3c; }
.wq-cvdraw-dot { width: 34px; height: 34px; border-radius: 50%; border: 2px solid transparent; cursor: pointer; padding: 0; }
.wq-cvdraw-dot.active { border-color: #1e293b; box-shadow: 0 0 0 2px #fff inset; }
.wq-cvdraw-stamp {
  width: 34px; height: 34px; border-radius: 10px; border: 2px solid transparent; background: #f1f5f9;
  cursor: pointer; font-size: 18px; display: flex; align-items: center; justify-content: center; padding: 0;
}
.wq-cvdraw-stamp.active { border-color: #d69a3c; background: #fff7e6; }
.wq-cvdraw-shape {
  width: 34px; height: 34px; border-radius: 10px; border: 2px solid transparent; background: #f1f5f9;
  cursor: pointer; font-size: 16px; display: flex; align-items: center; justify-content: center; padding: 0;
}
.wq-cvdraw-shape.active { border-color: #d69a3c; background: #fff7e6; }
.wq-cvdraw-texture {
  width: 34px; height: 34px; border-radius: 10px; border: 2px solid transparent; background: #f1f5f9;
  cursor: pointer; font-size: 16px; display: flex; align-items: center; justify-content: center; padding: 0;
}
.wq-cvdraw-texture.active { border-color: #3d6e8c; background: #e6f0f7; }
.wq-cvdraw-size {
  width: 36px; height: 36px; border-radius: 50%; background: #f1f5f9; border: 1px solid #d8dee9;
  cursor: pointer; display: flex; align-items: center; justify-content: center; padding: 0;
}
.wq-cvdraw-size.active { border-color: #1e293b; }
.wq-cvdraw-size i { border-radius: 50%; background: #1e293b; display: block; }
.wq-cvdraw-bar.size-medium .wq-cvdraw-toggle { width: 46px; height: 46px; font-size: 21px; }
.wq-cvdraw-bar.size-medium .wq-cvdraw-dot { width: 30px; height: 30px; }
.wq-cvdraw-bar.size-medium .wq-cvdraw-stamp { width: 30px; height: 30px; font-size: 16px; }
.wq-cvdraw-bar.size-medium .wq-cvdraw-shape { width: 30px; height: 30px; font-size: 14px; }
.wq-cvdraw-bar.size-medium .wq-cvdraw-texture { width: 30px; height: 30px; font-size: 14px; }
.wq-cvdraw-bar.size-medium .wq-cvdraw-size { width: 32px; height: 32px; }
.wq-cvdraw-bar.size-medium .wq-cvdraw-btn { width: 36px; height: 36px; font-size: 16px; }
.wq-cvdraw-bar.size-small .wq-cvdraw-toggle { width: 40px; height: 40px; font-size: 18px; }
.wq-cvdraw-bar.size-small .wq-cvdraw-dot { width: 26px; height: 26px; }
.wq-cvdraw-bar.size-small .wq-cvdraw-stamp { width: 26px; height: 26px; font-size: 14px; }
.wq-cvdraw-bar.size-small .wq-cvdraw-shape { width: 26px; height: 26px; font-size: 12px; }
.wq-cvdraw-bar.size-small .wq-cvdraw-texture { width: 26px; height: 26px; font-size: 12px; }
.wq-cvdraw-bar.size-small .wq-cvdraw-size { width: 28px; height: 28px; }
.wq-cvdraw-bar.size-small .wq-cvdraw-btn { width: 32px; height: 32px; font-size: 14px; }
.wq-cvdraw-btn {
  border: none; background: #f1f5f9; border-radius: 10px; width: 40px; height: 40px;
  cursor: pointer; font-size: 18px; line-height: 1; display: flex; align-items: center; justify-content: center;
}
.wq-cvdraw-btn.active { background: #d69a3c; color: #fff; }
.wq-cvdraw-btn:disabled { opacity: .35; cursor: not-allowed; }
.wq-cvdraw-eye.is-blinking { animation: wqDoodleEyeBlink 2.2s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) {
  .wq-cvdraw-eye.is-blinking { animation: none; opacity: .6; }
}

/* ---------- Opération posée (sheet-math-op.js) ---------- */
.wq-mathop { display: flex; align-items: center; justify-content: center; }
.wq-mo-grid { display: grid; gap: 3px; --mo-cell: 34px; }
.wq-mo { width: var(--mo-cell); height: var(--mo-cell); display: flex; align-items: center; justify-content: center; box-sizing: border-box; }
.wq-mo-digit { font: 800 1.25rem/1 'Outfit', sans-serif; color: #1e293b; }
.wq-mo-sign { font: 800 1.15rem/1 'Outfit', sans-serif; color: #c94f4f; }
.wq-mo-rule { border-top: 3px solid #1e293b; }
.wq-mo-ans, .wq-mo-carry {
  width: 100%; height: 100%; text-align: center; box-sizing: border-box;
  border-radius: 8px; font-family: 'Outfit', sans-serif; outline: none;
}
.wq-mo-ans { border: 2px solid #6366f1; background: rgba(99,102,241,.06); font-weight: 800; font-size: 1.15rem; color: #1e293b; }
.wq-mo-ans:focus { background: #fff; }
.wq-mo-carrywrap { padding: 4px; }
.wq-mo-carry { border: 1.5px dashed #d69a3c; background: rgba(214,154,60,.07); font-weight: 700; font-size: .8rem; color: #b45309; }

/* ---------- Droite graduée (sheet-number-line.js) ---------- */
.wq-numline { display: flex; align-items: center; }
.wq-nl-track { position: relative; width: 100%; height: 100%; min-height: 44px; cursor: pointer; touch-action: pinch-zoom; }
.wq-nl-line { position: absolute; left: 0; right: 0; top: 50%; height: 3px; background: #1e293b; border-radius: 2px; }
.wq-nl-tick { position: absolute; top: 50%; width: 2px; height: 10px; background: #1e293b; transform: translate(-50%, -50%); }
.wq-nl-tick.major { height: 16px; }
.wq-nl-label { position: absolute; top: calc(50% + 12px); transform: translateX(-50%); font: 700 .72rem/1 'Outfit', sans-serif; color: #334155; white-space: nowrap; }
.wq-nl-marker {
  position: absolute; top: calc(50% - 13px); width: 16px; height: 16px; border-radius: 50%;
  background: #6366f1; border: 3px solid #fff; box-shadow: 0 2px 6px rgba(15,23,42,.4);
  transform: translateX(-50%); pointer-events: none;
}
.wq-nl-marker.ok { background: #22c55e; }
.wq-nl-marker.ko { background: #ef4444; }
.wq-nl-marker.wq-nl-author { background: #22c55e; opacity: .85; }
.wq-nl-ghost { background: #22c55e; opacity: .55; outline: 2px dashed #16a34a; outline-offset: 2px; }

/* ---------- Schéma à légender (sheet-label-diagram.js) ---------- */
.wq-ld { display: flex; flex-direction: column; gap: 6px; }
.wq-ld-area {
  position: relative; flex: 1 1 auto; min-height: 0;
  background: #fff; border-radius: 8px; box-shadow: inset 0 0 0 1px rgba(0,0,0,.08);
}
.wq-ld-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; pointer-events: none; }
.wq-ld-hint { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font: 700 .78rem 'Outfit', sans-serif; color: #94a3b8; text-align: center; }
.wq-ld-pin {
  position: absolute; width: var(--ld-pin, 22px); height: var(--ld-pin, 22px); border-radius: 50%;
  background: #3d6e8c; color: #fff; text-align: center;
  font-family: 'Outfit', sans-serif; font-weight: 800;
  font-size: calc(var(--ld-pin, 22px) * 0.46); line-height: var(--ld-pin, 22px);
  transform: translate(-50%, -50%); box-shadow: 0 2px 6px rgba(0,0,0,.35); z-index: 2;
}
.wq-ld-pin.ok { background: #22c55e; box-shadow: 0 0 0 4px rgba(34,197,94,.35), 0 2px 6px rgba(0,0,0,.35); }
.wq-ld-pin.ko { background: #ef4444; box-shadow: 0 0 0 4px rgba(239,68,68,.35), 0 2px 6px rgba(0,0,0,.35); }
.wq-editor-preview .wq-ld-pin { pointer-events: auto; cursor: move; }
.wq-ld-tag {
  position: absolute; transform: translate(calc(var(--ld-pin, 22px) * 0.65), -50%);
  background: #fff; border: 2px solid #3d6e8c; border-radius: 999px; padding: 2px 10px;
  font-family: 'Outfit', sans-serif; font-weight: 700; font-size: var(--ld-chip-fs, 0.72rem);
  color: #1e293b; white-space: nowrap; cursor: pointer; z-index: 3;
  box-shadow: 0 2px 6px rgba(0,0,0,.2);
}
.wq-ld-tag.ok { border-color: #22c55e; background: #dcfce7; color: #14532d; box-shadow: 0 0 10px rgba(34,197,94,.5); }
.wq-ld-tag.ko { border-color: #ef4444; background: #fee2e2; color: #7f1d1d; text-decoration: line-through; box-shadow: 0 0 10px rgba(239,68,68,.5); }
.wq-ld-reveal {
  position: absolute; transform: translate(14px, 40%);
  font: 700 .68rem 'Outfit', sans-serif; color: #16a34a; background: #f0fdf4;
  border: 1px dashed #22c55e; border-radius: 8px; padding: 1px 8px; white-space: nowrap; z-index: 3;
}
.wq-ld-tray {
  flex: 0 0 auto; display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
  padding: 6px; background: rgba(61,110,140,.08); border-radius: 10px; min-height: 32px;
}
.wq-ld-chip {
  background: #fff; border: 2px solid #d69a3c; border-radius: 999px;
  padding: calc(var(--ld-chip-fs, 0.74rem) * 0.4) calc(var(--ld-chip-fs, 0.74rem) * 1.1);
  font-family: 'Outfit', sans-serif; font-weight: 700; font-size: var(--ld-chip-fs, 0.74rem);
  color: #1e293b; cursor: grab; user-select: none; touch-action: pinch-zoom;
}
.wq-ld-chip.used { display: none; }
.wq-ld-drag-ghost { position: fixed; z-index: 5000; pointer-events: none; opacity: .92; }

/* ---------- Flashcards (sheet-flashcards.js) ---------- */
.wq-fc { display: flex; flex-direction: column; gap: 6px; }
.wq-fc-head { display: flex; justify-content: space-between; align-items: center; font: 800 .74rem 'Outfit', sans-serif; color: #3b2f22; }
.wq-fc-card {
  flex: 1 1 auto; min-height: 0; position: relative; cursor: pointer;
  background: linear-gradient(150deg, #fffdf6, #ffeec6); border: 2px solid #d69a3c; border-radius: 14px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 12px 14px; box-shadow: 0 8px 18px -10px rgba(59,47,34,.45); text-align: center;
}
.wq-fc-card.is-answer { background: linear-gradient(150deg, #f2fbf4, #d8f5de); border-color: #22c55e; }
.wq-fc-side { font: 700 .95rem/1.5 'Outfit', 'Cairo', sans-serif; color: #1e293b; overflow: auto; max-height: 100%; }
.wq-fc-tap { position: absolute; bottom: 6px; left: 0; right: 0; font: 600 .58rem sans-serif; color: rgba(59,47,34,.5); text-transform: uppercase; letter-spacing: .4px; }
.wq-fc-actions { flex: 0 0 auto; display: flex; gap: 8px; }
.wq-fc-btn {
  flex: 1; border: none; border-radius: 10px; padding: 8px 6px; cursor: pointer;
  font: 800 .78rem 'Outfit', sans-serif; color: #fff;
}
.wq-fc-btn.ok { background: #22c55e; }
.wq-fc-btn.ko { background: #ef4444; }
.wq-fc-btn.restart { background: #6366f1; margin-top: 10px; flex: none; padding: 8px 16px; }
.wq-fc-end { font: 900 1.4rem 'Outfit', sans-serif; color: #3b2f22; display: flex; flex-direction: column; align-items: center; }
.wq-fc-preview .wq-fc-title { font: 800 .8rem 'Outfit', sans-serif; margin-bottom: 6px; }
.wq-fc-preview .wq-fc-q { font: 700 .85rem/1.4 'Outfit', 'Cairo', sans-serif; color: #1e293b; }
.wq-fc-preview .wq-fc-count { font: 700 .62rem sans-serif; color: rgba(59,47,34,.55); margin-top: 6px; text-transform: uppercase; }

/* ---------- Surligneur (sheet-highlighter.js) ---------- */
.wq-hl {
  --hl-color: #ffe066;
  display: flex; flex-direction: column; gap: 6px;
  padding: 4px; /* overflow stays visible so editor resize/rotate grips aren't clipped */
}
.wq-hl-hint {
  flex: 0 0 auto; font: 700 .62rem 'Outfit', sans-serif; color: #b45309;
  background: #fffbeb; border: 1px dashed #fcd34d; border-radius: 8px; padding: 3px 8px;
}
.wq-hl-prompt { flex: 0 0 auto; font: 700 .85rem/1.4 'Outfit', 'Cairo', sans-serif; color: #1e293b; }
.wq-hl-text {
  flex: 1 1 auto; min-height: 0; overflow: auto;
  font-family: 'Outfit', 'Cairo', sans-serif; font-size: 1em; line-height: 1.75;
  color: #1e293b; white-space: pre-wrap; word-break: break-word;
}
/* Word = the clickable unit. Rounded box-decoration so multi-line highlights
   stay pretty when a word wraps. */
.wq-hl-word {
  border-radius: 5px; padding: 0 1px; cursor: pointer;
  transition: background-color .1s ease; -webkit-box-decoration-break: clone; box-decoration-break: clone;
}
.wq-hl-word:hover { background: rgba(0,0,0,.06); }
.wq-hl-word.hl { background: var(--hl-color); }
/* Editor preview: children are pointer-events:none by theme rule — re-enable
   words so the author can click them to mark the answers. */
.wq-editor-preview .wq-hl-word { pointer-events: auto; }
.wq-editor-preview .wq-hl-word.author-hl {
  background: var(--hl-color); box-shadow: inset 0 -2px 0 rgba(0,0,0,.25);
}
/* Graded states (markGraded) */
.wq-hl-word.ok { background: #86efac; box-shadow: inset 0 0 0 1px #16a34a; }
.wq-hl-word.ko { background: #fecaca; box-shadow: inset 0 0 0 1px #dc2626; text-decoration: line-through; }
.wq-hl-word.miss { background: transparent; box-shadow: inset 0 -2px 0 #16a34a; border-bottom: 2px dotted #16a34a; }

/* ---------- Image à zones / hotspots (sheet-hotspots.js) ---------- */
.wq-hz { padding: 0; }
.wq-hz-area { position: absolute; inset: 0; border-radius: 6px; overflow: hidden; }
.wq-hz-img { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.wq-hz-hint {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font: 700 .78rem 'Outfit', sans-serif; color: #94a3b8; text-align: center;
}
/* Player: zones are invisible until the student clicks them. */
.wq-hz-zone { position: absolute; box-sizing: border-box; cursor: pointer; border-radius: 6px; }
.wq-hz-zone.picked { background: rgba(99,102,241,.22); box-shadow: inset 0 0 0 2px #6366f1; }
.wq-hz-zone.picked::after {
  content: '✓'; position: absolute; top: 2px; right: 4px;
  font: 800 .8rem sans-serif; color: #4338ca;
}
/* Graded states (markGraded) */
.wq-hz-zone.ok { background: rgba(34,197,94,.28); box-shadow: inset 0 0 0 2px #16a34a; }
.wq-hz-zone.ko { background: rgba(239,68,68,.28); box-shadow: inset 0 0 0 2px #dc2626; }
.wq-hz-zone.ko::after { content: '✗'; position: absolute; top: 2px; right: 4px; font: 800 .8rem sans-serif; color: #b91c1c; }
.wq-hz-zone.miss { background: transparent; box-shadow: inset 0 0 0 2px #16a34a; border: 1px dashed #16a34a; }
.wq-hz-zone.is-locked-grey { background: rgba(154,148,136,.28); box-shadow: inset 0 0 0 2px #9a9488; filter: grayscale(1); }
/* Zones sit inside `.wq-hz-area`, which clips (overflow:hidden) so an image
   can't spill past its widget — the shared silk/drag result-badge protrudes
   OUTSIDE its box on purpose and gets cut off there, invisibly depending on
   where the zone lands. This variant stays fully INSET, so it's never clipped
   regardless of zone position or widget size. */
.wq-hz-result-badge { position: absolute; pointer-events: none; z-index: 5; }
.wq-hz-result-badge::after {
  content: ''; position: absolute; top: 3px; left: 3px;
  width: 12px; height: 12px; border-radius: 50%;
  box-shadow: 0 1px 2px rgba(0,0,0,.35), 0 0 0 2px #fffdf6;
}
.wq-hz-result-badge.is-ok::after { background: var(--wq-green, #5c8a67); }
.wq-hz-result-badge.is-bad::after { background: var(--wq-red, #c94f4f); }
/* Editor authoring: zones are visible, draggable and resizable. */
.wq-editor-preview .wq-hz-zone { pointer-events: auto; }
.wq-editor-preview .wq-hz-handle { pointer-events: auto; }
.wq-hz-zone.author { background: rgba(99,102,241,.14); box-shadow: inset 0 0 0 2px #6366f1; cursor: move; touch-action: pinch-zoom; }
.wq-hz-zone.author.author-ok { background: rgba(34,197,94,.16); box-shadow: inset 0 0 0 2px #16a34a; }
.wq-hz-zone.author.author-ko { background: rgba(239,68,68,.16); box-shadow: inset 0 0 0 2px #dc2626; }
.wq-hz-num {
  position: absolute; top: 2px; left: 4px; font: 800 .68rem sans-serif; color: #1e293b;
  background: rgba(255,255,255,.85); border-radius: 5px; padding: 0 5px;
}
.wq-hz-handle {
  position: absolute; right: -6px; bottom: -6px; width: 14px; height: 14px;
  background: #6366f1; border: 2px solid #fff; border-radius: 4px; cursor: nwse-resize; touch-action: pinch-zoom;
}
/* Circular zones: round visual in both editor and player. In the player we
   also clip the hit area to the ellipse so only clicks INSIDE the circle
   count; in the editor we keep the full box grabbable (handle at the corner). */
.wq-hz-zone.wq-hz-circle { border-radius: 50%; }
.wq-hz:not(.wq-editor-preview) .wq-hz-zone.wq-hz-circle { clip-path: ellipse(50% 50% at 50% 50%); }
/* On a circle the corner glyph would be clipped away — center it instead. */
.wq-hz-zone.wq-hz-circle.picked::after,
.wq-hz-zone.wq-hz-circle.ko::after {
  top: 50%; left: 50%; right: auto; transform: translate(-50%, -50%);
}
/* Feedback banner (P4.2) shown over the image bottom after grading. */
.wq-hz-feedback {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 4;
  font: 700 .74rem/1.4 'Outfit', 'Cairo', sans-serif; padding: 6px 10px;
  border-radius: 0 0 6px 6px; text-align: center;
}
.wq-hz-feedback.ok { background: rgba(220,252,231,.96); color: #14532d; box-shadow: inset 0 2px 0 #22c55e; }
.wq-hz-feedback.ko { background: rgba(254,243,199,.96); color: #92400e; box-shadow: inset 0 2px 0 #f59e0b; }

/* ---------- Flashcards (quest-flashcards.js) — real 3D flip + skins ---------- */
.wq-fc3 { position: relative; display: flex; flex-direction: column; gap: 6px; font-family: 'Outfit', 'Cairo', sans-serif; }
/* Local audio toggle — combines with (never overrides) the platform's
   global media-mute; disabled+dim when global media is already muted, since
   local can't turn on what the global switch has turned off. */
.wq-fc3-audio-btn {
  cursor: pointer; border: none; border-radius: 999px; width: 28px; height: 28px;
  display: flex; align-items: center; justify-content: center; font-size: .85rem;
  background: rgba(0,0,0,.12); color: inherit; flex: 0 0 auto; padding: 0;
}
.wq-fc3-audio-btn:disabled { cursor: not-allowed; opacity: .5; }
.wq-fc3-audio-btn.corner {
  position: absolute; z-index: 5; background: rgba(0,0,0,.45); color: #fff;
  box-shadow: 0 2px 6px rgba(0,0,0,.35);
}
.wq-fc3-audio-btn.corner-tl { top: 8px; left: 8px; }
.wq-fc3-audio-btn.corner-tr { top: 8px; right: 8px; }
.wq-fc3-head {
  display: flex; align-items: center; gap: 8px; flex: 0 0 auto;
  font: 800 var(--fc-title-size, .8rem) 'Outfit', 'Cairo', sans-serif; color: var(--fc-title-color, #6b5a44);
}
/* flex:1 + text-align (not justify-content on the row) so the title can be
   left/center/right WITHIN the space it has, independent of the progress
   counter — the counter stays pinned to its own end regardless. */
.wq-fc3-head-title { flex: 1; min-width: 0; text-align: var(--fc-title-align, center); }
.wq-fc3-head-title.has-underlay {
  display: inline-block; background: var(--fc-title-underlay-color, var(--fc-accent, #d69a3c)); color: #fff;
  padding: 4px 12px; border-radius: 999px;
  box-shadow: 0 2px 6px -2px rgba(0,0,0,.3), 0 0 0 2px rgba(255,255,255,.35) inset;
}
.wq-fc3-prog { opacity: .65; font-weight: 700; flex: 0 0 auto; }
.wq-fc3-dots { flex: 0 0 auto; display: flex; flex-wrap: wrap; justify-content: center; gap: 5px; padding: 2px 0 4px; }
.wq-fc3-dot { width: 7px; height: 7px; border-radius: 50%; background: rgba(0,0,0,.15); transition: transform .15s, background .15s; }
.wq-fc3-dot.seen { background: var(--fc-accent, #5c8a67); }
.wq-fc3-dot.current { background: var(--fc-accent, #5c8a67); transform: scale(1.6); box-shadow: 0 0 0 2px rgba(255,255,255,.6); }
.wq-fc3-hint {
  flex: 1; display: flex; align-items: center; justify-content: center; text-align: center;
  color: #94a3b8; font: 700 .78rem 'Outfit', sans-serif; padding: 12px;
}

/* The 3D flip: `.wq-fc3-scene` gives perspective, `.wq-fc3-card` is the object
   that rotates, and each `.wq-fc3-face` is pinned to the same box with
   backface-visibility hidden so only one is ever legible at a time — the
   back face is pre-rotated 180° so it lands face-up exactly when the card
   itself finishes its own 180° turn.
   ONLY the picture lives inside this flipping card now. flex:1 1 with a
   min-height FLOOR (never disappears) but no ceiling: the text box below
   sizes to its own content, not a fixed share, so the image is free to
   grow into whatever it actually leaves unused — a forced min-height on
   the text box previously reserved a big empty gap for short answers,
   which is what made a short "JHJJJ" float far from the picture with the
   image left small and unchanged either way. --fc-img-share (an author
   slider, default 55%) is a starting preference, not a hard cap — it can
   still grow past it when text is short. */
.wq-fc3-scene { position: relative; flex: 1 1 var(--fc-img-share, 55%); min-height: 30%; perspective: 1400px; }
.wq-fc3-card {
  position: relative; width: 100%; height: 100%;
  transform-style: preserve-3d; transition: transform .55s cubic-bezier(.4,.2,.2,1);
  cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.wq-fc3-card.wq-fc3-flip.is-flipped { transform: rotateY(180deg); }
.wq-fc3-face {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: var(--fc-vjustify, center);
  backface-visibility: hidden; -webkit-backface-visibility: hidden;
  background: var(--fc-bg); color: var(--fc-text);
  border: var(--fc-border-w) var(--fc-border-style, solid) var(--fc-border);
  border-radius: var(--fc-radius); font-family: var(--fc-font);
  box-shadow: 0 6px 18px -6px rgba(0,0,0,.35), 0 0 0 1px rgba(255,255,255,.04) inset,
              0 0 22px -4px var(--fc-glow, transparent);
  padding: 14px; box-sizing: border-box; overflow: hidden;
}
.wq-fc3-back { transform: rotateY(180deg); }
/* Faint deck-level background decoration, BEHIND the content (z-index 0) so
   it never fights with text/image legibility regardless of opacity chosen. */
.wq-fc3-face::before {
  content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  border-radius: inherit; background-image: var(--fc-deco, none);
  background-size: cover; background-position: center; opacity: var(--fc-deco-opacity, .18);
}
.wq-fc3-content { position: relative; z-index: 1; display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; min-height: 0; }
.wq-fc3-content--empty { opacity: .35; }
/* width/height:100% + object-fit:contain — NOT width/height:auto — so a
   small source image is scaled UP to fill its box too, not just clamped
   down when oversized. auto/auto only ever shrinks, never grows, which left
   a small picture stranded tiny in a large card. */
.wq-fc3-img { width: 100%; height: 100%; max-width: 100%; max-height: 100%; object-fit: contain; border-radius: 8px; pointer-events: none; }
/* Deck "Format de l'image" override (22/08/2026) — JS sets width/height to
   auto + an explicit aspect-ratio only when a format is chosen; with an
   explicit ratio (not the image's own natural one) the auto/auto sizing
   fills the available box at that ratio — it does NOT fall back to the
   image's native pixel size, so the small-image-stays-tiny regression the
   default rule above exists to avoid doesn't apply here. */
/* Pinned "sticker" badge — a slight tilt + layered shadow reads as a physical
   tag stuck on the card, not a flat icon. Inset well clear of the corner
   (not flush at 8/8) and capped/ellipsised so a longer label can never
   poke past the card edge and get clipped by the face's overflow:hidden. */
.wq-fc3-badge {
  position: absolute; top: 14px; right: 18px; z-index: 2; max-width: 62%;
  background: var(--fc-accent, #d69a3c);
  color: #fff; font: 800 .78rem 'Outfit', sans-serif;
  padding: 5px 12px; border-radius: 999px; transform: rotate(-6deg);
  box-shadow: 0 3px 0 rgba(0,0,0,.22), 0 6px 12px -3px rgba(0,0,0,.4), 0 0 0 2px rgba(255,255,255,.55) inset;
  pointer-events: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* A completely separate, non-flipping container BELOW the picture. flex:0 0
   auto — it sizes to its OWN text, no forced min-height — a fixed floor
   reserved a big empty box even for one short word, which is what made the
   text's position jump around unpredictably relative to the image at
   different scales. max-height/overflow-y is only a safety net for a
   genuinely long paragraph, never the normal case. */
.wq-fc3-text {
  flex: 0 0 auto; max-height: 48%; overflow-y: auto; width: 100%; box-sizing: border-box;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  font: 700 var(--fc-text-size, 1.05rem)/1.35 inherit; color: var(--fc-text-color, inherit);
  text-align: var(--fc-text-align, center); word-break: break-word;
  background: var(--fc-text-bg, transparent); border-radius: 10px; padding: 8px 12px;
}
.wq-fc3-text-span { min-width: 0; }
/* On-demand audio button — only shown when autoPlayAudio is off (the new
   default): no sound plays until tapped, incl. the very first card. */
.wq-fc3-playbtn {
  flex: 0 0 auto; border: none; border-radius: 999px;
  width: var(--fc-playbtn-size, 26px); height: var(--fc-playbtn-size, 26px);
  display: flex; align-items: center; justify-content: center;
  font-size: calc(var(--fc-playbtn-size, 26px) * .42);
  background: var(--fc-playbtn-color, var(--fc-accent, #5c8a67)); color: #fff; cursor: pointer; padding: 0;
  box-shadow: 0 2px 6px -2px rgba(0,0,0,.35);
}

.wq-fc3-tap { flex: 0 0 auto; text-align: center; font: 700 .72rem 'Outfit', sans-serif; opacity: .55; }

.wq-fc3-actions { flex: 0 0 auto; display: flex; gap: 8px; visibility: hidden; opacity: 0; transition: opacity .2s; }
.wq-fc3-actions.show { visibility: visible; opacity: 1; }
.wq-fc3-btn {
  flex: 1; border: none; border-radius: 999px; padding: 9px 12px; cursor: pointer;
  font: 800 .78rem 'Outfit', 'Cairo', sans-serif; color: #fff;
  box-shadow: 0 4px 10px -3px rgba(0,0,0,.3); transition: transform .1s;
}
.wq-fc3-btn:active { transform: scale(.96); }
.wq-fc3-btn.ok { background: var(--fc-accent, #5c8a67); }
.wq-fc3-btn.ko { background: #c94f4f; }

.wq-fc3-end { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; }
.wq-fc3-end-score { font: 800 1.3rem 'Outfit', sans-serif; color: var(--fc-accent, #5c8a67); }
.wq-fc3-end.perfect .wq-fc3-end-score { font-size: 1.55rem; animation: wqFc3PerfectPop .5s cubic-bezier(.34,1.56,.64,1); }
@keyframes wqFc3PerfectPop { 0% { transform: scale(.4); opacity: 0; } 70% { transform: scale(1.15); } 100% { transform: scale(1); opacity: 1; } }
/* `.wq-fc3-btn`'s flex:1 is meant for the ✅/❌ ROW — inside `.wq-fc3-end`'s
   flex COLUMN it stretched the restart button to fill the entire card
   height instead of sizing to its own content. */
.wq-fc3-end .restart { flex: 0 0 auto; background: var(--fc-accent, #5c8a67); padding: 10px 20px; }
.wq-fc3-end .wq-fc3-btn-misses { flex: 0 0 auto; background: #c94f4f; padding: 8px 16px; font-size: .72rem; }

/* ---------- Section Frame (quest-section-frame.js) ---------- */
/* box-sizing:border-box already set inline — the frame's own border/fill
   never needs overflow:hidden or any pointer-events trick beyond the plain
   `pointer-events:none` set inline for the PLAYER build, so no resize-handle
   clipping concern here (unlike the widgets with an inner clipped frame). */
.wq-secframe-badge {
  position: absolute; z-index: 3; font-weight: 800; white-space: nowrap;
  padding: 4px 12px; border-radius: 999px;
  box-shadow: 0 3px 8px -2px rgba(0,0,0,.3), 0 0 0 2px rgba(255,255,255,.4) inset;
  font-family: 'Outfit', 'Cairo', sans-serif;
}
.wq-secframe-badge--top-left { top: -12px; left: 14px; }
.wq-secframe-badge--top-center { top: -12px; left: 50%; transform: translateX(-50%); }
.wq-secframe-badge--top-right { top: -12px; right: 14px; }
.wq-secframe-badge--bottom-left { bottom: -12px; left: 14px; }
.wq-secframe-badge--bottom-center { bottom: -12px; left: 50%; transform: translateX(-50%); }
.wq-secframe-badge--bottom-right { bottom: -12px; right: 14px; }
.wq-secframe-badge--left-center { left: -12px; top: 50%; transform: translateY(-50%); }
.wq-secframe-badge--right-center { right: -12px; top: 50%; transform: translateY(-50%); }
/* Shape variants — the base rule above is the "pill" default. */
.wq-secframe-badge-shape-circle {
  border-radius: 50%; width: 2.2em; height: 2.2em; padding: 0;
  display: flex; align-items: center; justify-content: center; text-align: center;
}
.wq-secframe-badge-shape-square { border-radius: 10px; }

.wq-secframe-content {
  position: absolute; inset: 0; z-index: 0;
  border-radius: inherit; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  pointer-events: none;
}
.wq-secframe-content img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; user-select: none;
}
.wq-secframe-ph-text {
  position: relative; z-index: 1;
  max-width: 88%; text-align: center;
  font-weight: 800; line-height: 1.25;
  font-family: 'Outfit', 'Cairo', sans-serif;
  word-wrap: break-word;
}

/* ---------- Image widget corner brackets (sheet-image.js) ---------- */
.wq-image-corner{position:absolute;box-sizing:border-box;pointer-events:none;}
.wq-image-corner--tl{top:-3px;left:-3px;}
.wq-image-corner--tr{top:-3px;right:-3px;}
.wq-image-corner--bl{bottom:-3px;left:-3px;}
.wq-image-corner--br{bottom:-3px;right:-3px;}

/* ---------- Scratch reveal (quest-scratch-reveal.js + reveal-engine.js) ---------- */
/* overflow:hidden lives on .wq-sr-frame, NOT .wq-sr itself — the editor's
   resize handle attaches to .wq-sr and sits just OUTSIDE its box
   (right:-6px/bottom:-6px by design), so overflow:hidden directly on .wq-sr
   would clip the handle and make the widget unresizable. Same pattern as
   .wq-hz-area for the hotspots widget. */
.wq-sr { position: relative; border-radius: 14px; background: #f1ece0; }
.wq-sr-frame { position: absolute; inset: 0; border-radius: inherit; overflow: hidden; }
.wq-sr-content { position: absolute; inset: 0; }
/* Same sizing convention as the coating's own drawImageCover() in
   quest-scratch-reveal.js — edge-to-edge, no padding, object-fit:cover, not
   contain — so an author reusing the SAME picture for both the coating and
   the revealed content gets it perfectly aligned instead of the coating
   filling the frame while the revealed image sat letterboxed/inset inside
   12px of padding. */
.wq-sr-img { width: 100%; height: 100%; object-fit: cover; pointer-events: none; }
/* ONE toast pill, in NORMAL FLOW above .wq-sr-frame (a sibling, not a
   child, not absolutely positioned over it) — external to the card, never
   overlapping the image regardless of mask shape. Its content is swapped
   in place at reveal time (see swapToastEnd() in quest-scratch-reveal.js),
   not replaced by a second element. */
.wq-sr-toast {
  flex: 0 0 auto; align-self: center; max-width: 92%; margin-bottom: 6px;
  font: 800 .85rem/1.3 'Outfit', 'Cairo', sans-serif; color: #fff; text-align: center;
  background: rgba(20,20,20,.78); padding: 7px 16px; border-radius: 999px;
  box-shadow: 0 4px 12px -3px rgba(0,0,0,.35), 0 0 0 2px rgba(255,255,255,.3) inset;
  word-break: break-word;
}
.wq-sr-toast-hidden { display: none; }
/* reveal-engine.js's canvas paints ON TOP of this via .wq-reveal-canvas
   (position:absolute, appended after .wq-sr-content) — no extra z-index
   needed, DOM order already puts it above. */
/* Instructions live BELOW the coating (normal flow), not overlaid on top of
   it — an overlaid hint used to cover a meaningful chunk of the picture,
   especially on smaller widget sizes. */
.wq-sr-footer { flex: 0 0 auto; display: flex; align-items: center; justify-content: center; gap: 8px; padding-top: 6px; }
.wq-sr-hint-row { text-align: center; font: 700 .75rem 'Outfit', sans-serif; color: #6b5a44; opacity: .8; }
.wq-sr-hold {
  border: none; border-radius: 999px; flex: 0 0 auto;
  padding: 6px 12px; font: 700 .68rem 'Outfit', sans-serif; color: #fff; background: #8b7fc7;
  cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.wq-sr-coat-preview {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font: 800 .85rem 'Outfit', sans-serif; color: #fff; text-shadow: 0 1px 3px rgba(0,0,0,.5);
}

/* ---------- Vidéo inline (sheet-video.js) ---------- */
.wq-video { display: flex; flex-direction: column; gap: 4px; }
.wq-video-title { flex: 0 0 auto; font: 800 .82rem 'Outfit', 'Cairo', sans-serif; color: #1e293b; }
.wq-video-frame {
  flex: 1 1 auto; min-height: 0; position: relative;
  background: #0f172a; border-radius: 8px; overflow: hidden;
}
.wq-video-frame iframe, .wq-video-frame video {
  position: absolute; inset: 0; width: 100%; height: 100%; border: 0; display: block;
}
.wq-video-frame video { object-fit: contain; background: #000; }
.wq-video-hint {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font: 700 .78rem 'Outfit', sans-serif; color: #94a3b8; text-align: center; padding: 8px;
}
/* Editor: light poster (YouTube thumbnail or dark card) + play badge. */
.wq-video-poster {
  position: absolute; inset: 0; background: #1e293b center/cover no-repeat;
  display: flex; align-items: center; justify-content: center;
}
.wq-video-play {
  width: 46px; height: 46px; border-radius: 50%; background: rgba(0,0,0,.55);
  color: #fff; font-size: 1.1rem; display: flex; align-items: center; justify-content: center;
  padding-left: 3px; box-shadow: 0 2px 10px rgba(0,0,0,.4);
}

/* ---------- Lecteur audio (sheet-audio.js) ---------- */
.wq-audio {
  --a-accent: #6366f1; --a-bg: #fff; --a-fg: #1e293b; --a-radius: 14px; --a-size: 1;
  display: flex; flex-direction: column; gap: 6px; justify-content: center;
  font-size: calc(.85rem * var(--a-size)); color: var(--a-fg);
  font-family: 'Outfit', 'Cairo', sans-serif;
  /* The card fill lives on THIS node (the actual resized rectangle), not on
     wq-audio-box — otherwise resizing taller/wider than the box's natural
     size left the extra space transparent, showing the canvas through it as
     a grey gap around the visible bar. box-shadow stays on wq-audio-box
     though (see the docked-player rule below): a blur placed on the wider
     node reads as a haze offset from the actual visible edges. */
  background: var(--a-bg); border-radius: var(--a-radius); padding: .55em .8em;
  border: var(--a-border-w, 0px) solid var(--a-border-c, transparent);
  cursor: pointer; /* the whole pill plays/pauses, not just the icon circle */
}
.wq-audio-locked { cursor: not-allowed; }
.wq-audio .wq-audio-progress, .wq-audio .wq-audio-mini { cursor: pointer; }
.wq-audio-title { font-weight: 800; font-size: 1em; line-height: 1.3; }
.wq-audio-stacked { text-align: center; }
.wq-audio-stacked .wq-audio-title { font-size: 1.1em; }
.wq-audio-box { display: flex; align-items: center; gap: .8em; box-shadow: 0 2px 8px rgba(0,0,0,.1); }
.wq-audio-button { background: transparent; border-color: transparent; }
.wq-audio-button .wq-audio-box { box-shadow: none; justify-content: center; }
.wq-audio-play {
  flex: 0 0 auto; border: none; cursor: pointer; padding: 0;
  width: 2.6em; height: 2.6em; background: var(--a-accent); color: #fff;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 3px 8px rgba(0,0,0,.22); transition: filter .15s, transform .08s;
}
.wq-audio-play:hover { filter: brightness(1.07); }
.wq-audio-play:active { transform: scale(.94); }
.wq-audio-button .wq-audio-play { width: 3.6em; height: 3.6em; }
.wq-audio-shape-circle .wq-audio-play { border-radius: 50%; }
.wq-audio-shape-rounded .wq-audio-play { border-radius: .55em; }
.wq-audio-shape-square .wq-audio-play { border-radius: 0; }
.wq-audio-ico { width: 1.25em; height: 1.25em; display: block; }
.wq-audio-progress { flex: 1 1 auto; min-width: 2.5em; }
.wq-audio-track {
  /* Renamed from .wq-audio-bar: that name collided with the widget ROOT's own
     layout-modifier class (node.className includes 'wq-audio-' + c.layout,
     i.e. literally "wq-audio-bar" for the default bar layout). Both rules
     matched the SAME root element, and this one's background silently won
     the cascade — overriding the configured "Fond du lecteur" colour on
     every bar-layout player, no matter what was picked. That was the actual
     bug behind "the background never changes" — not a caching or wiring
     issue after all. */
  position: relative; height: .5em; border-radius: 999px; cursor: pointer; touch-action: pinch-zoom;
  /* Was ALSO a fixed rgba(128,128,128,.28) regardless of the chosen theme —
     since this track spans most of the card's width, that fixed grey
     dominated the look no matter which (deliberately pale) "Fond du
     lecteur" swatch was picked. Tying it to
     --a-fg (already configurable) makes the whole card visibly react. */
  background: color-mix(in srgb, var(--a-fg) 18%, transparent);
}
.wq-audio-fill { position: absolute; left: 0; top: 0; bottom: 0; width: 0; background: var(--a-accent); border-radius: 999px; }
/* Piste verticale (demandé) : la barre/le fil se lit de bas en haut au lieu
   de gauche à droite — même piste (.wq-audio-track), juste tournée sur le
   côté. Le remplissage suit (JS bascule width→height, voir sheet-audio.js). */
/* node (.wq-audio) is flex-direction:column with justify-content:center —
   fine for a horizontal bar (content-sized height, centred), but a vertical
   track needs to actually STRETCH to fill the drawn rectangle's height, or
   it collapses to its content size and floats in the middle (signalé:
   "the segment is not all displayed" — the track was only a few px tall
   inside a much taller box). min-height:0 at each flex level is required
   for a flex child to shrink/grow past its content size in a column flow.
   Note: this rectangle is drawn box-sizing:border-box by applyRect,
   including this box's own padding — height:100% already accounts for it. */
.wq-audio.nr-vertical { justify-content: flex-start; }
.wq-audio.nr-vertical .wq-audio-box { flex-direction: column; flex: 1 1 auto; min-height: 0; height: 100%; }
.wq-audio.nr-vertical .wq-audio-progress { flex: 1 1 auto; align-self: stretch; display: flex; justify-content: center; min-width: 0; min-height: 0; }
.wq-audio.nr-vertical .wq-audio-track { width: .5em; height: 100%; min-height: 0; }
.wq-audio.nr-vertical .wq-audio-fill { left: 0; right: 0; top: auto; bottom: 0; width: auto; height: 0; }
.wq-audio-time { flex: 0 0 auto; font-size: .8em; font-variant-numeric: tabular-nums; opacity: .85; white-space: nowrap; }
.wq-audio-mini {
  flex: 0 0 auto; border: none; cursor: pointer; background: transparent; color: inherit;
  font-family: inherit; font-size: .85em; padding: .25em .45em; border-radius: .4em;
}
.wq-audio-mini:hover { background: rgba(128,128,128,.18); }
.wq-audio-speed { font-weight: 800; min-width: 2.4em; }
.wq-audio-loop.active { color: var(--a-accent); }
.wq-audio-hint {
  display: flex; align-items: center; justify-content: center; height: 100%;
  color: #94a3b8; font: 700 .78rem 'Outfit', sans-serif; text-align: center; padding: 6px;
}
/* Footer under the player: author message + plays-remaining (exam). */
.wq-audio-footer { display: flex; flex-direction: column; gap: 2px; margin-top: 2px; }
.wq-audio-stacked .wq-audio-footer, .wq-audio-button .wq-audio-footer { align-items: center; }
.wq-audio-msg { font-size: .82em; opacity: .9; line-height: 1.35; }
.wq-audio-remaining {
  font-size: .78em; font-weight: 800; color: var(--a-accent);
  display: inline-flex; align-items: center; gap: .35em;
}
.wq-audio-remaining::before { content: '🎧'; font-weight: 400; }
/* Play button locked once the exam listen-limit is exhausted. */
.wq-audio-play.locked { cursor: not-allowed; filter: grayscale(.7); opacity: .55; box-shadow: none; }
.wq-audio-locked .wq-audio-remaining { color: #dc2626; }
.wq-audio-locked .wq-audio-remaining::before { content: '🔒'; }

/* ---------- Remise en ordre (quest-reorder.js) ----------
   Style knobs live as CSS custom properties on .wq-reorder (set from JS only
   when the author actually picked something — empty stays on these
   defaults), so tile bg/text/border/radius/font-size are all one variable
   each instead of a rule per combination. */
.wq-reorder {
  --ro-tile-bg: #fff; --ro-tile-fg: #1e293b; --ro-tile-border: #cbd5e1;
  --ro-tile-radius: 9px; --ro-tile-fs: .92rem;
  --ro-img-size: 64px; --ro-img-h: 64px; --ro-img-fit: cover;
  --ro-zone-bg: rgba(99,102,241,.06); --ro-zone-border: #c7d2fe;
  --ro-zone-border-w: 2px; --ro-zone-border-style: dashed; --ro-zone-radius: 10px;
  --ro-bank-bg: transparent; --ro-bank-border: transparent;
  --ro-bank-border-w: 0px; --ro-bank-border-style: solid; --ro-bank-radius: 10px;
  display: flex; flex-direction: column; gap: 8px; overflow: auto; padding: 2px;
}
.wq-ro-prompt { flex: 0 0 auto; font: 700 .9rem/1.4 'Outfit', 'Cairo', sans-serif; color: #1e293b; }
.wq-ro-hintline { flex: 0 0 auto; font: 600 .78rem/1.4 'Outfit', 'Cairo', sans-serif; color: #6366f1; }
.wq-ro-hintbtn {
  flex: 0 0 auto; align-self: flex-start; font: 700 .72rem 'Outfit', sans-serif;
  color: #6366f1; background: #eef2ff; border: 1px solid #c7d2fe; border-radius: 999px;
  padding: 3px 10px; cursor: pointer;
}
.wq-ro-hint {
  display: flex; align-items: center; justify-content: center; min-height: 40px;
  color: #94a3b8; font: 700 .78rem 'Outfit', sans-serif; text-align: center;
}
.wq-ro-answer {
  flex: 0 0 auto; display: flex; flex-wrap: wrap; gap: 7px; align-items: center;
  min-height: 2.6em; padding: 8px; border-radius: var(--ro-zone-radius); box-sizing: border-box;
  background: var(--ro-zone-bg); border: var(--ro-zone-border-w) var(--ro-zone-border-style) var(--ro-zone-border);
}
.wq-ro-bank {
  flex: 0 0 auto; display: flex; flex-wrap: wrap; gap: 7px; align-items: center; padding: 4px 2px;
  background: var(--ro-bank-bg); border: var(--ro-bank-border-w) var(--ro-bank-border-style) var(--ro-bank-border);
  border-radius: var(--ro-bank-radius);
}
/* Éparpillée (demandé, façon plateau de jeu) : chaque tuile est positionnée
   en absolu (left/top/rotate posés en inline par scatterStyle() en JS — un
   seed par tuile, jamais Math.random au rendu, sinon elles sauteraient
   ailleurs à chaque re-render). Le conteneur a besoin d'une hauteur propre
   puisque plus aucune tuile n'est dans le flux pour la lui donner. */
.wq-ro-bank.scatter { position: relative; min-height: 140px; padding: 8px; }
.wq-ro-bank.scatter .wq-ro-tile { position: absolute; }
.wq-ro-bank.scatter .wq-ro-tile:hover, .wq-ro-bank.scatter .wq-ro-tile:focus-visible { z-index: 2; }
.wq-ro-placeholder { font: 600 .8rem 'Outfit', sans-serif; color: #94a3b8; padding: 2px 4px; }
.wq-ro-tile {
  font: 700 var(--ro-tile-fs) 'Outfit', 'Cairo', sans-serif; color: var(--ro-tile-fg);
  background: var(--ro-tile-bg); border: 2px solid var(--ro-tile-border); border-radius: var(--ro-tile-radius);
  padding: 6px 12px; cursor: pointer; user-select: none; line-height: 1.2;
  box-shadow: 0 2px 4px rgba(0,0,0,.06); transition: transform .08s, border-color .15s;
}
.wq-ro-tile:active { transform: scale(.95); }
.wq-ro-tile.bank { background: color-mix(in srgb, var(--ro-tile-bg) 85%, #6366f1 15%); border-color: #a5b4fc; }
.wq-editor-preview .wq-ro-tile { cursor: default; }
/* Variante image : la vignette remplace le texte, la légende (si présente
   dans l'URL après un « | ») reste en dessous. */
.wq-ro-tile.is-img { padding: 4px; display: flex; flex-direction: column; align-items: center; gap: 3px; }
.wq-ro-tile.is-img img { width: var(--ro-img-size); height: var(--ro-img-h); object-fit: var(--ro-img-fit); border-radius: calc(var(--ro-tile-radius) - 2px); display: block; }
.wq-ro-tile.is-img .wq-ro-tile-cap { font-size: .74em; max-width: var(--ro-img-size); text-align: center; }
/* Graded states */
.wq-ro-answer .wq-ro-tile.ok { background: #dcfce7; border-color: #22c55e; color: #14532d; }
.wq-ro-answer .wq-ro-tile.ko { background: #fee2e2; border-color: #ef4444; color: #7f1d1d; }
.wq-ro-reveal {
  flex: 0 0 auto; font: 700 .82rem 'Outfit', 'Cairo', sans-serif; color: #16a34a;
  background: #f0fdf4; border: 1px dashed #22c55e; border-radius: 8px; padding: 5px 10px;
}
/* Message de correction (facultatif, réglé par l'auteur) — bandeau discret
   sous les rangées, jamais un popup qui interromprait un enchaînement rapide
   de plusieurs essais. */
.wq-ro-fbmsg {
  flex: 0 0 auto; font: 700 .8rem 'Outfit', 'Cairo', sans-serif; padding: 6px 10px;
  border-radius: 8px; animation: wqRoFbIn .2s ease;
}
.wq-ro-fbmsg.ok { background: #f0fdf4; border: 1px dashed #22c55e; color: #16a34a; }
.wq-ro-fbmsg.ko { background: #fef2f2; border: 1px dashed #ef4444; color: #b91c1c; }
@keyframes wqRoFbIn { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: translateY(0); } }

/* ---- Skins (demandé) : 3 habillages préréglés, en plus des couleurs/tailles
   réglables une par une ci-dessus — un skin ne fait que poser des valeurs de
   départ différentes pour ces mêmes variables + une touche de forme propre
   (rotation légère façon étiquette pour "paper", pas de bordure pour "pill"). */
.wq-reorder.wq-ro-skin-pill { --ro-tile-radius: 999px; }
.wq-reorder.wq-ro-skin-pill .wq-ro-tile { border-width: 0; box-shadow: 0 2px 8px rgba(0,0,0,.12); }
.wq-reorder.wq-ro-skin-paper .wq-ro-tile {
  border-style: solid; box-shadow: 1px 2px 5px rgba(0,0,0,.15);
  transform: rotate(calc((var(--ro-tile-rot, 0)) * 1deg));
}
.wq-reorder.wq-ro-skin-paper .wq-ro-tile:nth-child(odd) { --ro-tile-rot: -1.5; }
.wq-reorder.wq-ro-skin-paper .wq-ro-tile:nth-child(even) { --ro-tile-rot: 1.5; }
.wq-reorder.wq-ro-skin-chalk { --ro-tile-bg: #1e293b; --ro-tile-fg: #f8fafc; --ro-tile-border: #475569; }
.wq-reorder.wq-ro-skin-chalk .wq-ro-answer { background: rgba(255,255,255,.04); border-color: #475569; }
.wq-reorder.wq-ro-skin-chalk .wq-ro-placeholder { color: #64748b; }

/* ---------- Menu déroulant (sheet-dropdown.js) ---------- */
.wq-dd {
  --dd-accent: #6366f1; --dd-size: 1;
  display: flex; flex-direction: column; gap: 4px; justify-content: center;
  font-size: calc(.9rem * var(--dd-size)); font-family: 'Outfit', 'Cairo', sans-serif;
}
.wq-dd-row { display: flex; align-items: center; gap: .5em; flex-wrap: wrap; }
.wq-dd-label { font-weight: 700; color: #1e293b; }
.wq-dd-wrap { position: relative; display: inline-flex; align-items: center; }
.wq-dd-wrap::after {
  content: '▾'; position: absolute; right: .6em; top: 50%; transform: translateY(-50%);
  pointer-events: none; color: var(--dd-accent); font-size: .9em;
}
.wq-dd-select {
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  font: inherit; color: #1e293b; background: #fff; cursor: pointer;
  border: 2px solid var(--dd-accent); border-radius: 9px;
  padding: .4em 2em .4em .7em; max-width: 100%;
  box-shadow: 0 2px 5px rgba(0,0,0,.06);
}
.wq-dd-select:focus { outline: none; box-shadow: 0 0 0 3px color-mix(in srgb, var(--dd-accent) 30%, transparent); }
.wq-dd-select:disabled { opacity: 1; cursor: default; }
.wq-dd-wrap.ok .wq-dd-select { border-color: #22c55e; background: #f0fdf4; color: #14532d; }
.wq-dd-wrap.ok::after { color: #22c55e; }
.wq-dd-wrap.ko .wq-dd-select { border-color: #ef4444; background: #fef2f2; color: #7f1d1d; }
.wq-dd-wrap.ko::after { color: #ef4444; }
.wq-dd-reveal { font: 700 .8em 'Outfit', 'Cairo', sans-serif; color: #16a34a; }
.wq-dd-cap { font: 700 .72em 'Outfit', sans-serif; color: #15803d; opacity: .85; } /* editor only */
.wq-dd-feedback {
  font: 700 .8em 'Outfit', 'Cairo', sans-serif; padding: 5px 10px; border-radius: 8px; margin-top: 2px;
}
.wq-dd-feedback.ok { background: #dcfce7; color: #14532d; }
.wq-dd-feedback.ko { background: #fef3c7; color: #92400e; }

/* ---------- Barème / pastille de points (sheet-points.js) ---------- */
.wq-pts { display: flex; align-items: center; justify-content: center; }
.wq-pts-inner {
  display: inline-flex; align-items: center; gap: .35em; white-space: nowrap;
  font-family: 'Outfit', 'Cairo', sans-serif; font-weight: 700; line-height: 1.1;
  font-size: calc(.95rem * var(--pts-size, 1)); padding: .32em .8em;
  color: var(--pts-color, #6366f1);
  background: color-mix(in srgb, var(--pts-color, #6366f1) 15%, #fff);
  border: 1.5px solid color-mix(in srgb, var(--pts-color, #6366f1) 40%, #fff);
}
.wq-pts-pill .wq-pts-inner { border-radius: 999px; }
.wq-pts-rounded .wq-pts-inner { border-radius: .5em; }
.wq-pts-ico { width: 1.05em; height: 1.05em; display: block; }
.wq-pts-coin { width: .8em; height: .8em; border-radius: 50%; background: currentColor; display: block; }
/* Graded outcome (v2 auto-link): recolour the pill after correction. */
.wq-pts-ok .wq-pts-inner { color: #15803d; background: #dcfce7; border-color: #22c55e; }
.wq-pts-partial .wq-pts-inner { color: #92400e; background: #fef3c7; border-color: #f59e0b; }
.wq-pts-ko .wq-pts-inner { color: #b91c1c; background: #fee2e2; border-color: #ef4444; }

/* ---------- Shared: hidden-by-a-button state ---------- */
.wq-hidden { display: none !important; }

/* ---------- Popup overlay (icon_button popup actions) ---------- */
.wq-popup-overlay {
  position: fixed; inset: 0; z-index: 2000;
  background: rgba(59, 47, 34, .55);
  display: flex; align-items: center; justify-content: center; padding: 20px;
}
.wq-popup-card {
  position: relative; background: #fffdf6; border-radius: 16px;
  max-width: 640px; width: 100%; max-height: 85vh; overflow: auto;
  box-shadow: 0 30px 60px rgba(0, 0, 0, .35);
  padding: 1.2rem 1.4rem 1.4rem;
  font-family: var(--wq-font, sans-serif); color: var(--wq-ink, #3b2f22);
}
.wq-popup-close {
  position: absolute; top: 10px; right: 12px; border: none; background: none;
  font-size: 1rem; color: var(--wq-ink-soft, #6b5a44); cursor: pointer;
}
.wq-popup-title {
  font-weight: 800; font-size: 1.05rem; margin: 0 1.4rem 0.8rem 0;
}
.wq-popup-body img { max-width: 100%; border-radius: 8px; display: block; }
.wq-popup-body iframe, .wq-popup-body video {
  width: 100%; aspect-ratio: 16 / 9; border: none; border-radius: 8px;
  display: block; background: #000;
}
.wq-popup-text { font-size: .95rem; line-height: 1.6; white-space: pre-wrap; }

/* ---------- Toast « bouton grisé » (shared-actions.js) -------------------
   Rappel bref, pas un blocage : disparaît seul, contrairement à la popup
   (qu'il faut fermer). Une seule pastille réutilisée à chaque déclenchement,
   plutôt qu'une par clic — sur <body>, position fixe, échappe au zoom du
   canevas comme le bouton « passer » du Robot Guide (même raison).
   Centré page (pas collé en bas) et dimensionné en clamp() (pas une taille
   fixe) — signalé : trop discret en bas, pas assez lisible sur petit écran.
   `scale()` plutôt qu'un `translateY` pour l'entrée/sortie : au centre de
   l'écran, un « pop » se lit mieux qu'un glissement, qui suggérerait une
   provenance (le bas, le haut…) qui n'a plus de sens ici. */
.wq-disabled-toast {
  position: fixed;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%) scale(.85);
  width: clamp(240px, 70vw, 460px);
  padding: clamp(16px, 4vw, 26px) clamp(20px, 5vw, 32px);
  border-radius: 18px;
  background: rgba(15, 23, 42, .94);
  color: #fff;
  font-weight: 700;
  font-size: clamp(.95rem, 2.6vw, 1.2rem);
  line-height: 1.45;
  text-align: center;
  box-shadow: 0 20px 48px rgba(15, 23, 42, .4);
  z-index: 2100;
  opacity: 0;
  pointer-events: none;
  transition: opacity .2s ease, transform .2s ease;
}
.wq-disabled-toast.show { opacity: 1; transform: translate(-50%, -50%) scale(1); }

/* ---------- Image picker (image-picker.js) ---------- */
.wq-imgpicker-card { max-width: 560px; }
.wq-imgpicker-tabs { display: flex; gap: 6px; margin: 0 0 .8rem; border-bottom: 1px solid var(--wq-line, #d8c69f); }
.wq-imgpicker-tab {
  font-family: inherit; font-weight: 700; font-size: .82rem; padding: .5rem .9rem; margin-bottom: -1px;
  border: none; border-bottom: 2px solid transparent; background: none; color: var(--wq-ink-soft, #6b5a44); cursor: pointer;
}
.wq-imgpicker-tab.active { color: var(--wq-ink, #3b2f22); border-bottom-color: var(--wq-gold, #d69a3c); }
.wq-imgpicker-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: 8px; }
.wq-imgpicker-thumb {
  aspect-ratio: 1 / 1; border: 1px solid var(--wq-line, #d8c69f); border-radius: 10px; background: #fff;
  padding: 4px; cursor: pointer; overflow: hidden; display: flex; align-items: center; justify-content: center;
}
.wq-imgpicker-thumb:hover { border-color: var(--wq-gold, #d69a3c); box-shadow: 0 4px 10px -4px rgba(0,0,0,.3); }
.wq-imgpicker-thumb img { width: 100%; height: 100%; object-fit: contain; display: block; }
.wq-imgpicker-empty { font-size: .85rem; color: var(--wq-ink-soft, #6b5a44); text-align: center; padding: 1.4rem 0; }
.wq-imgpicker-upload-row { margin-bottom: .8rem; }
.wq-imgpicker-upload-btn {
  font-family: inherit; font-weight: 700; font-size: .82rem; padding: .55rem 1rem; border-radius: 9px;
  border: 1px dashed var(--wq-gold, #d69a3c); background: #fffaf0; color: var(--wq-ink, #3b2f22); cursor: pointer; width: 100%;
}
.wq-imgpicker-upload-btn:hover { background: #fdf3dc; }
.wq-imgpicker-status { font-size: .78rem; color: var(--wq-ink-soft, #6b5a44); min-height: 1.2em; margin: .6rem 0 0; }

/* ---------- Background picker (background-picker.js) ---------- */
.wq-bgpicker-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; }
.wq-bgpicker-thumb {
  border: 1px solid var(--wq-line, #d8c69f); border-radius: 10px; background: #fff; padding: 0;
  cursor: pointer; overflow: hidden; display: flex; flex-direction: column;
}
.wq-bgpicker-thumb:hover { border-color: var(--wq-gold, #d69a3c); box-shadow: 0 4px 10px -4px rgba(0,0,0,.3); }
.wq-bgpicker-frame { width: 100%; height: 90px; border: none; display: block; pointer-events: none; }
.wq-bgpicker-lbl { font-size: .78rem; font-weight: 700; padding: 6px 8px; color: var(--wq-ink, #3b2f22); text-align: center; }

/* ---------- props-kit textarea (popup text, TTS text) ---------- */
.wq-pk-textarea {
  width: 100%; padding: 0.6rem 0.7rem; border: 1px solid var(--wq-line, #d8c69f);
  border-radius: 9px; font-family: var(--wq-font, sans-serif); font-size: 0.85rem;
  outline: none; background: #fff; resize: vertical;
}
.wq-pk-textarea:focus { border-color: var(--wq-gold, #d69a3c); }

/* ---------- Video, Quest inline (quest-video.js) ---------- */
.wq-qvideo {
  --qv-accent: #6366f1; --qv-bg: #0f172a; --qv-radius: 14px;
  display: flex; flex-direction: column; gap: 6px;
  font-family: 'Outfit', 'Cairo', sans-serif;
  /* Control-bar sizes below are in `cqw` (% of THIS element's own rendered
     width), not fixed px — a widget an author places small must get a small
     bar, a big one a big bar, independent of the canvas-wide zoom/fit scale
     (fixed separately in quest-zoom-pan.js). Without this, every skin's
     buttons stayed a fixed 32-46px however tiny the author sized the video
     zone, dominating/overflowing it — the "controls are still big, don't
     resize" bug. `inline-size` (not `size`) since only the bar's own width
     drives its layout; height is intrinsic to that. */
  container-type: inline-size;
}
.wq-qvideo-title {
  font-weight: 800; font-size: .95em; color: var(--wq-ink, #3b2f22);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.wq-qvideo-frame {
  position: relative; flex: 1; width: 100%; min-height: 0;
  background: var(--qv-bg, #0f172a); border-radius: var(--qv-radius, 14px);
  overflow: hidden; box-shadow: 0 6px 18px rgba(0, 0, 0, .18);
}
.wq-qvideo-frame iframe, .wq-qvideo-frame video {
  position: absolute; inset: 0; width: 100%; height: 100%; border: none; display: block;
}
.wq-qvideo-poster { position: absolute; inset: 0; background: #000 center/cover no-repeat; }
.wq-qvideo-loader {
  position: absolute; inset: 0; z-index: 3; display: flex; align-items: center; justify-content: center;
  background: var(--qv-bg, #0f172a); pointer-events: none;
}
.wq-qvideo-spin {
  width: clamp(22px, 16cqw, 44px); height: clamp(22px, 16cqw, 44px); border-radius: 50%;
  border: clamp(2.5px, 2cqw, 4px) solid rgba(255, 255, 255, .18);
  border-top-color: var(--qv-accent, #6366f1); animation: wq-qvideo-spin .8s linear infinite;
}
@keyframes wq-qvideo-spin { to { transform: rotate(360deg); } }
.wq-qvideo-hint {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  text-align: center; padding: 10px; color: #cbd5e1; font-weight: 700; font-size: .8rem;
  background: rgba(255, 255, 255, .06);
}
.wq-qvideo-play {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: 20%; aspect-ratio: 1; min-width: 40px; max-width: 76px;
  border-radius: 50%; background: var(--qv-accent, #6366f1); color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-size: 1.4rem; box-shadow: 0 8px 20px rgba(0, 0, 0, .35); pointer-events: none;
}

/* ---------- Video, Quest popup/lightbox mode ---------- */
.wq-qvideo-frame--clickable { cursor: pointer; }
.wq-qvideo-frame--clickable:hover .wq-qvideo-play { filter: brightness(1.12); }

.wq-qvideo-lightbox {
  position: fixed; inset: 0; z-index: 99999;
  background: rgba(4, 8, 20, .86);
  display: flex; align-items: center; justify-content: center;
  padding: 4vh 4vw; animation: wq-qvideo-fade .15s ease;
}
@keyframes wq-qvideo-fade { from { opacity: 0; } to { opacity: 1; } }
.wq-qvideo-lightbox-inner {
  position: relative; width: min(92vw, 1100px); aspect-ratio: 16 / 9;
  background: var(--qv-bg, #0f172a); border-radius: var(--qv-radius, 14px);
  overflow: hidden; box-shadow: 0 24px 60px rgba(0, 0, 0, .5);
}
.wq-qvideo-lightbox-inner iframe, .wq-qvideo-lightbox-inner video {
  position: absolute; inset: 0; width: 100%; height: 100%; border: none; display: block;
}
.wq-qvideo-lightbox-close {
  position: absolute; top: 10px; right: 10px; z-index: 2;
  width: 36px; height: 36px; border-radius: 50%; border: none;
  background: rgba(15, 23, 42, .7); color: #fff; font-size: 1.2rem; line-height: 1;
  display: flex; align-items: center; justify-content: center; cursor: pointer;
}
.wq-qvideo-lightbox-close:hover { background: var(--qv-accent, #6366f1); }

/* ---------- Video, Quest custom skins (playful / elegant) — LOCAL video only;
   a YouTube iframe keeps its own default controls regardless. ---------- */
.wq-qvideo-frame--split { display: flex; flex-direction: column; }
.wq-qvideo-frame--split video { position: static; flex: 1; min-height: 0; width: 100%; height: 100%; }

.wq-qvideo-ctrl { position: relative; flex: 0 0 auto; display: flex; flex-direction: column; gap: 6px; font-family: 'Outfit', 'Cairo', sans-serif; }
.wq-qvc-progress { padding: 0 2px; }
.wq-qvc-track { position: relative; cursor: pointer; }
.wq-qvc-fill { position: absolute; top: 0; bottom: 0; left: 0; width: 0%; }
.wq-qvc-handle { position: absolute; top: 50%; left: 0%; pointer-events: none; }
.wq-qvc-row { display: flex; align-items: center; gap: 6px; }
.wq-qvc-btn { border: none; cursor: pointer; display: flex; align-items: center; justify-content: center; padding: 0; }
.wq-qvc-btn svg { width: 55%; height: 55%; }
.wq-qvc-spacer { flex: 1; }
.wq-qvc-time { white-space: nowrap; }

/* --- Ludique: a solid, chunky, always-visible bar UNDER the picture ---
   Sizes below are clamp(min, Ncqw, max) — N chosen so the clamp's MAX is
   the original fixed-px value (unchanged look on a normally-sized widget),
   scaling down proportionally as the widget itself gets smaller, floored at
   MIN so a tiny widget still has tappable buttons. */
.wq-qvideo-ctrl--playful { background: #2f6fb0; padding: clamp(4px, 2.5cqw, 10px) clamp(5px, 3cqw, 12px) clamp(6px, 3cqw, 12px); }
.wq-qvideo-ctrl--playful .wq-qvc-track { height: clamp(4px, 2cqw, 8px); border-radius: 999px; background: rgba(255, 255, 255, .32); }
.wq-qvideo-ctrl--playful .wq-qvc-fill { border-radius: 999px; background: #e0483e; }
.wq-qvideo-ctrl--playful .wq-qvc-handle {
  width: clamp(9px, 4.5cqw, 18px); height: clamp(9px, 4.5cqw, 18px); border-radius: 50%; background: #fff; border: 3px solid #e0483e;
  transform: translate(-50%, -50%); box-shadow: 0 2px 4px rgba(0, 0, 0, .3);
}
.wq-qvideo-ctrl--playful .wq-qvc-row { flex-wrap: wrap; gap: clamp(3px, 1.5cqw, 6px); }
.wq-qvideo-ctrl--playful .wq-qvc-btn {
  width: clamp(20px, 10cqw, 40px); height: clamp(18px, 9cqw, 36px); border-radius: clamp(6px, 2.75cqw, 11px); color: #fff;
  box-shadow: 0 3px 0 rgba(0, 0, 0, .22); transition: transform .08s ease, box-shadow .08s ease;
}
.wq-qvideo-ctrl--playful .wq-qvc-btn:active { transform: translateY(2px); box-shadow: 0 1px 0 rgba(0, 0, 0, .22); }
.wq-qvideo-ctrl--playful .wq-qvc-play { background: #3a7dc4; width: clamp(23px, 11.5cqw, 46px); }
.wq-qvideo-ctrl--playful .wq-qvc-rw { background: #f0a23a; }
.wq-qvideo-ctrl--playful .wq-qvc-fw { background: #8b6fd6; }
.wq-qvideo-ctrl--playful .wq-qvc-vol { background: #5cb85c; }
.wq-qvideo-ctrl--playful .wq-qvc-speed {
  background: #f0a23a; color: #fff; font-weight: 800; font-size: clamp(.6rem, 2.7cqw, .72rem); border-radius: clamp(6px, 2.75cqw, 11px);
  width: auto; padding: 0 clamp(6px, 2.5cqw, 10px); height: clamp(18px, 9cqw, 36px); box-shadow: 0 3px 0 rgba(0, 0, 0, .22);
}
.wq-qvideo-ctrl--playful .wq-qvc-fs { background: #e6597a; }
.wq-qvideo-ctrl--playful .wq-qvc-time {
  background: #16283c; color: #fff; font-weight: 700; font-size: clamp(.6rem, 2.7cqw, .74rem); padding: 0 clamp(6px, 3cqw, 12px); height: clamp(18px, 9cqw, 36px);
  border-radius: clamp(5px, 2.5cqw, 10px); display: flex; align-items: center; font-variant-numeric: tabular-nums;
}

/* --- Élégant: a translucent bar that floats over the picture and hides itself --- */
.wq-qvideo-ctrl--elegant {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  background: linear-gradient(to top, rgba(0, 0, 0, .75), rgba(0, 0, 0, 0) 90%);
  padding: clamp(10px, 6.5cqw, 26px) clamp(5px, 3cqw, 12px) clamp(3px, 2cqw, 8px); opacity: 0; transform: translateY(6px); pointer-events: none;
  transition: opacity .22s ease, transform .22s ease;
}
.wq-qvideo-ctrl--elegant.show { opacity: 1; transform: translateY(0); pointer-events: auto; }
.wq-qvideo-ctrl--elegant .wq-qvc-track { height: clamp(2px, 1cqw, 4px); border-radius: 999px; background: rgba(255, 255, 255, .28); }
.wq-qvideo-ctrl--elegant .wq-qvc-fill { border-radius: 999px; background: var(--qv-accent, #6366f1); }
.wq-qvideo-ctrl--elegant .wq-qvc-handle {
  width: clamp(6px, 3cqw, 12px); height: clamp(6px, 3cqw, 12px); border-radius: 50%; background: var(--qv-accent, #6366f1);
  transform: translate(-50%, -50%) scale(0); box-shadow: 0 0 0 4px rgba(255, 255, 255, .15);
  transition: transform .15s ease;
}
.wq-qvideo-ctrl--elegant .wq-qvc-track:hover .wq-qvc-handle { transform: translate(-50%, -50%) scale(1); }
.wq-qvideo-ctrl--elegant .wq-qvc-btn {
  width: clamp(15px, 7.5cqw, 30px); height: clamp(15px, 7.5cqw, 30px); border-radius: clamp(4px, 2cqw, 8px); background: transparent; color: #fff; opacity: .92;
  transition: background .15s ease, opacity .15s ease;
}
.wq-qvideo-ctrl--elegant .wq-qvc-btn:hover { background: rgba(255, 255, 255, .14); opacity: 1; }
.wq-qvideo-ctrl--elegant .wq-qvc-speed { font-size: clamp(.56rem, 2.5cqw, .68rem); font-weight: 700; width: auto; padding: 0 clamp(4px, 2cqw, 8px); color: #fff; background: transparent; }
.wq-qvideo-ctrl--elegant .wq-qvc-speed:hover { background: rgba(255, 255, 255, .14); }
.wq-qvideo-ctrl--elegant .wq-qvc-time { color: rgba(255, 255, 255, .85); font-size: clamp(.58rem, 2.6cqw, .7rem); font-variant-numeric: tabular-nums; padding: 0 clamp(2px, 1cqw, 4px); }

/* --- Carnet: the platform's own kraft-paper palette (see --wq-* tokens
   above) — a flat, simple bar under the picture, plus an outer paper "card"
   around the whole widget so it echoes the Quest default look on purpose. --- */
.wq-qvideo--carnet-card {
  background: var(--wq-paper, #f6ecd8); border: 1px solid var(--wq-line, #d8c69f);
  border-radius: 14px; box-shadow: 0 14px 26px -16px rgba(59, 47, 34, .5);
  padding: 10px; transform: rotate(-0.4deg);
}
.wq-qvideo--carnet-card .wq-qvideo-title { color: var(--wq-ink, #3b2f22); }
.wq-qvideo-ctrl--carnet { background: var(--wq-paper, #f6ecd8); padding: clamp(4px, 2.25cqw, 9px) clamp(4px, 2.5cqw, 10px) clamp(1px, .75cqw, 3px); }
.wq-qvideo-ctrl--carnet .wq-qvc-track { height: clamp(3px, 1.25cqw, 5px); border-radius: 3px; background: var(--wq-paper-dark, #ecdcbb); }
.wq-qvideo-ctrl--carnet .wq-qvc-fill { border-radius: 3px; background: var(--wq-blue, #3d6e8c); }
.wq-qvideo-ctrl--carnet .wq-qvc-handle {
  width: clamp(5px, 2.25cqw, 9px); height: clamp(5px, 2.25cqw, 9px); border-radius: 50%; background: var(--wq-gold, #d69a3c);
  border: 2px solid var(--wq-paper, #f6ecd8); box-shadow: 0 1px 3px rgba(0, 0, 0, .3);
}
.wq-qvideo-ctrl--carnet .wq-qvc-btn {
  width: clamp(16px, 8cqw, 32px); height: clamp(16px, 8cqw, 32px); border-radius: 50%; background: var(--wq-paper-dark, #ecdcbb);
  color: var(--wq-ink, #3b2f22); transition: background .12s ease;
}
.wq-qvideo-ctrl--carnet .wq-qvc-btn:hover { background: var(--wq-line, #d8c69f); }
.wq-qvideo-ctrl--carnet .wq-qvc-play { background: var(--wq-blue, #3d6e8c); color: #fdfaf0; }
.wq-qvideo-ctrl--carnet .wq-qvc-speed {
  background: transparent; border: 1px solid var(--wq-line, #d8c69f); color: var(--wq-ink-soft, #6b5a44);
  font-weight: 700; font-size: clamp(.56rem, 2.5cqw, .68rem); width: auto; padding: 0 clamp(5px, 2.5cqw, 10px); height: clamp(16px, 8cqw, 32px); border-radius: 999px;
}
.wq-qvideo-ctrl--carnet .wq-qvc-speed:hover { background: var(--wq-paper-dark, #ecdcbb); }
.wq-qvideo-ctrl--carnet .wq-qvc-time { color: var(--wq-ink-soft, #6b5a44); font-size: clamp(.6rem, 2.6cqw, .72rem); font-variant-numeric: tabular-nums; }

/* ---------- Wordwall embed, Quest (quest-wordwall.js) ---------- */
.wq-wordwall {
  --ww-accent: #6366f1; --ww-bg: #0f172a; --ww-radius: 14px;
  display: flex; flex-direction: column; gap: 6px;
  font-family: 'Outfit', 'Cairo', sans-serif;
}
.wq-wordwall-title {
  font-weight: 800; font-size: .95em; color: var(--wq-ink, #3b2f22);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.wq-wordwall-frame {
  position: relative; flex: 1; width: 100%; min-height: 0;
  background: var(--ww-bg, #0f172a); border-radius: var(--ww-radius, 14px);
  overflow: hidden; box-shadow: 0 6px 18px rgba(0, 0, 0, .18);
}
.wq-wordwall-frame iframe {
  position: absolute; inset: 0; width: 100%; height: 100%; border: none; display: block;
  transition: opacity .2s ease;
}
.wq-wordwall-hint {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  text-align: center; padding: 10px; color: #cbd5e1; font-weight: 700; font-size: .8rem;
  background: rgba(255, 255, 255, .06);
}
.wq-wordwall-poster {
  position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 6px; color: #e2e8f0;
}
.wq-wordwall-poster-ic { font-size: 2.4rem; opacity: .85; }
.wq-wordwall-poster-lbl { font-weight: 800; font-size: .85rem; opacity: .9; }
.wq-wordwall-frame--clickable { cursor: pointer; }
.wq-wordwall-frame--clickable:hover .wq-qvideo-play { filter: brightness(1.12); }

.wq-wordwall-lightbox {
  position: fixed; inset: 0; z-index: 99999;
  background: rgba(4, 8, 20, var(--ww-backdrop-opacity, .86));
  display: flex; align-items: center; justify-content: center;
  padding: 4vh 4vw;
}
/* Même plafond fixe (720px) que l'ancienne popup narration -- même corrigé
   ici pour la même raison : minuscule au milieu d'un grand fond sombre. */
.wq-wordwall-lightbox-inner {
  position: relative; width: min(92vw, 1100px); height: min(86vh, 760px); max-height: 90vh;
  background: var(--ww-bg, #0f172a); border-radius: var(--ww-radius, 14px);
  overflow: hidden; box-shadow: 0 24px 60px rgba(0, 0, 0, .5);
  display: flex; flex-direction: column;
}
.wq-wordwall-lightbox-header {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 14px; background: var(--ww-header-bg, var(--ww-accent, #6366f1)); color: #fff;
  font-weight: 800; font-size: .85rem; flex: 0 0 auto;
}
.wq-wordwall-lightbox-title {
  flex: 1; min-width: 0; color: var(--ww-title-color, #fff);
  text-align: var(--ww-title-align, left);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.wq-wordwall-lightbox-close {
  border: none; background: #dc2626; color: #fff;
  width: 28px; height: 28px; border-radius: 50%; cursor: pointer;
  display: flex; align-items: center; justify-content: center; font-size: 1rem; flex: 0 0 auto;
  box-shadow: 0 3px 8px rgba(220, 38, 38, .45);
  transition: transform .1s ease, box-shadow .1s ease;
}
.wq-wordwall-lightbox-close:hover { background: #ef4444; transform: scale(1.08); box-shadow: 0 4px 10px rgba(220, 38, 38, .55); }
.wq-wordwall-lightbox-close:active { transform: scale(.94); }
.wq-wordwall-lightbox-body { position: relative; flex: 1; min-height: 380px; }
.wq-wordwall-lightbox-body iframe {
  position: absolute; inset: 0; width: 100%; height: 100%; border: none; display: block;
  transition: opacity .2s ease;
}

/* A ring of chasing dots -- mirrors Wordwall's own loading animation, so the
   popup/frame never shows an empty flash while the embed paints. */
.wq-wordwall-spinner {
  position: absolute; top: 50%; left: 50%; width: 1px; height: 1px; z-index: 2; display: none;
}
.wq-wordwall-spinner.show { display: block; }
.wq-wordwall-spinner span {
  position: absolute; top: 0; left: 0; width: 6px; height: 6px; margin: -3px 0 0 -3px;
  border-radius: 50%; background: var(--ww-accent, #6366f1);
  transform: rotate(calc(var(--i) * 45deg)) translateY(-18px);
  animation: wq-ww-spin 1.1s linear infinite;
  animation-delay: calc(var(--i) * -0.1375s);
  opacity: .25;
}
@keyframes wq-ww-spin { 0% { opacity: 1; } 100% { opacity: .25; } }

/* ---------- Generic iFrame embed, Quest (quest-iframe.js) ---------- */
.wq-iframe {
  --ifr-accent: #6366f1; --ifr-bg: #0f172a; --ifr-radius: 14px;
  display: flex; flex-direction: column; gap: 6px;
  font-family: 'Outfit', 'Cairo', sans-serif;
}
.wq-iframe-title {
  font-weight: 800; font-size: .95em; color: var(--wq-ink, #3b2f22);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.wq-iframe-frame {
  position: relative; flex: 1; width: 100%; min-height: 0;
  background: var(--ifr-bg, #0f172a); border-radius: var(--ifr-radius, 14px);
  overflow: hidden; box-shadow: 0 6px 18px rgba(0, 0, 0, .18);
}
/* Ratio presets CLAMP the frame's own height so an author never ends up with
   a squashed/stretched embed; 'auto' (no class) leaves the zone's placed
   height in charge — flex:1 above already does that. */
.wq-iframe-frame.ratio-16-9 { aspect-ratio: 16 / 9; flex: 0 0 auto; }
.wq-iframe-frame.ratio-4-3  { aspect-ratio: 4 / 3;  flex: 0 0 auto; }
.wq-iframe-frame.ratio-1-1  { aspect-ratio: 1 / 1;  flex: 0 0 auto; }
.wq-iframe-frame iframe {
  position: absolute; inset: 0; width: 100%; height: 100%; border: none; display: block;
  transition: opacity .2s ease;
}
.wq-iframe-hint {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  text-align: center; padding: 10px; color: #cbd5e1; font-weight: 700; font-size: .8rem;
  background: rgba(255, 255, 255, .06);
}
.wq-iframe-poster {
  position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 6px; color: #e2e8f0;
}
.wq-iframe-poster-ic { font-size: 2.4rem; opacity: .85; }
.wq-iframe-poster-lbl { font-weight: 800; font-size: .85rem; opacity: .9; }
.wq-iframe-frame--clickable { cursor: pointer; }
.wq-iframe-frame--clickable:hover .wq-qvideo-play { filter: brightness(1.12); }

.wq-iframe-error {
  position: absolute; inset: 0; display: none; flex-direction: column; align-items: center;
  justify-content: center; gap: 8px; padding: 14px; text-align: center; background: rgba(15, 23, 42, .92);
}
.wq-iframe-error.show { display: flex; }
.wq-iframe-error-msg { color: #e2e8f0; font-size: .78rem; font-weight: 600; margin: 0; max-width: 300px; }
.wq-iframe-retry {
  border: none; background: var(--ifr-accent, #6366f1); color: #fff; width: 38px; height: 38px;
  border-radius: 50%; cursor: pointer; font-size: 1rem; display: flex; align-items: center; justify-content: center;
}
.wq-iframe-retry:hover { filter: brightness(1.1); }

.wq-iframe-spinner {
  position: absolute; top: 50%; left: 50%; width: 1px; height: 1px; z-index: 2; display: none;
}
.wq-iframe-spinner.show { display: block; }
.wq-iframe-spinner span {
  position: absolute; top: 0; left: 0; width: 6px; height: 6px; margin: -3px 0 0 -3px;
  border-radius: 50%; background: var(--ifr-accent, #6366f1);
  transform: rotate(calc(var(--i) * 45deg)) translateY(-18px);
  animation: wq-embed-spin 1.1s linear infinite;
  animation-delay: calc(var(--i) * -0.1375s);
  opacity: .25;
}
@keyframes wq-embed-spin { 0% { opacity: 1; } 100% { opacity: .25; } }

/* ---------- html_frame widget (quest-html-frame.js) — a normal-page iframe
   zone, distinct from wq-iframe above (which is aimed at external providers
   and stays ratio-clamped/sandboxed). This one fills its own placed rect
   exactly and goes native-fullscreen via a body-level portal. */
.wq-html-frame {
  --hf-bg: #0f172a; --hf-radius: 12px;
  position: relative; width: 100%; height: 100%;
  background: var(--hf-bg); border-radius: var(--hf-radius);
  overflow: hidden; box-shadow: 0 6px 18px rgba(0, 0, 0, .18);
}
.wq-html-frame-poster {
  position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 6px; color: #e2e8f0; text-align: center; padding: 10px;
}
.wq-html-frame-poster-ic { font-size: 2.4rem; opacity: .85; }
.wq-html-frame-poster-lbl { font-weight: 800; font-size: .8rem; opacity: .9; }
.wq-html-frame-hint {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  text-align: center; padding: 10px; color: #cbd5e1; font-weight: 700; font-size: .8rem;
  background: rgba(255, 255, 255, .06);
}
.wq-html-frame-host {
  position: absolute; inset: 0; width: 100%; height: 100%;
}
.wq-html-frame-iframe {
  position: absolute; inset: 0; width: 100%; height: 100%; border: none; display: block;
  /* Phase C (kid/ludique) — fondu au changement de fichier (Fichier ◀/▶),
     piloté par la classe --switching dans quest-html-frame.js. */
  transition: opacity .18s ease;
}
.wq-html-frame-iframe--switching { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  .wq-html-frame-iframe { transition: none; }
}
/* Portal state: `host` has been reparented to <body> and is (or is about to
   be) the native fullscreen element — see wireFullscreen() in
   quest-html-frame.js. 100dvw/100dvh, unconstrained by the canvas's own
   size/zoom transform, since it now sits OUTSIDE that transformed ancestor. */
.wq-html-frame-host--fs {
  position: fixed; inset: 0; width: 100dvw; height: 100dvh; z-index: 99999; background: #000;
}
/* Note: the old always-on floating ✕ circle (.wq-html-frame-close-btn) is
   gone — "Fermer" is now a per-bar nav-header button (.wq-html-frame-
   navheader-btn--close below), independently placeable/toggleable like the
   Fichier/Page groups, instead of a single hardcoded overlay icon. */
.wq-html-frame-fs-btn {
  position: absolute; top: 8px; right: 8px; z-index: 2; border: none; background: rgba(15, 23, 42, .55);
  color: #fff; width: 32px; height: 32px; border-radius: 50%; cursor: pointer;
  display: flex; align-items: center; justify-content: center; font-size: .95rem;
  opacity: 0; transition: opacity .15s ease, background .15s ease;
}
.wq-html-frame-fs-btn:hover { background: rgba(15, 23, 42, .85); }
.wq-html-frame-host:hover .wq-html-frame-fs-btn { opacity: 1; }
.wq-html-frame-host--fs .wq-html-frame-fs-btn { display: none; }

/* CSS-only "expand" overlay (displayMode 'expand'/'auto-expand') — the SAME
   body-portal technique as --fs above (see createPortal()/wireDisplay() in
   quest-html-frame.js) but WITHOUT calling native requestFullscreen(), so it
   can be triggered automatically on mount (native fullscreen cannot: browsers
   refuse it without a direct user gesture). z-index stays clearly below --fs
   (99999) so a true fullscreen requested on top of an already-expanded
   widget still wins visually. */
.wq-html-frame-host--expand {
  position: fixed; inset: 0; width: 100dvw; height: 100dvh; z-index: 9000; background: #000;
}
.wq-html-frame-expand-btn {
  position: absolute; top: 8px; right: 84px; z-index: 2; border: none; background: rgba(15, 23, 42, .55);
  color: #fff; width: 32px; height: 32px; border-radius: 50%; cursor: pointer;
  display: flex; align-items: center; justify-content: center; font-size: .95rem;
  opacity: 0; transition: opacity .15s ease, background .15s ease;
}
.wq-html-frame-expand-btn:hover { background: rgba(15, 23, 42, .85); }
.wq-html-frame-host:hover .wq-html-frame-expand-btn { opacity: 1; }
.wq-html-frame-host--expand .wq-html-frame-expand-btn { display: none; }

/* Floating bar(s) — quest-html-frame.js now renders up to TWO independent
   bars (`header`/`footer`, each its own instance of this markup) instead of
   one. By default ('auto' visibility) a bar is only ever VISIBLE while the
   host actually covers the viewport, native fullscreen or CSS expand alike
   — hidden in the normal in-canvas state no matter what — UNLESS the bar
   carries the --always modifier (config visibility:'always'), which is
   exempt from that hiding rule and renders inline atop the widget's own box
   even in the plain 'normal' displayMode. */
.wq-html-frame-navheader {
  position: absolute; left: 0; right: 0; z-index: 3;
  /* 3-zone grid (left / center / right), each an `auto`- or `1fr`-sized
     column — see buildNavHeader() in quest-html-frame.js: each column is a
     flex container (.wq-html-frame-navheader-col below) the JS appends
     whichever of the Fichier/Page/Fermer groups belong there into, per that
     bar's own fileNavPosition/pageNavPosition/closePosition. Replaces the
     old fixed 2-group (leftGroup/rightGroup) + align('edges'|'center')
     model — each of the 3 groups is now independently positioned. */
  display: none; grid-template-columns: 1fr auto 1fr; align-items: center;
  padding: 10px 16px; gap: 10px; pointer-events: none;
}
.wq-html-frame-host--fs .wq-html-frame-navheader,
.wq-html-frame-host--expand .wq-html-frame-navheader {
  display: grid;
}
.wq-html-frame-navheader.wq-html-frame-navheader--always {
  display: grid;
}
.wq-html-frame-navheader--top { top: 0; }
.wq-html-frame-navheader--bottom { bottom: 0; }
/* One flex container per grid zone — a zone with nothing routed into it
   (see buildNavHeader()) renders empty, still reserving its grid column, so
   a lone group in "left"/"right" still hugs that edge exactly like the old
   align:'edges' groups did, and "center" behaves like the old align:
   'center' cluster. The 12px gap here is the FIXED spacing used only
   between DIFFERENT groups that happen to share the same zone (e.g.
   fileNavPosition and closePosition both 'left') — distinct from
   `barCfg.btnGap`, which is scoped per-pair via inline style on
   .wq-html-frame-navheader-pair below (the gap WITHIN one pair's own two
   buttons, e.g. Fichier ◀ to Fichier ▶). */
.wq-html-frame-navheader-col { display: flex; align-items: center; gap: 12px; }
.wq-html-frame-navheader-col--left { justify-content: flex-start; }
.wq-html-frame-navheader-col--center { justify-content: center; }
.wq-html-frame-navheader-col--right { justify-content: flex-end; }
/* Wraps just ONE pair's two buttons (Fichier ◀/▶ or Page ◀/▶) so
   `barCfg.btnGap` (quest-html-frame.js's buildNavHeader()) can be applied
   as this element's own inline `style.gap`, scoped to just that pair —
   never bleeding into the fixed 12px above between unrelated groups. */
.wq-html-frame-navheader-pair { display: flex; align-items: center; }
.wq-html-frame-navheader-btn {
  /* --hf-nav-color is set on the header itself (inline style, from
     barCfg.color) ONLY when that bar is color-locked (barCfg.lockColor —
     see buildNavHeader() in quest-html-frame.js); otherwise it's left unset
     on purpose so the fallback chain below applies instead: --wq-gold is
     the platform's own theme accent (defined on .wq-mode-quest above,
     already reused the same way elsewhere in this file, e.g. .wq-qc-opt's
     primary button background), so an unlocked bar's buttons genuinely
     re-theme live if the platform's theme changes — no JS involved. */
  pointer-events: auto; border: none; cursor: pointer;
  font-weight: 800; font-family: inherit; color: #fff; background: var(--hf-nav-color, var(--wq-gold, #d69a3c));
  box-shadow: 0 4px 14px rgba(0, 0, 0, .35);
  /* Phase A (kid/ludique) — rebond tactile au clic, apparié au petit son de
     tapSound() dans quest-html-frame.js. Désactivé pour qui a demandé moins
     de mouvement au niveau OS/navigateur. */
  transition: transform .12s ease;
}
.wq-html-frame-navheader-btn:active { transform: scale(0.88); }
@media (prefers-reduced-motion: reduce) {
  .wq-html-frame-navheader-btn { transition: none; }
  .wq-html-frame-navheader-btn:active { transform: none; }
}
.wq-html-frame-navheader--small .wq-html-frame-navheader-btn { font-size: .68rem; padding: 6px 12px; }
.wq-html-frame-navheader--medium .wq-html-frame-navheader-btn { font-size: .8rem; padding: 8px 16px; }
.wq-html-frame-navheader--large .wq-html-frame-navheader-btn { font-size: .95rem; padding: 10px 22px; }
/* btnShape: 'rounded' (default pill look, same as before this feature),
   'square' (sharp corners), 'circle' (fully round, icon-only content — see
   buildNavHeader() for why only circle swaps to arrow/✕-only labels; the
   fixed width/height here is what keeps a 1-2-char icon visually circular
   instead of oval). */
.wq-html-frame-navheader--shape-rounded .wq-html-frame-navheader-btn { border-radius: 999px; }
.wq-html-frame-navheader--shape-square .wq-html-frame-navheader-btn { border-radius: 6px; }
.wq-html-frame-navheader--shape-circle .wq-html-frame-navheader-btn {
  border-radius: 50%; padding: 0; display: flex; align-items: center; justify-content: center;
}
.wq-html-frame-navheader--shape-circle.wq-html-frame-navheader--small .wq-html-frame-navheader-btn { width: 28px; height: 28px; font-size: .8rem; }
.wq-html-frame-navheader--shape-circle.wq-html-frame-navheader--medium .wq-html-frame-navheader-btn { width: 36px; height: 36px; font-size: .95rem; }
.wq-html-frame-navheader--shape-circle.wq-html-frame-navheader--large .wq-html-frame-navheader-btn { width: 44px; height: 44px; font-size: 1.1rem; }
/* "Fichier ◀/▶" disable at the ends instead of wrapping (same convention as
   html-viewer-player.php's hvPrev/hvNext) once currentPageIndex hits either
   edge of pages[]. */
.wq-html-frame-navheader-btn:disabled { opacity: .35; cursor: not-allowed; box-shadow: none; }

/* Phase D (kid/ludique) — confettis de fin, seulement au moment où on
   ATTEINT le dernier fichier de la séquence en avançant (voir burstConfetti()
   dans quest-html-frame.js). z-index 2 : au-dessus de l'iframe (auto),
   sous la barre de nav (3), pour ne jamais gêner un bouton. */
.wq-html-frame-confetti { position: absolute; inset: 0; z-index: 2; pointer-events: none; overflow: hidden; }
.wq-html-frame-confetti span {
  position: absolute; top: -10%; width: 7px; height: 12px; opacity: 0;
  animation: wq-hf-confetti-fall 1.1s ease-in forwards;
}
@keyframes wq-hf-confetti-fall {
  0% { opacity: 1; transform: translateY(0) rotate(0deg); }
  100% { opacity: 0; transform: translateY(220%) rotate(340deg); }
}
@media (prefers-reduced-motion: reduce) { .wq-html-frame-confetti { display: none; } }

/* ---------- Shared embed lightbox (popup) — first used by quest-iframe.js
   and icon_button.js's "Popup — iFrame" action, deliberately generic
   (wq-embed-*, not wq-iframe-*): quest-video.js, quest-wordwall.js and
   icon_button.js's own popup_video/popup_image/popup_text each already
   carry their own near-identical lightbox; a future pass could point them
   at this one instead of a 4th/5th copy.
   Deliberately NOT aspect-ratio-clamped: an arbitrary embedded page is
   rarely actually 16:9, and locking the box to a ratio just wastes viewport
   space and forces an inner scrollbar for no reason — this popup exists to
   give the embed as much room as the screen can spare. */
.wq-embed-lightbox {
  position: fixed; inset: 0; z-index: 99999;
  background: rgba(4, 8, 20, .9);
  display: flex; align-items: center; justify-content: center;
  padding: 2vh 2vw;
}
.wq-embed-lightbox-inner {
  position: relative; width: min(97vw, 1400px); height: min(94vh, 980px);
  background: var(--eb-bg, #0f172a); border-radius: var(--eb-radius, 14px);
  overflow: hidden; box-shadow: 0 24px 60px rgba(0, 0, 0, .5);
  display: flex; flex-direction: column;
}
/* En-tête réduit au strict nécessaire (titre + fermer) : la place qu'il
   prend est de la place qu'on retire à l'embed lui-même. */
.wq-embed-lightbox-header {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 5px 10px 5px 14px; background: var(--eb-accent, #6366f1); color: #fff;
  font-weight: 800; font-size: .78rem; flex: 0 0 auto; min-height: 34px;
}
.wq-embed-lightbox-close {
  border: none; background: rgba(255, 255, 255, .2); color: #fff;
  width: 24px; height: 24px; border-radius: 50%; cursor: pointer;
  display: flex; align-items: center; justify-content: center; font-size: .85rem; flex: 0 0 auto;
}
.wq-embed-lightbox-close:hover { background: rgba(255, 255, 255, .32); }
.wq-embed-lightbox-body { position: relative; flex: 1; min-height: 0; }
.wq-embed-lightbox-body iframe {
  position: absolute; inset: 0; width: 100%; height: 100%; border: none; display: block;
  transition: opacity .2s ease;
}
@media (max-width: 640px) {
  .wq-embed-lightbox { padding: 0; }
  .wq-embed-lightbox-inner { width: 100vw; height: 100vh; border-radius: 0; }
}

/* Retry state -- shown instead of an endlessly-spinning loader once the
   iframe has been stuck past a reasonable timeout, or the browser is known
   to be offline. A cross-origin iframe has no reliable "failed" signal, so
   this timeout+offline-check combo is the practical substitute. */
.wq-wordwall-error {
  position: absolute; inset: 0; z-index: 3; display: none;
  flex-direction: column; align-items: center; justify-content: center; gap: 14px;
  background: var(--ww-bg, #0f172a); text-align: center; padding: 20px;
}
.wq-wordwall-error.show { display: flex; }
.wq-wordwall-error-msg { color: #e2e8f0; font-weight: 700; font-size: .85rem; max-width: 280px; margin: 0; }
.wq-wordwall-retry {
  width: 64px; height: 64px; border-radius: 50%; border: none; cursor: pointer;
  background: #dc2626; color: #fff; font-size: 1.8rem;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 8px 20px rgba(220, 38, 38, .4);
  transition: transform .1s ease, box-shadow .1s ease;
}
.wq-wordwall-retry:hover { transform: scale(1.06); box-shadow: 0 10px 24px rgba(220, 38, 38, .5); }
.wq-wordwall-retry:active { transform: scale(.96); }

/* ═══════════════════════════════════════════════════════════════════════
   VISIONNEUSE D'IMAGE (image_viewer) & COMPARATEUR (image_compare)
   Parti pris : la scène occupe 100 % de la zone posée sur la page, et les
   contrôles FLOTTENT par-dessus. Rien ne vole de hauteur à l'image — c'est
   la condition du « maximum de visualisation ». Le plein écran est une
   option, jamais le mode d'affichage par défaut.
   ═══════════════════════════════════════════════════════════════════════ */

/* CONFINEMENT — la zone posée sur la page est une limite absolue. Ceinture
   (overflow sur le conteneur) ET bretelles (contraintes sur l'image elle-même),
   pour qu'aucun cas de figure ne laisse l'image déborder du canvas. Seul le
   ruban adhésif rouvre le débordement : son bout dépasse par construction. */
.wq-imgview, .wq-imgcmp {
  box-sizing: border-box; overflow: hidden; contain: layout paint;
}
.wq-imgview.wq-iv-frame-tape, .wq-imgcmp.wq-iv-frame-tape { overflow: visible; contain: layout; }
.wq-iv-img, .wq-cmp-img, .wq-iv-nav-img { max-width: 100%; max-height: 100%; }

/* Cartouche d'invite quand rien n'est configuré (éditeur + player) */
.wq-iv-hint {
  display: flex; align-items: center; justify-content: center;
  width: 100%; height: 100%; box-sizing: border-box; padding: 8px;
  text-align: center; border: 2px dashed rgba(61, 110, 140, .5); border-radius: 10px;
  background: rgba(61, 110, 140, .06); color: #3d6e8c; font-size: .8rem; line-height: 1.35;
}

/* ── Scène ─────────────────────────────────────────────────────────────
   SEUL endroit du thème à garder `touch-action: none`. Partout ailleurs il
   est passé à `pinch-zoom` pour rendre le pincement au navigateur (le
   glisser à un doigt reste au widget). Ici c'est l'inverse : la Visionneuse
   implémente SON PROPRE pincement (createZoomEngine) — lui rendre le geste
   natif casserait son zoom à deux doigts, qui est sa raison d'être. */
.wq-iv-stage {
  position: relative; width: 100%; height: 100%; overflow: hidden;
  border-radius: inherit; touch-action: none;
}
.wq-iv-img {
  position: absolute; inset: 0; width: 100%; height: 100%; display: block;
  transform-origin: center center; will-change: transform;
  transition: transform .12s ease-out, filter .25s ease;
  user-select: none; -webkit-user-drag: none;
}
.wq-iv-stage.is-zoomed .wq-iv-img { cursor: grab; transition: transform .06s linear; }
.wq-iv-stage.is-grabbing .wq-iv-img { cursor: grabbing; }
/* Molette/trackpad en rafale : zéro transition, suivi 1:1 (cf. createZoomEngine) */
.wq-iv-img.wq-iv-instant { transition: none !important; }

/* ── Contrôles superposés ──────────────────────────────────────────── */
.wq-iv-ctrl {
  position: absolute; z-index: 4; display: flex; gap: 4px; padding: 4px;
  border-radius: 999px; background: rgba(15, 23, 42, .55);
  backdrop-filter: blur(6px); opacity: 0; transition: opacity .18s ease;
}
.wq-imgview:hover .wq-iv-ctrl, .wq-iv-ctrl.is-always { opacity: 1; }
.wq-iv-ctrl-br { right: 10px; bottom: 10px; }
.wq-iv-ctrl-bl { left: 10px; bottom: 10px; }
.wq-iv-ctrl-tr { right: 10px; top: 10px; }
.wq-iv-ctrl-tl { left: 10px; top: 10px; }
.wq-iv-ctrl-tc { top: 10px; left: 50%; transform: translateX(-50%); }
.wq-iv-ctrl-bc { bottom: 10px; left: 50%; transform: translateX(-50%); }
.wq-iv-btn {
  width: var(--wq-iv-btn-size, 30px); height: var(--wq-iv-btn-size, 30px);
  min-width: var(--wq-iv-btn-size, 30px);
  border: none; border-radius: 50%; cursor: pointer;
  background: var(--wq-iv-btn-bg, #fff); color: var(--wq-iv-btn-ink, #0f172a);
  font-size: calc(var(--wq-iv-btn-size, 30px) * .42); font-weight: 700; line-height: 1;
  display: flex; align-items: center; justify-content: center;
  transition: transform .1s ease, opacity .1s ease;
}
.wq-iv-btn:hover { transform: scale(1.08); }
.wq-iv-btn:active { transform: scale(.94); }
/* Forme */
.wq-iv-btn-circle .wq-iv-btn { border-radius: 50%; }
.wq-iv-btn-round  .wq-iv-btn { border-radius: 9px; }
.wq-iv-btn-square .wq-iv-btn { border-radius: 3px; }
/* Style */
.wq-iv-bs-glass   .wq-iv-btn { background: color-mix(in srgb, var(--wq-iv-btn-bg, #fff) 88%, transparent); backdrop-filter: blur(4px); }
.wq-iv-bs-solid   .wq-iv-btn { background: var(--wq-iv-btn-bg, #fff); box-shadow: 0 2px 8px rgba(0, 0, 0, .28); }
.wq-iv-bs-outline .wq-iv-btn { background: transparent; border: 2px solid var(--wq-iv-btn-bg, #fff); color: var(--wq-iv-btn-bg, #fff); }
.wq-iv-bs-ghost   .wq-iv-btn { background: transparent; color: var(--wq-iv-btn-bg, #fff); text-shadow: 0 1px 4px rgba(0, 0, 0, .6); }
.wq-iv-bs-ghost .wq-iv-ctrl, .wq-iv-bs-outline .wq-iv-ctrl { background: transparent; backdrop-filter: none; }

/* ── Explorateur (mini-carte) ── overlay flottant, PAR-DESSUS la scène,
   jamais docké : ne vole plus jamais de largeur à l'image. Positionné dans
   le coin opposé aux contrôles (calculé en JS, cf. buildNav) pour ne jamais
   les chevaucher. Masqué par défaut (`is-visible` le montre) : soit
   automatiquement pendant un zoom (zone assez grande), soit via le bouton
   🗺 de la barre de contrôles sur les petites zones. */
.wq-iv-nav {
  position: absolute; z-index: 5; box-sizing: border-box; overflow: hidden;
  cursor: crosshair; min-width: 90px; min-height: 70px;
  background: rgba(15, 23, 42, .68); border: 1px solid rgba(255, 255, 255, .22);
  border-radius: 8px; box-shadow: 0 8px 22px rgba(0, 0, 0, .35);
  opacity: 0; pointer-events: none; transition: opacity .18s ease;
}
.wq-iv-nav.is-visible { opacity: 1; pointer-events: auto; }
.wq-iv-nav-tl { top: 10px; left: 10px; }
.wq-iv-nav-tr { top: 10px; right: 10px; }
.wq-iv-nav-bl { bottom: 10px; left: 10px; }
.wq-iv-nav-br { bottom: 10px; right: 10px; }
.wq-iv-nav-tc { top: 10px; left: 50%; transform: translateX(-50%); }
.wq-iv-nav-bc { bottom: 10px; left: 50%; transform: translateX(-50%); }
.wq-iv-nav-img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: contain; opacity: .85; user-select: none; -webkit-user-drag: none;
}
.wq-iv-nav-view {
  position: absolute; box-sizing: border-box; pointer-events: none;
  border: 2px solid #fff; border-radius: 3px;
  box-shadow: 0 0 0 9999px rgba(15, 23, 42, .38); transition: all .1s linear;
}

/* ── Effets d'apparition (joueur seulement) ────────────────────────── */
@keyframes wqIvFade    { from { opacity: 0; } to { opacity: 1; } }
@keyframes wqIvZoomIn  { from { opacity: 0; transform: scale(1.14); } to { opacity: 1; transform: scale(1); } }
@keyframes wqIvBlurIn  { from { opacity: 0; filter: blur(14px); } to { opacity: 1; filter: blur(0); } }
@keyframes wqIvCurtain { from { clip-path: inset(0 50% 0 50%); } to { clip-path: inset(0 0 0 0); } }
@keyframes wqIvKen     { from { transform: scale(1) translate(0, 0); } to { transform: scale(1.12) translate(-2%, -2%); } }
@keyframes wqIvShine   { from { left: -60%; } to { left: 130%; } }

.wq-iv-fx-fade     .wq-iv-img { animation: wqIvFade .55s ease both; }
.wq-iv-fx-zoomin   .wq-iv-img { animation: wqIvZoomIn .6s cubic-bezier(.22, .9, .3, 1) both; }
.wq-iv-fx-blurin   .wq-iv-img { animation: wqIvBlurIn .75s ease both; }
.wq-iv-fx-curtain  .wq-iv-stage { animation: wqIvCurtain .7s cubic-bezier(.5, 0, .2, 1) both; }
.wq-iv-fx-kenburns .wq-iv-img { animation: wqIvKen 18s ease-in-out infinite alternate; }
/* Éclat : une bande lumineuse balaie l'image une fois */
.wq-iv-fx-shine .wq-iv-stage::after {
  content: ''; position: absolute; top: -20%; bottom: -20%; width: 45%; z-index: 3;
  pointer-events: none; transform: skewX(-18deg);
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .42), transparent);
  animation: wqIvShine 1.5s ease-out .25s both;
}

/* ── Effets au survol ──────────────────────────────────────────────── */
.wq-iv-hx-lift     { transition: transform .22s ease, box-shadow .22s ease; }
.wq-iv-hx-lift:hover     { transform: translateY(-4px); box-shadow: 0 16px 34px rgba(0, 0, 0, .3); }
.wq-iv-hx-glow           { transition: box-shadow .25s ease; }
.wq-iv-hx-glow:hover     { box-shadow: 0 0 0 3px rgba(99, 102, 241, .55), 0 0 26px rgba(99, 102, 241, .5); }
.wq-iv-hx-tilt           { transition: transform .25s ease; }
.wq-iv-hx-tilt:hover     { transform: perspective(700px) rotateX(3deg) rotateY(-3deg) scale(1.015); }
.wq-iv-hx-saturate .wq-iv-img { transition: filter .3s ease; }
.wq-iv-hx-saturate:hover .wq-iv-img { filter: saturate(1.45) contrast(1.06); }
/* Aperçu figé côté éditeur : montre où les contrôles apparaîtront */
.wq-iv-ctrl-ghost { opacity: .45; pointer-events: none; }
.wq-iv-ctrl-ghost span {
  width: 30px; height: 30px; border-radius: 50%; background: rgba(255, 255, 255, .8);
  color: #0f172a; font-size: .8rem; display: flex; align-items: center; justify-content: center;
}

/* ── Loupe ─────────────────────────────────────────────────────────── */
.wq-iv-lens {
  position: absolute; z-index: 3; pointer-events: none; border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, .9); background-repeat: no-repeat;
  box-shadow: 0 6px 22px rgba(0, 0, 0, .35); opacity: 0; transition: opacity .12s ease;
}
.wq-iv-lens.on { opacity: 1; }

/* ---------- Labo Détective (quest-svt-lab.js) ----------
   En colonne : en-tête (titre + onglets) → scène (flex:1) → deux bandeaux
   de pied de page (zoom, puis outils) — façon référence fournie ("THE LAB"). */
.wq-svt-lab {
  position: relative; overflow: hidden; border-radius: 12px; background: #0f172a;
  display: flex; flex-direction: column;
}
/* ---- En-tête : DEUX bandeaux séparés (demandé, "exactement comme la
   référence") — signalé que les entasser dans un seul bloc sombre ne
   correspondait pas à la maquette fournie : la fine barre de titre reste
   sombre, les onglets vivent sur le fond clair du Labo juste en dessous. ---- */
.wq-svt-titlebar { flex: 0 0 auto; background: #1e293b; padding: 8px 12px; }
.wq-svt-title {
  color: #fff; font: 800 1rem/1.2 'Outfit', 'Cairo', sans-serif; text-align: center;
  letter-spacing: .5px; text-transform: uppercase;
}
/* Sous-titre (demandé, "beautiful title and subtitle") — plus discret que
   le titre, juste en dessous. */
.wq-svt-subtitle {
  color: #94a3b8; font: 600 .74rem 'Outfit', 'Cairo', sans-serif; text-align: center;
  margin-top: -2px;
}
/* Onglets colorés (demandé, "colorful with hover effect", "sur fond clair
   comme la référence") — rangée de carrés arrondis SUR LE FOND CLAIR du
   Labo (pas dans la barre sombre), dégradé + relief pour lire "vraie
   pastille" plutôt qu'un simple aplat, et un vrai hover distinct de l'état
   actif (avant : seule l'opacité changeait, jamais testée au survol). */
.wq-svt-tabs {
  flex: 0 0 auto; display: flex; justify-content: center; gap: 8px;
  overflow-x: auto; overflow-y: hidden; background: #fffdf6; padding: 8px 10px;
}
.wq-svt-tabbtn {
  flex: 0 0 auto; width: 48px; height: 48px; border-radius: 14px; border: none; cursor: pointer;
  background: linear-gradient(150deg, var(--wq-svt-tab-c, #8b5cf6), color-mix(in srgb, var(--wq-svt-tab-c, #8b5cf6) 70%, #000));
  color: #fff; font-size: 1.4rem;
  display: flex; align-items: center; justify-content: center;
  opacity: .62; transform: scale(.88); transition: opacity .15s ease, transform .15s ease, box-shadow .15s ease;
  box-shadow: 0 3px 8px rgba(0,0,0,.3);
}
.wq-svt-tabbtn:hover { opacity: .85; transform: scale(.96); box-shadow: 0 5px 12px rgba(0,0,0,.4); }
.wq-svt-tabbtn.active { opacity: 1; transform: scale(1.05); box-shadow: 0 6px 16px rgba(0,0,0,.45), 0 0 0 2px #fff inset; }
/* ---- Scène ---- */
.wq-svt-stage { position: relative; flex: 1 1 auto; min-height: 0; }
.wq-svt-zoomwrap { position: absolute; inset: 0; transition: transform .25s cubic-bezier(.2,.8,.2,1); transform-origin: center; }
.wq-svt-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; user-select: none; }
.wq-svt-hint {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  color: #94a3b8; font: 700 .82rem 'Outfit', sans-serif; text-align: center; padding: 10px;
}
.wq-svt-toolbar-preview {
  position: absolute; left: 6px; bottom: 6px; font-size: 1rem;
  background: rgba(15,23,42,.7); border-radius: 999px; padding: 3px 8px;
}
/* Loupe "plus belle, cadre et skin" (demandé) — anneau métallique double +
   poignée en biais façon vraie loupe, posés SUR .wq-iv-lens (garde son
   fond/position déjà calculés en JS) sans dupliquer cette règle partagée. */
.wq-svt-lens {
  border: 4px solid #fef3c7; box-shadow:
    0 0 0 3px #92400e, 0 8px 22px rgba(0,0,0,.45), inset 0 0 18px rgba(0,0,0,.25);
}
.wq-svt-lens::after {
  content: ''; position: absolute; right: -8px; bottom: -26px;
  width: 12px; height: 34px; border-radius: 6px;
  background: linear-gradient(135deg, #92400e, #451a03);
  transform: rotate(45deg); transform-origin: top center;
  box-shadow: 0 2px 6px rgba(0,0,0,.4);
}
/* Skin Rayons X (demandé, "loupe et rayons X se ressemblent") — cadre bleu
   "scanner" sans poignée (:not() annule la poignée dorée héritée ci-dessus),
   avec un balayage lumineux animé façon appareil médical. */
.wq-svt-lens.wq-svt-lens-xray {
  border: 4px solid #38bdf8; box-shadow:
    0 0 0 3px #0c4a6e, 0 0 24px 4px rgba(56,189,248,.5), inset 0 0 18px rgba(0,0,0,.4);
}
.wq-svt-lens.wq-svt-lens-xray::after { display: none; }
.wq-svt-lens.wq-svt-lens-xray::before {
  content: ''; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: linear-gradient(180deg, transparent 0%, rgba(56,189,248,.35) 48%, transparent 52%);
  background-size: 100% 220%;
  animation: wqSvtXrayScan 1.6s linear infinite;
}
@keyframes wqSvtXrayScan {
  0% { background-position: 0 0; }
  100% { background-position: 0 -220%; }
}
/* Main ludique (demandé) — remplace le curseur système pendant qu'un outil-
   lentille est actif (voir .wq-svt-tool-active ci-dessous, cursor:none). */
.wq-svt-hand {
  position: absolute; z-index: 8; font-size: 1.6rem; pointer-events: none;
  opacity: 0; transition: opacity .1s ease; filter: drop-shadow(0 3px 4px rgba(0,0,0,.4));
  transform: rotate(-15deg);
}
.wq-svt-hand.on { opacity: 1; }
.wq-svt-stage.wq-svt-tool-active { cursor: none; }
/* Badge de grossissement en direct (demandé, "live zoom") */
.wq-svt-lens-zoombadge {
  position: absolute; z-index: 8; transform: translate(-50%, -100%);
  background: #1e293b; color: #fde68a; font: 800 .72rem 'Outfit', sans-serif;
  padding: 3px 8px; border-radius: 999px; opacity: 0; pointer-events: none;
  transition: opacity .1s ease; white-space: nowrap;
}
.wq-svt-lens-zoombadge.on { opacity: 1; }
/* Doodle — dessin libre (demandé, "movable doodle tools + undo/redo") */
.wq-svt-doodle {
  position: absolute; inset: 0; z-index: 6; pointer-events: none; touch-action: none; cursor: crosshair;
}
/* Panneau doodle (demandé, "plus grand, déplaçable, barre sticky façon
   appli Android") — signalé "où est le côté nav Android" : le premier essai
   était une pilule flottante CENTRÉE avec des marges de chaque côté, donc
   lisait comme une bulle d'action plutôt qu'une VRAIE barre de navigation.
   Corrigé : bord à bord (left:0/right:0/bottom:0), coins arrondis SEULEMENT
   en haut — exactement la forme d'une bottom nav bar Android, collée aux
   trois bords. .wq-svt-doodle-free (posée au premier glissé de la poignée)
   redevient une pilule flottante, puisqu'une fois détachée elle n'est plus
   une "barre" mais un panneau libre. */
.wq-svt-doodle-panel {
  display: none; position: absolute; left: 0; right: 0; bottom: 0;
  z-index: 8; align-items: center; justify-content: center; gap: 10px; background: #fff;
  border-radius: 18px 18px 0 0; padding: 10px 14px; box-shadow: 0 -6px 20px rgba(0,0,0,.25);
  overflow-x: auto;
}
.wq-svt-doodle-panel.on { display: flex; }
.wq-svt-doodle-panel.wq-svt-doodle-free {
  left: auto; right: auto; bottom: auto; border-radius: 999px;
  box-shadow: 0 8px 24px rgba(0,0,0,.35); max-width: calc(100% - 20px);
}
.wq-svt-doodle-grip {
  flex: 0 0 auto; width: 26px; height: 40px; border-radius: 10px; background: #f1f5f9;
  color: #94a3b8; font-size: 1.1rem; cursor: grab; touch-action: none;
  display: flex; align-items: center; justify-content: center;
}
.wq-svt-doodle-grip:active { cursor: grabbing; background: #e2e8f0; }
.wq-svt-doodle-group { display: flex; gap: 6px; }
.wq-svt-doodle-style {
  flex: 0 0 auto; width: 44px; height: 44px; border-radius: 12px; border: 1px solid #e2e8f0; background: #f8fafc;
  color: #1e293b; font-size: 1.2rem; cursor: pointer; display: flex; align-items: center; justify-content: center;
  transition: background .12s ease, transform .1s ease;
}
.wq-svt-doodle-style:hover { background: #eef2ff; transform: translateY(-1px); }
.wq-svt-doodle-style.active { background: #1e293b; color: #fff; border-color: #1e293b; }
.wq-svt-doodle-swatches { display: flex; gap: 8px; margin-left: 4px; padding-left: 10px; border-left: 1px solid #e2e8f0; }
.wq-svt-doodle-swatch {
  flex: 0 0 auto; width: 34px; height: 34px; border-radius: 50%; border: 2px solid #fff; box-shadow: 0 0 0 1px #e2e8f0; cursor: pointer;
  transition: transform .1s ease;
}
.wq-svt-doodle-swatch:hover { transform: scale(1.1); }
.wq-svt-doodle-swatch.active { box-shadow: 0 0 0 3px #1e293b; }
/* Carte "preuve de détective" (demandé, "screenshot confirmation, beautiful
   wow") — confirmation façon photo Polaroid tamponnée, avec quelques
   étincelles de célébration, plutôt qu'un téléchargement instantané muet. */
.wq-svt-evidence-overlay {
  position: absolute; inset: 0; z-index: 9; display: flex; align-items: center; justify-content: center;
  background: rgba(15,23,42,.6); backdrop-filter: blur(3px);
  opacity: 0; pointer-events: none; transition: opacity .2s ease;
}
.wq-svt-evidence-overlay.on { opacity: 1; pointer-events: auto; }
.wq-svt-evidence-card {
  position: relative; background: #fffdf6; border-radius: 14px; padding: 14px 16px 16px;
  width: min(240px, 82%); box-shadow: 0 24px 60px rgba(0,0,0,.5);
  transform: rotate(-2deg) scale(.9); transition: transform .25s cubic-bezier(.2,.8,.2,1);
  text-align: center;
}
.wq-svt-evidence-overlay.on .wq-svt-evidence-card { transform: rotate(-2deg) scale(1); }
.wq-svt-evidence-stamp {
  position: absolute; top: -10px; right: -10px; transform: rotate(12deg);
  background: #ef4444; color: #fff; font: 800 .62rem 'Outfit', sans-serif; letter-spacing: .5px;
  padding: 4px 8px; border-radius: 6px; border: 2px solid #fff; box-shadow: 0 3px 8px rgba(0,0,0,.3);
}
.wq-svt-evidence-photo {
  border: 1px solid #e2e8f0; border-radius: 8px; overflow: hidden; margin-bottom: 8px;
  box-shadow: inset 0 0 0 6px #fff;
}
.wq-svt-evidence-photo img { display: block; width: 100%; height: auto; }
.wq-svt-evidence-title { font: 800 .88rem 'Outfit', 'Cairo', sans-serif; color: #1e293b; }
.wq-svt-evidence-sub { font: 600 .68rem 'Outfit', sans-serif; color: #64748b; margin: 2px 0 10px; }
.wq-svt-evidence-actions { display: flex; gap: 8px; }
.wq-svt-evidence-btn {
  flex: 1; padding: 8px 6px; border: none; border-radius: 999px; cursor: pointer;
  font: 700 .68rem 'Outfit', sans-serif;
}
.wq-svt-evidence-dl { background: #1e293b; color: #fff; }
.wq-svt-evidence-close { background: #f1f5f9; color: #475569; }
.wq-svt-evidence-spark {
  position: absolute; font-size: 1.1rem; pointer-events: none;
  animation: wqSvtEvidenceSpark .9s ease-out forwards;
}
@keyframes wqSvtEvidenceSpark {
  to { transform: translate(var(--dx), var(--dy)) rotate(360deg); opacity: 0; }
}
/* Annuler/rétablir — haut-gauche, façon référence, visibles seulement en
   mode Doodle (ils n'agissent que sur les traits, pas sur les autres outils). */
.wq-svt-undoredo { display: none; position: absolute; left: 10px; top: 10px; z-index: 8; gap: 6px; }
.wq-svt-undoredo.on { display: flex; }
.wq-svt-ur-btn {
  width: 34px; height: 34px; border-radius: 50%; border: none; cursor: pointer;
  background: #fff; color: #1e293b; font-size: 1.1rem; box-shadow: 0 3px 8px rgba(0,0,0,.3);
  display: flex; align-items: center; justify-content: center;
}
.wq-svt-ur-btn:disabled { opacity: .35; cursor: default; }
/* Bouton maison (mode immersif) */
.wq-svt-home {
  position: absolute; left: 10px; top: 10px; z-index: 7;
  width: 40px; height: 40px; border-radius: 50%; border: 2px solid #fff;
  background: rgba(15,23,42,.75); color: #fff; font-size: 1.05rem; cursor: pointer;
  align-items: center; justify-content: center; box-shadow: 0 3px 10px rgba(0,0,0,.4);
}
.wq-svt-home:hover { background: #1e293b; }
/* Repère numéroté — cliquable en jeu, simple pastille statique dans l'éditeur. */
.wq-svt-pin {
  position: absolute; z-index: 4; width: 24px; height: 24px; margin: -12px 0 0 -12px;
  border-radius: 50%; background: #f59e0b; color: #1e293b; border: 2px solid #fff;
  font: 800 .72rem 'Outfit', sans-serif; display: flex; align-items: center; justify-content: center;
  cursor: pointer; box-shadow: 0 2px 8px rgba(0,0,0,.35); padding: 0;
  animation: wqSvtPinPulse 1.8s ease-in-out infinite;
}
@keyframes wqSvtPinPulse {
  0%, 100% { box-shadow: 0 2px 8px rgba(0,0,0,.35), 0 0 0 0 rgba(245,158,11,.5); }
  50% { box-shadow: 0 2px 8px rgba(0,0,0,.35), 0 0 0 6px rgba(245,158,11,0); }
}
.wq-svt-pin-hidden { display: none; }
.wq-svt-pinpop {
  position: absolute; z-index: 6; max-width: 200px; transform: translate(-50%, -120%);
  background: #1e293b; color: #fff; font-size: .76rem; line-height: 1.4; padding: 7px 10px;
  border-radius: 8px; opacity: 0; pointer-events: none; transition: opacity .15s ease;
}
.wq-svt-pinpop.show { opacity: 1; }
/* ---- Pied de page n°1 : sous-outils de l'outil sélectionné (demandé,
   "au lieu du zoom, exposer les sous-outils, zone colorée et boutons") —
   repliée quand aucun outil actif, colorée selon l'outil sinon (variables
   posées par .wq-svt-subbar-{mag|xray|pins|doodle}, mêmes teintes que les
   boutons d'outils pour que la zone se lise comme "appartenant" au bouton
   actif). ---- */
.wq-svt-subbar {
  display: none; flex: 0 0 auto; align-items: center; justify-content: center;
  gap: 14px; padding: 10px 14px; flex-wrap: wrap;
  background: #0b1220; transition: background .15s ease;
}
.wq-svt-subbar.on { display: flex; }
.wq-svt-subbar-mag { background: linear-gradient(#3b2a63, #0b1220); }
.wq-svt-subbar-xray { background: linear-gradient(#1e3a63, #0b1220); }
.wq-svt-subbar-pins { background: linear-gradient(#5c3a0b, #0b1220); }
.wq-svt-subbar-doodle { background: linear-gradient(#5c1f1f, #0b1220); }
.wq-svt-subrow { display: flex; align-items: center; gap: 8px; }
.wq-svt-sublbl { color: #cbd5e1; font: 700 .74rem 'Outfit', sans-serif; }
.wq-svt-subval { color: #fff; font: 800 .8rem 'Outfit', sans-serif; min-width: 3.2em; text-align: center; }
.wq-svt-substep {
  width: 30px; height: 30px; border-radius: 50%; border: none; cursor: pointer;
  background: rgba(255,255,255,.16); color: #fff; font-size: .85rem;
  display: flex; align-items: center; justify-content: center; transition: background .12s ease, transform .1s ease;
}
.wq-svt-substep:hover { background: rgba(255,255,255,.28); }
.wq-svt-substep:active { transform: scale(.9); }
.wq-svt-subhint { color: #fde68a; font: 700 .78rem 'Outfit', sans-serif; text-align: center; }
/* ---- Pied de page n°2 : outils (Loupe/Rayons X/Repères), boutons ronds
   colorés et ludiques (demandé) plutôt que des icônes plates. ---- */
.wq-svt-toolbar {
  flex: 0 0 auto; display: flex; align-items: center; justify-content: center; gap: 10px;
  background: #1e293b; padding: 10px;
}
/* Boutons d'outils (demandé, "enhance the icons and aspect") — dégradé +
   liseré au lieu d'un aplat de couleur, pour un vrai relief façon icône
   d'appli plutôt qu'un simple rond plat. */
.wq-svt-tool {
  width: 48px; height: 48px; border-radius: 50%; border: 2px solid rgba(255,255,255,.25); cursor: pointer;
  background: linear-gradient(150deg, var(--wq-svt-tool-c, #6366f1), color-mix(in srgb, var(--wq-svt-tool-c, #6366f1) 65%, #000));
  color: #fff; font-size: 1.3rem;
  display: flex; align-items: center; justify-content: center;
  opacity: .68; box-shadow: 0 3px 8px rgba(0,0,0,.3);
  transition: opacity .12s ease, transform .12s ease, box-shadow .12s ease;
}
.wq-svt-tool:hover { opacity: .9; transform: translateY(-2px); box-shadow: 0 6px 14px rgba(0,0,0,.4); }
.wq-svt-tool.active { opacity: 1; transform: scale(1.12); box-shadow: 0 6px 16px rgba(0,0,0,.45), 0 0 0 2px #fff inset; }

/* ── Légende ───────────────────────────────────────────────────────── */
.wq-iv-cap { display: flex; flex-direction: column; gap: 2px; padding: 7px 11px; line-height: 1.35; }
.wq-iv-cap-overlay {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2; backdrop-filter: blur(4px);
}
.wq-iv-cap-below { border-radius: 0 0 10px 10px; }
.wq-iv-cap-t { font-size: .82rem; font-weight: 800; }
.wq-iv-cap-p { font-size: .72rem; opacity: .92; }

/* ── Cadres (partagés visionneuse + comparateur) ───────────────────── */
.wq-iv-frame-simple   { border: 3px solid var(--wq-iv-frame-color, #fff); border-radius: 6px; }
.wq-iv-frame-shadow   { box-shadow: 0 14px 34px rgba(0, 0, 0, .38); border-radius: 8px; }
.wq-iv-frame-polaroid {
  background: var(--wq-iv-frame-color, #fff); padding: 10px 10px 30px;
  border-radius: 3px; box-shadow: 0 10px 26px rgba(0, 0, 0, .3);
}
.wq-iv-frame-corners { padding: 8px; }
.wq-iv-frame-corners::before, .wq-iv-frame-corners::after {
  content: ''; position: absolute; width: 20px; height: 20px; z-index: 5;
  border: 3px solid var(--wq-iv-frame-color, #fff);
}
.wq-iv-frame-corners::before { top: 0; left: 0; border-right: none; border-bottom: none; }
.wq-iv-frame-corners::after { bottom: 0; right: 0; border-left: none; border-top: none; }
.wq-iv-frame-tape { padding: 6px; }
.wq-iv-frame-tape::before {
  content: ''; position: absolute; top: -10px; left: 50%; z-index: 5;
  width: 76px; height: 22px; transform: translateX(-50%) rotate(-3deg);
  background: var(--wq-iv-frame-color, #fff); opacity: .78;
  box-shadow: 0 2px 6px rgba(0, 0, 0, .2);
}

/* ── Plein écran (option) ──────────────────────────────────────────── */
.wq-iv-fs {
  position: fixed; inset: 0; z-index: 99999; display: flex;
  align-items: center; justify-content: center;
  background: rgba(8, 12, 22, .93); backdrop-filter: blur(3px);
  animation: wqIvFsIn .16s ease-out;
}
@keyframes wqIvFsIn { from { opacity: 0; } to { opacity: 1; } }
/* La scène du plein écran réutilise .wq-iv-stage/.wq-iv-img tels quels (même
   moteur zoom/pan/pinch, mêmes boutons, même mini-carte) : ce modificateur
   ne fait que caler sa taille sur le viewport, lettrboxing inclus. */
.wq-iv-fs-stage { width: 94vw; height: 92vh; border-radius: 8px; }
.wq-iv-fs-close {
  position: absolute; top: 18px; right: 20px; z-index: 5;
  width: 42px; height: 42px; border: 2px solid rgba(255, 255, 255, .85);
  border-radius: 50%; cursor: pointer; font-size: 1.1rem; font-weight: 700;
  background: #e11d48; color: #fff; box-shadow: 0 4px 14px rgba(0, 0, 0, .45);
}
.wq-iv-fs-close:hover { background: #be123c; }

/* ── Visite guidée : lecture (barre en plein écran) ─────────────────── */
.wq-iv-tour {
  position: absolute; z-index: 6; left: 50%; bottom: 18px; transform: translateX(-50%);
  display: flex; align-items: center; gap: 12px; padding: 8px 14px;
  border-radius: 999px; background: rgba(15, 23, 42, .78); backdrop-filter: blur(6px);
  max-width: 90%;
}
.wq-iv-tour-nav {
  width: 34px; height: 34px; border: none; border-radius: 50%; cursor: pointer;
  background: #fff; color: #0f172a; font-size: .9rem; font-weight: 700;
  display: flex; align-items: center; justify-content: center; flex: 0 0 auto;
}
.wq-iv-tour-nav:disabled { opacity: .35; cursor: default; }
.wq-iv-tour-cap {
  color: #fff; font-size: .82rem; font-weight: 600; text-align: center;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 42vw;
}
.wq-iv-tour-close {
  position: absolute; z-index: 6; left: 50%; bottom: 66px; transform: translateX(-50%);
  border: none; border-radius: 999px; padding: 6px 14px; cursor: pointer;
  background: rgba(255, 255, 255, .12); color: #fff; font-size: .68rem;
  backdrop-filter: blur(4px);
}
.wq-iv-tour-close:hover { background: rgba(255, 255, 255, .22); }

/* ── Visite guidée : modale d'édition des arrêts ─────────────────────── */
.wq-tour-modal {
  position: fixed; inset: 0; z-index: 99999; display: flex;
  align-items: center; justify-content: center;
  background: rgba(8, 12, 22, .72); padding: 20px;
}
.wq-tour-card {
  width: min(480px, 100%); max-height: 90vh; overflow-y: auto;
  background: #fff; border-radius: 12px; padding: 18px;
  box-shadow: 0 20px 50px rgba(0, 0, 0, .4); font-family: inherit;
}
.wq-tour-title { margin: 0 0 12px; font-size: 1rem; font-weight: 800; color: #0f172a; }
.wq-tour-preview {
  position: relative; width: 100%; aspect-ratio: 16 / 10; overflow: hidden;
  border-radius: 8px; background: #0f172a; cursor: crosshair;
}
.wq-tour-preview img { width: 100%; height: 100%; object-fit: contain; user-select: none; -webkit-user-drag: none; }
.wq-tour-marker {
  position: absolute; width: 18px; height: 18px; margin: -9px 0 0 -9px;
  border-radius: 50%; border: 3px solid #f59e0b; background: rgba(245, 158, 11, .35);
  pointer-events: none; box-shadow: 0 0 0 2px rgba(255, 255, 255, .9);
}
.wq-tour-hint { font-size: .68rem; color: #64748b; line-height: 1.5; margin: 8px 0; }
.wq-tour-row { display: flex; align-items: center; gap: 8px; font-size: .74rem; margin: 8px 0; }
.wq-tour-row input[type="range"] { flex: 1; }
.wq-tour-zoomval { font-weight: 700; min-width: 34px; text-align: right; }
.wq-tour-caption-input {
  width: 100%; box-sizing: border-box; padding: 7px 9px; margin: 4px 0 8px;
  border: 1px solid #d8dee9; border-radius: 8px; font-size: .78rem; font-family: inherit;
}
.wq-tour-add {
  width: 100%; padding: 9px; border: none; border-radius: 9px; cursor: pointer;
  background: #6366f1; color: #fff; font-weight: 700; font-size: .78rem;
}
.wq-tour-list { margin-top: 12px; border-top: 1px solid #e2e8f0; padding-top: 10px; }
.wq-tour-empty { font-size: .74rem; color: #94a3b8; margin: 0; }
.wq-tour-item {
  display: flex; align-items: center; gap: 6px; padding: 6px 0;
  border-bottom: 1px solid #f1f5f9; font-size: .74rem;
}
.wq-tour-item-lbl { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wq-tour-item button {
  width: 24px; height: 24px; border: 1px solid #d8dee9; border-radius: 6px;
  background: #fff; cursor: pointer; font-size: .72rem; flex: 0 0 auto;
}
.wq-tour-item button:disabled { opacity: .35; cursor: default; }
.wq-tour-close {
  width: 100%; margin-top: 14px; padding: 9px; border: 1px solid #d8dee9; border-radius: 9px;
  background: #fff; cursor: pointer; font-size: .78rem; font-weight: 600;
}

/* ── Coquille de réglages partagée (settings-shell.js) ──────────────────
   Deux rendus pour les MÊMES onglets : replié dans le panneau latéral
   (le canvas reste visible pendant qu'on règle) ou en popup (de la place
   pour les panneaux riches). La bascule ⤢/⇤ est mémorisée. */

/* Rendu popup */
.wq-set-modal {
  position: fixed; inset: 0; z-index: 99999; display: flex;
  align-items: center; justify-content: center;
  background: rgba(8, 12, 22, .72); padding: 20px;
}
.wq-set-card {
  width: min(640px, 100%); max-height: 88vh; display: flex; flex-direction: column;
  background: #fff; border-radius: 12px; box-shadow: 0 20px 50px rgba(0, 0, 0, .4);
  font-family: inherit; overflow: hidden;
}
.wq-set-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 18px; border-bottom: 1px solid #e2e8f0; flex: 0 0 auto;
}
.wq-set-head h3 { margin: 0; font-size: 1rem; font-weight: 800; color: #0f172a; }
.wq-set-headtools { display: flex; align-items: center; gap: 6px; }
.wq-set-close {
  width: 30px; height: 30px; border: none; border-radius: 50%; cursor: pointer;
  background: #f1f5f9; color: #0f172a; font-size: .9rem;
}
.wq-set-close:hover { background: #e2e8f0; }
.wq-set-top { padding: 10px 18px 0; flex: 0 0 auto; }
.wq-set-card > .wq-set-tabs { padding: 10px 18px 0; }
.wq-set-card > .wq-set-body { padding: 16px 18px; }
.wq-set-card > .wq-set-foot { padding: 12px 18px; }

/* Rendu panneau latéral */
.wq-set-inline-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 6px; margin-bottom: 8px;
}
.wq-set-inline-title {
  font-size: .68rem; font-weight: 800; text-transform: uppercase;
  letter-spacing: .4px; color: #64748b;
}
.wq-set-modebtn {
  width: 26px; height: 26px; flex: 0 0 auto; border: 1px solid #d8dee9;
  border-radius: 7px; background: #fff; cursor: pointer; font-size: .8rem; color: #0f172a;
}
.wq-set-modebtn:hover { background: #f1f5f9; }
.wq-set-openbtn {
  width: 100%; padding: 10px; border: 1px solid #d8dee9; border-radius: 9px;
  background: #fff; cursor: pointer; font-family: inherit; font-size: .8rem; font-weight: 700;
}
.wq-set-openbtn:hover { background: #f1f5f9; }
.wq-set-inline-link {
  width: 100%; margin-top: 6px; padding: 6px; border: none; background: none;
  cursor: pointer; font-family: inherit; font-size: .66rem; color: #6366f1; text-align: center;
}
.wq-set-inline-link:hover { text-decoration: underline; }
.wq-set-tabsel {
  width: 100%; box-sizing: border-box; padding: 7px 8px; margin-bottom: 10px;
  border: 1px solid #d8dee9; border-radius: 8px; background: #fff;
  font-family: inherit; font-size: .76rem; font-weight: 700;
}

/* Communs aux deux rendus */
.wq-set-tabs {
  display: flex; gap: 4px; border-bottom: 1px solid #e2e8f0;
  flex: 0 0 auto; overflow-x: auto;
}
.wq-set-tab {
  padding: 8px 14px; border: none; border-radius: 8px 8px 0 0; cursor: pointer;
  background: transparent; color: #64748b; font-family: inherit; font-size: .76rem; font-weight: 700;
  white-space: nowrap;
}
.wq-set-tab.active { background: #f1f5f9; color: #0f172a; }
.wq-set-body { overflow-y: auto; flex: 1 1 auto; }
.wq-set-foot {
  display: flex; align-items: center; gap: 8px; flex: 0 0 auto; flex-wrap: wrap;
  padding-top: 12px; margin-top: 12px; border-top: 1px solid #e2e8f0;
}
.wq-set-card > .wq-set-foot { margin-top: 0; background: #f8fafc; }
.wq-set-status {
  flex: 1; min-width: 90px; font-size: .68rem; color: #64748b; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.wq-set-btn {
  padding: 8px 12px; border: 1px solid #d8dee9; border-radius: 8px; cursor: pointer;
  background: #fff; color: #0f172a; font-family: inherit; font-size: .72rem; font-weight: 600;
  flex: 0 0 auto;
}
.wq-set-btn:hover { background: #f1f5f9; }
.wq-set-btn.primary { background: #6366f1; border-color: #6366f1; color: #fff; }
.wq-set-btn.primary:hover { background: #4f46e5; }

/* Presets — au-dessus des onglets, car un preset porte des réglages de
   plusieurs onglets à la fois. */
.wq-iv-presets { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.wq-iv-preset-select {
  flex: 1; min-width: 0; padding: 6px 8px; border: 1px solid #d8dee9;
  border-radius: 8px; font-family: inherit; font-size: .74rem; background: #fff;
}
.wq-iv-preset-btn {
  padding: 6px 10px; border: 1px solid #d8dee9; border-radius: 8px; cursor: pointer;
  background: #fff; color: #0f172a; font-family: inherit; font-size: .72rem; font-weight: 600;
  flex: 0 0 auto; white-space: nowrap;
}
.wq-iv-preset-btn:hover:not(:disabled) { background: #f1f5f9; }
.wq-iv-preset-btn:disabled { opacity: .4; cursor: default; }
.wq-iv-preset-btn.primary { background: #6366f1; border-color: #6366f1; color: #fff; }
.wq-iv-preset-btn.primary:hover:not(:disabled) { background: #4f46e5; }
.wq-iv-preset-btn.danger { color: #be123c; border-color: #fda4af; }
.wq-iv-preset-btn.on { background: #fef3c7; border-color: #f59e0b; color: #92400e; }
.wq-iv-preset-name { display: flex; align-items: center; gap: 6px; margin-top: 6px; }
.wq-iv-preset-name input {
  flex: 1; min-width: 0; padding: 6px 8px; border: 1px solid #d8dee9;
  border-radius: 8px; font-family: inherit; font-size: .74rem;
}
.wq-iv-preset-note { font-size: .66rem; color: #64748b; min-height: 1em; margin-top: 5px; }
.wq-iv-preset-note.bad { color: #be123c; }

/* ═══ COMPARATEUR AVANT / APRÈS ═══════════════════════════════════════ */
.wq-cmp-stage {
  position: relative; width: 100%; height: 100%; overflow: hidden;
  border-radius: inherit; touch-action: pinch-zoom; cursor: ew-resize;
}
.wq-cmp-stage.is-h { cursor: ns-resize; }
.wq-cmp-stage.is-dragging { cursor: grabbing; }
.wq-cmp-img {
  position: absolute; inset: 0; width: 100%; height: 100%; display: block;
  user-select: none; -webkit-user-drag: none;
}
.wq-cmp-b { z-index: 2; }

.wq-cmp-handle {
  position: absolute; z-index: 4; display: flex; align-items: center;
  justify-content: center; background: transparent; outline: none;
}
.is-v .wq-cmp-handle { top: 0; bottom: 0; width: 30px; margin-left: -15px; cursor: ew-resize; }
.is-h .wq-cmp-handle { left: 0; right: 0; height: 30px; margin-top: -15px; cursor: ns-resize; }
/* Le trait lui-même */
.wq-cmp-handle::before {
  content: ''; position: absolute; background: var(--wq-cmp-color, #fff);
  box-shadow: 0 0 10px rgba(0, 0, 0, .35);
}
.is-v .wq-cmp-handle::before { top: 0; bottom: 0; left: 50%; width: var(--wq-cmp-w, 3px); transform: translateX(-50%); }
.is-h .wq-cmp-handle::before { left: 0; right: 0; top: 50%; height: var(--wq-cmp-w, 3px); transform: translateY(-50%); }

.wq-cmp-grip {
  position: relative; z-index: 1; width: 38px; height: 38px; border-radius: 50%;
  background: var(--wq-cmp-color, #fff); color: #0f172a;
  display: flex; align-items: center; justify-content: center;
  font-size: 1rem; font-weight: 800; box-shadow: 0 4px 14px rgba(0, 0, 0, .35);
  transition: transform .1s ease;
}
.wq-cmp-handle:hover .wq-cmp-grip { transform: scale(1.09); }
.wq-cmp-handle:focus-visible .wq-cmp-grip { outline: 3px solid #6366f1; outline-offset: 3px; }
.grip-circle .wq-cmp-grip { width: 22px; height: 22px; }
.is-h .grip-arrows .wq-cmp-grip { transform: rotate(90deg); }

.wq-cmp-lab {
  position: absolute; z-index: 3; padding: 4px 10px; border-radius: 999px;
  font-size: .7rem; font-weight: 700; letter-spacing: .2px;
  backdrop-filter: blur(4px); pointer-events: none;
}
.is-v .lab-a { left: 10px; top: 10px; }
.is-v .lab-b { right: 10px; top: 10px; }
.is-h .lab-a { left: 10px; top: 10px; }
.is-h .lab-b { left: 10px; bottom: 10px; }

/* ═══════════════════════════════════════════════════════════════════════
   PLAN DES PAGES (quest-page-map.js) — vue d'ensemble, réordonnancement au
   glisser-déposer, repères de nature des pages.
   Les repères combinent TOUJOURS une icône/un texte à la couleur : une
   bordure colorée seule ne se lit ni en niveaux de gris ni pour un
   daltonien, et c'est justement l'information qu'on vient chercher ici.
   ═══════════════════════════════════════════════════════════════════════ */
.wq-pm-modal {
  position: fixed; inset: 0; z-index: 99999; display: flex;
  align-items: center; justify-content: center;
  background: rgba(8, 12, 22, .74); padding: 24px;
}
.wq-pm-card {
  width: min(1000px, 100%); max-height: 88vh; display: flex; flex-direction: column;
  background: #fff; border-radius: 14px; box-shadow: 0 24px 60px rgba(0, 0, 0, .45);
  overflow: hidden; font-family: inherit;
}
.wq-pm-head {
  display: flex; align-items: center; gap: 12px; flex: 0 0 auto;
  padding: 14px 20px; border-bottom: 1px solid #e2e8f0;
}
.wq-pm-head h3 { margin: 0; font-size: 1.02rem; font-weight: 800; color: #0f172a; }
.wq-pm-status {
  flex: 1; font-size: .72rem; color: #15803d; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.wq-pm-status.bad { color: #be123c; }
.wq-pm-close {
  width: 32px; height: 32px; flex: 0 0 auto; border: none; border-radius: 50%;
  cursor: pointer; background: #f1f5f9; color: #0f172a; font-size: .95rem;
}
.wq-pm-close:hover { background: #e2e8f0; }
.wq-pm-body { padding: 16px 20px 20px; overflow-y: auto; flex: 1 1 auto; }

.wq-pm-sect {
  font-size: .64rem; font-weight: 800; text-transform: uppercase;
  letter-spacing: .5px; color: #64748b; margin: 14px 0 4px;
}
.wq-pm-body > div:first-child .wq-pm-sect { margin-top: 0; }
.wq-pm-hint { font-size: .68rem; color: #94a3b8; line-height: 1.5; margin: 0 0 10px; }
.wq-pm-empty { font-size: .74rem; color: #94a3b8; margin: 0; }

.wq-pm-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 12px; margin-bottom: 6px;
}
.wq-pm-item {
  border: 2px solid #e2e8f0; border-radius: 10px; padding: 8px; background: #fff;
  display: flex; flex-direction: column; gap: 6px; position: relative;
  transition: border-color .15s ease, box-shadow .15s ease, transform .08s ease;
}
.wq-pm-item.is-draggable { cursor: grab; }
.wq-pm-item.is-draggable:active { cursor: grabbing; }
.wq-pm-item.is-dragging { opacity: .4; transform: scale(.97); }
/* Page ouverte : anneau plein, le repère le plus fort de la grille. */
.wq-pm-item.is-current { border-color: #6366f1; box-shadow: 0 0 0 3px rgba(99, 102, 241, .22); }
.wq-pm-item.is-ghost { border-style: dashed; border-color: #a78bfa; }
.wq-pm-item.is-master { border-color: #f59e0b; }
/* Brouillon : hachures + vignette éteinte — se voit même en noir et blanc. */
.wq-pm-item.is-draft .wq-pm-thumb { filter: grayscale(.85) opacity(.55); }
.wq-pm-item.is-draft .wq-pm-thumb::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: repeating-linear-gradient(45deg,
    rgba(100, 116, 139, .16) 0 6px, transparent 6px 12px);
}
/* Trait d'insertion pendant le glisser */
.wq-pm-item.drop-before::before, .wq-pm-item.drop-after::before {
  content: ''; position: absolute; top: -2px; bottom: -2px; width: 3px;
  background: #6366f1; border-radius: 2px;
}
.wq-pm-item.drop-before::before { left: -8px; }
.wq-pm-item.drop-after::before { right: -8px; }

.wq-pm-thumb {
  position: relative; aspect-ratio: 3 / 4; overflow: hidden; border-radius: 6px;
  background: #f1f5f9; display: flex; align-items: center; justify-content: center;
}
.wq-pm-thumb img { width: 100%; height: 100%; object-fit: cover; user-select: none; }
.wq-pm-num {
  position: absolute; top: 5px; left: 5px; min-width: 20px; height: 20px; padding: 0 5px;
  border-radius: 6px; background: rgba(15, 23, 42, .82); color: #fff;
  font-size: .68rem; font-weight: 800; display: flex; align-items: center; justify-content: center;
}
.wq-pm-tags { display: flex; flex-wrap: wrap; gap: 4px; }
.wq-pm-tag {
  font-size: .6rem; font-weight: 700; padding: 2px 6px; border-radius: 999px;
  border: 1px solid transparent; white-space: nowrap;
}
.wq-pm-tag-normal { background: #f1f5f9; color: #475569; border-color: #e2e8f0; }
.wq-pm-tag-ghost  { background: #f5f3ff; color: #6d28d9; border-color: #ddd6fe; }
.wq-pm-tag-master { background: #fffbeb; color: #92400e; border-color: #fde68a; }
.wq-pm-tag-draft  { background: #f8fafc; color: #475569; border-color: #cbd5e1;
  background-image: repeating-linear-gradient(45deg,
    rgba(100, 116, 139, .14) 0 4px, transparent 4px 8px); }

.wq-pm-acts { display: flex; gap: 4px; margin-top: auto; }
.wq-pm-act {
  flex: 1; padding: 5px 4px; border: 1px solid #d8dee9; border-radius: 7px;
  background: #fff; cursor: pointer; font-family: inherit; font-size: .64rem;
  font-weight: 600; color: #0f172a; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.wq-pm-act:hover { background: #f1f5f9; }
.wq-pm-act.on { background: #f1f5f9; border-color: #94a3b8; }

.wq-pm-legend {
  margin-top: 16px; padding-top: 12px; border-top: 1px solid #e2e8f0;
  display: flex; flex-wrap: wrap; gap: 6px 18px;
}
.wq-pm-legend-row {
  display: flex; align-items: center; gap: 6px; font-size: .66rem; color: #64748b;
}
.wq-pm-legend-sw {
  width: 16px; height: 16px; border-radius: 4px; border: 2px solid transparent; flex: 0 0 auto;
}
.wq-pm-legend-sw.wq-pm-tag-ghost { border-style: dashed; }

/* ── Plan des pages : densité, silhouette du contenu, déplacement lointain ──
   Trois crans de taille plutôt qu'un curseur : on cherche « tout voir » ou
   « voir en détail », pas un réglage fin. Aux petites tailles, les libellés
   et étiquettes texte s'effacent — c'est le bandeau de couleur SUR la
   vignette qui porte alors l'information. */
.wq-pm-dens { display: flex; gap: 3px; flex: 0 0 auto; }
.wq-pm-densbtn {
  width: 28px; height: 28px; border: 1px solid #d8dee9; border-radius: 7px;
  background: #fff; cursor: pointer; font-size: .7rem; color: #64748b; line-height: 1;
}
.wq-pm-densbtn:hover { background: #f1f5f9; }
.wq-pm-densbtn.active { background: #eef2ff; border-color: #6366f1; color: #4338ca; }

.wq-pm-s .wq-pm-grid { grid-template-columns: repeat(auto-fill, minmax(78px, 1fr)); gap: 8px; }
.wq-pm-m .wq-pm-grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; }
.wq-pm-l .wq-pm-grid { grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 14px; }
.wq-pm-s .wq-pm-item { padding: 4px; gap: 3px; }
/* Petite densité : plus de place pour du texte — on garde la vignette, son
   numéro et son bandeau, qui suffisent à repérer et à glisser. */
.wq-pm-s .wq-pm-tags { display: none; }
.wq-pm-s .wq-pm-lbl { display: none; }
.wq-pm-s .wq-pm-act { padding: 3px 2px; font-size: .7rem; }
.wq-pm-s .wq-pm-pos { width: 34px; }
.wq-pm-ico { display: none; }
.wq-pm-s .wq-pm-ico { display: inline; }

/* Silhouette : un bloc par élément, à sa vraie position en %. */
.wq-pm-mini { position: absolute; inset: 0; pointer-events: none; }
.wq-pm-blk {
  position: absolute; box-sizing: border-box; border-radius: 2px;
  border: 1px solid rgba(255, 255, 255, .55); min-width: 2px; min-height: 2px;
}
.wq-pm-blk-g { background: rgba(99, 102, 241, .62); }   /* noté */
.wq-pm-blk-c { background: rgba(13, 148, 136, .55); }   /* contenu / média */
.wq-pm-blk-d { background: rgba(245, 158, 11, .5); }    /* décor */
.wq-pm-blank {
  font-size: .6rem; color: #cbd5e1; font-weight: 700;
  text-transform: uppercase; letter-spacing: .5px;
}

/* Bandeau de nature, posé sur la vignette (lisible à toutes les densités). */
.wq-pm-ribbon {
  position: absolute; top: 5px; right: 5px; width: 20px; height: 20px;
  border-radius: 6px; display: flex; align-items: center; justify-content: center;
  font-size: .62rem; border: 1px solid transparent;
}
.wq-pm-ribbon.is-none { display: none; }

/* Déplacement lointain : sur 100 pages, c'est la DISTANCE le problème, pas la
   taille des vignettes — glisser de la page 5 à la 87 reste pénible quelle
   que soit l'échelle. Ce champ règle ce cas ; le glisser reste pour les
   voisines. */
.wq-pm-pos {
  width: 46px; flex: 0 0 auto; padding: 5px 4px; border: 1px solid #d8dee9;
  border-radius: 7px; font-family: inherit; font-size: .64rem; font-weight: 700;
  text-align: center; color: #0f172a; background: #fff;
}
.wq-pm-pos:focus { outline: 2px solid #6366f1; outline-offset: -1px; }

/* Nom d'auteur bilingue sur les cartes du plan des pages. L'arabe a sa propre
   ligne en RTL : mêlé au français sur une même ligne, l'ordre des caractères
   s'inverse à l'affichage. */
.wq-pm-names { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.wq-pm-name {
  font-size: .68rem; font-weight: 700; color: #0f172a; line-height: 1.3;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.wq-pm-name-ar { font-weight: 600; color: #475569; text-align: right; }
.wq-pm-s .wq-pm-names { display: none; }

/* ═══════════════════════════════════════════════════════════════════════
   WOW BOOK BOOST — design sonore, page tournée, étoiles & série
   Contrainte qui gouverne tout ce bloc : rester fluide sur une tablette
   Android d'entrée de gamme. On n'anime donc QUE transform et opacity (le
   compositeur s'en charge), jamais une propriété qui force un recalcul de
   mise en page.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── Page tournée ───────────────────────────────────────────────────────
   Le sens vient du JS (avance/recul) : une page qui part du même côté quels
   que soient le geste ne se lit pas comme un livre. `backface-visibility`
   évite le clignotement blanc à mi-rotation sur WebKit. */
@keyframes wqFlipNext {
  0%   { transform: perspective(1400px) rotateY(-14deg) translateX(4%); opacity: .35; }
  100% { transform: perspective(1400px) rotateY(0deg) translateX(0); opacity: 1; }
}
@keyframes wqFlipPrev {
  0%   { transform: perspective(1400px) rotateY(14deg) translateX(-4%); opacity: .35; }
  100% { transform: perspective(1400px) rotateY(0deg) translateX(0); opacity: 1; }
}
.wq-flip-next { animation: wqFlipNext .38s cubic-bezier(.22, .9, .3, 1) both; backface-visibility: hidden; }
.wq-flip-prev { animation: wqFlipPrev .38s cubic-bezier(.22, .9, .3, 1) both; backface-visibility: hidden; }
/* Filet de sécurité : le JS teste déjà prefers-reduced-motion, mais si un
   thème ou un chrome pose la classe autrement, le réglage système gagne. */
@media (prefers-reduced-motion: reduce) {
  .wq-flip-next, .wq-flip-prev { animation: none !important; }
}

/* ── Bouton de coupure du son ───────────────────────────────────────────
   Sur <body>, hors du canvas : le canvas porte un transform:scale (zoom du
   lecteur) qui ferait dériver et grossir un bouton fixe à chaque cran. */
.wq-mute-btn {
  position: fixed; z-index: 9998; top: 14px; right: 14px;
  width: 42px; height: 42px; border-radius: 50%; cursor: pointer;
  border: 2px solid rgba(255, 255, 255, .8); background: rgba(15, 23, 42, .72);
  color: #fff; font-size: 1.05rem; line-height: 1;
  display: flex; align-items: center; justify-content: center;
  backdrop-filter: blur(6px); box-shadow: 0 4px 14px rgba(0, 0, 0, .3);
  transition: transform .12s ease, background .15s ease;
}
.wq-mute-btn:hover { transform: scale(1.06); }
.wq-mute-btn:active { transform: scale(.94); }
.wq-mute-bl { top: auto; right: auto; bottom: 14px; left: 14px; }
.wq-mute-br { top: auto; bottom: 14px; right: 14px; }
.wq-mute-tl { right: auto; left: 14px; }

/* ── Pastille de série ────────────────────────────────────────────────── */
.wq-streak-badge {
  position: fixed; z-index: 9998; top: 14px; right: 66px;
  padding: 7px 12px; border-radius: 999px; pointer-events: none;
  background: rgba(15, 23, 42, .72); color: #fff; font-size: .82rem;
  display: flex; align-items: center; gap: 5px;
  backdrop-filter: blur(6px); box-shadow: 0 4px 14px rgba(0, 0, 0, .3);
}
.wq-streak-badge strong { font-size: .92rem; }
.wq-streak-bl { top: auto; right: auto; bottom: 14px; left: 66px; }

/* ── Étoiles & encart de fin ────────────────────────────────────────────
   Les trois étoiles sont TOUJOURS visibles, les non gagnées en creux : c'est
   ce qui donne envie de refaire la leçon. N'afficher que les étoiles
   obtenues enlèverait l'objectif. */
.wq-reward-box { margin-top: 14px; text-align: center; }
.wq-stars { display: flex; justify-content: center; gap: 8px; margin-bottom: 8px; }
.wq-star { font-size: 2.1rem; line-height: 1; color: #cbd5e1; }
.wq-star.on { color: #f59e0b; text-shadow: 0 2px 10px rgba(245, 158, 11, .45); }
.wq-stars.is-anim .wq-star.on { animation: wqStarPop .45s cubic-bezier(.2, 1.5, .4, 1) both; }
@keyframes wqStarPop {
  0%   { transform: scale(0) rotate(-40deg); opacity: 0; }
  70%  { transform: scale(1.25) rotate(6deg); opacity: 1; }
  100% { transform: scale(1) rotate(0); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .wq-stars.is-anim .wq-star.on { animation: none; }
}
.wq-reward-line { margin: 4px 0 2px; font-size: .92rem; font-weight: 700; }
.wq-reward-streak { margin: 2px 0 0; font-size: .8rem; opacity: .85; }

/* ---------- Dictionnaire parlant (quest-dictionary.js) — Phase 1 du trio
   Dictionnaire + Dictée + Enregistrement ---------- */
.wq-dico {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 10px; padding: 16px; box-sizing: border-box; text-align: center;
  overflow: hidden;
  background: var(--dico-bg, #ffffff); border-radius: var(--dico-radius, 16px);
  border: 1px solid rgba(15, 23, 42, .08); box-shadow: 0 4px 14px rgba(15, 23, 42, .08);
  font-family: 'Outfit', 'Cairo', sans-serif;
}
/* Vue détail — jamais de scroll (voir fitDetail() dans quest-dictionary.js) :
   le texte rétrécit pour toujours tenir, plutôt que de défiler ou couper. */
.wq-dico-detail { display: flex; flex-direction: column; align-items: center; gap: 10px; min-height: 0; }
/* Vue liste (plusieurs mots) — remplace le centrage vertical de la vue détail
   par un alignement en haut + zone de résultats qui prend toute la hauteur
   restante et défile, plutôt que de déborder du widget. */
.wq-dico:has(.wq-dico-list) { justify-content: flex-start; }
.wq-dico-search-wrap { width: 100%; flex: 0 0 auto; }
.wq-dico-search {
  width: 100%; box-sizing: border-box; padding: 8px 10px; border-radius: 10px;
  border: 1px solid var(--dico-panel-border, rgba(15, 23, 42, .15)); font-family: inherit; font-size: .82rem;
  color: var(--dico-ink, #1e293b); background: var(--dico-panel-bg, rgba(15, 23, 42, .06));
}
.wq-dico-search::placeholder { color: var(--dico-ink, #1e293b); opacity: .55; }
.wq-dico-list { width: 100%; flex: 1 1 auto; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: 4px; }
.wq-dico-list-item {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  text-align: inherit; padding: 9px 12px; border-radius: 10px; border: 1px solid var(--dico-panel-border, rgba(15, 23, 42, .1));
  background: var(--dico-panel-bg, rgba(15, 23, 42, .06)); color: var(--dico-ink, #1e293b); font-family: inherit;
  font-size: .85rem; font-weight: 700; cursor: pointer;
}
.wq-dico-list-item:hover { filter: brightness(0.96); }
/* Option "Mots multicolores" — chaque ligne prend une couleur de la palette,
   cycliquement (voir listMulticolor dans quest-dictionary.js) ; le texte
   reste toujours blanc, jamais l'encre calculée, puisque la ligne porte
   maintenant sa PROPRE couleur pleine, plus le fond translucide neutre. */
.wq-dico-list-item.is-multicolor { color: #fff; border-color: transparent; }
.wq-dico-list-item.is-multicolor:hover { filter: brightness(1.08); }
.wq-dico-back {
  align-self: flex-start; display: inline-flex; align-items: center; gap: 4px;
  border: none; cursor: pointer; font-family: inherit; font-weight: 800; font-size: .75rem;
  color: #fff; background: var(--dico-accent, #6366f1); border-radius: 999px; padding: 6px 14px 6px 10px;
  box-shadow: 0 3px 10px rgba(0, 0, 0, .2); margin-bottom: 4px;
}
.wq-dico-back:hover { filter: brightness(1.08); }
.wq-dico-poster { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.wq-dico-poster-ic { font-size: 2rem; opacity: .8; }
.wq-dico-poster-lbl { font-weight: 800; font-size: .78rem; opacity: .85; padding: 0 8px; }
.wq-dico-hint { font-size: .8rem; opacity: .6; color: var(--dico-ink, #1e293b); }
.wq-dico-img { max-width: 70%; max-height: 40%; object-fit: contain; border-radius: 10px; }
.wq-dico-term {
  font-family: var(--dico-term-font, inherit); font-weight: var(--dico-term-weight, 800);
  font-style: var(--dico-term-style, normal); text-decoration: var(--dico-term-deco, none);
  font-size: 1.3rem; color: var(--dico-term-color, var(--dico-ink, #1e293b)); word-break: break-word;
}
.wq-dico-tag {
  display: inline-block; padding: 2px 10px; border-radius: 999px; color: #fff;
  font-size: .66rem; font-weight: 800; letter-spacing: .3px;
}
.wq-dico-tagrow { display: flex; flex-wrap: wrap; gap: 5px; width: 100%; flex: 0 0 auto; }
.wq-dico-tag-chip { border: none; cursor: pointer; opacity: .45; transition: opacity .15s; }
.wq-dico-tag-chip.is-off { opacity: 1; }
.wq-dico-tag-dot { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto; }
.wq-dico-row { display: flex; gap: 10px; align-items: center; }
.wq-dico-listen {
  width: 48px; height: 48px; border-radius: 50%; border: none; cursor: pointer;
  background: var(--dico-accent, #6366f1); color: #fff; font-size: 1.3rem;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 4px 14px rgba(0, 0, 0, .25); transition: transform .15s ease;
}
.wq-dico-listen:hover { filter: brightness(1.08); }
.wq-dico-listen:active { transform: scale(0.9); }
.wq-dico-listen.is-speaking { animation: wqDicoPulse .55s ease-in-out infinite; }
/* "Gros bouton" (kid/ludique) — variante de taille, jamais le comportement. */
.wq-dico-listen.is-big { width: 72px; height: 72px; font-size: 2rem; }
/* "Multicolore" (kid/ludique) — dégradé arc-en-ciel qui tourne doucement au
   lieu de l'accent uni, purement décoratif. */
.wq-dico-listen.is-rainbow {
  background: conic-gradient(from 0deg, #f43f5e, #f59e0b, #22c55e, #0ea5e9, #8b5cf6, #f43f5e);
  animation: wqDicoRainbow 6s linear infinite;
}
@keyframes wqDicoRainbow { to { filter: hue-rotate(360deg); } }
@keyframes wqDicoPulse {
  0%, 100% { box-shadow: 0 4px 14px rgba(0, 0, 0, .25), 0 0 0 0 rgba(99, 102, 241, .5); }
  50% { box-shadow: 0 4px 14px rgba(0, 0, 0, .25), 0 0 0 8px rgba(99, 102, 241, 0); }
}
.wq-dico-reveal {
  padding: 10px 16px; border-radius: 999px; border: 1px solid rgba(15, 23, 42, .15);
  background: #fff; cursor: pointer; font-weight: 700; font-size: .8rem; font-family: inherit;
}
.wq-dico-reveal:hover { background: #f8fafc; }
.wq-dico-def {
  font-family: var(--dico-def-font, inherit); font-size: .85rem; line-height: 1.4;
  max-width: 90%; color: var(--dico-def-color, var(--dico-ink, #1e293b));
}
.wq-dico-def.wq-dico-def-boxed { background: var(--dico-def-bg); padding: 8px 14px; border-radius: 12px; }
/* FX de révélation (voir flip() dans quest-dictionary.js, joué en même temps
   que cette pop-in) — pas au masquage, seulement quand la définition apparaît. */
.wq-dico-def-pop { animation: wqDicoDefPop .35s cubic-bezier(.22, 1.4, .4, 1); }
@keyframes wqDicoDefPop {
  0% { opacity: 0; transform: scale(0.85) translateY(4px); }
  100% { opacity: 1; transform: scale(1) translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .wq-dico-listen.is-speaking, .wq-dico-listen.is-rainbow, .wq-dico-def-pop { animation: none; }
}

/* Ruban en coin — même position/style que le ruban "DEMO" de studio.php,
   pour rester cohérent avec le reste de la plateforme. */
.wq-dico-badge {
  position: absolute; top: 10px; right: 10px; z-index: 6; color: #fff;
  font-size: .66rem; font-weight: 800; letter-spacing: .3px;
  padding: 4px 10px; border-radius: 999px; box-shadow: 0 2px 6px rgba(0, 0, 0, .3);
}
/* Effet 3D — relief plus marqué sur le cadre ET le bouton écouter. */
.wq-dico.is-3d {
  box-shadow: 0 10px 0 -2px rgba(15, 23, 42, .12), 0 14px 22px -6px rgba(15, 23, 42, .35);
}
.wq-dico.is-3d .wq-dico-listen { box-shadow: 0 6px 0 rgba(0, 0, 0, .25), 0 10px 18px -4px rgba(0, 0, 0, .4); }
.wq-dico.is-3d .wq-dico-listen:active { box-shadow: 0 2px 0 rgba(0, 0, 0, .25); transform: translateY(4px) scale(0.96); }
/* Halo pulsant — ambiant, autour du cadre entier, indépendant du pulse du
   bouton écouter pendant qu'il parle (is-speaking, déjà existant). */
.wq-dico.is-pulsing { animation: wqDicoFramePulse 1.8s ease-in-out infinite; }
@keyframes wqDicoFramePulse {
  0%, 100% { box-shadow: 0 4px 14px rgba(15, 23, 42, .08), 0 0 0 0 var(--dico-accent, #6366f1); }
  50% { box-shadow: 0 4px 14px rgba(15, 23, 42, .08), 0 0 0 10px transparent; }
}
/* Contour coloré — bordure dédiée, distincte du liseré neutre par défaut. */
.wq-dico.has-outline { border: 3px solid var(--dico-outline, #6366f1); }
@media (prefers-reduced-motion: reduce) {
  .wq-dico.is-pulsing { animation: none; }
}
