@barocss/math-editor 0.4.0 → 0.6.1

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.
Files changed (76) hide show
  1. package/API-SESSION.md +35 -1
  2. package/API-WEB-COMPONENT.md +2 -0
  3. package/CHANGELOG.md +109 -0
  4. package/CLIPBOARD.md +54 -0
  5. package/EDITING-SCENARIOS.md +209 -0
  6. package/GETTING-STARTED.md +54 -0
  7. package/IMPLEMENTATION.md +105 -0
  8. package/KEYBOARD.md +41 -0
  9. package/LATEX-GUIDE.md +52 -2
  10. package/LATEX-MODEL.md +12 -0
  11. package/LATEX-SCOPE.md +10 -1
  12. package/README.md +119 -23
  13. package/RELEASING.md +95 -10
  14. package/RENDERING-TESTS.md +79 -0
  15. package/ROADMAP.md +238 -6
  16. package/STYLING.md +28 -1
  17. package/TEXT-EDITORS.md +157 -0
  18. package/VALIDATION.md +433 -0
  19. package/dist/context-tools.d.ts +21 -0
  20. package/dist/context-tools.js +37 -0
  21. package/dist/dom/caret-geometry.js +1 -1
  22. package/dist/dom/context-keyboard.d.ts +2 -0
  23. package/dist/dom/context-keyboard.js +22 -0
  24. package/dist/dom/help.d.ts +5 -0
  25. package/dist/dom/help.js +104 -0
  26. package/dist/dom/menu-position.d.ts +3 -0
  27. package/dist/dom/menu-position.js +49 -4
  28. package/dist/dom/readable-layout.d.ts +3 -0
  29. package/dist/dom/readable-layout.js +52 -0
  30. package/dist/dom/toolbar-catalog.d.ts +1 -1
  31. package/dist/dom/toolbar.d.ts +2 -0
  32. package/dist/dom/toolbar.js +8 -1
  33. package/dist/dom.d.ts +13 -1
  34. package/dist/dom.js +323 -51
  35. package/dist/enter-policy.js +1 -1
  36. package/dist/latex.js +11 -0
  37. package/dist/lines.d.ts +2 -0
  38. package/dist/lines.js +15 -0
  39. package/dist/locales/en.js +33 -3
  40. package/dist/locales/en.json +33 -3
  41. package/dist/locales/ko.js +33 -3
  42. package/dist/locales/ko.json +33 -3
  43. package/dist/math-editor-toolbar.js +2 -1
  44. package/dist/math-editor.d.ts +4 -1
  45. package/dist/math-editor.js +506 -296
  46. package/dist/math-layout.d.ts +12 -0
  47. package/dist/math-layout.js +59 -0
  48. package/dist/math-spacing.d.ts +13 -0
  49. package/dist/math-spacing.js +87 -0
  50. package/dist/model.d.ts +6 -0
  51. package/dist/model.js +72 -5
  52. package/dist/range.d.ts +10 -2
  53. package/dist/range.js +31 -6
  54. package/dist/root-transform.d.ts +19 -0
  55. package/dist/root-transform.js +69 -0
  56. package/dist/selection-shortcuts.d.ts +13 -0
  57. package/dist/selection-shortcuts.js +35 -0
  58. package/dist/session.d.ts +1 -0
  59. package/dist/session.js +1 -1
  60. package/dist/suggestions.d.ts +9 -0
  61. package/dist/suggestions.js +53 -0
  62. package/dist/symbols.d.ts +1 -1
  63. package/dist/symbols.js +1 -0
  64. package/dist/vertical-navigation.d.ts +5 -0
  65. package/dist/vertical-navigation.js +33 -0
  66. package/dist/web-component.js +9 -1
  67. package/package.json +11 -3
  68. package/src/fonts/KaTeX_Math-Italic.woff2 +0 -0
  69. package/src/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  70. package/src/fonts/README.md +18 -0
  71. package/src/shapes/README.md +21 -0
  72. package/src/shapes/parenthesis-bottom.svg +1 -0
  73. package/src/shapes/parenthesis-top.svg +1 -0
  74. package/src/shapes/parenthesis.svg +1 -0
  75. package/src/shapes/radical.svg +1 -0
  76. package/src/style.css +882 -61
package/src/style.css CHANGED
@@ -1,10 +1,27 @@
1
- /* Use lining numerals for mathematical baselines and a clear similarity sign.
2
- Georgia's text numerals have uneven heights and its U+223C is unusually curled. */
1
+ /* Match the reference math faces in both editable inputs and passive runs.
2
+ The bundled fonts retain their KaTeX license in src/fonts. */
3
3
  @font-face {
4
4
  font-family: 'Barocss Math Glyphs';
5
5
  src: url('./fonts/KaTeX_Main-Regular.woff2') format('woff2');
6
- unicode-range: U+0030-0039, U+223C;
6
+ font-style: normal;
7
+ font-weight: 400;
8
+ font-display: swap;
9
+ }
10
+ @font-face {
11
+ font-family: 'Barocss Math Glyphs';
12
+ src: url('./fonts/KaTeX_Math-Italic.woff2') format('woff2');
13
+ font-style: italic;
14
+ font-weight: 400;
15
+ font-display: swap;
7
16
  }
17
+ @font-face {
18
+ font-family: 'Barocss Large Operators';
19
+ src: url('./fonts/KaTeX_Size2-Regular.woff2') format('woff2');
20
+ font-style: normal;
21
+ font-display: swap;
22
+ }
23
+ /* Editing glyphs have a readable floor. Set --me-min-font-size: 0px for
24
+ unmodified TeX size ratios. This does not change serialized math. */
8
25
  .me-editor {
9
26
  color: var(--me-text, #202c27);
10
27
  font-family: var(--me-ui-font-family, system-ui, sans-serif);
@@ -33,7 +50,10 @@
33
50
  font: 12px var(--me-ui-font-family, system-ui, sans-serif);
34
51
  }
35
52
  .me-tools button span {
36
- font: 20px 'Barocss Math Glyphs', Georgia, serif;
53
+ font:
54
+ 20px 'Barocss Math Glyphs',
55
+ Georgia,
56
+ serif;
37
57
  }
38
58
  .me-tools button:hover {
39
59
  background: var(--me-hover-background, #edf3ef);
@@ -71,7 +91,11 @@
71
91
  }
72
92
  .me-input,
73
93
  .me-measure {
74
- font: italic var(--me-font-size, 22px) 'Barocss Math Glyphs', Georgia, 'Times New Roman', serif;
94
+ font:
95
+ italic max(var(--me-min-font-size, 14px), var(--me-font-size, 22px)) 'Barocss Math Glyphs',
96
+ Georgia,
97
+ 'Times New Roman',
98
+ serif;
75
99
  line-height: 1.35;
76
100
  min-width: 1ch;
77
101
  border: 0;
@@ -110,7 +134,10 @@
110
134
  margin-top: 4px;
111
135
  }
112
136
  .me-radical {
113
- font: 33px 'Barocss Math Glyphs', Georgia, serif;
137
+ font:
138
+ 33px 'Barocss Math Glyphs',
139
+ Georgia,
140
+ serif;
114
141
  }
115
142
  .me-superscript > .me-slot:last-child {
116
143
  align-self: flex-start;
@@ -125,11 +152,12 @@
125
152
  align-self: flex-end;
126
153
  transform: translateY(0.3em);
127
154
  }
155
+ /* Normal scripts use TeX script size; root indices use scriptscript size (VIS-004/005). */
128
156
  .me-superscript > .me-slot:last-child .me-input,
129
157
  .me-subscript > .me-slot:last-child .me-input,
130
158
  .me-superscript > .me-slot:last-child .me-measure,
131
159
  .me-subscript > .me-slot:last-child .me-measure {
132
- font-size: calc(var(--me-font-size, 22px) * 16 / 22);
160
+ font-size: max(var(--me-min-font-size, 14px), calc(var(--me-font-size, 22px) * 0.7));
133
161
  }
134
162
  .me-suggestions {
135
163
  position: absolute;
@@ -260,7 +288,10 @@
260
288
  min-height: 54px;
261
289
  }
262
290
  .me-candidate-glyph {
263
- font: 26px 'Barocss Math Glyphs', Georgia, serif;
291
+ font:
292
+ 26px 'Barocss Math Glyphs',
293
+ Georgia,
294
+ serif;
264
295
  min-width: 42px;
265
296
  flex-shrink: 0;
266
297
  text-align: center;
@@ -286,16 +317,22 @@
286
317
  }
287
318
  .me-limit .me-input,
288
319
  .me-limit .me-measure {
289
- font-size: calc(var(--me-font-size, 22px) * 14 / 22);
320
+ font-size: max(var(--me-min-font-size, 14px), calc(var(--me-font-size, 22px) * 0.7));
290
321
  }
291
322
  .me-operator-glyph {
292
- font: 35px/1 'Barocss Math Glyphs', Georgia, serif;
323
+ font:
324
+ calc(var(--me-font-size, 22px) * 1.59) / 1 'Barocss Math Glyphs',
325
+ Georgia,
326
+ serif;
293
327
  }
294
328
  .me-large-operator {
295
329
  gap: 8px;
296
330
  }
297
331
  .me-delimiter {
298
- font: 28px/1 'Barocss Math Glyphs', Georgia, serif;
332
+ font:
333
+ 28px/1 'Barocss Math Glyphs',
334
+ Georgia,
335
+ serif;
299
336
  }
300
337
 
301
338
  /* Slot roles are presentation metadata, not a claim that text is a variable or constant. */
@@ -593,7 +630,11 @@
593
630
  align-items: center;
594
631
  justify-content: center;
595
632
  white-space: pre;
596
- font: italic var(--me-font-size, 22px) / 1.35 'Barocss Math Glyphs', Georgia, 'Times New Roman',
633
+ font:
634
+ italic max(var(--me-min-font-size, 14px), var(--me-font-size, 22px)) / 1.35
635
+ 'Barocss Math Glyphs',
636
+ Georgia,
637
+ 'Times New Roman',
597
638
  serif;
598
639
  color: var(--me-ink);
599
640
  border-radius: 4px;
@@ -616,10 +657,10 @@
616
657
  }
617
658
  .me-superscript > .me-slot:last-child .me-preview-token,
618
659
  .me-subscript > .me-slot:last-child .me-preview-token {
619
- font-size: calc(var(--me-font-size, 22px) * 16 / 22);
660
+ font-size: max(var(--me-min-font-size, 14px), calc(var(--me-font-size, 22px) * 0.7));
620
661
  }
621
662
  .me-limit .me-preview-token {
622
- font-size: calc(var(--me-font-size, 22px) * 14 / 22);
663
+ font-size: max(var(--me-min-font-size, 14px), calc(var(--me-font-size, 22px) * 0.7));
623
664
  }
624
665
  .me-range-highlight,
625
666
  .me-empty[data-range-selected='true'] {
@@ -719,7 +760,11 @@
719
760
  border-color: var(--me-accent, #9cbbac);
720
761
  }
721
762
  .me-symbol-glyph {
722
- font: 25px/1.2 'Barocss Math Glyphs', Georgia, 'Times New Roman', serif;
763
+ font:
764
+ 25px/1.2 'Barocss Math Glyphs',
765
+ Georgia,
766
+ 'Times New Roman',
767
+ serif;
723
768
  }
724
769
  .me-symbol-browser button:focus-visible,
725
770
  .me-symbol-search input:focus-visible {
@@ -767,11 +812,15 @@
767
812
  }
768
813
  .me-dom-editor[data-mode='inline'] {
769
814
  display: inline-block;
815
+ max-width: 100%;
816
+ box-sizing: border-box;
770
817
  vertical-align: middle;
771
818
  border: 0;
772
819
  }
773
820
  .me-dom-editor[data-mode='inline'] .me-surface {
774
821
  display: inline-block;
822
+ max-width: 100%;
823
+ box-sizing: border-box;
775
824
  padding: var(--me-inline-padding, 2px 4px);
776
825
  min-height: 0;
777
826
  }
@@ -804,7 +853,7 @@
804
853
  grid-row: 1;
805
854
  }
806
855
  .me-scripts > .me-slot:not(:first-child) :is(.me-input, .me-measure, .me-preview-token) {
807
- font-size: calc(var(--me-font-size, 22px) * 16 / 22);
856
+ font-size: max(var(--me-min-font-size, 14px), calc(var(--me-font-size, 22px) * 0.7));
808
857
  }
809
858
 
810
859
  .me-textGroup,
@@ -850,7 +899,7 @@
850
899
  margin-top: 4px;
851
900
  }
852
901
  .me-indexedRoot > .me-slot:nth-last-child(2) :is(.me-input, .me-measure, .me-preview-token) {
853
- font-size: calc(var(--me-font-size, 22px) * 14 / 22);
902
+ font-size: max(var(--me-min-font-size, 14px), calc(var(--me-font-size, 22px) * 0.5));
854
903
  }
855
904
 
856
905
  /* Accents follow the editable body's width, including nested structures. */
@@ -943,13 +992,16 @@
943
992
  gap: 4px;
944
993
  }
945
994
  .me-limit-glyph {
946
- font: normal var(--me-font-size, 22px) / 1.1 'Barocss Math Glyphs', Georgia, serif;
995
+ font:
996
+ normal max(var(--me-min-font-size, 14px), var(--me-font-size, 22px)) / 1.1 'Barocss Math Glyphs',
997
+ Georgia,
998
+ serif;
947
999
  }
948
1000
  .me-limit-operator > .me-limits {
949
1001
  align-self: baseline;
950
1002
  }
951
1003
  .me-limit-operator .me-limit :is(.me-input, .me-measure, .me-preview-token) {
952
- font-size: calc(var(--me-font-size, 22px) * 14 / 22);
1004
+ font-size: max(var(--me-min-font-size, 14px), calc(var(--me-font-size, 22px) * 0.7));
953
1005
  line-height: 1.1;
954
1006
  padding-block: 1px;
955
1007
  }
@@ -995,18 +1047,34 @@
995
1047
  .me-superscript > .me-slot:last-child :is(.me-quad, .me-qquad),
996
1048
  .me-subscript > .me-slot:last-child :is(.me-quad, .me-qquad),
997
1049
  .me-scripts > .me-slot:not(:first-child) :is(.me-quad, .me-qquad) {
998
- font-size: calc(var(--me-font-size, 22px) * 16 / 22);
1050
+ font-size: max(var(--me-min-font-size, 14px), calc(var(--me-font-size, 22px) * 16 / 22));
999
1051
  }
1000
1052
  .me-limit :is(.me-quad, .me-qquad) {
1001
- font-size: calc(var(--me-font-size, 22px) * 14 / 22);
1053
+ font-size: max(var(--me-min-font-size, 14px), calc(var(--me-font-size, 22px) * 0.7));
1002
1054
  }
1003
1055
 
1004
1056
  /* Structured delimiters export as \left/\right and stretch with their body. */
1057
+ /* Fence bodies must not add an inline line box below their nested flex row. */
1058
+ :is(
1059
+ .me-parentheses,
1060
+ .me-brackets,
1061
+ .me-absolute,
1062
+ .me-braces,
1063
+ .me-angle,
1064
+ .me-openClosed,
1065
+ .me-closedOpen,
1066
+ .me-fenced,
1067
+ .me-norm
1068
+ )
1069
+ > .me-slot {
1070
+ display: inline-flex;
1071
+ align-items: center;
1072
+ }
1005
1073
  :is(.me-parentheses, .me-brackets, .me-absolute) > .me-delimiter {
1006
1074
  align-self: stretch;
1007
1075
  flex: 0 0 7px;
1008
1076
  box-sizing: border-box;
1009
- min-height: 26px;
1077
+ min-height: calc(var(--me-font-size, 22px) * 1.2);
1010
1078
  font-size: 0;
1011
1079
  }
1012
1080
  :is(.me-parentheses, .me-brackets, .me-absolute) > .me-delimiter:first-child {
@@ -1015,19 +1083,19 @@
1015
1083
  :is(.me-parentheses, .me-brackets, .me-absolute) > .me-delimiter:last-child {
1016
1084
  border-right: 1.5px solid currentColor;
1017
1085
  }
1018
- /* A tapered curve keeps its bow at tall sizes; an elliptical border flattens. */
1086
+ /* The outline mask is shared with mixed fences in the contour rules below. */
1019
1087
  .me-parentheses > .me-delimiter:first-child,
1020
1088
  .me-parentheses > .me-delimiter:last-child {
1021
- flex-basis: 8px;
1022
1089
  border: 0;
1023
1090
  background: currentColor;
1024
- mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 100' preserveAspectRatio='none'%3E%3Cpath d='M14 0C4 16 0 32 0 50C0 68 4 84 14 100L14 97C7 80 3 65 3 50C3 35 7 20 14 3Z'/%3E%3C/svg%3E")
1025
- center / 100% 100% no-repeat;
1026
1091
  }
1027
1092
  .me-parentheses > .me-delimiter:last-child {
1028
1093
  transform: scaleX(-1);
1029
1094
  }
1030
- .me-parentheses:has(> .me-slot .me-structure) > .me-delimiter {
1095
+ .me-parentheses:has(
1096
+ > .me-slot :is(.me-fraction, .me-root, .me-indexedRoot, .me-matrix, .me-cases, .me-superscript)
1097
+ )
1098
+ > .me-delimiter {
1031
1099
  flex-basis: 14px;
1032
1100
  }
1033
1101
  .me-brackets > .me-delimiter {
@@ -1045,14 +1113,14 @@
1045
1113
  :is(.me-braces, .me-angle, .me-openClosed, .me-closedOpen, .me-fenced) > .me-delimiter {
1046
1114
  align-self: stretch;
1047
1115
  flex: 0 0 12px;
1048
- min-height: 26px;
1116
+ min-height: calc(var(--me-font-size, 22px) * 1.2);
1049
1117
  box-sizing: border-box;
1050
1118
  font-size: 0;
1051
1119
  }
1052
1120
  :is(.me-openClosed, .me-closedOpen, .me-fenced) > :is([data-fence='('], [data-fence=')']),
1053
1121
  .me-matrix[data-environment='pmatrix'] > .me-matrix-delimiter {
1054
1122
  background: currentColor;
1055
- mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 100' preserveAspectRatio='none'%3E%3Cpath d='M14 0C4 16 0 32 0 50C0 68 4 84 14 100L14 97C7 80 3 65 3 50C3 35 7 20 14 3Z'/%3E%3C/svg%3E")
1123
+ mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 100' preserveAspectRatio='none'%3E%3Cpath d='M14 0C4 16 0 32 0 50C0 68 4 84 14 100L14 98C7 80 2.5 65 2.5 50C2.5 35 7 20 14 2Z'/%3E%3C/svg%3E")
1056
1124
  center / 100% 100% no-repeat;
1057
1125
  }
1058
1126
  .me-delimiter[data-fence=')'] {
@@ -1104,7 +1172,7 @@
1104
1172
  :is(.me-overset, .me-underset)
1105
1173
  > .me-slot:first-child
1106
1174
  :is(.me-input, .me-preview-token, .me-measure) {
1107
- font-size: calc(var(--me-font-size, 22px) * 14 / 22);
1175
+ font-size: max(var(--me-min-font-size, 14px), calc(var(--me-font-size, 22px) * 0.7));
1108
1176
  }
1109
1177
  /* Square and indexed roots share a radical joined to the radicand's overbar. */
1110
1178
  .me-root > .me-radical,
@@ -1116,17 +1184,6 @@
1116
1184
  margin-top: 4px;
1117
1185
  font-size: 0;
1118
1186
  background: currentColor;
1119
- clip-path: polygon(
1120
- 0 55%,
1121
- 6px 50%,
1122
- 12px 88%,
1123
- 21px 0,
1124
- 100% 0,
1125
- 14px 100%,
1126
- 11px 100%,
1127
- 5px 58%,
1128
- 1px 61%
1129
- );
1130
1187
  }
1131
1188
  .me-indexedRoot > .me-slot:nth-last-child(2) {
1132
1189
  margin-right: -9px;
@@ -1169,7 +1226,7 @@
1169
1226
  > .me-operator-glyph {
1170
1227
  grid-column: 1;
1171
1228
  grid-row: 1 / 3;
1172
- font-size: 44px;
1229
+ font-size: max(var(--me-min-font-size, 14px), calc(var(--me-font-size, 22px) * 2));
1173
1230
  }
1174
1231
  :is(
1175
1232
  [data-structure='integral'],
@@ -1229,11 +1286,12 @@
1229
1286
  /* Keep nested fractions readable while avoiding full-size recursive stacks.
1230
1287
  Apply the same size to the input, passive glyph and measuring twin. */
1231
1288
  .me-fraction .me-fraction :is(.me-input, .me-measure, .me-preview-token) {
1232
- font-size: calc(var(--me-font-size, 22px) * 16 / 22);
1233
- line-height: 1.2;
1289
+ font-size: max(var(--me-min-font-size, 14px), calc(var(--me-font-size, 22px) * 0.7));
1290
+ line-height: 1;
1291
+ padding-block: 0;
1234
1292
  }
1235
1293
  .me-fraction .me-fraction .me-fraction :is(.me-input, .me-measure, .me-preview-token) {
1236
- font-size: 12px;
1294
+ font-size: max(var(--me-min-font-size, 14px), calc(var(--me-font-size, 22px) * 0.5));
1237
1295
  }
1238
1296
  .me-fraction .me-fraction .me-row {
1239
1297
  min-height: 0;
@@ -1242,6 +1300,38 @@
1242
1300
  padding: 0 3px;
1243
1301
  }
1244
1302
 
1303
+ /* Resolve every fraction descendant from its own row style. Transparent
1304
+ structures (norms, fences, roots) must not reset their body's term size.
1305
+ The input, measuring twin and passive glyph share the same rule. */
1306
+ .me-editor .me-fraction .me-row[data-layout-style] {
1307
+ min-height: 0;
1308
+ }
1309
+ .me-editor
1310
+ .me-fraction
1311
+ .me-row[data-layout-style]
1312
+ > .me-run
1313
+ :is(.me-input, .me-measure, .me-preview-token) {
1314
+ padding-block: 0;
1315
+ line-height: 1.25;
1316
+ font-size: max(var(--me-min-font-size, 14px), var(--me-font-size, 22px));
1317
+ }
1318
+ .me-editor
1319
+ .me-fraction
1320
+ .me-row[data-layout-style='script']
1321
+ > .me-run
1322
+ :is(.me-input, .me-measure, .me-preview-token) {
1323
+ line-height: 1.1;
1324
+ font-size: max(var(--me-min-font-size, 14px), calc(var(--me-font-size, 22px) * 0.7));
1325
+ }
1326
+ .me-editor
1327
+ .me-fraction
1328
+ .me-row[data-layout-style='scriptscript']
1329
+ > .me-run
1330
+ :is(.me-input, .me-measure, .me-preview-token) {
1331
+ line-height: 1.1;
1332
+ font-size: max(var(--me-min-font-size, 14px), calc(var(--me-font-size, 22px) * 0.5));
1333
+ }
1334
+
1245
1335
  .me-vec,
1246
1336
  .me-hat,
1247
1337
  .me-overline {
@@ -1271,7 +1361,7 @@
1271
1361
  .me-fenced > .me-delimiter[data-fence='‖'] {
1272
1362
  align-self: stretch;
1273
1363
  flex: 0 0 9px;
1274
- min-height: 26px;
1364
+ min-height: calc(var(--me-font-size, 22px) * 1.2);
1275
1365
  box-sizing: border-box;
1276
1366
  font-size: 0;
1277
1367
  border-left: 4px double currentColor;
@@ -1288,9 +1378,11 @@
1288
1378
  unicode-range: U+222E;
1289
1379
  }
1290
1380
  [data-structure='contourIntegral'][data-limit-placement] > .me-limits > .me-operator-glyph {
1291
- font: normal var(--me-font-size, 22px) / 2.3 'Barocss Contour', serif;
1292
- width: 25px;
1293
- height: 51px;
1381
+ font:
1382
+ normal max(var(--me-min-font-size, 14px), var(--me-font-size, 22px)) / 2.3 'Barocss Contour',
1383
+ serif;
1384
+ width: calc(var(--me-font-size, 22px) * 25 / 22);
1385
+ height: calc(var(--me-font-size, 22px) * 2.3);
1294
1386
  transform: none;
1295
1387
  }
1296
1388
 
@@ -1314,7 +1406,7 @@
1314
1406
  :is(.me-overbrace, .me-underbrace)
1315
1407
  > .me-slot:first-child
1316
1408
  :is(.me-input, .me-measure, .me-preview-token) {
1317
- font-size: calc(var(--me-font-size, 22px) * 14 / 22);
1409
+ font-size: max(var(--me-min-font-size, 14px), calc(var(--me-font-size, 22px) * 0.7));
1318
1410
  line-height: 1.1;
1319
1411
  }
1320
1412
  :is(.me-overbrace, .me-underbrace) > .me-slot:last-child {
@@ -1322,20 +1414,23 @@
1322
1414
  width: 100%;
1323
1415
  box-sizing: border-box;
1324
1416
  }
1417
+ :is(.me-overbrace, .me-underbrace) > .me-slot:last-child {
1418
+ min-width: calc(var(--me-font-size, 22px) * 1.6);
1419
+ }
1325
1420
  .me-overbrace > .me-slot:last-child {
1326
- padding-top: 9px;
1421
+ padding-top: calc(var(--me-font-size, 22px) * 0.4);
1327
1422
  }
1328
1423
  .me-underbrace > .me-slot:last-child {
1329
- padding-bottom: 9px;
1424
+ padding-bottom: calc(var(--me-font-size, 22px) * 0.4);
1330
1425
  }
1331
1426
  :is(.me-overbrace, .me-underbrace) > .me-slot:last-child::before {
1332
1427
  content: '';
1333
1428
  position: absolute;
1334
1429
  inset-inline: 0;
1335
1430
  top: 0;
1336
- height: 8px;
1431
+ height: calc(var(--me-font-size, 22px) * 0.35);
1337
1432
  background: currentColor;
1338
- mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 12' preserveAspectRatio='none'%3E%3Cpath d='M0 12Q0 5 12 5L38 5Q48 5 50 0Q52 5 62 5L88 5Q100 5 100 12L98 12Q98 8 88 8L62 8Q53 8 50 4Q47 8 38 8L12 8Q2 8 2 12Z'/%3E%3C/svg%3E")
1433
+ mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 12' preserveAspectRatio='none'%3E%3Cpath d='M0 12C4 6 12 7 24 5C37 3 45 2 50 0C55 2 63 3 76 5C88 7 96 6 100 12L98 12C94 9 86 10 75 8C62 6 54 5 50 3C46 5 38 6 25 8C14 10 6 9 2 12Z'/%3E%3C/svg%3E")
1339
1434
  center / 100% 100% no-repeat;
1340
1435
  pointer-events: none;
1341
1436
  }
@@ -1494,7 +1589,7 @@
1494
1589
  )[data-limit-placement='nolimits']
1495
1590
  > .me-limits
1496
1591
  > .me-operator-glyph {
1497
- font-size: 44px;
1592
+ font-size: max(var(--me-min-font-size, 14px), calc(var(--me-font-size, 22px) * 2));
1498
1593
  }
1499
1594
 
1500
1595
  /* TeX math units: 18mu = 1em. Negative spacing has no painted hit box. */
@@ -1529,13 +1624,13 @@
1529
1624
  /* Explicit fraction/binomial styles override the surrounding default size.
1530
1625
  Nested explicit styles use the nearest style container's inherited value. */
1531
1626
  .me-structure[data-math-style='display'] {
1532
- --me-explicit-size: 22px;
1627
+ --me-explicit-size: var(--me-font-size, 22px);
1533
1628
  }
1534
1629
  .me-structure[data-math-style='text'] {
1535
- --me-explicit-size: 16px;
1630
+ --me-explicit-size: calc(var(--me-font-size, 22px) * 0.7);
1536
1631
  }
1537
- .me-structure[data-math-style] :is(.me-input, .me-measure, .me-preview-token) {
1538
- font-size: var(--me-explicit-size);
1632
+ .me-structure[data-math-style] > .me-slot :is(.me-input, .me-measure, .me-preview-token) {
1633
+ font-size: max(var(--me-min-font-size, 14px), var(--me-explicit-size));
1539
1634
  }
1540
1635
  .me-structure[data-math-style='text'] > .me-slot > .me-row {
1541
1636
  min-height: 0;
@@ -1547,7 +1642,7 @@
1547
1642
  :is(.me-superscript, .me-subscript, .me-scripts)
1548
1643
  > .me-slot:not(:first-child)
1549
1644
  :is(.me-input, .me-measure, .me-preview-token) {
1550
- font-size: calc(var(--me-explicit-size) * 0.7273);
1645
+ font-size: max(var(--me-min-font-size, 14px), calc(var(--me-explicit-size) * 0.7273));
1551
1646
  }
1552
1647
 
1553
1648
  /* Alphabet fonts are scoped to editable runs, never delimiter/operator glyphs.
@@ -1656,7 +1751,9 @@
1656
1751
  .me-utility-panel {
1657
1752
  padding: 12px;
1658
1753
  border-top: 1px solid var(--me-line, #dcdfe2);
1659
- font: 13px/1.5 system-ui, sans-serif;
1754
+ font:
1755
+ 13px/1.5 system-ui,
1756
+ sans-serif;
1660
1757
  color: var(--me-text, #253b33);
1661
1758
  }
1662
1759
  .me-utility-panel label {
@@ -1727,3 +1824,727 @@
1727
1824
  align-items: center;
1728
1825
  gap: 8px;
1729
1826
  }
1827
+
1828
+ /* A fraction inside a script uses scriptscript-sized terms. Its rows must not
1829
+ retain the body's minimum line height, including while a term is editable. */
1830
+ :is(.me-superscript, .me-subscript, .me-scripts)
1831
+ > .me-slot:not(:first-child)
1832
+ .me-fraction:not([data-math-style='display'])
1833
+ :is(.me-input, .me-measure, .me-preview-token) {
1834
+ font-size: max(var(--me-min-font-size, 14px), calc(var(--me-font-size, 22px) * 0.5));
1835
+ line-height: 1.1;
1836
+ padding-block: 0;
1837
+ }
1838
+ :is(.me-superscript, .me-subscript, .me-scripts)
1839
+ > .me-slot:not(:first-child)
1840
+ .me-fraction:not([data-math-style='display'])
1841
+ .me-row {
1842
+ min-height: 0;
1843
+ }
1844
+ :is(.me-superscript, .me-subscript, .me-scripts)
1845
+ > .me-slot:not(:first-child)
1846
+ .me-fraction:not([data-math-style='display'])
1847
+ > .me-slot {
1848
+ padding: 0 2px;
1849
+ }
1850
+ /* Compact fraction terms already reduce the script height. A simple base needs
1851
+ only a small shift; a tall structured base needs height-relative clearance. */
1852
+ .me-superscript > .me-slot:last-child:has(> .me-row > .me-fraction) {
1853
+ transform: translateY(-0.2em);
1854
+ }
1855
+ .me-subscript > .me-slot:last-child:has(> .me-row > .me-fraction) {
1856
+ transform: translateY(0.2em);
1857
+ }
1858
+ .me-superscript:has(> .me-slot:first-child > .me-row > .me-structure)
1859
+ > .me-slot:last-child:has(> .me-row > .me-fraction) {
1860
+ transform: translateY(-45%);
1861
+ }
1862
+ .me-subscript:has(> .me-slot:first-child > .me-row > .me-structure)
1863
+ > .me-slot:last-child:has(> .me-row > .me-fraction) {
1864
+ transform: translateY(45%);
1865
+ }
1866
+ /* Empty model boundaries are caret targets, not extra space before a script. */
1867
+ :is(.me-superscript, .me-subscript, .me-scripts)
1868
+ > .me-slot:not(:first-child)
1869
+ > .me-row
1870
+ > .me-empty-boundary:not(:focus-within)
1871
+ > .me-measure {
1872
+ min-width: 1px;
1873
+ width: 1px;
1874
+ padding-inline: 0;
1875
+ }
1876
+ :is(.me-superscript, .me-subscript, .me-scripts)
1877
+ > .me-slot:not(:first-child)
1878
+ > .me-row
1879
+ > .me-fraction {
1880
+ margin-inline: 1px;
1881
+ }
1882
+
1883
+ /* Query-independent structure actions remain visible while their operand is edited. */
1884
+ .me-context-footer {
1885
+ display: flex;
1886
+ align-items: center;
1887
+ flex-wrap: wrap;
1888
+ gap: 8px 12px;
1889
+ padding: 10px 14px;
1890
+ border-top: 1px solid var(--me-line, #d9e1dd);
1891
+ background: var(--me-subtle-background, #f6f8f6);
1892
+ color: var(--me-text, #202c27);
1893
+ font: 12px/1.4 var(--me-ui-font-family, system-ui, sans-serif);
1894
+ text-align: start;
1895
+ }
1896
+ .me-context-footer[hidden] {
1897
+ display: none;
1898
+ }
1899
+ .me-context-label {
1900
+ font-weight: 600;
1901
+ }
1902
+ .me-context-actions {
1903
+ display: flex;
1904
+ flex-wrap: wrap;
1905
+ gap: 6px;
1906
+ }
1907
+ .me-context-button {
1908
+ appearance: none;
1909
+ font: inherit;
1910
+ color: inherit;
1911
+ background: var(--me-panel-background, white);
1912
+ border: 1px solid var(--me-line, #cbd8cf);
1913
+ border-radius: var(--me-control-radius, 6px);
1914
+ padding: 6px 10px;
1915
+ cursor: pointer;
1916
+ }
1917
+ .me-context-button:hover:not(:disabled) {
1918
+ background: var(--me-hover-background, #e7efe9);
1919
+ }
1920
+ .me-context-button:focus-visible {
1921
+ outline: 2px solid var(--me-accent, #236957);
1922
+ outline-offset: 2px;
1923
+ }
1924
+ .me-context-button:disabled {
1925
+ opacity: 0.5;
1926
+ cursor: default;
1927
+ }
1928
+ .me-context-hint {
1929
+ color: var(--me-muted, #708075);
1930
+ font-size: 11px;
1931
+ }
1932
+ .me-context-button[aria-pressed='true'] {
1933
+ background: var(--me-hover-background, #e7efe9);
1934
+ color: var(--me-accent, #236957);
1935
+ font-weight: 600;
1936
+ }
1937
+
1938
+ /* Geometry audit: remove UI line-box struts from math stacks. Keep the same
1939
+ metrics for passive text, the input, and its measuring span. */
1940
+ .me-large-operator > .me-limits > .me-limit {
1941
+ display: inline-flex;
1942
+ }
1943
+ .me-large-operator > .me-limits > .me-limit > .me-row {
1944
+ min-height: 0;
1945
+ }
1946
+ .me-large-operator .me-limit :is(.me-input, .me-measure, .me-preview-token) {
1947
+ line-height: 1.1;
1948
+ padding-block: 0;
1949
+ }
1950
+ /* Side bounds span the full integral height, with room for the glyph's slant. */
1951
+ :is(
1952
+ [data-structure='integral'],
1953
+ [data-structure='doubleIntegral'],
1954
+ [data-structure='tripleIntegral'],
1955
+ [data-structure='contourIntegral']
1956
+ )
1957
+ > .me-limits
1958
+ > :is(.me-limit:first-child, .me-limit:last-child) {
1959
+ position: relative;
1960
+ }
1961
+ :is(
1962
+ [data-structure='integral'],
1963
+ [data-structure='doubleIntegral'],
1964
+ [data-structure='tripleIntegral'],
1965
+ [data-structure='contourIntegral']
1966
+ )
1967
+ > .me-limits
1968
+ > .me-operator-glyph {
1969
+ font-size: max(var(--me-min-font-size, 14px), calc(var(--me-font-size, 22px) * 2));
1970
+ }
1971
+ :is(
1972
+ [data-structure='integral'],
1973
+ [data-structure='doubleIntegral'],
1974
+ [data-structure='tripleIntegral'],
1975
+ [data-structure='contourIntegral']
1976
+ )
1977
+ > .me-limits
1978
+ > .me-limit:first-child {
1979
+ top: calc(var(--me-font-size, 22px) * -0.35);
1980
+ }
1981
+ :is(
1982
+ [data-structure='integral'],
1983
+ [data-structure='doubleIntegral'],
1984
+ [data-structure='tripleIntegral'],
1985
+ [data-structure='contourIntegral']
1986
+ )
1987
+ > .me-limits
1988
+ > .me-limit:last-child {
1989
+ top: calc(var(--me-font-size, 22px) * 0.25);
1990
+ }
1991
+ :is(
1992
+ [data-structure='integral'],
1993
+ [data-structure='doubleIntegral'],
1994
+ [data-structure='tripleIntegral'],
1995
+ [data-structure='contourIntegral']
1996
+ )[data-limit-placement='limits']
1997
+ > .me-limits
1998
+ > .me-limit {
1999
+ top: 0;
2000
+ }
2001
+ /* Annotation rows overlap their text line boxes, not their painted glyphs. */
2002
+ :is(.me-overset, .me-underset) > .me-slot {
2003
+ display: inline-flex;
2004
+ justify-content: center;
2005
+ }
2006
+ :is(.me-overset, .me-underset) > .me-slot > .me-row {
2007
+ min-height: 0;
2008
+ }
2009
+ :is(.me-overset, .me-underset) > .me-slot :is(.me-input, .me-measure, .me-preview-token) {
2010
+ line-height: 1;
2011
+ padding-block: 0;
2012
+ }
2013
+ .me-overset > .me-slot:first-child {
2014
+ margin-bottom: calc(var(--me-font-size, 22px) * -0.2);
2015
+ }
2016
+ .me-underset > .me-slot:first-child {
2017
+ margin-top: calc(var(--me-font-size, 22px) * -0.2);
2018
+ }
2019
+ /* Matrix environments use text-style cells; aligned/cases retain display rows. */
2020
+ .me-matrix[data-structure='matrix'] > .me-matrix-grid {
2021
+ row-gap: calc(var(--me-font-size, 22px) * 0.07);
2022
+ }
2023
+ .me-matrix[data-structure='matrix'] > .me-matrix-grid > .me-matrix-cell > .me-row {
2024
+ min-height: 0;
2025
+ }
2026
+ .me-matrix[data-structure='matrix']
2027
+ > .me-matrix-grid
2028
+ > .me-matrix-cell
2029
+ > .me-row
2030
+ > .me-run
2031
+ :is(.me-input, .me-measure, .me-preview-token) {
2032
+ line-height: 1.2;
2033
+ padding-block: 0;
2034
+ }
2035
+ .me-editor
2036
+ .me-matrix[data-structure='matrix']
2037
+ .me-fraction:not([data-math-style='display'])
2038
+ > .me-slot
2039
+ > .me-row
2040
+ > .me-run
2041
+ :is(.me-input, .me-measure, .me-preview-token) {
2042
+ font-size: max(var(--me-min-font-size, 14px), calc(var(--me-font-size, 22px) * 0.7));
2043
+ line-height: 0.85;
2044
+ padding-block: 0;
2045
+ }
2046
+ .me-matrix[data-structure='matrix'] .me-fraction:not([data-math-style='display']) .me-row {
2047
+ min-height: 0;
2048
+ }
2049
+
2050
+ /* Brace annotations need a compact body row as well as a compact label row. */
2051
+ :is(.me-overbrace, .me-underbrace) > .me-slot > .me-row {
2052
+ min-height: 0;
2053
+ }
2054
+ :is(.me-overbrace, .me-underbrace) > .me-slot :is(.me-input, .me-measure, .me-preview-token) {
2055
+ line-height: 1.1;
2056
+ padding-block: 0;
2057
+ }
2058
+ /* A display fraction in a script keeps full-size terms. Raise/lower the whole
2059
+ stack so that its near edge clears the base, not just its fraction bar. */
2060
+ .me-superscript > .me-slot:last-child:has(> .me-row > .me-fraction[data-math-style='display']) {
2061
+ transform: translateY(-30%);
2062
+ }
2063
+ .me-subscript > .me-slot:last-child:has(> .me-row > .me-fraction[data-math-style='display']) {
2064
+ transform: translateY(30%);
2065
+ }
2066
+
2067
+ /* Use the display operator glyphs themselves, including their italic correction,
2068
+ rather than enlarging/skewing a text-font integral or sum. */
2069
+ .me-large-operator[data-structure][data-limit-placement] > .me-limits > .me-operator-glyph {
2070
+ font:
2071
+ normal max(var(--me-min-font-size, 14px), var(--me-font-size, 22px)) / 1.6
2072
+ 'Barocss Large Operators',
2073
+ serif;
2074
+ transform: none;
2075
+ width: auto;
2076
+ height: calc(var(--me-font-size, 22px) * 1.6);
2077
+ }
2078
+ .me-large-operator:is(
2079
+ [data-structure='integral'],
2080
+ [data-structure='doubleIntegral'],
2081
+ [data-structure='tripleIntegral'],
2082
+ [data-structure='contourIntegral']
2083
+ )[data-limit-placement]
2084
+ > .me-limits
2085
+ > .me-operator-glyph {
2086
+ line-height: 2.3;
2087
+ height: calc(var(--me-font-size, 22px) * 2.3);
2088
+ }
2089
+ /* Keep fence curvature and stroke proportional to the chosen math size. */
2090
+ .me-parentheses > .me-delimiter,
2091
+ :is(.me-openClosed, .me-closedOpen, .me-fenced) > :is([data-fence='('], [data-fence=')']) {
2092
+ flex-basis: calc(var(--me-font-size, 22px) * 0.389);
2093
+ }
2094
+ .me-parentheses:has(
2095
+ > .me-slot :is(.me-fraction, .me-root, .me-indexedRoot, .me-matrix, .me-cases, .me-superscript)
2096
+ )
2097
+ > .me-delimiter,
2098
+ :is(.me-openClosed, .me-closedOpen, .me-fenced):has(
2099
+ > .me-slot :is(.me-fraction, .me-root, .me-indexedRoot, .me-matrix, .me-cases, .me-superscript)
2100
+ )
2101
+ > :is([data-fence='('], [data-fence=')']) {
2102
+ flex-basis: calc(var(--me-font-size, 22px) * 0.55);
2103
+ }
2104
+ .me-matrix[data-environment='pmatrix'] > .me-matrix-delimiter {
2105
+ width: calc(var(--me-font-size, 22px) * 0.55);
2106
+ }
2107
+ .me-delimiter:is([data-fence='{'], [data-fence='}']),
2108
+ .me-matrix:is([data-environment='Bmatrix'], [data-structure='cases']) > .me-matrix-delimiter {
2109
+ width: calc(var(--me-font-size, 22px) * 0.55);
2110
+ flex-basis: calc(var(--me-font-size, 22px) * 0.55);
2111
+ }
2112
+
2113
+ /* Brace outlines derived from KaTeX 0.16.28 svgGeometry.js (MIT; see
2114
+ fonts/LICENSE-KaTeX.txt). Clip three slices so long braces keep curved ends. */
2115
+ :is(.me-overbrace, .me-underbrace) > .me-slot:last-child::before {
2116
+ height: calc(var(--me-font-size, 22px) * 0.548);
2117
+ mask: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22100%25%22%20height%3D%22100%25%22%3E%3Csvg%20x%3D%220%22%20width%3D%2225%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%20400000%20548%22%20preserveAspectRatio%3D%22xMinYMin%20slice%22%3E%3Cpath%20d%3D%22M6%20548l-6-6v-35l6-11c56-104%20135.3-181.3%20238-232%2057.3-28.7%20117%20-45%20179-50h399577v120H403c-43.3%207-81%2015-113%2026-100.7%2033-179.7%2091-237%20174-2.7%20%205-6%209-10%2013-.7%201-7.3%201-20%201H6z%22%2F%3E%3C%2Fsvg%3E%3Csvg%20x%3D%2225%25%22%20width%3D%2250%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%20400000%20548%22%20preserveAspectRatio%3D%22xMidYMin%20slice%22%3E%3Cpath%20d%3D%22M200428%20334%20c-100.7-8.3-195.3-44-280-108-55.3-42-101.7-93-139-153l-9-14c-2.7%204-5.7%208.7-9%2014%20-53.3%2086.7-123.7%20153-211%20199-66.7%2036-137.3%2056.3-212%2062H0V214h199568c178.3-11.7%20%20311.7-78.3%20403-201%206-8%209.7-12%2011-12%20.7-.7%206.7-1%2018-1s17.3.3%2018%201c1.3%200%205%204%2011%20%2012%2044.7%2059.3%20101.3%20106.3%20170%20141s145.3%2054.3%20229%2060h199572v120z%22%2F%3E%3C%2Fsvg%3E%3Csvg%20x%3D%2275%25%22%20width%3D%2225%25%22%20height%3D%22100%25%22%20viewBox%3D%220%200%20400000%20548%22%20preserveAspectRatio%3D%22xMaxYMin%20slice%22%3E%3Cpath%20d%3D%22M400000%20542l%20-6%206h-17c-12.7%200-19.3-.3-20-1-4-4-7.3-8.3-10-13-35.3-51.3-80.8-93.8-136.5-127.5%20s-117.2-55.8-184.5-66.5c-.7%200-2-.3-4-1-18.7-2.7-76-4.3-172-5H0V214h399571l6%201%20c124.7%208%20235%2061.7%20331%20161%2031.3%2033.3%2059.7%2072.7%2085%20118l7%2013v35z%22%2F%3E%3C%2Fsvg%3E%3C%2Fsvg%3E')
2118
+ center / 100% 100% no-repeat;
2119
+ }
2120
+ .me-overbrace > .me-slot:last-child {
2121
+ padding-top: calc(var(--me-font-size, 22px) * 0.598);
2122
+ }
2123
+ .me-underbrace > .me-slot:last-child {
2124
+ padding-bottom: calc(var(--me-font-size, 22px) * 0.598);
2125
+ }
2126
+ .me-overbrace > .me-slot:first-child {
2127
+ margin-bottom: calc(var(--me-font-size, 22px) * -0.2);
2128
+ }
2129
+ .me-underbrace > .me-slot:first-child {
2130
+ margin-top: calc(var(--me-font-size, 22px) * -0.2);
2131
+ }
2132
+ .me-root > .me-radical,
2133
+ .me-indexedRoot > .me-radical {
2134
+ width: calc(var(--me-font-size, 22px) * 0.85);
2135
+ }
2136
+ .me-indexedRoot > .me-slot:nth-last-child(2) {
2137
+ align-self: center;
2138
+ display: inline-flex;
2139
+ margin-right: calc(var(--me-font-size, 22px) * -0.6);
2140
+ margin-top: 0;
2141
+ transform: translate(
2142
+ calc(var(--me-font-size, 22px) * 0.35),
2143
+ calc(var(--me-font-size, 22px) * -0.3)
2144
+ );
2145
+ }
2146
+ .me-indexedRoot > .me-slot:nth-last-child(2) > .me-row {
2147
+ min-height: 0;
2148
+ }
2149
+ .me-matrix[data-structure='matrix'] > .me-matrix-grid {
2150
+ column-gap: calc(var(--me-font-size, 22px) * 0.8);
2151
+ }
2152
+
2153
+ /* TeX leaves a thin space after a large operator. Integral side limits also
2154
+ need its italic correction so their upper label clears the slanted tip. */
2155
+ .me-large-operator {
2156
+ gap: calc(var(--me-font-size, 22px) / 6);
2157
+ }
2158
+ .me-large-operator:is(
2159
+ [data-structure='integral'],
2160
+ [data-structure='doubleIntegral'],
2161
+ [data-structure='tripleIntegral'],
2162
+ [data-structure='contourIntegral']
2163
+ ):not([data-limit-placement='limits'])
2164
+ > .me-limits
2165
+ > .me-limit:first-child {
2166
+ margin-left: calc(var(--me-font-size, 22px) * 0.44445);
2167
+ }
2168
+ .me-large-operator:is(
2169
+ [data-structure='integral'],
2170
+ [data-structure='doubleIntegral'],
2171
+ [data-structure='tripleIntegral'],
2172
+ [data-structure='contourIntegral']
2173
+ )[data-limit-placement='limits']
2174
+ > .me-limits
2175
+ > .me-operator-glyph {
2176
+ padding-inline-end: calc(var(--me-font-size, 22px) * 0.44445);
2177
+ }
2178
+ .me-large-operator:is(
2179
+ [data-structure='integral'],
2180
+ [data-structure='doubleIntegral'],
2181
+ [data-structure='tripleIntegral'],
2182
+ [data-structure='contourIntegral']
2183
+ )[data-limit-placement='limits']
2184
+ > .me-limits
2185
+ > .me-limit:last-child {
2186
+ transform: translateX(calc(var(--me-font-size, 22px) * -0.22222));
2187
+ }
2188
+ /* The upright glyph's lower side limit no longer needs the negative offset
2189
+ used for the skewed text-font integral. */
2190
+ .me-large-operator:is(
2191
+ [data-structure='integral'],
2192
+ [data-structure='doubleIntegral'],
2193
+ [data-structure='tripleIntegral'],
2194
+ [data-structure='contourIntegral']
2195
+ ):not([data-limit-placement='limits'])
2196
+ > .me-limits
2197
+ > .me-limit:last-child {
2198
+ margin-left: 0;
2199
+ }
2200
+ /* A radical encloses math ink rather than the taller UI text line box.
2201
+ Tall nested structures continue to determine their own row height. */
2202
+ :is(.me-root, .me-indexedRoot) > .me-slot:last-child {
2203
+ display: inline-flex;
2204
+ align-items: center;
2205
+ }
2206
+ :is(.me-root, .me-indexedRoot) > .me-slot:last-child > .me-row {
2207
+ min-height: 0;
2208
+ }
2209
+ :is(.me-root, .me-indexedRoot)
2210
+ > .me-slot:last-child
2211
+ > .me-row
2212
+ > .me-empty-boundary:not(:focus-within)
2213
+ > .me-measure {
2214
+ min-height: 0;
2215
+ }
2216
+ :is(.me-root, .me-indexedRoot)
2217
+ > .me-slot:last-child
2218
+ > .me-row
2219
+ > .me-run
2220
+ :is(.me-input, .me-measure, .me-preview-token) {
2221
+ line-height: 1;
2222
+ padding-block: 0;
2223
+ }
2224
+
2225
+ /* Inline math uses text-style operator glyphs and side limits by default.
2226
+ Explicit limits/nolimits remain authoritative. */
2227
+ @font-face {
2228
+ font-family: 'Barocss Small Operators';
2229
+ src: url('./fonts/KaTeX_Size1-Regular.woff2') format('woff2');
2230
+ font-style: normal;
2231
+ font-display: swap;
2232
+ }
2233
+ /* TeX stops reducing nested scripts at scriptscript size. */
2234
+ :is(.me-superscript, .me-subscript, .me-scripts)
2235
+ > .me-slot:not(:first-child)
2236
+ :is(.me-superscript, .me-subscript, .me-scripts)
2237
+ > .me-slot:not(:first-child)
2238
+ :is(.me-input, .me-measure, .me-preview-token) {
2239
+ font-size: max(var(--me-min-font-size, 14px), calc(var(--me-font-size, 22px) * 0.5));
2240
+ line-height: 1.1;
2241
+ padding-block: 0;
2242
+ }
2243
+ :is(.me-superscript, .me-subscript, .me-scripts)
2244
+ > .me-slot:not(:first-child)
2245
+ :is(.me-superscript, .me-subscript, .me-scripts)
2246
+ > .me-slot:not(:first-child)
2247
+ > .me-row {
2248
+ min-height: 0;
2249
+ }
2250
+ .me-superscript > .me-slot:last-child:has(> .me-row > :is(.me-root, .me-indexedRoot)) {
2251
+ transform: translateY(-15%);
2252
+ }
2253
+
2254
+ /* Nested scripts need less lift after their line boxes shrink. */
2255
+ :is(.me-superscript, .me-subscript, .me-scripts)
2256
+ > .me-slot:not(:first-child)
2257
+ .me-superscript
2258
+ > .me-slot:last-child {
2259
+ transform: translateY(-0.1em);
2260
+ }
2261
+
2262
+ /* KaTeX glyph contours retain the short curve and tall end caps. The cap
2263
+ length is bounded; only the straight stem extends for very tall bodies. */
2264
+ .me-parentheses > .me-delimiter,
2265
+ :is(.me-openClosed, .me-closedOpen, .me-fenced) > :is([data-fence='('], [data-fence=')']) {
2266
+ mask: url('./shapes/parenthesis.svg') center / 61.44% var(--me-font-size, 22px) no-repeat;
2267
+ }
2268
+ .me-parentheses:has(
2269
+ > .me-slot :is(.me-fraction, .me-root, .me-indexedRoot, .me-matrix, .me-cases, .me-superscript)
2270
+ )
2271
+ > .me-delimiter,
2272
+ :is(.me-openClosed, .me-closedOpen, .me-fenced):has(
2273
+ > .me-slot :is(.me-fraction, .me-root, .me-indexedRoot, .me-matrix, .me-cases, .me-superscript)
2274
+ )
2275
+ > :is([data-fence='('], [data-fence=')']),
2276
+ .me-matrix[data-environment='pmatrix'] > .me-matrix-delimiter {
2277
+ --me-fence-cap: min(50%, calc(var(--me-font-size, 22px) * 1.809));
2278
+ mask:
2279
+ url('./shapes/parenthesis-top.svg') left top / 100% var(--me-fence-cap) no-repeat,
2280
+ url('./shapes/parenthesis-bottom.svg') left bottom / 100% var(--me-fence-cap) no-repeat,
2281
+ linear-gradient(currentColor, currentColor) left center / 22.826%
2282
+ calc(100% - var(--me-fence-cap) - var(--me-fence-cap) + 1px) no-repeat;
2283
+ }
2284
+
2285
+ /* The font contour has a tapered entry and thin rising stroke. Reusing it
2286
+ avoids the thick uniform diagonal produced by the old polygon. */
2287
+ :is(.me-root, .me-indexedRoot) > .me-radical {
2288
+ clip-path: none;
2289
+ mask: url('./shapes/radical.svg') center / 100% 100% no-repeat;
2290
+ }
2291
+
2292
+ /* Radical geometry follows the containing math style, including the editing
2293
+ minimum. The radicand's flex slot supplies extra height for tall contents. */
2294
+ .me-row {
2295
+ --me-radical-size: max(var(--me-min-font-size, 14px), var(--me-font-size, 22px));
2296
+ }
2297
+ .me-row[data-layout-style='script'] {
2298
+ --me-radical-size: max(var(--me-min-font-size, 14px), calc(var(--me-font-size, 22px) * 0.7));
2299
+ }
2300
+ .me-row[data-layout-style='scriptscript'] {
2301
+ --me-radical-size: max(var(--me-min-font-size, 14px), calc(var(--me-font-size, 22px) * 0.5));
2302
+ }
2303
+ .me-editor .me-row > :is(.me-root, .me-indexedRoot) > .me-radical {
2304
+ width: calc(var(--me-radical-size) * 0.85);
2305
+ min-height: var(--me-radical-size);
2306
+ margin-top: calc(var(--me-radical-size) * 0.1);
2307
+ }
2308
+ .me-editor :is(.me-root, .me-indexedRoot) > .me-slot:last-child {
2309
+ margin-top: calc(var(--me-radical-size) * 0.1);
2310
+ }
2311
+
2312
+ /* A nested radical needs clearance above its own rule. Without this space,
2313
+ successive rules collapse together even when the operand metrics agree. */
2314
+ :is(.me-root, .me-indexedRoot)
2315
+ > .me-slot:last-child:has(> .me-row > :is(.me-root, .me-indexedRoot)) {
2316
+ padding-top: calc(var(--me-radical-size) * 0.25);
2317
+ }
2318
+
2319
+ /* Resolve reduced operator styles from model slots. Display operators retain
2320
+ their existing geometry; text/script contexts use Size1 and side limits. */
2321
+ .me-editor [data-operator-style] {
2322
+ --me-operator-scale: 1;
2323
+ --me-bound-scale: 0.7;
2324
+ --me-operator-size: calc(var(--me-font-size, 22px) * var(--me-operator-scale));
2325
+ }
2326
+ .me-editor [data-operator-style='script'] {
2327
+ --me-operator-scale: 0.7;
2328
+ --me-bound-scale: 0.5;
2329
+ }
2330
+ .me-editor [data-operator-style='scriptscript'] {
2331
+ --me-operator-scale: 0.5;
2332
+ --me-bound-scale: 0.5;
2333
+ }
2334
+ .me-editor
2335
+ .me-large-operator[data-operator-style]:not([data-operator-style='display'])
2336
+ > .me-limits
2337
+ > .me-operator-glyph {
2338
+ font:
2339
+ normal var(--me-operator-size) / 1.1 'Barocss Small Operators',
2340
+ serif;
2341
+ height: calc(var(--me-operator-size) * 1.1);
2342
+ transform: none;
2343
+ }
2344
+ .me-editor
2345
+ :is(.me-large-operator, .me-limit-operator)[data-operator-style]:not(
2346
+ [data-operator-style='display']
2347
+ ) {
2348
+ gap: calc(var(--me-operator-size) / 6);
2349
+ }
2350
+ .me-editor .me-large-operator[data-operator-style][data-layout-limits='side'] > .me-limits {
2351
+ display: inline-grid;
2352
+ grid-template-columns: max-content max-content;
2353
+ grid-template-rows: auto auto;
2354
+ align-items: center;
2355
+ }
2356
+ .me-editor
2357
+ .me-large-operator[data-operator-style][data-layout-limits='side']
2358
+ > .me-limits
2359
+ > .me-operator-glyph {
2360
+ grid-column: 1;
2361
+ grid-row: 1 / 3;
2362
+ }
2363
+ .me-editor
2364
+ .me-large-operator[data-operator-style][data-layout-limits='side']
2365
+ > .me-limits
2366
+ > .me-limit:first-child {
2367
+ grid-column: 2;
2368
+ grid-row: 1;
2369
+ }
2370
+ .me-editor
2371
+ .me-large-operator[data-operator-style][data-layout-limits='side']
2372
+ > .me-limits
2373
+ > .me-limit:last-child {
2374
+ grid-column: 2;
2375
+ grid-row: 2;
2376
+ }
2377
+ .me-editor
2378
+ .me-large-operator[data-operator-style]:not([data-operator-style='display'])
2379
+ > .me-limits
2380
+ > .me-limit {
2381
+ top: 0;
2382
+ margin-left: 0;
2383
+ }
2384
+ .me-editor
2385
+ .me-large-operator[data-operator-style]:not([data-operator-style='display']):is(
2386
+ [data-structure='integral'],
2387
+ [data-structure='doubleIntegral'],
2388
+ [data-structure='tripleIntegral'],
2389
+ [data-structure='contourIntegral']
2390
+ )[data-layout-limits='side']
2391
+ > .me-limits
2392
+ > .me-limit:first-child {
2393
+ margin-left: calc(var(--me-operator-size) * 0.19445);
2394
+ top: calc(var(--me-operator-size) * -0.12);
2395
+ }
2396
+ .me-editor
2397
+ .me-large-operator[data-operator-style]:not([data-operator-style='display']):is(
2398
+ [data-structure='integral'],
2399
+ [data-structure='doubleIntegral'],
2400
+ [data-structure='tripleIntegral'],
2401
+ [data-structure='contourIntegral']
2402
+ )[data-layout-limits='side']
2403
+ > .me-limits
2404
+ > .me-limit:last-child {
2405
+ top: calc(var(--me-operator-size) * 0.08);
2406
+ }
2407
+ .me-editor
2408
+ .me-large-operator[data-operator-style]:not([data-operator-style='display']):is(
2409
+ [data-structure='integral'],
2410
+ [data-structure='doubleIntegral'],
2411
+ [data-structure='tripleIntegral'],
2412
+ [data-structure='contourIntegral']
2413
+ )[data-layout-limits='stacked']
2414
+ > .me-limits
2415
+ > .me-operator-glyph {
2416
+ padding-inline-end: calc(var(--me-operator-size) * 0.19445);
2417
+ }
2418
+ .me-editor
2419
+ .me-large-operator[data-operator-style]:not([data-operator-style='display']):is(
2420
+ [data-structure='integral'],
2421
+ [data-structure='doubleIntegral'],
2422
+ [data-structure='tripleIntegral'],
2423
+ [data-structure='contourIntegral']
2424
+ )[data-layout-limits='stacked']
2425
+ > .me-limits
2426
+ > .me-limit:last-child {
2427
+ transform: translateX(calc(var(--me-operator-size) * -0.097225));
2428
+ }
2429
+ .me-editor
2430
+ .me-limit-operator[data-operator-style]:not([data-operator-style='display'])
2431
+ > .me-limits
2432
+ > .me-limit-glyph {
2433
+ font-size: var(--me-operator-size);
2434
+ }
2435
+ .me-editor .me-limit-operator[data-operator-style][data-layout-limits='side'] > .me-limits {
2436
+ flex-direction: row;
2437
+ align-items: center;
2438
+ gap: 0;
2439
+ }
2440
+ .me-editor
2441
+ .me-limit-operator[data-operator-style][data-layout-limits='side']
2442
+ > .me-limits
2443
+ > .me-limit {
2444
+ transform: translateY(calc(var(--me-operator-size) * 0.18));
2445
+ }
2446
+ /* Row styles distinguish a nested operator body from its own smaller bounds.
2447
+ Do not apply an ancestor bound's size to every descendant text token. */
2448
+ .me-editor [data-operator-style]:not([data-operator-style='display']) .me-row[data-layout-style] {
2449
+ min-height: 0;
2450
+ }
2451
+ .me-editor
2452
+ [data-operator-style]:not([data-operator-style='display'])
2453
+ .me-row[data-layout-style]
2454
+ > .me-run
2455
+ :is(.me-input, .me-measure, .me-preview-token) {
2456
+ font-size: max(var(--me-min-font-size, 14px), var(--me-font-size, 22px));
2457
+ line-height: 1.1;
2458
+ padding-block: 0;
2459
+ }
2460
+ .me-editor
2461
+ [data-operator-style]:not([data-operator-style='display'])
2462
+ .me-row[data-layout-style='script']
2463
+ > .me-run
2464
+ :is(.me-input, .me-measure, .me-preview-token) {
2465
+ font-size: max(var(--me-min-font-size, 14px), calc(var(--me-font-size, 22px) * 0.7));
2466
+ }
2467
+ .me-editor
2468
+ [data-operator-style]:not([data-operator-style='display'])
2469
+ .me-row[data-layout-style='scriptscript']
2470
+ > .me-run
2471
+ :is(.me-input, .me-measure, .me-preview-token) {
2472
+ font-size: max(var(--me-min-font-size, 14px), calc(var(--me-font-size, 22px) * 0.5));
2473
+ }
2474
+
2475
+ /* Glyph width and mathematical spacing are separate from the caret hit area.
2476
+ Binary/relation/punctuation gaps disappear in script styles. Empty slots
2477
+ retain their existing minimum width; only model boundaries shrink. */
2478
+ .me-row {
2479
+ --me-spacing-unit: calc(var(--me-font-size, 22px) / 18);
2480
+ }
2481
+ .me-row[data-layout-style='script'],
2482
+ .me-row[data-layout-style='scriptscript'] {
2483
+ --me-spacing-unit: 0px;
2484
+ }
2485
+ .me-row > :is(.me-run, .me-operatorName, .me-fraction)[data-math-spacing='true'] {
2486
+ margin-left: calc(var(--me-space-before, 0) * var(--me-spacing-unit));
2487
+ margin-right: calc(var(--me-space-after, 0) * var(--me-spacing-unit));
2488
+ }
2489
+ .me-run[data-math-spacing='true']:not(.me-empty) > .me-measure {
2490
+ padding-inline: 0;
2491
+ min-width: 0;
2492
+ }
2493
+ .me-row > .me-empty-boundary:not(:focus-within) > .me-measure {
2494
+ min-width: 1px;
2495
+ width: 1px;
2496
+ padding-inline: 0;
2497
+ }
2498
+
2499
+ /* Function names contribute glyph width only. The row sets their thin spacing,
2500
+ including the suppressed gap before an opening parenthesis. */
2501
+ .me-operatorName > .me-slot > .me-row > .me-run:not(.me-empty) > .me-measure {
2502
+ min-width: 0;
2503
+ padding-inline: 0;
2504
+ }
2505
+ .me-row[data-layout-style='script'] {
2506
+ --me-tight-unit: calc(max(var(--me-min-font-size, 14px), var(--me-font-size, 22px) * 0.7) / 18);
2507
+ }
2508
+ .me-row[data-layout-style='scriptscript'] {
2509
+ --me-tight-unit: calc(max(var(--me-min-font-size, 14px), var(--me-font-size, 22px) * 0.5) / 18);
2510
+ }
2511
+ .me-row:is([data-layout-style='script'], [data-layout-style='scriptscript'])
2512
+ > [data-math-spacing='true'] {
2513
+ margin-left: calc(var(--me-tight-before, 0) * var(--me-tight-unit));
2514
+ margin-right: calc(var(--me-tight-after, 0) * var(--me-tight-unit));
2515
+ }
2516
+
2517
+ /* Help uses the top layer to avoid clipping inside narrow or embedded fields. */
2518
+ .me-help {
2519
+ width: min(560px, calc(100vw - 40px));
2520
+ max-height: calc(100vh - 48px);
2521
+ box-sizing: border-box;
2522
+ overflow: auto;
2523
+ padding: 24px;
2524
+ border: 1px solid var(--me-line, #dcdfe2);
2525
+ border-radius: 12px;
2526
+ background: var(--me-control-bg, #fff);
2527
+ color: var(--me-text, #253b33);
2528
+ text-align: start;
2529
+ }
2530
+ .me-help::backdrop {
2531
+ background: rgb(0 0 0 / 25%);
2532
+ }
2533
+ .me-help h2 {
2534
+ margin: 0 0 8px;
2535
+ font:
2536
+ 600 20px/1.4 system-ui,
2537
+ sans-serif;
2538
+ }
2539
+ .me-help dl {
2540
+ display: grid;
2541
+ gap: 8px 16px;
2542
+ grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
2543
+ }
2544
+ .me-help dt {
2545
+ font-weight: 600;
2546
+ overflow-wrap: anywhere;
2547
+ }
2548
+ .me-help dd {
2549
+ margin: 0;
2550
+ }