/* document-editor.css — éditeur de support de formation (voir docs/plan/PLAN.md). Tout est scopé sous .docEditor3 : aucune règle ici ne touche jamais html[data-theme] (figé "dark" pour le reste du site, voir templates/base.html) — le thème clair/sombre de CET éditeur est un attribut data-theme posé sur .docEditor3 lui-même (voir static/document/js/document-editor.js), avec ses propres tokens --doc-* ci-dessous plutôt que les --forge-* globaux. */ /* Demande explicite : l'éditeur occupe TOUTE la largeur de la fenêtre, bord à bord — .content limite normalement à 760px (voir static/style.css) et .content-wide à 1600px, tous deux avec un padding fixe. Neutralisé ici pour cette page précise seulement (ce fichier n'est chargé QUE par templates/document/document_edit.html) : même sélecteur que la règle du site (`body.objectEditBody > main.content`, spécificité identique), mais chargé après static/style.css dans
(voir son {% block extra_head %}) donc prioritaire à spécificité égale. */ body.objectEditBody > main.content { max-width: none; width: 100%; padding: 0; margin: 0; } /* La modale (#docScenarioTreeModal) partage ces tokens --doc-* MAIS reste volontairement un FRÈRE de .docEditor3 dans le HTML (jamais un descendant) : main.content (voir body.objectEditBody dans static/style.css) a déjà `overflow:hidden`, qui ROGNE VISUELLEMENT tout descendant `position:fixed` à sa propre boîte (même bug déjà trouvé le 20/09/2026 pour le bandeau d'outils, voir plus bas) — un `position:fixed` doit donc rester un frère de .docEditor3, jamais un enfant, pour couvrir le VRAI viewport. D'où la duplication de ce sélecteur ici plutôt qu'un simple héritage de variables CSS (qui ne franchit pas la frontière DOM entre frères) — voir aussi forgeDocApplyTheme (static/document/js/document-editor.js), qui pose le même data-theme sur les deux éléments. */ .docEditor3, #docScenarioTreeModal { --doc-bg: var(--forge-bg); --doc-bg-2: var(--forge-bg-secondary); --doc-card: var(--forge-card); --doc-border: var(--forge-border); --doc-text: var(--forge-text); --doc-muted: var(--forge-text-muted); --doc-accent: var(--accent); --doc-accent-2: var(--accent-2); --doc-glow: 0 0 0 1px rgb(255 95 46 / 25%), 0 8px 24px -6px rgb(255 95 46 / 25%); --doc-quiz-success-bg: rgb(59 165 93 / 12%); --doc-quiz-success-border: #3ba55d; --doc-quiz-success-text: #8fe3ab; --doc-quiz-danger-bg: rgb(255 95 46 / 12%); --doc-quiz-danger-border: #ff5f2e; --doc-quiz-danger-text: #ffb3a0; } .docEditor3 { /* Remplit main.content (voir body.objectEditBody dans static/style.css : `main.content` y est déjà `flex:1 1 auto; min-height:0; overflow:hidden; display:flex; flex-direction:column;`) — jamais `position:fixed` : cet ancêtre a `overflow:hidden`, qui ROGNE VISUELLEMENT tout descendant `position:fixed` à sa propre boîte (laquelle commence sous la barre de navigation du site, pas au vrai sommet du viewport) — bug réel trouvé le 20/09/2026 : le bandeau d'outils (56px) tombait alors entièrement dans la zone rognée, invisible, alors que le reste de l'éditeur semblait décalé vers le haut à sa place. */ flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; background: var(--doc-bg); color: var(--doc-text); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; } .docEditor3[data-theme="light"], #docScenarioTreeModal[data-theme="light"] { --doc-bg: #f6f5f2; --doc-bg-2: #fff; --doc-card: #fff; --doc-border: #e3e1db; --doc-text: #14161c; --doc-muted: #6b7280; --doc-glow: 0 0 0 1px rgb(255 95 46 / 30%), 0 8px 24px -6px rgb(255 95 46 / 30%); --doc-quiz-success-bg: #e4f5ea; --doc-quiz-success-border: #2e7d46; --doc-quiz-success-text: #1d4c2c; --doc-quiz-danger-bg: #fdede8; --doc-quiz-danger-border: #c1451f; --doc-quiz-danger-text: #7a1418; } .docEditor3 *, #docScenarioTreeModal * { box-sizing: border-box; } .docEditor3 button { font-family: inherit; } /* ===== TOPBAR ===== */ .docTopbar { height: 56px; flex-shrink: 0; background: var(--doc-bg-2); border-bottom: 1px solid var(--doc-border); display: flex; align-items: center; justify-content: space-between; padding: 0 20px; gap: 12px; } .docCrumb { display: flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 600; min-width: 0; overflow: hidden; } .docCrumbDim { color: var(--doc-muted); font-weight: 400; white-space: nowrap; text-decoration: none; } .docCrumbCur { font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--doc-text); } .docTopbarActions { display: flex; align-items: center; gap: 10px; flex-shrink: 0; } .docIconBtn { width: 34px; height: 34px; border-radius: 10px; border: 1px solid var(--doc-border); background: transparent; color: var(--doc-text); display: flex; align-items: center; justify-content: center; cursor: pointer; } .docIconBtn:hover:not(:disabled) { border-color: var(--doc-muted); } .docIconBtn:disabled { opacity: 0.35; cursor: default; } .docDividerV { width: 1px; height: 22px; background: var(--doc-border); margin: 0 4px; } .docBtnSecondary { height: 34px; padding: 0 14px; border-radius: 10px; border: 1px solid var(--doc-border); background: transparent; color: var(--doc-text); font-size: 14px; font-weight: 600; display: flex; align-items: center; gap: 7px; cursor: pointer; } .docBtnSecondary:hover { border-color: var(--doc-muted); } .docBtnPrimary { border-color: var(--doc-accent); color: var(--doc-accent); } .docBtnPrimary:hover { background: rgb(255 95 46 / 8%); } .docWidthPicker { display: flex; gap: 4px; background: var(--doc-card); border: 1px solid var(--doc-border); border-radius: 10px; padding: 3px; } .docWidthBtn { border: none; background: transparent; color: var(--doc-muted); font-size: 12.5px; font-weight: 600; padding: 5px 10px; border-radius: 7px; cursor: pointer; } .docWidthBtn.is-active { background: rgb(255 95 46 / 12%); color: var(--doc-accent); } /* ===== BODY LAYOUT ===== */ .docBodyWrap { flex: 1; display: flex; min-height: 0; position: relative; } .docSidebar { flex-shrink: 0; background: var(--doc-bg-2); padding: 20px 16px; overflow-y: auto; display: flex; flex-direction: column; gap: 22px; } .docSidebarLeft { width: 248px; border-right: 1px solid var(--doc-border); } .docSidebarRight { width: 300px; border-left: 1px solid var(--doc-border); } .docSectionLabel { font-size: 12px; font-weight: 700; letter-spacing: 0.04em; color: var(--doc-muted); margin-bottom: 10px; } .docLibItem { border: 1px solid var(--doc-border); border-radius: 10px; cursor: grab; background: var(--doc-card); transition: border-color 0.15s ease, box-shadow 0.15s ease; } .docLibItem:hover { border-color: var(--doc-accent); box-shadow: var(--doc-glow); } .docLibItem--row { padding: 9px 10px; display: flex; align-items: center; gap: 10px; } .docLibItem span:last-child { font-size: 12.5px; font-weight: 600; } .docLibList { display: flex; flex-direction: column; gap: 6px; } .docLibIcon { width: 18px; height: 18px; display: inline-flex; align-items: center; justify-content: center; font-size: 14px; flex-shrink: 0; } .docLibIcon--paragraphe::before { content: "¶"; } .docLibIcon--image::before { content: "🖼"; } .docLibIcon--bouton::before { content: "⬚"; } .docLibIcon--titre::before { content: "T"; font-weight: 800; } .docLibIcon--quiz::before { content: "?"; color: var(--doc-accent); font-weight: 800; } .docLibIcon--association::before { content: "⇄"; color: var(--doc-accent); } .docLibIcon--memory::before { content: "▤"; color: var(--doc-accent); } .docLibIcon--mots::before { content: "▦"; color: var(--doc-accent); } .docLibIcon--scenario::before { content: "◈"; color: var(--doc-accent); } .docLibIcon--zones::before { content: "⚠"; color: var(--doc-accent); } /* ---- CANVAS ---- */ .docCanvasArea { flex: 1; background: var(--doc-bg); padding: 36px 40px; overflow: auto; display: flex; flex-direction: column; align-items: center; position: relative; } /* Page au format A4 PAYSAGE, taille FIXE comme une vraie diapositive (retour utilisateur du 23/09/2026 : "une page [...] dois etre un format a4 orienter horizontalement comme une slide [...] le contenu ne defile pas, si ya plus de place les contenu va sur une autre page") — ratio 297:210 (A4 paysage) fixé par aspect-ratio, jamais height:fit-content comme avant (la page ne grandit plus avec son contenu). overflow:hidden : le contenu qui dépasse est clipsé, PAS de défilement interne — au créateur de répartir sur plusieurs pages, comme un vrai logiciel de diaporama ne reflow jamais automatiquement une diapositive trop pleine. */ .docPage { width: 960px; max-width: 100%; aspect-ratio: 297 / 210; background: var(--doc-card); border: 1px solid var(--doc-border); border-radius: 16px; box-shadow: 0 1px 3px rgb(0 0 0 / 30%); padding: 48px 52px; position: relative; overflow: hidden; transform-origin: top center; transition: width 0.2s ease; } /* Enfant qui reçoit le HTML rendu (voir #docPage vs #docPageContent dans document-editor.js — le rafraîchissement du canevas ne remplace QUE ce contenu, jamais .docPage elle-même). */ .docPageContent { display: flex; flex-direction: column; gap: 18px; height: 100%; } .docPage.docPage--fixedWidth { width: var(--doc-preview-width, 760px); padding: 28px 20px; } /* Un mini-jeu occupe TOUTE la page, à lui seul (retour utilisateur du 23/09/2026 : "un mini jeu dois occupper toute une page" — confirmé : "une page avec mini-jeu = uniquement ce mini-jeu"). Garantie posée côté serveur (routes/document/document_element_add.py : impossible d'ajouter un mini-jeu sur une page non vide, ni d'ajouter autre chose sur une page qui en contient déjà un) — :only-child ici n'est donc jamais un cas ambigu, juste la mise en forme plein-cadre de cette garantie. Le padding de .docPage disparaît (plein bord) et le badge mini-jeu (nom/"2 paires"/etc.) disparaît ENTIÈREMENT (retour utilisateur du 23/09/2026 : "ces éléments [...] doivent disparaitre et le composant mini jeu pren toute la place") — plus une simple réduction d'espace, le joueur seul occupe toute la hauteur. */ .docPage:has(> .docPageContent > .docMinigame:only-child) { padding: 0; } .docPageContent > .docMinigame:only-child { flex: 1; display: flex; flex-direction: column; border-radius: 0; border-width: 0; } .docPageContent > .docMinigame:only-child .docMinigameBadge { display: none; } .docPageContent > .docMinigame:only-child > [class$="Player"] { flex: 1; min-height: 0; } .docRow { position: relative; } .docRow > [data-element-id] { flex: 1 1 220px; min-width: 0; } [data-element-id] { position: relative; border-radius: 8px; padding: 6px; margin: -6px; cursor: pointer; transition: background 0.1s ease; } [data-kind="row"] > [data-element-id] { margin: 0; } [data-element-id]:hover { background: rgb(255 95 46 / 6%); } [data-element-id].docSelected { background: rgb(255 95 46 / 10%); outline: 1px dashed var(--doc-accent); } [data-element-id].docDropTarget--before { box-shadow: inset 0 3px 0 0 var(--doc-accent); } [data-element-id].docDropTarget--after { box-shadow: inset 0 -3px 0 0 var(--doc-accent); } [data-element-id].docDropTarget--mergeLeft { box-shadow: inset 3px 0 0 0 var(--doc-accent); } [data-element-id].docDropTarget--mergeRight { box-shadow: inset -3px 0 0 0 var(--doc-accent); } .docText { outline: none; } .docImage.docImagePlaceholder { width: 100%; height: 190px; border-radius: 10px; background: var(--doc-bg-2); border: 1px dashed var(--doc-border); display: flex; align-items: center; justify-content: center; gap: 8px; color: var(--doc-muted); font-size: 13px; font-weight: 600; } img.docImage { max-width: 100%; border-radius: 10px; display: block; } .docButton { border: none; border-radius: 999px; padding: 10px 22px; font-weight: 700; font-size: 14px; background: var(--doc-accent); color: #14100c; cursor: pointer; } .docMinigame { border: 1px solid var(--doc-accent); border-radius: 12px; background: rgb(255 95 46 / 8%); } .docMinigameBadge { padding: 18px 20px; display: flex; align-items: center; justify-content: space-between; gap: 12px; } .docMinigameLabel { font-size: 15px; font-weight: 700; } .docMinigamePlaceholder { font-size: 12.5px; color: var(--doc-muted); } /* ---- Quiz/Association/Memory/Mots mêlés/Scénario : le joueur RÉEL est désormais VISIBLE en permanence, édition ET Aperçu (retour utilisateur du 23/09/2026 : "les mini jeux doive etre visible meme en edition mais jouable dans l'apercus") — seule l'INTERACTIVITÉ (répondre/glisser/retourner une carte) reste réservée au Mode Aperçu, via pointer-events ci-dessous (jamais via display:none, sinon rien ne serait visible en édition). ---- */ /* Le joueur remplit TOUTE la hauteur/largeur disponible (voir [class$="Player"] plus haut, flex:1 dans .docMinigame:only-child) ET sa CARTE interne (.docQuizCard, .docAssocCard, .docMemoryCardWrap...) doit elle aussi occuper toute cette place, pas juste une carte centrée avec une largeur confortable (retour utilisateur du 23/09/2026 : "le mini jeu dois prendre toute la hauteur et la largeur du document" — une carte à largeur limitée, même centrée, ne suffisait pas). align-items:stretch (valeur par défaut, posée explicitement pour être claire) étire la carte sur tout l'axe croisé ; sa largeur 100% (voir chaque carte plus bas, sans max-width) fait le reste. */ .docQuizPlayer, .docAssocPlayer, .docMemoryPlayer, .docMotsPlayer, .docScenarioPlayer { pointer-events: none; display: flex; align-items: stretch; padding: 24px; } .docEditor3.docEditor3--preview [data-kind="quiz"], .docEditor3.docEditor3--preview [data-kind="association"], .docEditor3.docEditor3--preview [data-kind="memory"], .docEditor3.docEditor3--preview [data-kind="mots"], .docEditor3.docEditor3--preview [data-kind="scenario"] { border: none; background: transparent; } .docEditor3.docEditor3--preview .docQuizPlayer, .docEditor3.docEditor3--preview .docQuizPlayer *, .docEditor3.docEditor3--preview .docAssocPlayer, .docEditor3.docEditor3--preview .docAssocPlayer *, .docEditor3.docEditor3--preview .docMemoryPlayer, .docEditor3.docEditor3--preview .docMemoryPlayer *, .docEditor3.docEditor3--preview .docMotsPlayer, .docEditor3.docEditor3--preview .docMotsPlayer *, .docEditor3.docEditor3--preview .docScenarioPlayer, .docEditor3.docEditor3--preview .docScenarioPlayer * { /* Deux raisons cumulées de désactiver pointer-events ailleurs, toutes les deux réactivées ICI en Mode Aperçu : (1) .docEditor3--preview désactive pointer-events sur tout [data-element-id] (voir plus bas) pour empêcher la sélection/le déplacement pendant l'Aperçu ; (2) le joueur lui-même est pointer-events:none PAR DÉFAUT (voir plus haut) pour rester visible mais non "jouable" hors Aperçu (retour utilisateur du 23/09/2026). Cette règle est donc le SEUL endroit où un mini-jeu redevient réellement cliquable/glissable. */ pointer-events: auto; } .docQuizCard, .docQuizResultCard { /* Toute la hauteur/largeur du DOCUMENT (retour utilisateur du 23/09/2026), pas juste une carte confortable centrée : la carte elle-même (fond/bordure) couvre désormais toute la page ; display:flex + justify-content:center centre son CONTENU à l'intérieur de cette grande surface, plutôt que de le laisser collé en haut ou étiré verticalement de façon disgracieuse. */ width: 100%; display: flex; flex-direction: column; justify-content: center; background: linear-gradient(180deg, var(--doc-card), var(--doc-bg-2)); border: 1px solid var(--doc-border); border-radius: 16px; padding: 1.8rem; } .docQuizResultCard { text-align: center; } .docQuizKicker { font-size: 12px; font-weight: 700; letter-spacing: 0.04em; color: var(--doc-accent); margin-bottom: 6px; } .docQuizPlayerTitle { font-size: 1.15rem; font-weight: 700; margin: 0 0 20px; } .docQuizProgressTrack { height: 4px; background: var(--doc-border); border-radius: 2px; overflow: hidden; margin-bottom: 10px; } .docQuizProgressFill { height: 100%; width: 0%; background: linear-gradient(120deg, var(--doc-accent), var(--doc-accent-2)); transition: width 0.2s ease; } .docQuizMeta { display: flex; justify-content: space-between; font-size: 13px; color: var(--doc-muted); font-weight: 600; margin-bottom: 20px; } .docQuizQuestionText { font-size: 17px; font-weight: 700; line-height: 1.3; margin: 0 0 18px; } .docQuizOptions { display: flex; flex-direction: column; gap: 10px; } .docQuizOption { text-align: left; padding: 13px 15px; border: 1px solid var(--doc-border); background: var(--doc-bg-2); color: var(--doc-text); border-radius: 10px; font-size: 15px; font-weight: 500; cursor: pointer; display: flex; align-items: center; gap: 12px; transition: border-color 0.15s ease; } .docQuizOption:hover:not(:disabled) { border-color: var(--doc-accent); } .docQuizOptionLetter { flex-shrink: 0; width: 24px; height: 24px; border-radius: 50%; border: 1px solid var(--doc-border); display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 12.5px; color: var(--doc-muted); } .docQuizOption.is-correct { border-color: var(--doc-quiz-success-border); background: var(--doc-quiz-success-bg); } .docQuizOption.is-correct .docQuizOptionLetter { border-color: var(--doc-quiz-success-border); background: var(--doc-quiz-success-border); color: #0b0e14; } .docQuizOption.is-wrong { border-color: var(--doc-quiz-danger-border); background: var(--doc-quiz-danger-bg); } .docQuizOption.is-wrong .docQuizOptionLetter { border-color: var(--doc-accent); background: var(--doc-accent); color: #0b0e14; } .docQuizOption:disabled:not(.is-correct, .is-wrong) { opacity: 0.45; } .docQuizFeedback { display: none; margin-top: 16px; padding: 13px 15px; border-radius: 10px; font-size: 14px; line-height: 1.5; } .docQuizFeedback.is-visible { display: block; } .docQuizFeedback.is-ok { background: var(--doc-quiz-success-bg); color: var(--doc-quiz-success-text); border: 1px solid var(--doc-quiz-success-border); } .docQuizFeedback.is-ko { background: var(--doc-quiz-danger-bg); color: var(--doc-quiz-danger-text); border: 1px solid var(--doc-quiz-danger-border); } .docQuizNextBar { margin-top: 20px; display: flex; justify-content: flex-end; } .docQuizNextBtn { padding: 0.75rem 1.6rem; border-radius: 10px; border: none; background: linear-gradient(120deg, var(--doc-accent), var(--doc-accent-2)); color: #14100c; font-weight: 700; font-size: 14px; cursor: pointer; opacity: 0; pointer-events: none; transition: opacity 0.2s ease; } .docQuizNextBtn.is-visible { opacity: 1; pointer-events: auto; } .docQuizResultBig { font-weight: 800; font-size: 44px; background: linear-gradient(120deg, var(--doc-accent), var(--doc-accent-2)); background-clip: text; color: transparent; line-height: 1; } .docQuizResultSub { margin-top: 6px; margin-bottom: 18px; font-size: 13px; color: var(--doc-muted); font-weight: 600; } .docQuizRestartBtn { padding: 0.7rem 1.5rem; border-radius: 10px; background: transparent; border: 1px solid var(--doc-border); color: var(--doc-text); font-weight: 600; font-size: 14px; cursor: pointer; } /* ---- Association : plateau de glisser-déposer (voir docs/plan/PLAN.md, "relier visuellement deux éléments qui vont ensemble"). Réutilise .docQuizFeedback/.docQuizKicker (même rôle visuel) plutôt que de dupliquer ces règles. ---- */ .docAssocCard { width: 100%; display: flex; flex-direction: column; justify-content: center; background: linear-gradient(180deg, var(--doc-card), var(--doc-bg-2)); border: 1px solid var(--doc-border); border-radius: 16px; padding: 1.8rem; } .docAssocTitle { font-size: 1.15rem; font-weight: 700; margin: 0 0 14px; } .docAssocMeta { font-size: 13px; color: var(--doc-muted); font-weight: 600; margin-bottom: 16px; } .docAssocBoard { display: flex; gap: 24px; } .docAssocColumn { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 10px; } .docAssocItem, .docAssocSlot { padding: 13px 15px; border: 1px solid var(--doc-border); background: var(--doc-bg-2); color: var(--doc-text); border-radius: 10px; font-size: 14px; font-weight: 500; transition: border-color 0.15s ease, opacity 0.15s ease; } .docAssocItem { cursor: grab; } .docAssocItem:hover, .docAssocSlot:hover { border-color: var(--doc-accent); } .docAssocItem.is-selected { border-color: var(--doc-accent); box-shadow: var(--doc-glow); } .docAssocItem.is-matched, .docAssocSlot.is-matched { border-color: var(--doc-quiz-success-border); background: var(--doc-quiz-success-bg); color: var(--doc-quiz-success-text); cursor: default; opacity: 0.85; } .docAssocItem.is-wrong, .docAssocSlot.is-wrong { border-color: var(--doc-quiz-danger-border); background: var(--doc-quiz-danger-bg); } /* ---- Barre de bouton "Recommencer" partagée par tous les mini-jeux SAUF le Quiz (qui garde son propre écran de résultat séparé) : le plateau de jeu reste affiché en permanence une fois terminé, seul ce bouton apparaît/disparaît (voir retour utilisateur du 20/09/2026). ---- */ .docMinigameRestartBar { display: none; margin-top: 20px; text-align: center; } .docMinigameRestartBar.is-visible { display: block; } .docMinigameRestartBar button { padding: 0.7rem 1.5rem; border-radius: 10px; background: transparent; border: 1px solid var(--doc-border); color: var(--doc-text); font-weight: 600; font-size: 14px; cursor: pointer; } /* ---- Association : panneau Propriétés — paires reliées visuellement par un glyphe entre les deux champs (voir forgeDocRenderAssociationPairHtml, static/document/js/document-editor.js). Empilement VERTICAL (pas côte à côte) : la colonne du panneau Propriétés est trop étroite pour deux champs de texte libre côte à côte, voir retour utilisateur du 20/09/2026. ---- */ .docAssocPairRow { display: flex; flex-direction: column; gap: 8px; border: 1px solid var(--doc-border); border-radius: 10px; padding: 12px; margin-bottom: 10px; background: var(--doc-card); } .docAssocPairInput { width: 100%; resize: vertical; border: 1px solid var(--doc-border); border-radius: 8px; padding: 8px 10px; font-size: 13px; font-family: inherit; color: var(--doc-text); background: var(--doc-bg-2); } .docAssocPairLink { align-self: center; color: var(--doc-accent); font-weight: 700; font-size: 15px; } /* ---- Memory : panneau Propriétés — étiquette au-dessus de chaque champ recto/verso (voir forgeDocRenderMemoryCardHtml). Réutilise .docAssocPairRow/.docAssocPairInput (même carte, mêmes champs) plutôt que de dupliquer leurs règles. ---- */ .docMemoryFaceLabel { font-size: 11.5px; font-weight: 700; letter-spacing: 0.03em; color: var(--doc-muted); text-transform: uppercase; margin-top: 4px; } /* ---- Memory : plateau de jeu (voir docs/plan/PLAN.md, "retourner des cartes pour constituer des paires d'images identiques"). Réutilise .docAssocTitle/.docAssocMeta/.docMinigameRestartBar (mêmes rôles visuels, voir forgeDocRenderMemoryProps ci-dessus). ---- */ .docMemoryCardWrap { width: 100%; display: flex; flex-direction: column; justify-content: center; background: linear-gradient(180deg, var(--doc-card), var(--doc-bg-2)); border: 1px solid var(--doc-border); border-radius: 16px; padding: 1.8rem; } .docMemoryGrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(90px, 1fr)); gap: 12px; } .docMemoryCard { aspect-ratio: 3 / 4; perspective: 700px; cursor: pointer; } .docMemoryCardInner { position: relative; width: 100%; height: 100%; transition: transform 0.4s ease; transform-style: preserve-3d; } .docMemoryCard.is-flipped .docMemoryCardInner { transform: rotateY(180deg); } .docMemoryCard.is-matched { /* Une paire trouvée reste face retournée en PERMANENCE (voir forgeDocMemoryFlip, static/document/js/document-editor.js — la classe is-flipped n'est jamais retirée pour une carte appariée). Pas d'opacité réduite ici : une carte à 55% d'opacité, à côté de cartes face cachée pleinement opaques, se lisait comme "repartie face cachée" (retour utilisateur du 20/09/2026) alors qu'elle restait techniquement retournée — la bordure verte ci-dessous suffit à signaler l'état "trouvée", sans jamais assombrir le contenu révélé. */ cursor: default; } .docMemoryCardFace { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; padding: 6px; border-radius: 10px; border: 1px solid var(--doc-border); background: var(--doc-bg-2); backface-visibility: hidden; overflow: hidden; text-align: center; font-size: 12px; color: var(--doc-text); } .docMemoryCardFace img { max-width: 100%; max-height: 60%; object-fit: contain; } .docMemoryCardFront { background: linear-gradient(135deg, var(--doc-accent), var(--doc-accent-2)); color: #14100c; } .docMemoryCardBackGlyph { font-size: 26px; font-weight: 800; } .docMemoryCardBack { transform: rotateY(180deg); border-color: var(--doc-accent); } .docMemoryCard.is-matched .docMemoryCardFace.docMemoryCardBack { border-color: var(--doc-quiz-success-border); background: var(--doc-quiz-success-bg); color: var(--doc-quiz-success-text); } /* ---- Mots mêlés : grille interactive (voir docs/plan/PLAN.md, "mots cachés horizontalement/verticalement/en diagonale"). Réutilise .docAssocCard/.docAssocTitle/.docAssocMeta/.docMinigameRestartBar (mêmes rôles visuels que l'Association/Memory ci-dessus). ---- */ .docMotsBoard { display: flex; flex-wrap: wrap; gap: 24px; align-items: flex-start; } .docMotsGrid { display: grid; gap: 3px; width: min(100%, 420px); user-select: none; } .docMotsCell { aspect-ratio: 1; display: flex; align-items: center; justify-content: center; border: 1px solid var(--doc-border); background: var(--doc-bg-2); color: var(--doc-text); font-weight: 700; font-size: 13px; border-radius: 4px; cursor: pointer; } .docMotsCell.is-selecting { border-color: var(--doc-accent); background: rgb(255 95 46 / 18%); } .docMotsCell.is-found { border-color: var(--doc-quiz-success-border); background: var(--doc-quiz-success-bg); color: var(--doc-quiz-success-text); cursor: default; } .docMotsWordList { display: flex; flex-direction: column; gap: 8px; min-width: 140px; } .docMotsWordChip { padding: 8px 12px; border: 1px solid var(--doc-border); border-radius: 8px; font-size: 13px; font-weight: 600; color: var(--doc-text); background: var(--doc-bg-2); } .docMotsWordChip.is-found { border-color: var(--doc-quiz-success-border); background: var(--doc-quiz-success-bg); color: var(--doc-quiz-success-text); text-decoration: line-through; } .docUnknown { font-size: 12.5px; color: var(--doc-muted); border: 1px dashed var(--doc-border); border-radius: 8px; padding: 10px; } .docZoomPill { position: absolute; bottom: 24px; left: 50%; transform: translateX(-50%); background: var(--doc-card); border: 1px solid var(--doc-border); border-radius: 999px; height: 36px; padding: 0 6px; display: flex; align-items: center; gap: 6px; box-shadow: 0 2px 6px rgb(0 0 0 / 30%); } .docZoomPill button { width: 26px; height: 26px; border-radius: 999px; border: none; background: transparent; color: var(--doc-text); cursor: pointer; font-size: 15px; font-weight: 700; } .docZoomPill button:hover { background: var(--doc-bg-2); } .docZoomPill span { font-size: 12.5px; font-weight: 700; color: var(--doc-muted); width: 40px; text-align: center; } /* ---- Pilule de navigation entre PAGES en Mode Aperçu (retour utilisateur du 21/09/2026 : "il faut implémenter un système de page", navigation "page par page avec Suivant/Précédent"). Même position que .docZoomPill ci-dessus (jamais affichées en même temps : docZoomPill est masquée en Aperçu, voir plus bas) — .is-visible posée par forgeDocUpdatePageNavPill (static/document/js/document-editor.js) uniquement en Mode Aperçu ET s'il y a plus d'une page, jamais un sélecteur CSS seul (une pilule "Page 1 / 1" n'aurait aucun sens). ---- */ .docPageNavPill { display: none; position: absolute; bottom: 24px; left: 50%; transform: translateX(-50%); background: var(--doc-card); border: 1px solid var(--doc-border); border-radius: 999px; height: 36px; padding: 0 10px; align-items: center; gap: 10px; box-shadow: 0 2px 6px rgb(0 0 0 / 30%); } .docPageNavPill.is-visible { display: flex; } .docPageNavPill button { width: 26px; height: 26px; border-radius: 999px; border: none; background: transparent; color: var(--doc-text); cursor: pointer; font-size: 16px; font-weight: 700; } .docPageNavPill button:hover:not(:disabled) { background: var(--doc-bg-2); } .docPageNavPill button:disabled { opacity: 0.35; cursor: default; } .docPageNavPill span { font-size: 12.5px; font-weight: 700; color: var(--doc-muted); white-space: nowrap; } /* ---- Panneau GAUCHE à ONGLETS (retour utilisateur du 23/09/2026 : "il dois avoir deux onglets [...] un onglet page [...] un onglet mise en page avec les fonctionnalité et la disposition actuel sans la section page") : "Pages" (gestion complète, panneau dédié plein hauteur) et "Mise en page" (bibliothèque d'éléments, inchangée). ---- */ .docSidebarTabs { display: flex; flex-shrink: 0; border-bottom: 1px solid var(--doc-border); margin: -20px -16px 0; padding: 0 8px; } .docSidebarTab { flex: 1; padding: 10px 8px; border: none; /* border-radius:0 obligatoire : le bouton Bulma générique (static/style.css) pose border-radius:var(--bulma-control-radius) sur TOUT