From a4bf477fdac4cbc83e1bd37bbe5bb277758a0eec Mon Sep 17 00:00:00 2001 From: ccadmingit1 Date: Thu, 20 Aug 2026 12:43:30 +0000 Subject: [PATCH] Imported design export as-is (5/5) --- .../_ds_bundle.js | 47359 ++++++++++++++++ .../fonts/geomanist-regular.woff | Bin 0 -> 25544 bytes assets/vendor/react-dom.min.js | 267 + assets/vendor/react.min.js | 31 + support.js | 1911 + 5 files changed, 49568 insertions(+) create mode 100644 _ds/eazy-design-system-019e085a-0638-7c53-ad03-c4d5f4423a34/_ds_bundle.js create mode 100644 _ds/eazy-design-system-019e085a-0638-7c53-ad03-c4d5f4423a34/fonts/geomanist-regular.woff create mode 100644 assets/vendor/react-dom.min.js create mode 100644 assets/vendor/react.min.js create mode 100644 support.js diff --git a/_ds/eazy-design-system-019e085a-0638-7c53-ad03-c4d5f4423a34/_ds_bundle.js b/_ds/eazy-design-system-019e085a-0638-7c53-ad03-c4d5f4423a34/_ds_bundle.js new file mode 100644 index 0000000..bbc0641 --- /dev/null +++ b/_ds/eazy-design-system-019e085a-0638-7c53-ad03-c4d5f4423a34/_ds_bundle.js @@ -0,0 +1,47359 @@ +/* @ds-bundle: {"format":4,"namespace":"EazyDesignSystem_019e08","components":[{"name":"EzButton","sourcePath":"components/EzButton/EzButton.jsx"}],"sourceHashes":{"components/EzButton/EzButton.jsx":"d9ee37b8d784","eazy-landing/doc-page.js":"62024d965071","eazy-landing/script.js":"79d70d9bff98","exports/eazy-math-diagnostic/app.js":"c2dbf692f7de","flashcards/Deck.jsx":"5797696c99cd","flashcards/Flashcard.jsx":"d89d2a57d2e5","flashcards/deck-data.js":"605ee8fc5290","flashcards/ios-frame.jsx":"d67eb3ffe562","flashcards/tweaks-panel.jsx":"a1107c630a56","quiz-game-export/QuizGameExport.jsx":"96b531136862","quiz-game-export/words.js":"35263fe45fb0","quiz-game-server/QuizGameServer.jsx":"590d586f60af","quiz-game/Game.standalone.jsx":"ccb27042040f","quiz-game/QuizGame.jsx":"57c1f54eb3c3","quiz-game/design-canvas.jsx":"c9095ef15594","quiz-game/dist/game.js":"0af452a8a961","quiz-game/dist/words.js":"35263fe45fb0","quiz-game/end-sketches.jsx":"344c4dbd2767","quiz-game/ios-frame.jsx":"911f9ccc95e7","quiz-game/words.js":"35263fe45fb0","quiz/Quiz.jsx":"eebec2992326","quiz/ios-frame.jsx":"d67eb3ffe562","quiz/quiz-data.js":"65c69e1a9cee","quiz/tweaks-panel.jsx":"a1107c630a56","role-game/RoleGame.jsx":"951d60cdd5d9","role-game/ios-frame.jsx":"d67eb3ffe562","role-game/levels.jsx":"50926fa55b23","role-game/levelup-sketches.jsx":"3eeab92f6555","role-game/levelup-variants.jsx":"90097990162b","role-game/questions.js":"7ccc83478f55","role-game/tweaks-panel.jsx":"a1107c630a56","tetri-psychometry-export/tetri-game.jsx":"0f0fbec59b26","tetri-psychometry-export/words.js":"35263fe45fb0","tetri-psychometry/TetriGame.jsx":"e3a6c86b8e20","tetri-psychometry/words.js":"35263fe45fb0","tetri-vocab/VocabGame.jsx":"818ad56f6fce","tetri-vocab/vocab-data.js":"704c9f66fcdf","ui_kits/flyer/FlyerBulletList.jsx":"c777714ad9ab","ui_kits/flyer/FlyerEventStamp.jsx":"51049c1d957d","ui_kits/flyer/FlyerFrame.jsx":"4657083a384b","ui_kits/flyer/FlyerHeadline.jsx":"7e70d6e424dc","ui_kits/flyer/FlyerLogoBlock.jsx":"226ec15611c3","ui_kits/web/BannerCTA.jsx":"c2cfe1aff5d6","ui_kits/web/CourseGrid.jsx":"3e5dd3062642","ui_kits/web/Footer.jsx":"ee1960cf5310","ui_kits/web/Hero.jsx":"39c9519cb9c6","ui_kits/web/Includes.jsx":"853a71769dcb","ui_kits/web/LeadForm.jsx":"56cd43f920cc","ui_kits/web/SiteHeader.jsx":"1cfdb3887752","word-game/design-canvas.jsx":"d3ddcf4241b9","workshop-followup/doc-page.js":"62024d965071","workshop-followup/habits-data.js":"4afdc952666e","workshop-followup/מקור-לעריכה/habits-data.js":"4afdc952666e"},"inlinedExternals":[],"unexposedExports":[]} */ + +(() => { + +const __ds_ns = (window.EazyDesignSystem_019e08 = window.EazyDesignSystem_019e08 || {}); + +const __ds_scope = {}; + +(__ds_ns.__errors = __ds_ns.__errors || []); + +// components/EzButton/EzButton.jsx +try { (() => { +/* global React */ +const { + useState +} = React; + +/** + * EzButton — the eazy brand button. + * Solid fills only (no gradients), pill radius, Avigul display type. + * Hover darkens the fill 8% per the brand spec; active presses to scale(.99). + */ +function EzButton({ + children, + variant = "primary", + type = "button", + disabled = false, + onClick +}) { + const [hover, setHover] = useState(false); + const [active, setActive] = useState(false); + const base = { + fontFamily: "var(--font-display, system-ui)", + fontWeight: 700, + fontSize: 16, + lineHeight: 1, + borderRadius: 999, + padding: "12px 28px", + cursor: disabled ? "not-allowed" : "pointer", + opacity: disabled ? 0.4 : 1, + border: 0, + transition: "background .15s, color .15s, transform .08s", + transform: active && !disabled ? "scale(.99)" : "none", + outlineOffset: 2 + }; + const skins = { + primary: { + background: hover && !disabled ? "var(--ez-orange-deep)" : "var(--ez-orange)", + color: "#fff" + }, + secondary: { + background: hover && !disabled ? "var(--ez-lavender-deep)" : "var(--ez-lavender)", + color: hover && !disabled ? "#fff" : "#1d1a3a" + }, + ghost: { + background: hover && !disabled ? "var(--ez-ink)" : "transparent", + color: hover && !disabled ? "#fff" : "var(--ez-ink)", + border: "1.5px solid var(--ez-ink)", + padding: "11px 26px" + }, + link: { + background: "transparent", + color: hover && !disabled ? "var(--ez-orange-deep)" : "var(--ez-lavender-deep)", + padding: "12px 0" + } + }; + return /*#__PURE__*/React.createElement("button", { + type: type, + disabled: disabled, + onClick: onClick, + onMouseEnter: () => setHover(true), + onMouseLeave: () => { + setHover(false); + setActive(false); + }, + onMouseDown: () => setActive(true), + onMouseUp: () => setActive(false), + style: { + ...base, + ...skins[variant] + } + }, children); +} +Object.assign(__ds_scope, { EzButton }); +})(); } catch (e) { __ds_ns.__errors.push({ path: "components/EzButton/EzButton.jsx", error: String((e && e.message) || e) }); } + +// eazy-landing/doc-page.js +try { (() => { +// @ds-adherence-ignore -- omelette starter scaffold (raw elements/hex/px by design) +/* BEGIN USAGE */ +/** + * — paged-document shell for printable HTML. + * + * On screen the document renders as a single continuous sheet on a desk + * background (Google Docs' pageless view): you scroll one tall page card. + * There is no manual page-splitting — write the whole document as normal + * flow inside and the browser's print engine paginates it at + * export. + * + * At print the component injects `@page { size: …; margin: 0 }` (which + * leaves Chrome no margin box to draw its date/URL/page-count header in) + * and moves the visual margin onto the sheet's own padding, so the printed + * page has the same inset you see on screen. Standard break-hygiene rules + * (`break-inside: avoid` on figures, code blocks, images and table rows; + * `orphans/widows: 3`) are applied so paragraphs and groups split cleanly. + * On screen and at print, headings default to `text-wrap: balance` and + * body text (p, li, blockquote, figcaption) to `text-wrap: pretty`, so + * the document avoids widowed/orphaned words; the defaults have zero + * specificity, so any text-wrap you declare on those elements wins. + * + * Usage: + * + * + *

Title

+ *

…body…

+ *
+ * + * + * Attributes: + * size — letter | a4 | legal (default letter) + * width / height — explicit CSS lengths, override `size` + * margin — printable inset on every page (default 0.75in) + * + * Running header/footer (optional): give an element `slot="header"` or + * `slot="footer"` and it repeats on every printed page via + * `position: fixed`. To keep body text from sliding under it, the + * component prints inside a single-cell table whose / are + * spacers sized to the header/footer height — browsers repeat thead/tfoot + * on every page, so each sheet's content starts below the header and ends + * above the footer. On screen the header/footer render once at the + * top/bottom of the sheet. + * + * Author content as static HTML so the user can click-to-edit any text + * directly. Do not set width/padding/background on the document body — + * the component owns the sheet box. + */ +/* END USAGE */ + +(() => { + const PAPER = { + letter: ['8.5in', '11in'], + a4: ['210mm', '297mm'], + legal: ['8.5in', '14in'] + }; + const CSS_LENGTH = /^\d+(\.\d+)?(px|in|mm|cm|pt|pc)$/; + const safeLen = (v, fb) => CSS_LENGTH.test((v || '').trim()) ? v.trim() : fb; + const stylesheet = ` + :host { + position: relative; + display: block; + min-height: 100vh; + background: #ece8dd; + padding: 48px 24px; + box-sizing: border-box; + font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif; + --doc-page-w: 8.5in; + --doc-page-h: 11in; + --doc-page-margin: 0.75in; + --doc-hdr-h: 0px; + --doc-ftr-h: 0px; + } + .sheet { + width: var(--doc-page-w); + margin: 0 auto; + background: #fff; + box-shadow: 0 2px 14px rgba(20, 20, 19, 0.12); + border-radius: 2px; + box-sizing: border-box; + padding: var(--doc-page-margin); + } + .frame { width: 100%; border-collapse: collapse; } + .frame td, .frame th { padding: 0; text-align: left; font-weight: inherit; } + .hdr-space { height: var(--doc-hdr-h); } + .ftr-space { height: var(--doc-ftr-h); } + ::slotted([slot="header"]), + ::slotted([slot="footer"]) { display: block; box-sizing: border-box; } + @media print { + :host { background: none; padding: 0; min-height: 0; } + .sheet { + width: auto; margin: 0; box-shadow: none; border-radius: 0; + padding: 0 var(--doc-page-margin); + } + /* The thead/tfoot spacers repeat on every page, so they carry the + * vertical page margin (which the sheet's own padding cannot, since + * that padding is consumed once on the first/last page). The running + * header/footer are fixed inside that band. */ + .hdr-space { height: max(var(--doc-page-margin), calc(var(--doc-hdr-h) + 0.35in)); } + .ftr-space { height: max(var(--doc-page-margin), calc(var(--doc-ftr-h) + 0.35in)); } + ::slotted([slot="header"]) { + position: fixed; top: 0; left: 0; right: 0; margin: 0; + padding: calc(var(--doc-page-margin) * 0.45) var(--doc-page-margin) 0; + } + ::slotted([slot="footer"]) { + position: fixed; bottom: 0; left: 0; right: 0; margin: 0; + padding: 0 var(--doc-page-margin) calc(var(--doc-page-margin) * 0.45); + } + } + `; + class DocPage extends HTMLElement { + static get observedAttributes() { + return ['size', 'width', 'height', 'margin']; + } + constructor() { + super(); + this._root = this.attachShadow({ + mode: 'open' + }); + this._mo = typeof MutationObserver === 'function' ? new MutationObserver(() => this._scheduleMeasure()) : null; + } + get pageWidth() { + const named = PAPER[(this.getAttribute('size') || '').toLowerCase()]; + return safeLen(this.getAttribute('width'), named ? named[0] : PAPER.letter[0]); + } + get pageHeight() { + const named = PAPER[(this.getAttribute('size') || '').toLowerCase()]; + return safeLen(this.getAttribute('height'), named ? named[1] : PAPER.letter[1]); + } + get pageMargin() { + return safeLen(this.getAttribute('margin'), '0.75in'); + } + connectedCallback() { + if (!this._sheet) this._render(); + this._syncSize(); + this._syncPrintPageRule(); + this._ensureTextWrapDefaults(); + if (this._mo) this._mo.observe(this, { + subtree: true, + childList: true, + characterData: true, + attributes: true + }); + this._onResize = () => this._scheduleMeasure(); + window.addEventListener('resize', this._onResize); + if (document.fonts && document.fonts.ready) { + document.fonts.ready.then(() => this._scheduleMeasure()); + } + this._scheduleMeasure(); + } + disconnectedCallback() { + window.removeEventListener('resize', this._onResize); + if (this._mo) this._mo.disconnect(); + if (this._raf) { + cancelAnimationFrame(this._raf); + this._raf = null; + } + // Drop the head rules when the last doc-page leaves, so a deleted + // document's @page geometry and text-wrap defaults can't apply to + // whatever replaces it. + if (!document.querySelector('doc-page')) { + ['doc-page-print', 'doc-page-text-wrap'].forEach(id => { + const tag = document.getElementById(id); + if (tag) tag.remove(); + }); + } + } + attributeChangedCallback() { + if (!this._sheet) return; + this._syncSize(); + this._syncPrintPageRule(); + this._scheduleMeasure(); + } + _render() { + this._root.innerHTML = ` + + +
+ + + + + +
`; + this._sheet = this._root.querySelector('.sheet'); + this._vars = this._root.getElementById('vars'); + } + + /** Runtime sizing lives in a shadow ' : '') + '' + xml + ''; + return save(new Blob([html], { + type: 'text/html' + }), 'html'); + } + + // PNG: the SVG's own width/height must be the output resolution — an + // -loaded SVG rasterizes at its intrinsic size, so sizing it at 1× + // and ctx.scale()-ing up would just upscale a 1× bitmap. viewBox maps the + // w×h foreignObject onto the px·w × px·h SVG canvas so the browser renders + // the HTML at full resolution. + const px = 3; + const svg = '' + (fontCss ? '' : '') + xml + ''; + const img = new Image(); + await new Promise((res, rej) => { + img.onload = res; + img.onerror = () => rej(new Error('svg load failed')); + img.src = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svg); + }); + const cv = document.createElement('canvas'); + cv.width = w * px; + cv.height = h * px; + cv.getContext('2d').drawImage(img, 0, 0); + cv.toBlob(blob => save(blob, 'png'), 'image/png'); +} +function DCArtboardFrame({ + sectionId, + artboard, + label, + order, + onRename, + onReorder, + onFocus, + onDelete +}) { + const { + id: rawId, + label: rawLabel, + width = 260, + height = 480, + children, + style = {} + } = artboard.props; + const id = rawId ?? rawLabel; + const ref = React.useRef(null); + const cardRef = React.useRef(null); + const menuRef = React.useRef(null); + const [menuOpen, setMenuOpen] = React.useState(false); + const [confirming, setConfirming] = React.useState(false); + + // ⋯ menu: close on any outside pointerdown. Two-click delete lives inside + // the menu — first click arms the row, second commits; closing disarms. + React.useEffect(() => { + if (!menuOpen) { + setConfirming(false); + return; + } + const off = e => { + if (!menuRef.current || !menuRef.current.contains(e.target)) setMenuOpen(false); + }; + document.addEventListener('pointerdown', off, true); + return () => document.removeEventListener('pointerdown', off, true); + }, [menuOpen]); + const doExport = kind => { + setMenuOpen(false); + if (!cardRef.current) return; + const name = String(label || id || 'artboard').replace(/[^\w\s.-]+/g, '_'); + dcExport(cardRef.current, width, height, name, kind).catch(e => console.error('[design-canvas] export failed:', e)); + }; + + // Live drag-reorder: dragged card sticks to cursor; siblings slide into + // their would-be slots in real time via transforms. DOM order only + // changes on drop. + const onGripDown = e => { + e.preventDefault(); + e.stopPropagation(); + const me = ref.current; + // translateX is applied in local (pre-scale) space but pointer deltas and + // getBoundingClientRect().left are screen-space — divide by the viewport's + // current scale so the dragged card tracks the cursor at any zoom level. + const scale = me.getBoundingClientRect().width / me.offsetWidth || 1; + const peers = Array.from(document.querySelectorAll(`[data-dc-section="${sectionId}"] [data-dc-slot]`)); + const homes = peers.map(el => ({ + el, + id: el.dataset.dcSlot, + x: el.getBoundingClientRect().left + })); + const slotXs = homes.map(h => h.x); + const startIdx = order.indexOf(id); + const startX = e.clientX; + let liveOrder = order.slice(); + me.classList.add('dc-dragging'); + const layout = () => { + for (const h of homes) { + if (h.id === id) continue; + const slot = liveOrder.indexOf(h.id); + h.el.style.transform = `translateX(${(slotXs[slot] - h.x) / scale}px)`; + } + }; + const move = ev => { + const dx = ev.clientX - startX; + me.style.transform = `translateX(${dx / scale}px)`; + const cur = homes[startIdx].x + dx; + let nearest = 0, + best = Infinity; + for (let i = 0; i < slotXs.length; i++) { + const d = Math.abs(slotXs[i] - cur); + if (d < best) { + best = d; + nearest = i; + } + } + if (liveOrder.indexOf(id) !== nearest) { + liveOrder = order.filter(k => k !== id); + liveOrder.splice(nearest, 0, id); + layout(); + } + }; + const up = () => { + document.removeEventListener('pointermove', move); + document.removeEventListener('pointerup', up); + const finalSlot = liveOrder.indexOf(id); + me.classList.remove('dc-dragging'); + me.style.transform = `translateX(${(slotXs[finalSlot] - homes[startIdx].x) / scale}px)`; + // After the settle transition, kill transitions + clear transforms + + // commit the reorder in the same frame so there's no visual snap-back. + setTimeout(() => { + for (const h of homes) { + h.el.style.transition = 'none'; + h.el.style.transform = ''; + } + if (liveOrder.join('|') !== order.join('|')) onReorder(liveOrder); + requestAnimationFrame(() => requestAnimationFrame(() => { + for (const h of homes) h.el.style.transition = ''; + })); + }, 180); + }; + document.addEventListener('pointermove', move); + document.addEventListener('pointerup', up); + }; + return /*#__PURE__*/React.createElement("div", { + ref: ref, + "data-dc-slot": id, + style: { + position: 'relative', + flexShrink: 0 + } + }, /*#__PURE__*/React.createElement("div", { + className: "dc-header", + "data-noncommentable": "", + style: { + color: DC.label + }, + onPointerDown: e => e.stopPropagation() + }, /*#__PURE__*/React.createElement("div", { + className: "dc-labelrow" + }, /*#__PURE__*/React.createElement("div", { + className: "dc-grip", + onPointerDown: onGripDown, + title: "Drag to reorder" + }, /*#__PURE__*/React.createElement("svg", { + width: "9", + height: "13", + viewBox: "0 0 9 13", + fill: "currentColor" + }, /*#__PURE__*/React.createElement("circle", { + cx: "2", + cy: "2", + r: "1.1" + }), /*#__PURE__*/React.createElement("circle", { + cx: "7", + cy: "2", + r: "1.1" + }), /*#__PURE__*/React.createElement("circle", { + cx: "2", + cy: "6.5", + r: "1.1" + }), /*#__PURE__*/React.createElement("circle", { + cx: "7", + cy: "6.5", + r: "1.1" + }), /*#__PURE__*/React.createElement("circle", { + cx: "2", + cy: "11", + r: "1.1" + }), /*#__PURE__*/React.createElement("circle", { + cx: "7", + cy: "11", + r: "1.1" + }))), /*#__PURE__*/React.createElement("div", { + className: "dc-labeltext", + onClick: onFocus, + title: "Click to focus" + }, /*#__PURE__*/React.createElement(DCEditable, { + value: label, + onChange: onRename, + onClick: e => e.stopPropagation(), + style: { + fontSize: 15, + fontWeight: 500, + color: DC.label, + lineHeight: 1 + } + }))), /*#__PURE__*/React.createElement("div", { + className: "dc-btns" + }, /*#__PURE__*/React.createElement("div", { + ref: menuRef, + style: { + position: 'relative' + } + }, /*#__PURE__*/React.createElement("button", { + className: "dc-kebab", + title: "More", + onClick: () => setMenuOpen(o => !o) + }, /*#__PURE__*/React.createElement("svg", { + width: "12", + height: "12", + viewBox: "0 0 12 12", + fill: "currentColor" + }, /*#__PURE__*/React.createElement("circle", { + cx: "2.5", + cy: "6", + r: "1.1" + }), /*#__PURE__*/React.createElement("circle", { + cx: "6", + cy: "6", + r: "1.1" + }), /*#__PURE__*/React.createElement("circle", { + cx: "9.5", + cy: "6", + r: "1.1" + }))), menuOpen && /*#__PURE__*/React.createElement("div", { + className: "dc-menu", + onPointerDown: e => e.stopPropagation() + }, /*#__PURE__*/React.createElement("button", { + onClick: () => doExport('png') + }, "Download PNG"), /*#__PURE__*/React.createElement("button", { + onClick: () => doExport('html') + }, "Download HTML"), /*#__PURE__*/React.createElement("hr", null), /*#__PURE__*/React.createElement("button", { + className: "dc-danger", + onClick: () => { + if (confirming) { + setMenuOpen(false); + onDelete(); + } else setConfirming(true); + } + }, confirming ? 'Click again to delete' : 'Delete'))), /*#__PURE__*/React.createElement("button", { + className: "dc-expand", + onClick: onFocus, + title: "Focus" + }, /*#__PURE__*/React.createElement("svg", { + width: "12", + height: "12", + viewBox: "0 0 12 12", + fill: "none", + stroke: "currentColor", + strokeWidth: "1.6", + strokeLinecap: "round" + }, /*#__PURE__*/React.createElement("path", { + d: "M7 1h4v4M5 11H1V7M11 1L7.5 4.5M1 11l3.5-3.5" + }))))), /*#__PURE__*/React.createElement("div", { + ref: cardRef, + className: "dc-card", + style: { + borderRadius: 2, + boxShadow: '0 1px 3px rgba(0,0,0,.08),0 4px 16px rgba(0,0,0,.06)', + overflow: 'hidden', + width, + height, + background: '#fff', + ...style + } + }, children || /*#__PURE__*/React.createElement("div", { + style: { + height: '100%', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + color: '#bbb', + fontSize: 13, + fontFamily: DC.font + } + }, id))); +} + +// Inline rename — commits on blur or Enter. +function DCEditable({ + value, + onChange, + style, + tag = 'span', + onClick +}) { + const T = tag; + return /*#__PURE__*/React.createElement(T, { + className: "dc-editable", + contentEditable: true, + suppressContentEditableWarning: true, + onClick: onClick, + onPointerDown: e => e.stopPropagation(), + onBlur: e => onChange && onChange(e.currentTarget.textContent), + onKeyDown: e => { + if (e.key === 'Enter') { + e.preventDefault(); + e.currentTarget.blur(); + } + }, + style: style + }, value); +} + +// ───────────────────────────────────────────────────────────── +// Focus mode — overlay one artboard; ←/→ within section, ↑/↓ across +// sections, Esc or backdrop click to exit. +// ───────────────────────────────────────────────────────────── +function DCFocusOverlay({ + entry, + sectionMeta, + sectionOrder +}) { + const ctx = React.useContext(DCCtx); + const { + sectionId, + artboard + } = entry; + const sec = ctx.section(sectionId); + const meta = sectionMeta[sectionId]; + const peers = meta.slotIds; + const aid = artboard.props.id ?? artboard.props.label; + const idx = peers.indexOf(aid); + const secIdx = sectionOrder.indexOf(sectionId); + const go = d => { + const n = peers[(idx + d + peers.length) % peers.length]; + if (n) ctx.setFocus(`${sectionId}/${n}`); + }; + const goSection = d => { + // Sections whose artboards are all deleted have slotIds:[] — step past + // them to the next non-empty section so ↑/↓ doesn't dead-end. + const n = sectionOrder.length; + for (let i = 1; i < n; i++) { + const ns = sectionOrder[((secIdx + d * i) % n + n) % n]; + const first = sectionMeta[ns] && sectionMeta[ns].slotIds[0]; + if (first) { + ctx.setFocus(`${ns}/${first}`); + return; + } + } + }; + React.useEffect(() => { + const k = e => { + if (e.key === 'ArrowLeft') { + e.preventDefault(); + go(-1); + } + if (e.key === 'ArrowRight') { + e.preventDefault(); + go(1); + } + if (e.key === 'ArrowUp') { + e.preventDefault(); + goSection(-1); + } + if (e.key === 'ArrowDown') { + e.preventDefault(); + goSection(1); + } + }; + document.addEventListener('keydown', k); + return () => document.removeEventListener('keydown', k); + }); + const { + width = 260, + height = 480, + children + } = artboard.props; + const [vp, setVp] = React.useState({ + w: window.innerWidth, + h: window.innerHeight + }); + React.useEffect(() => { + const r = () => setVp({ + w: window.innerWidth, + h: window.innerHeight + }); + window.addEventListener('resize', r); + return () => window.removeEventListener('resize', r); + }, []); + const scale = Math.max(0.1, Math.min((vp.w - 200) / width, (vp.h - 260) / height, 2)); + const [ddOpen, setDd] = React.useState(false); + const Arrow = ({ + dir, + onClick + }) => /*#__PURE__*/React.createElement("button", { + onClick: e => { + e.stopPropagation(); + onClick(); + }, + style: { + position: 'absolute', + top: '50%', + [dir]: 28, + transform: 'translateY(-50%)', + border: 'none', + background: 'rgba(255,255,255,.08)', + color: 'rgba(255,255,255,.9)', + width: 44, + height: 44, + borderRadius: 22, + fontSize: 18, + cursor: 'pointer', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + transition: 'background .15s' + }, + onMouseEnter: e => e.currentTarget.style.background = 'rgba(255,255,255,.18)', + onMouseLeave: e => e.currentTarget.style.background = 'rgba(255,255,255,.08)' + }, /*#__PURE__*/React.createElement("svg", { + width: "18", + height: "18", + viewBox: "0 0 18 18", + fill: "none", + stroke: "currentColor", + strokeWidth: "2", + strokeLinecap: "round" + }, /*#__PURE__*/React.createElement("path", { + d: dir === 'left' ? 'M11 3L5 9l6 6' : 'M7 3l6 6-6 6' + }))); + + // Portal to body so position:fixed is the real viewport regardless of any + // transform on DesignCanvas's ancestors (including the canvas zoom itself). + return ReactDOM.createPortal(/*#__PURE__*/React.createElement("div", { + onClick: () => ctx.setFocus(null), + onWheel: e => e.preventDefault(), + style: { + position: 'fixed', + inset: 0, + zIndex: 100, + background: 'rgba(24,20,16,.6)', + backdropFilter: 'blur(14px)', + fontFamily: DC.font, + color: '#fff' + } + }, /*#__PURE__*/React.createElement("div", { + onClick: e => e.stopPropagation(), + style: { + position: 'absolute', + top: 0, + left: 0, + right: 0, + height: 72, + display: 'flex', + alignItems: 'flex-start', + padding: '16px 20px 0', + gap: 16 + } + }, /*#__PURE__*/React.createElement("div", { + style: { + position: 'relative' + } + }, /*#__PURE__*/React.createElement("button", { + onClick: () => setDd(o => !o), + style: { + border: 'none', + background: 'transparent', + color: '#fff', + cursor: 'pointer', + padding: '6px 8px', + borderRadius: 6, + textAlign: 'left', + fontFamily: 'inherit' + } + }, /*#__PURE__*/React.createElement("span", { + style: { + display: 'flex', + alignItems: 'center', + gap: 8 + } + }, /*#__PURE__*/React.createElement("span", { + style: { + fontSize: 18, + fontWeight: 600, + letterSpacing: -0.3 + } + }, meta.title), /*#__PURE__*/React.createElement("svg", { + width: "11", + height: "11", + viewBox: "0 0 11 11", + fill: "none", + stroke: "currentColor", + strokeWidth: "1.8", + strokeLinecap: "round", + style: { + opacity: .7 + } + }, /*#__PURE__*/React.createElement("path", { + d: "M2 4l3.5 3.5L9 4" + }))), meta.subtitle && /*#__PURE__*/React.createElement("span", { + style: { + display: 'block', + fontSize: 13, + opacity: .6, + fontWeight: 400, + marginTop: 2 + } + }, meta.subtitle)), ddOpen && /*#__PURE__*/React.createElement("div", { + style: { + position: 'absolute', + top: '100%', + left: 0, + marginTop: 4, + background: '#2a251f', + borderRadius: 8, + boxShadow: '0 8px 32px rgba(0,0,0,.4)', + padding: 4, + minWidth: 200, + zIndex: 10 + } + }, sectionOrder.filter(sid => sectionMeta[sid].slotIds.length).map(sid => /*#__PURE__*/React.createElement("button", { + key: sid, + onClick: () => { + setDd(false); + const f = sectionMeta[sid].slotIds[0]; + if (f) ctx.setFocus(`${sid}/${f}`); + }, + style: { + display: 'block', + width: '100%', + textAlign: 'left', + border: 'none', + cursor: 'pointer', + background: sid === sectionId ? 'rgba(255,255,255,.1)' : 'transparent', + color: '#fff', + padding: '8px 12px', + borderRadius: 5, + fontSize: 14, + fontWeight: sid === sectionId ? 600 : 400, + fontFamily: 'inherit' + } + }, sectionMeta[sid].title)))), /*#__PURE__*/React.createElement("div", { + style: { + flex: 1 + } + }), /*#__PURE__*/React.createElement("button", { + onClick: () => ctx.setFocus(null), + onMouseEnter: e => e.currentTarget.style.background = 'rgba(255,255,255,.12)', + onMouseLeave: e => e.currentTarget.style.background = 'transparent', + style: { + border: 'none', + background: 'transparent', + color: 'rgba(255,255,255,.7)', + width: 32, + height: 32, + borderRadius: 16, + fontSize: 20, + cursor: 'pointer', + lineHeight: 1, + transition: 'background .12s' + } + }, "\xD7")), /*#__PURE__*/React.createElement("div", { + style: { + position: 'absolute', + top: 64, + bottom: 56, + left: 100, + right: 100, + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + gap: 16 + } + }, /*#__PURE__*/React.createElement("div", { + onClick: e => e.stopPropagation(), + style: { + width: width * scale, + height: height * scale, + position: 'relative' + } + }, /*#__PURE__*/React.createElement("div", { + style: { + width, + height, + transform: `scale(${scale})`, + transformOrigin: 'top left', + background: '#fff', + borderRadius: 2, + overflow: 'hidden', + boxShadow: '0 20px 80px rgba(0,0,0,.4)' + } + }, children || /*#__PURE__*/React.createElement("div", { + style: { + height: '100%', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + color: '#bbb' + } + }, aid))), /*#__PURE__*/React.createElement("div", { + onClick: e => e.stopPropagation(), + style: { + fontSize: 14, + fontWeight: 500, + opacity: .85, + textAlign: 'center' + } + }, (sec.labels || {})[aid] ?? artboard.props.label, /*#__PURE__*/React.createElement("span", { + style: { + opacity: .5, + marginLeft: 10, + fontVariantNumeric: 'tabular-nums' + } + }, idx + 1, " / ", peers.length))), /*#__PURE__*/React.createElement(Arrow, { + dir: "left", + onClick: () => go(-1) + }), /*#__PURE__*/React.createElement(Arrow, { + dir: "right", + onClick: () => go(1) + }), /*#__PURE__*/React.createElement("div", { + onClick: e => e.stopPropagation(), + style: { + position: 'absolute', + bottom: 20, + left: '50%', + transform: 'translateX(-50%)', + display: 'flex', + gap: 8 + } + }, peers.map((p, i) => /*#__PURE__*/React.createElement("button", { + key: p, + onClick: () => ctx.setFocus(`${sectionId}/${p}`), + style: { + border: 'none', + padding: 0, + cursor: 'pointer', + width: 6, + height: 6, + borderRadius: 3, + background: i === idx ? '#fff' : 'rgba(255,255,255,.3)' + } + })))), document.body); +} + +// ───────────────────────────────────────────────────────────── +// Post-it — absolute-positioned sticky note +// ───────────────────────────────────────────────────────────── +function DCPostIt({ + children, + top, + left, + right, + bottom, + rotate = -2, + width = 180 +}) { + return /*#__PURE__*/React.createElement("div", { + style: { + position: 'absolute', + top, + left, + right, + bottom, + width, + background: DC.postitBg, + padding: '14px 16px', + fontFamily: '"Comic Sans MS", "Marker Felt", "Segoe Print", cursive', + fontSize: 14, + lineHeight: 1.4, + color: DC.postitText, + boxShadow: '0 2px 8px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.08)', + transform: `rotate(${rotate}deg)`, + zIndex: 5 + } + }, children); +} +Object.assign(window, { + DesignCanvas, + DCSection, + DCArtboard, + DCPostIt +}); +})(); } catch (e) { __ds_ns.__errors.push({ path: "quiz-game/design-canvas.jsx", error: String((e && e.message) || e) }); } + +// quiz-game/dist/game.js +try { (() => { +"use strict"; + +function _typeof(o) { + "@babel/helpers - typeof"; + + return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { + return typeof o; + } : function (o) { + return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; + }, _typeof(o); +} +function ownKeys(e, r) { + var t = Object.keys(e); + if (Object.getOwnPropertySymbols) { + var o = Object.getOwnPropertySymbols(e); + r && (o = o.filter(function (r) { + return Object.getOwnPropertyDescriptor(e, r).enumerable; + })), t.push.apply(t, o); + } + return t; +} +function _objectSpread(e) { + for (var r = 1; r < arguments.length; r++) { + var t = null != arguments[r] ? arguments[r] : {}; + r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { + _defineProperty(e, r, t[r]); + }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { + Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); + }); + } + return e; +} +function _defineProperty(e, r, t) { + return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { + value: t, + enumerable: !0, + configurable: !0, + writable: !0 + }) : e[r] = t, e; +} +function _toPropertyKey(t) { + var i = _toPrimitive(t, "string"); + return "symbol" == _typeof(i) ? i : i + ""; +} +function _toPrimitive(t, r) { + if ("object" != _typeof(t) || !t) return t; + var e = t[Symbol.toPrimitive]; + if (void 0 !== e) { + var i = e.call(t, r || "default"); + if ("object" != _typeof(i)) return i; + throw new TypeError("@@toPrimitive must return a primitive value."); + } + return ("string" === r ? String : Number)(t); +} +function _regenerator() { + /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */var e, + t, + r = "function" == typeof Symbol ? Symbol : {}, + n = r.iterator || "@@iterator", + o = r.toStringTag || "@@toStringTag"; + function i(r, n, o, i) { + var c = n && n.prototype instanceof Generator ? n : Generator, + u = Object.create(c.prototype); + return _regeneratorDefine2(u, "_invoke", function (r, n, o) { + var i, + c, + u, + f = 0, + p = o || [], + y = !1, + G = { + p: 0, + n: 0, + v: e, + a: d, + f: d.bind(e, 4), + d: function d(t, r) { + return i = t, c = 0, u = e, G.n = r, a; + } + }; + function d(r, n) { + for (c = r, u = n, t = 0; !y && f && !o && t < p.length; t++) { + var o, + i = p[t], + d = G.p, + l = i[2]; + r > 3 ? (o = l === n) && (u = i[(c = i[4]) ? 5 : (c = 3, 3)], i[4] = i[5] = e) : i[0] <= d && ((o = r < 2 && d < i[1]) ? (c = 0, G.v = n, G.n = i[1]) : d < l && (o = r < 3 || i[0] > n || n > l) && (i[4] = r, i[5] = n, G.n = l, c = 0)); + } + if (o || r > 1) return a; + throw y = !0, n; + } + return function (o, p, l) { + if (f > 1) throw TypeError("Generator is already running"); + for (y && 1 === p && d(p, l), c = p, u = l; (t = c < 2 ? e : u) || !y;) { + i || (c ? c < 3 ? (c > 1 && (G.n = -1), d(c, u)) : G.n = u : G.v = u); + try { + if (f = 2, i) { + if (c || (o = "next"), t = i[o]) { + if (!(t = t.call(i, u))) throw TypeError("iterator result is not an object"); + if (!t.done) return t; + u = t.value, c < 2 && (c = 0); + } else 1 === c && (t = i.return) && t.call(i), c < 2 && (u = TypeError("The iterator does not provide a '" + o + "' method"), c = 1); + i = e; + } else if ((t = (y = G.n < 0) ? u : r.call(n, G)) !== a) break; + } catch (t) { + i = e, c = 1, u = t; + } finally { + f = 1; + } + } + return { + value: t, + done: y + }; + }; + }(r, o, i), !0), u; + } + var a = {}; + function Generator() {} + function GeneratorFunction() {} + function GeneratorFunctionPrototype() {} + t = Object.getPrototypeOf; + var c = [][n] ? t(t([][n]())) : (_regeneratorDefine2(t = {}, n, function () { + return this; + }), t), + u = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(c); + function f(e) { + return Object.setPrototypeOf ? Object.setPrototypeOf(e, GeneratorFunctionPrototype) : (e.__proto__ = GeneratorFunctionPrototype, _regeneratorDefine2(e, o, "GeneratorFunction")), e.prototype = Object.create(u), e; + } + return GeneratorFunction.prototype = GeneratorFunctionPrototype, _regeneratorDefine2(u, "constructor", GeneratorFunctionPrototype), _regeneratorDefine2(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = "GeneratorFunction", _regeneratorDefine2(GeneratorFunctionPrototype, o, "GeneratorFunction"), _regeneratorDefine2(u), _regeneratorDefine2(u, o, "Generator"), _regeneratorDefine2(u, n, function () { + return this; + }), _regeneratorDefine2(u, "toString", function () { + return "[object Generator]"; + }), (_regenerator = function _regenerator() { + return { + w: i, + m: f + }; + })(); +} +function _regeneratorDefine2(e, r, n, t) { + var i = Object.defineProperty; + try { + i({}, "", {}); + } catch (e) { + i = 0; + } + _regeneratorDefine2 = function _regeneratorDefine(e, r, n, t) { + function o(r, n) { + _regeneratorDefine2(e, r, function (e) { + return this._invoke(r, n, e); + }); + } + r ? i ? i(e, r, { + value: n, + enumerable: !t, + configurable: !t, + writable: !t + }) : e[r] = n : (o("next", 0), o("throw", 1), o("return", 2)); + }, _regeneratorDefine2(e, r, n, t); +} +function asyncGeneratorStep(n, t, e, r, o, a, c) { + try { + var i = n[a](c), + u = i.value; + } catch (n) { + return void e(n); + } + i.done ? t(u) : Promise.resolve(u).then(r, o); +} +function _asyncToGenerator(n) { + return function () { + var t = this, + e = arguments; + return new Promise(function (r, o) { + var a = n.apply(t, e); + function _next(n) { + asyncGeneratorStep(a, r, o, _next, _throw, "next", n); + } + function _throw(n) { + asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); + } + _next(void 0); + }); + }; +} +function _slicedToArray(r, e) { + return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); +} +function _nonIterableRest() { + throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); +} +function _iterableToArrayLimit(r, l) { + var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; + if (null != t) { + var e, + n, + i, + u, + a = [], + f = !0, + o = !1; + try { + if (i = (t = t.call(r)).next, 0 === l) { + if (Object(t) !== t) return; + f = !1; + } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); + } catch (r) { + o = !0, n = r; + } finally { + try { + if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; + } finally { + if (o) throw n; + } + } + return a; + } +} +function _arrayWithHoles(r) { + if (Array.isArray(r)) return r; +} +function _createForOfIteratorHelper(r, e) { + var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; + if (!t) { + if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { + t && (r = t); + var _n = 0, + F = function F() {}; + return { + s: F, + n: function n() { + return _n >= r.length ? { + done: !0 + } : { + done: !1, + value: r[_n++] + }; + }, + e: function e(r) { + throw r; + }, + f: F + }; + } + throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); + } + var o, + a = !0, + u = !1; + return { + s: function s() { + t = t.call(r); + }, + n: function n() { + var r = t.next(); + return a = r.done, r; + }, + e: function e(r) { + u = !0, o = r; + }, + f: function f() { + try { + a || null == t.return || t.return(); + } finally { + if (u) throw o; + } + } + }; +} +function _toConsumableArray(r) { + return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); +} +function _nonIterableSpread() { + throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); +} +function _unsupportedIterableToArray(r, a) { + if (r) { + if ("string" == typeof r) return _arrayLikeToArray(r, a); + var t = {}.toString.call(r).slice(8, -1); + return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; + } +} +function _iterableToArray(r) { + if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); +} +function _arrayWithoutHoles(r) { + if (Array.isArray(r)) return _arrayLikeToArray(r); +} +function _arrayLikeToArray(r, a) { + (null == a || a > r.length) && (a = r.length); + for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; + return n; +} +/* global React, XLSX */ +var _React = React, + useState = _React.useState, + useEffect = _React.useEffect, + useRef = _React.useRef, + useCallback = _React.useCallback, + useLayoutEffect = _React.useLayoutEffect, + useMemo = _React.useMemo; + +/* ---------- built-in sample dictionary ---------- */ +var SAMPLE_DICT = [{ + en: "ENHANCE", + he: "להעצים, לשפר", + ipa: "/ɪnˈhæns/" +}, { + en: "MITIGATE", + he: "להקל, למתן", + ipa: "/ˈmɪtɪˌɡeɪt/" +}, { + en: "AMBIGUOUS", + he: "דו-משמעי, עמום", + ipa: "/æmˈbɪɡjuəs/" +}, { + en: "ADVOCATE", + he: "לתמוך, להמליץ", + ipa: "/ˈædvəˌkeɪt/" +}, { + en: "SCRUTINIZE", + he: "לבחון בקפדנות", + ipa: "/ˈskruːtəˌnaɪz/" +}, { + en: "INEVITABLE", + he: "בלתי נמנע", + ipa: "/ɪˈnɛvɪtəbəl/" +}, { + en: "DILIGENT", + he: "חרוץ, שקדן", + ipa: "/ˈdɪlɪdʒənt/" +}, { + en: "OBSOLETE", + he: "מיושן, יצא משימוש", + ipa: "/ˌabsəˈliːt/" +}, { + en: "CANDID", + he: "הֵן, ישיר, ספונטני", + ipa: "/ˈkændɪd/" +}, { + en: "TENACIOUS", + he: "עיקש, דבק במטרה", + ipa: "/təˈneɪʃəs/" +}]; +var STAGGER = [0, 40, 14, 56]; +var DICT_STORAGE_KEY = "ez-mcq-dict-v2"; +var DICT_NAME_KEY = "ez-mcq-dict-name-v2"; +var MUTED_KEY = "ez-mcq-muted-v1"; +var LB_KEY = "ez-mcq-leaderboard-v1"; + +/* ---------- sound engine (WebAudio FX + background music) ---------- */ +var Sound = { + ctx: null, + muted: false, + music: null, + //