@mathscan/math-exercise-engine 1.1.14 → 1.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +424 -54
- package/dist/index.js +325 -63
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +326 -64
- package/dist/index.mjs.map +1 -1
- package/dist/style.css +385 -68
- package/package.json +1 -1
package/dist/style.css
CHANGED
|
@@ -68,6 +68,9 @@
|
|
|
68
68
|
/** Margin between inline elements (0.25rem = 4px) */
|
|
69
69
|
--exercise-element-margin: 0.25rem;
|
|
70
70
|
|
|
71
|
+
/** Minimum space kept between the exercise content and the numeric keypad */
|
|
72
|
+
--exercise-keypad-gap: 1rem;
|
|
73
|
+
|
|
71
74
|
/* ========================================
|
|
72
75
|
TYPOGRAPHY VARIABLES
|
|
73
76
|
======================================== */
|
|
@@ -152,6 +155,10 @@
|
|
|
152
155
|
display: flex;
|
|
153
156
|
justify-content: space-between;
|
|
154
157
|
align-items: flex-start;
|
|
158
|
+
/* Guaranteed breathing room between the content and the keypad.
|
|
159
|
+
space-between alone only separates them while there is leftover
|
|
160
|
+
space, so wide content would otherwise run right up to the keypad. */
|
|
161
|
+
gap: var(--exercise-keypad-gap);
|
|
155
162
|
}
|
|
156
163
|
|
|
157
164
|
/* When inside a keypad layout, the exercise layout must grow to fill
|
|
@@ -319,15 +326,7 @@ mark {
|
|
|
319
326
|
font-weight: bold;
|
|
320
327
|
}
|
|
321
328
|
|
|
322
|
-
/*
|
|
323
|
-
IMAGE
|
|
324
|
-
======================================== */
|
|
325
|
-
|
|
326
|
-
.image-item {
|
|
327
|
-
vertical-align: middle;
|
|
328
|
-
max-width: 100%;
|
|
329
|
-
object-fit: contain;
|
|
330
|
-
}
|
|
329
|
+
/* Image styles live in image.css */
|
|
331
330
|
|
|
332
331
|
/* ========================================
|
|
333
332
|
OPERATORS & SYMBOLS
|
|
@@ -546,7 +545,7 @@ mark {
|
|
|
546
545
|
}
|
|
547
546
|
|
|
548
547
|
.pill-bg-path {
|
|
549
|
-
fill: var(--exercise-pill-bg, #
|
|
548
|
+
fill: var(--exercise-pill-bg, #ffe7b4);
|
|
550
549
|
}
|
|
551
550
|
|
|
552
551
|
/*
|
|
@@ -685,11 +684,14 @@ button.drag-option {
|
|
|
685
684
|
/**
|
|
686
685
|
* Keypad container dimensions:
|
|
687
686
|
* - min-width: 150px ensures keypad is always usable
|
|
688
|
-
* -
|
|
687
|
+
* - flex-shrink: 0 so the keypad keeps its size and the content
|
|
688
|
+
* (flex: 1; min-width: 0) absorbs the squeeze instead
|
|
689
|
+
* - margin-right: 5px keeps it off the outer edge; the space on its
|
|
690
|
+
* left comes from the container gap (--exercise-keypad-gap)
|
|
689
691
|
*/
|
|
690
692
|
min-width: 150px;
|
|
693
|
+
flex-shrink: 0;
|
|
691
694
|
margin-right: 5px;
|
|
692
|
-
margin-left: 5px;
|
|
693
695
|
}
|
|
694
696
|
|
|
695
697
|
.numeric-keypad {
|
|
@@ -780,10 +782,8 @@ button.drag-option {
|
|
|
780
782
|
|
|
781
783
|
.exercise-table {
|
|
782
784
|
border-spacing: 0;
|
|
783
|
-
border: 2px solid var(--exercise-table-border, #8b7ec8);
|
|
784
|
-
border-radius: 12px;
|
|
785
|
-
overflow: hidden;
|
|
786
785
|
font-size: small;
|
|
786
|
+
width: 100%;
|
|
787
787
|
}
|
|
788
788
|
|
|
789
789
|
.exercise-table-cell {
|
|
@@ -801,12 +801,32 @@ button.drag-option {
|
|
|
801
801
|
}
|
|
802
802
|
|
|
803
803
|
table.exercise-table {
|
|
804
|
-
border-collapse:
|
|
804
|
+
border-collapse: separate;
|
|
805
|
+
border-spacing: 0;
|
|
805
806
|
}
|
|
806
807
|
|
|
807
808
|
td.exercise-table-cell,
|
|
808
809
|
th.exercise-table-cell {
|
|
809
|
-
|
|
810
|
+
box-shadow: inset -2px -2px 0 0 #7c6cf2;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
td.exercise-table-cell:last-child,
|
|
814
|
+
th.exercise-table-cell:last-child {
|
|
815
|
+
box-shadow: inset 0 -2px 0 0 #7c6cf2;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
tr.exercise-table-row:last-child td.exercise-table-cell,
|
|
819
|
+
tr.exercise-table-row:last-child th.exercise-table-cell,
|
|
820
|
+
td.exercise-table-cell.exercise-table-cell--last-row,
|
|
821
|
+
th.exercise-table-cell.exercise-table-cell--last-row {
|
|
822
|
+
box-shadow: inset -2px 0 0 0 #7c6cf2;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
tr.exercise-table-row:last-child td.exercise-table-cell:last-child,
|
|
826
|
+
tr.exercise-table-row:last-child th.exercise-table-cell:last-child,
|
|
827
|
+
td.exercise-table-cell.exercise-table-cell--last-row:last-child,
|
|
828
|
+
th.exercise-table-cell.exercise-table-cell--last-row:last-child {
|
|
829
|
+
box-shadow: none;
|
|
810
830
|
}
|
|
811
831
|
|
|
812
832
|
/* ========================================
|
|
@@ -968,11 +988,11 @@ th.exercise-table-cell {
|
|
|
968
988
|
fill: var(--visual-fraction-hover-color);
|
|
969
989
|
}
|
|
970
990
|
|
|
971
|
-
.visual-fraction-widget__sector[role=
|
|
991
|
+
.visual-fraction-widget__sector[role='button']:focus {
|
|
972
992
|
outline: none;
|
|
973
993
|
}
|
|
974
994
|
|
|
975
|
-
.visual-fraction-widget__sector[role=
|
|
995
|
+
.visual-fraction-widget__sector[role='button']:focus-visible {
|
|
976
996
|
/* Keyboard-only focus indicator: a drop-shadow that follows the SVG shape
|
|
977
997
|
instead of a rectangle, preserving accessibility without the visual glitch. */
|
|
978
998
|
outline: none;
|
|
@@ -1106,102 +1126,394 @@ th.exercise-table-cell {
|
|
|
1106
1126
|
======================================== */
|
|
1107
1127
|
|
|
1108
1128
|
.pair-matcher-widget {
|
|
1109
|
-
--pm-orange: #
|
|
1110
|
-
--pm-
|
|
1111
|
-
--pm-
|
|
1112
|
-
--pm-
|
|
1113
|
-
--pm-
|
|
1114
|
-
|
|
1115
|
-
|
|
1129
|
+
--pm-orange: #ffca76;
|
|
1130
|
+
--pm-purple: #705dc0;
|
|
1131
|
+
--pm-selected-bg: #e7e2ff;
|
|
1132
|
+
--pm-selected-border: #ae9cff;
|
|
1133
|
+
--pm-card-width: 163px;
|
|
1134
|
+
--pm-card-height: 82px;
|
|
1135
|
+
--pm-card-radius: 12px;
|
|
1136
|
+
--pm-card-border-width: 1px;
|
|
1137
|
+
--pm-dot-size: 17px;
|
|
1138
|
+
--pm-dot-border-width: 2px;
|
|
1139
|
+
--pm-line-color: var(--pm-orange);
|
|
1140
|
+
--pm-line-color-correct: #43b925;
|
|
1141
|
+
--pm-line-color-incorrect: #d6234d;
|
|
1142
|
+
--pm-line-width: 4px;
|
|
1143
|
+
position: relative;
|
|
1144
|
+
display: flex;
|
|
1145
|
+
flex-direction: column;
|
|
1146
|
+
gap: 52px;
|
|
1147
|
+
width: max-content;
|
|
1148
|
+
max-width: 100%;
|
|
1149
|
+
margin-inline: auto;
|
|
1150
|
+
padding: 0;
|
|
1116
1151
|
}
|
|
1117
1152
|
|
|
1118
1153
|
.pair-matcher-row {
|
|
1119
|
-
position: relative;
|
|
1154
|
+
position: relative;
|
|
1155
|
+
z-index: 2;
|
|
1156
|
+
display: grid;
|
|
1120
1157
|
grid-template-columns: repeat(var(--pm-cols, 3), minmax(0, var(--pm-card-width)));
|
|
1121
|
-
justify-content: center;
|
|
1158
|
+
justify-content: center;
|
|
1159
|
+
gap: 18px;
|
|
1160
|
+
align-items: stretch;
|
|
1161
|
+
min-width: 0;
|
|
1122
1162
|
}
|
|
1123
1163
|
|
|
1124
|
-
.pair-matcher-cell {
|
|
1164
|
+
.pair-matcher-cell {
|
|
1165
|
+
display: flex;
|
|
1166
|
+
flex-direction: column;
|
|
1167
|
+
align-items: center;
|
|
1168
|
+
min-width: 0;
|
|
1169
|
+
}
|
|
1125
1170
|
|
|
1126
1171
|
.pair-matcher-card {
|
|
1127
|
-
box-sizing: border-box;
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1172
|
+
box-sizing: border-box;
|
|
1173
|
+
display: flex;
|
|
1174
|
+
align-items: center;
|
|
1175
|
+
justify-content: center;
|
|
1176
|
+
width: 100%;
|
|
1177
|
+
min-width: 0;
|
|
1178
|
+
max-width: 100%;
|
|
1179
|
+
align-self: stretch;
|
|
1180
|
+
flex: 1 1 auto;
|
|
1181
|
+
min-height: var(--pm-card-height);
|
|
1182
|
+
height: auto;
|
|
1183
|
+
padding: 6px 8px;
|
|
1184
|
+
border: var(--pm-card-border-width) solid var(--pm-orange);
|
|
1185
|
+
border-radius: var(--pm-card-radius);
|
|
1186
|
+
background: #fff;
|
|
1187
|
+
color: var(--pm-purple);
|
|
1188
|
+
font: 500 1rem / 1.2 var(--exercise-font-family, inherit);
|
|
1189
|
+
letter-spacing: 0;
|
|
1190
|
+
text-align: center;
|
|
1191
|
+
word-break: normal;
|
|
1192
|
+
overflow-wrap: break-word;
|
|
1193
|
+
white-space: normal;
|
|
1194
|
+
hyphens: auto;
|
|
1195
|
+
overflow: visible;
|
|
1196
|
+
cursor: pointer;
|
|
1197
|
+
transition:
|
|
1198
|
+
background 0.35s ease,
|
|
1199
|
+
border-color 0.35s ease,
|
|
1200
|
+
transform 0.2s ease;
|
|
1136
1201
|
}
|
|
1137
1202
|
|
|
1138
|
-
.pair-matcher-card:not([aria-disabled=
|
|
1203
|
+
.pair-matcher-card:not([aria-disabled='true']):active {
|
|
1204
|
+
transform: scale(0.98);
|
|
1205
|
+
}
|
|
1139
1206
|
|
|
1140
|
-
.pair-matcher-card[aria-disabled=
|
|
1207
|
+
.pair-matcher-card[aria-disabled='true'] {
|
|
1208
|
+
cursor: default;
|
|
1209
|
+
}
|
|
1141
1210
|
|
|
1142
|
-
.pair-matcher-card--pending,
|
|
1211
|
+
.pair-matcher-card--pending,
|
|
1212
|
+
.pair-matcher-card--flash {
|
|
1213
|
+
border-color: var(--pm-selected-border);
|
|
1214
|
+
background: var(--pm-selected-bg);
|
|
1215
|
+
}
|
|
1143
1216
|
|
|
1144
|
-
.pair-matcher-card--correct
|
|
1217
|
+
.pair-matcher-card--correct {
|
|
1218
|
+
border-color: #43b925;
|
|
1219
|
+
background: #f2ffee;
|
|
1220
|
+
color: #43b925;
|
|
1221
|
+
}
|
|
1145
1222
|
|
|
1146
|
-
.pair-matcher-card--incorrect {
|
|
1223
|
+
.pair-matcher-card--incorrect {
|
|
1224
|
+
border-color: #d6234d;
|
|
1225
|
+
background: #fff0f7;
|
|
1226
|
+
color: #d6234d;
|
|
1227
|
+
}
|
|
1147
1228
|
|
|
1148
1229
|
.pair-matcher-dot {
|
|
1149
|
-
position: relative;
|
|
1150
|
-
|
|
1151
|
-
|
|
1230
|
+
position: relative;
|
|
1231
|
+
z-index: 3;
|
|
1232
|
+
flex-shrink: 0;
|
|
1233
|
+
width: var(--pm-dot-size);
|
|
1234
|
+
height: var(--pm-dot-size);
|
|
1235
|
+
border: var(--pm-dot-border-width) solid var(--pm-orange);
|
|
1236
|
+
border-radius: 50%;
|
|
1237
|
+
background: #fff;
|
|
1152
1238
|
}
|
|
1153
1239
|
|
|
1154
|
-
.pair-matcher-dot--south
|
|
1240
|
+
.pair-matcher-dot--south {
|
|
1241
|
+
margin-top: calc(var(--pm-dot-size) / -2);
|
|
1242
|
+
}
|
|
1155
1243
|
|
|
1156
|
-
.pair-matcher-dot--north
|
|
1244
|
+
.pair-matcher-dot--north {
|
|
1245
|
+
margin-bottom: calc(var(--pm-dot-size) / -2);
|
|
1246
|
+
}
|
|
1157
1247
|
|
|
1158
|
-
.pair-matcher-dot--active
|
|
1248
|
+
.pair-matcher-dot--active {
|
|
1249
|
+
background: var(--pm-orange);
|
|
1250
|
+
}
|
|
1159
1251
|
|
|
1160
|
-
.pair-matcher-dot--pending {
|
|
1252
|
+
.pair-matcher-dot--pending {
|
|
1253
|
+
border-color: var(--pm-selected-border);
|
|
1254
|
+
background: #fff;
|
|
1255
|
+
}
|
|
1161
1256
|
|
|
1162
|
-
.pair-matcher-dot--correct
|
|
1257
|
+
.pair-matcher-dot--correct {
|
|
1258
|
+
border-color: #43b925;
|
|
1259
|
+
background: #43b925;
|
|
1260
|
+
}
|
|
1163
1261
|
|
|
1164
|
-
.pair-matcher-dot--incorrect {
|
|
1262
|
+
.pair-matcher-dot--incorrect {
|
|
1263
|
+
border-color: #d6234d;
|
|
1264
|
+
background: #d6234d;
|
|
1265
|
+
}
|
|
1165
1266
|
|
|
1166
1267
|
.pair-matcher-lines {
|
|
1167
|
-
position: absolute;
|
|
1168
|
-
|
|
1268
|
+
position: absolute;
|
|
1269
|
+
inset: 0;
|
|
1270
|
+
z-index: 1;
|
|
1271
|
+
width: 100%;
|
|
1272
|
+
height: 100%;
|
|
1273
|
+
overflow: visible;
|
|
1274
|
+
pointer-events: none;
|
|
1169
1275
|
}
|
|
1170
1276
|
|
|
1171
|
-
.pair-matcher-line {
|
|
1277
|
+
.pair-matcher-line {
|
|
1278
|
+
stroke-dasharray: 1;
|
|
1279
|
+
animation: pair-matcher-line-draw 0.5s ease both;
|
|
1280
|
+
}
|
|
1172
1281
|
|
|
1173
|
-
@keyframes pair-matcher-line-draw {
|
|
1282
|
+
@keyframes pair-matcher-line-draw {
|
|
1283
|
+
from {
|
|
1284
|
+
stroke-dashoffset: 1;
|
|
1285
|
+
}
|
|
1286
|
+
to {
|
|
1287
|
+
stroke-dashoffset: 0;
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1174
1290
|
|
|
1175
1291
|
.pair-matcher-card .text-item,
|
|
1176
1292
|
.pair-matcher-card .question-text,
|
|
1177
1293
|
.pair-matcher-card .group {
|
|
1178
|
-
margin: 0;
|
|
1179
|
-
|
|
1180
|
-
|
|
1294
|
+
margin: 0;
|
|
1295
|
+
min-width: 0;
|
|
1296
|
+
max-width: 100%;
|
|
1297
|
+
color: inherit;
|
|
1298
|
+
font: inherit;
|
|
1299
|
+
overflow-wrap: break-word;
|
|
1300
|
+
word-break: normal;
|
|
1301
|
+
white-space: normal;
|
|
1181
1302
|
}
|
|
1182
1303
|
|
|
1183
1304
|
.pair-matcher-card:not(.pair-matcher-card--rtl) .text-item,
|
|
1184
1305
|
.pair-matcher-card:not(.pair-matcher-card--rtl) .question-text,
|
|
1185
|
-
.pair-matcher-card:not(.pair-matcher-card--rtl) .group {
|
|
1306
|
+
.pair-matcher-card:not(.pair-matcher-card--rtl) .group {
|
|
1307
|
+
overflow-wrap: break-word;
|
|
1308
|
+
}
|
|
1186
1309
|
|
|
1187
|
-
.pair-matcher-card--rtl {
|
|
1310
|
+
.pair-matcher-card--rtl {
|
|
1311
|
+
direction: rtl;
|
|
1312
|
+
unicode-bidi: plaintext;
|
|
1313
|
+
}
|
|
1188
1314
|
|
|
1189
1315
|
.pair-matcher-card-content {
|
|
1190
|
-
display: block;
|
|
1316
|
+
display: block;
|
|
1317
|
+
width: 100%;
|
|
1318
|
+
min-width: 0;
|
|
1319
|
+
max-width: 100%;
|
|
1320
|
+
text-align: inherit;
|
|
1321
|
+
white-space: normal;
|
|
1191
1322
|
}
|
|
1192
1323
|
|
|
1193
|
-
.pair-matcher-card-content .space {
|
|
1324
|
+
.pair-matcher-card-content .space {
|
|
1325
|
+
display: inline;
|
|
1326
|
+
width: auto;
|
|
1327
|
+
}
|
|
1194
1328
|
|
|
1195
1329
|
.pair-matcher-card .text-item-arabic,
|
|
1196
1330
|
.pair-matcher-card .question-text-arabic {
|
|
1197
|
-
direction: rtl;
|
|
1198
|
-
|
|
1331
|
+
direction: rtl;
|
|
1332
|
+
font-size: 0.72rem;
|
|
1333
|
+
line-height: 1.15;
|
|
1334
|
+
overflow-wrap: normal;
|
|
1335
|
+
word-break: normal;
|
|
1336
|
+
hyphens: manual;
|
|
1199
1337
|
}
|
|
1200
1338
|
|
|
1201
1339
|
@media (max-width: 420px) {
|
|
1202
|
-
.pair-matcher-widget {
|
|
1203
|
-
|
|
1204
|
-
|
|
1340
|
+
.pair-matcher-widget {
|
|
1341
|
+
gap: 46px;
|
|
1342
|
+
}
|
|
1343
|
+
.pair-matcher-row {
|
|
1344
|
+
grid-template-columns: repeat(var(--pm-cols, 3), minmax(0, 1fr));
|
|
1345
|
+
gap: 12px;
|
|
1346
|
+
}
|
|
1347
|
+
.pair-matcher-card {
|
|
1348
|
+
min-height: 58px;
|
|
1349
|
+
padding: 6px 7px;
|
|
1350
|
+
font-size: 0.92rem;
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
/**
|
|
1355
|
+
* Image Styles
|
|
1356
|
+
*
|
|
1357
|
+
* Inline images and their fullscreen (lightbox) view.
|
|
1358
|
+
* The lightbox is portalled to document.body, so its rules must not depend
|
|
1359
|
+
* on any ancestor inside .math-exercise-renderer.
|
|
1360
|
+
*/
|
|
1361
|
+
|
|
1362
|
+
/* ========================================
|
|
1363
|
+
INLINE IMAGE
|
|
1364
|
+
======================================== */
|
|
1365
|
+
|
|
1366
|
+
/**
|
|
1367
|
+
* Wrapper exists only for zoomable images. It is exactly the size of the
|
|
1368
|
+
* image — no padding, no gap, no extra track — because .exercise-line is a
|
|
1369
|
+
* flex row: any width the wrapper adds would push every later item along,
|
|
1370
|
+
* which would move a second inline image on the same line.
|
|
1371
|
+
*/
|
|
1372
|
+
|
|
1373
|
+
.image-item-wrapper {
|
|
1374
|
+
position: relative;
|
|
1375
|
+
display: inline-block;
|
|
1376
|
+
/* line-height: 0 stops the inline descender gap from making the wrapper
|
|
1377
|
+
taller than the image it wraps. */
|
|
1378
|
+
line-height: 0;
|
|
1379
|
+
vertical-align: middle;
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
.image-item {
|
|
1383
|
+
vertical-align: middle;
|
|
1384
|
+
max-width: 100%;
|
|
1385
|
+
object-fit: contain;
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
.image-item-zoomable {
|
|
1389
|
+
cursor: zoom-in;
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
/**
|
|
1393
|
+
* Expand affordance. Always visible: sitting outside the image, it costs
|
|
1394
|
+
* nothing to show, and a hover-reveal would be undiscoverable on touch.
|
|
1395
|
+
*
|
|
1396
|
+
* The diamond artwork carries all the chrome, so the button contributes no
|
|
1397
|
+
* border or background of its own. Its `color` drives the glyph, which is
|
|
1398
|
+
* drawn with currentColor.
|
|
1399
|
+
*
|
|
1400
|
+
* Absolutely positioned over the image's top-right corner: out of flow, so
|
|
1401
|
+
* it costs zero layout width.
|
|
1402
|
+
*
|
|
1403
|
+
* The overhang is deliberately small. .exercise-line is a flex row with only
|
|
1404
|
+
* a 0.25rem gap, so anything hanging past the image's right edge lands on the
|
|
1405
|
+
* next item — a live button there would swallow clicks meant for the input
|
|
1406
|
+
* beside the image. At 30% the badge still reads as a corner badge while the
|
|
1407
|
+
* part sticking out is a few pixels of tapering tip.
|
|
1408
|
+
*
|
|
1409
|
+
* clip-path does the rest: it removes the square's dead corners from the hit
|
|
1410
|
+
* area (clipped-away regions do not receive pointer events), which is exactly
|
|
1411
|
+
* where the box poked furthest into its neighbours. The polygon runs through
|
|
1412
|
+
* the diamond's four tips with a little tolerance for the 2px stroke, so it
|
|
1413
|
+
* circumscribes the artwork and clips no visible pixels.
|
|
1414
|
+
*/
|
|
1415
|
+
|
|
1416
|
+
.image-zoom-btn {
|
|
1417
|
+
position: absolute;
|
|
1418
|
+
top: 0;
|
|
1419
|
+
right: 0;
|
|
1420
|
+
transform: translate(30%, -30%);
|
|
1421
|
+
clip-path: polygon(50.75% 13%, 90% 52.5%, 50.75% 92%, 11.5% 52.5%);
|
|
1422
|
+
display: flex;
|
|
1423
|
+
align-items: center;
|
|
1424
|
+
justify-content: center;
|
|
1425
|
+
flex-shrink: 0;
|
|
1426
|
+
/* Slightly larger than a plain square button: the diamond only fills
|
|
1427
|
+
~75% of its viewBox, so the visible badge lands near 1.7rem. */
|
|
1428
|
+
width: 2.25rem;
|
|
1429
|
+
height: 2.25rem;
|
|
1430
|
+
padding: 0;
|
|
1431
|
+
border: none;
|
|
1432
|
+
background: none;
|
|
1433
|
+
color: var(--exercise-accent, #705dc0);
|
|
1434
|
+
line-height: 0;
|
|
1435
|
+
cursor: zoom-in;
|
|
1436
|
+
transition: transform 0.15s ease;
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
.image-zoom-icon {
|
|
1440
|
+
width: 100%;
|
|
1441
|
+
height: 100%;
|
|
1442
|
+
display: block;
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
/* The translate must be repeated here: transform is one property, so a bare
|
|
1446
|
+
scale() would drop the positioning and snap the badge back onto the image. */
|
|
1447
|
+
|
|
1448
|
+
.image-zoom-btn:hover,
|
|
1449
|
+
.image-zoom-btn:focus-visible {
|
|
1450
|
+
transform: translate(30%, -30%) scale(1.08);
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1454
|
+
.image-zoom-btn {
|
|
1455
|
+
transition: none;
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
.image-zoom-btn:hover,
|
|
1459
|
+
.image-zoom-btn:focus-visible {
|
|
1460
|
+
transform: translate(30%, -30%);
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
/* ========================================
|
|
1465
|
+
FULLSCREEN LIGHTBOX
|
|
1466
|
+
======================================== */
|
|
1467
|
+
|
|
1468
|
+
.image-lightbox {
|
|
1469
|
+
position: fixed;
|
|
1470
|
+
inset: 0;
|
|
1471
|
+
z-index: 1000;
|
|
1472
|
+
display: flex;
|
|
1473
|
+
align-items: center;
|
|
1474
|
+
justify-content: center;
|
|
1475
|
+
padding: 2rem;
|
|
1476
|
+
background: rgba(0, 0, 0, 0.85);
|
|
1477
|
+
cursor: zoom-out;
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
.image-lightbox-img {
|
|
1481
|
+
max-width: 100%;
|
|
1482
|
+
max-height: 100%;
|
|
1483
|
+
object-fit: contain;
|
|
1484
|
+
cursor: default;
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
.image-lightbox-close {
|
|
1488
|
+
position: absolute;
|
|
1489
|
+
top: 1rem;
|
|
1490
|
+
right: 1rem;
|
|
1491
|
+
display: flex;
|
|
1492
|
+
align-items: center;
|
|
1493
|
+
justify-content: center;
|
|
1494
|
+
width: 2.5rem;
|
|
1495
|
+
height: 2.5rem;
|
|
1496
|
+
padding: 0;
|
|
1497
|
+
border: none;
|
|
1498
|
+
border-radius: 50%;
|
|
1499
|
+
/* Solid white disc: the cross is the accent purple, which would be muddy
|
|
1500
|
+
read straight against the dark backdrop. */
|
|
1501
|
+
background: rgba(255, 255, 255, 0.95);
|
|
1502
|
+
color: var(--exercise-accent, #705dc0);
|
|
1503
|
+
line-height: 0;
|
|
1504
|
+
cursor: pointer;
|
|
1505
|
+
transition: background 0.15s ease;
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
.image-lightbox-close-icon {
|
|
1509
|
+
width: 1.5rem;
|
|
1510
|
+
height: 1.5rem;
|
|
1511
|
+
display: block;
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
.image-lightbox-close:hover,
|
|
1515
|
+
.image-lightbox-close:focus-visible {
|
|
1516
|
+
background: #ffffff;
|
|
1205
1517
|
}
|
|
1206
1518
|
|
|
1207
1519
|
/**
|
|
@@ -2171,6 +2483,11 @@ th.exercise-table-cell {
|
|
|
2171
2483
|
/** Reduce gap between keypad buttons */
|
|
2172
2484
|
gap: var(--exercise-element-margin);
|
|
2173
2485
|
}
|
|
2486
|
+
|
|
2487
|
+
.exercise-layout-container.has-keypad {
|
|
2488
|
+
/** Tighter separation between content and keypad on narrow screens */
|
|
2489
|
+
gap: calc(var(--exercise-keypad-gap) * 0.5);
|
|
2490
|
+
}
|
|
2174
2491
|
}
|
|
2175
2492
|
|
|
2176
2493
|
/* ========================================
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mathscan/math-exercise-engine",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.16",
|
|
4
4
|
"description": "A DSL parser and validator for math exercises - transforms text-based exercise definitions into structured AST and JSON",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|