@messagevisor/catalog 0.1.0 → 0.2.0

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/src/node/index.ts CHANGED
@@ -241,7 +241,7 @@ interface CatalogBuildContext {
241
241
  repositoryRootDirectoryPath: string;
242
242
  outputDirectoryPath: string;
243
243
  dataDirectoryPath: string;
244
- fullHistory: CatalogHistoryEntry[];
244
+ historyIndex: CatalogHistoryIndex;
245
245
  runtime: CatalogRuntime;
246
246
  devEditors: CatalogDevEditor[];
247
247
  duplicateResultsBySet: Record<string, CatalogDuplicateTranslationsSetResult>;
@@ -258,6 +258,21 @@ interface EntityPathInfo {
258
258
  set?: string;
259
259
  }
260
260
 
261
+ interface CatalogHistoryIndex {
262
+ entries: CatalogHistoryEntry[];
263
+ bySet: Record<string, CatalogHistoryEntry[]>;
264
+ byEntity: Record<string, CatalogHistoryEntry[]>;
265
+ lastModifiedByEntity: Record<string, CatalogLastModified>;
266
+ }
267
+
268
+ interface StreamingGitCommit {
269
+ commit: string;
270
+ author: string;
271
+ timestamp: string;
272
+ entities: CatalogHistoryEntity[];
273
+ seenEntityKeys: Set<string>;
274
+ }
275
+
261
276
  function toPosixPath(value: string) {
262
277
  return value.split(path.sep).join("/");
263
278
  }
@@ -393,25 +408,11 @@ function getTargetMessageKeys(target: Target, messageKeys: string[]) {
393
408
  .sort();
394
409
  }
395
410
 
396
- function getLastModified(
397
- history: CatalogHistoryEntry[],
398
- type: CatalogEntityType,
399
- key: string,
400
- set?: string,
401
- ): CatalogLastModified | undefined {
402
- const entry = history.find((candidate) =>
403
- candidate.entities.some(
404
- (entity) =>
405
- entity.type === type &&
406
- entity.key === key &&
407
- (typeof set === "undefined" || entity.set === set),
408
- ),
409
- );
410
-
411
- if (!entry) {
412
- return undefined;
413
- }
411
+ function getHistoryEntityKey(type: CatalogEntityType | "test", key: string, set?: string) {
412
+ return `${set || ""}\x1f${type}\x1f${key}`;
413
+ }
414
414
 
415
+ function toLastModified(entry: CatalogHistoryEntry): CatalogLastModified {
415
416
  return {
416
417
  commit: entry.commit,
417
418
  author: entry.author,
@@ -419,11 +420,20 @@ function getLastModified(
419
420
  };
420
421
  }
421
422
 
423
+ function getLastModified(
424
+ historyIndex: CatalogHistoryIndex,
425
+ type: CatalogEntityType,
426
+ key: string,
427
+ set?: string,
428
+ ): CatalogLastModified | undefined {
429
+ return historyIndex.lastModifiedByEntity[getHistoryEntityKey(type, key, set)];
430
+ }
431
+
422
432
  function getEntitySummary(
423
433
  entity: Locale | Message | Attribute | Segment | Target,
424
434
  type: CatalogEntityType,
425
435
  key: string,
426
- history: CatalogHistoryEntry[],
436
+ historyIndex: CatalogHistoryIndex,
427
437
  set?: string,
428
438
  extra: Partial<CatalogEntitySummary> = {},
429
439
  ): CatalogEntitySummary {
@@ -433,7 +443,7 @@ function getEntitySummary(
433
443
  archived: (entity as any).archived,
434
444
  deprecated: (entity as any).deprecated,
435
445
  ...extra,
436
- lastModified: getLastModified(history, type, key, set),
446
+ lastModified: getLastModified(historyIndex, type, key, set),
437
447
  href: `entities/${type}/${encodeKey(key)}.json`,
438
448
  };
439
449
  }
@@ -710,6 +720,186 @@ function runGit(rootDirectoryPath: string, args: string[]) {
710
720
  });
711
721
  }
712
722
 
723
+ function getCatalogHistoryPathPatterns(rootDirectoryPath: string, projectConfig: any) {
724
+ return projectConfig.sets
725
+ ? [path.relative(rootDirectoryPath, projectConfig.setsDirectoryPath)]
726
+ : [
727
+ path.relative(rootDirectoryPath, projectConfig.localesDirectoryPath),
728
+ path.relative(rootDirectoryPath, projectConfig.messagesDirectoryPath),
729
+ path.relative(rootDirectoryPath, projectConfig.attributesDirectoryPath),
730
+ path.relative(rootDirectoryPath, projectConfig.segmentsDirectoryPath),
731
+ path.relative(rootDirectoryPath, projectConfig.targetsDirectoryPath),
732
+ path.relative(rootDirectoryPath, projectConfig.testsDirectoryPath),
733
+ ];
734
+ }
735
+
736
+ function createEmptyHistoryIndex(): CatalogHistoryIndex {
737
+ return {
738
+ entries: [],
739
+ bySet: {},
740
+ byEntity: {},
741
+ lastModifiedByEntity: {},
742
+ };
743
+ }
744
+
745
+ function addHistoryIndexEntry(
746
+ target: Record<string, CatalogHistoryEntry[]>,
747
+ key: string,
748
+ entry: CatalogHistoryEntry,
749
+ ) {
750
+ if (!target[key]) {
751
+ target[key] = [];
752
+ }
753
+
754
+ target[key].push(entry);
755
+ }
756
+
757
+ function buildCatalogHistoryIndex(entries: CatalogHistoryEntry[]): CatalogHistoryIndex {
758
+ const index = createEmptyHistoryIndex();
759
+ index.entries = entries;
760
+
761
+ for (const entry of entries) {
762
+ const seenSets = new Set<string>();
763
+
764
+ for (const entity of entry.entities) {
765
+ if (entity.type === "test") {
766
+ continue;
767
+ }
768
+
769
+ const entityKey = getHistoryEntityKey(entity.type, entity.key, entity.set);
770
+ addHistoryIndexEntry(index.byEntity, entityKey, entry);
771
+
772
+ if (!index.lastModifiedByEntity[entityKey]) {
773
+ index.lastModifiedByEntity[entityKey] = toLastModified(entry);
774
+ }
775
+
776
+ if (entity.set && !seenSets.has(entity.set)) {
777
+ seenSets.add(entity.set);
778
+ addHistoryIndexEntry(index.bySet, entity.set, entry);
779
+ }
780
+ }
781
+ }
782
+
783
+ return index;
784
+ }
785
+
786
+ function appendHistoryEntry(
787
+ history: CatalogHistoryEntry[],
788
+ current: StreamingGitCommit | undefined,
789
+ ) {
790
+ if (!current || current.entities.length === 0) {
791
+ return;
792
+ }
793
+
794
+ history.push({
795
+ commit: current.commit,
796
+ author: current.author,
797
+ timestamp: current.timestamp,
798
+ entities: current.entities,
799
+ });
800
+ }
801
+
802
+ function addHistoryEntity(current: StreamingGitCommit, entity: CatalogHistoryEntity) {
803
+ if (entity.type === "test") {
804
+ return;
805
+ }
806
+
807
+ const entityKey = getHistoryEntityKey(entity.type, entity.key, entity.set);
808
+
809
+ if (current.seenEntityKeys.has(entityKey)) {
810
+ return;
811
+ }
812
+
813
+ current.seenEntityKeys.add(entityKey);
814
+ current.entities.push(entity);
815
+ }
816
+
817
+ async function streamCatalogGitHistory(
818
+ rootDirectoryPath: string,
819
+ projectConfig: any,
820
+ ): Promise<CatalogHistoryEntry[]> {
821
+ const pathPatterns = getCatalogHistoryPathPatterns(rootDirectoryPath, projectConfig);
822
+ const args = [
823
+ "-C",
824
+ rootDirectoryPath,
825
+ "log",
826
+ "--name-only",
827
+ "--pretty=format:%x1e%h%x1f%an%x1f%aI",
828
+ "--relative",
829
+ "--no-merges",
830
+ "--",
831
+ ...pathPatterns,
832
+ ];
833
+
834
+ return new Promise((resolve, reject) => {
835
+ let current: StreamingGitCommit | undefined;
836
+ let buffer = "";
837
+ const history: CatalogHistoryEntry[] = [];
838
+ const git = childProcess.spawn("git", args, {
839
+ stdio: ["ignore", "pipe", "ignore"],
840
+ });
841
+
842
+ function processLine(line: string) {
843
+ if (!line) {
844
+ return;
845
+ }
846
+
847
+ if (line.startsWith("\x1e")) {
848
+ appendHistoryEntry(history, current);
849
+
850
+ const [commit, author, timestamp] = line.slice(1).split("\x1f");
851
+ current =
852
+ commit && author && timestamp
853
+ ? {
854
+ commit,
855
+ author,
856
+ timestamp,
857
+ entities: [],
858
+ seenEntityKeys: new Set(),
859
+ }
860
+ : undefined;
861
+ return;
862
+ }
863
+
864
+ if (!current) {
865
+ return;
866
+ }
867
+
868
+ const entity = getEntityInfoFromRelativePath(rootDirectoryPath, projectConfig, line);
869
+
870
+ if (entity) {
871
+ addHistoryEntity(current, entity);
872
+ }
873
+ }
874
+
875
+ git.stdout.setEncoding("utf8");
876
+ git.stdout.on("data", (chunk: string) => {
877
+ buffer += chunk;
878
+ const lines = buffer.split(/\r?\n/);
879
+ buffer = lines.pop() || "";
880
+
881
+ for (const line of lines) {
882
+ processLine(line);
883
+ }
884
+ });
885
+ git.on("error", reject);
886
+ git.on("close", (code) => {
887
+ if (buffer) {
888
+ processLine(buffer);
889
+ }
890
+
891
+ appendHistoryEntry(history, current);
892
+
893
+ if (code === 0) {
894
+ resolve(history);
895
+ return;
896
+ }
897
+
898
+ reject(new Error(`git log exited with code ${code}`));
899
+ });
900
+ });
901
+ }
902
+
713
903
  function isExecutableFile(filePath: string) {
714
904
  try {
715
905
  const stat = fs.statSync(filePath);
@@ -791,51 +981,16 @@ function detectDevEditors(): CatalogDevEditor[] {
791
981
  return editors;
792
982
  }
793
983
 
794
- function getGitHistory(rootDirectoryPath: string, projectConfig: any): CatalogHistoryEntry[] {
984
+ async function getGitHistoryIndex(
985
+ rootDirectoryPath: string,
986
+ projectConfig: any,
987
+ ): Promise<CatalogHistoryIndex> {
795
988
  try {
796
- const pathPatterns = projectConfig.sets
797
- ? [path.relative(rootDirectoryPath, projectConfig.setsDirectoryPath)]
798
- : [
799
- path.relative(rootDirectoryPath, projectConfig.localesDirectoryPath),
800
- path.relative(rootDirectoryPath, projectConfig.messagesDirectoryPath),
801
- path.relative(rootDirectoryPath, projectConfig.attributesDirectoryPath),
802
- path.relative(rootDirectoryPath, projectConfig.segmentsDirectoryPath),
803
- path.relative(rootDirectoryPath, projectConfig.targetsDirectoryPath),
804
- path.relative(rootDirectoryPath, projectConfig.testsDirectoryPath),
805
- ];
806
- const raw = runGit(rootDirectoryPath, [
807
- "log",
808
- "--name-only",
809
- "--pretty=format:%h|%an|%aI",
810
- "--relative",
811
- "--no-merges",
812
- "--",
813
- ...pathPatterns,
814
- ]);
815
- const blocks = raw.split("\n\n");
816
- const history: CatalogHistoryEntry[] = [];
817
-
818
- for (const block of blocks) {
819
- if (!block.trim()) {
820
- continue;
821
- }
822
-
823
- const lines = block.split("\n").filter(Boolean);
824
- const [commit, author, timestamp] = lines[0].split("|");
825
- const entities = lines
826
- .slice(1)
827
- .map((line) => getEntityInfoFromRelativePath(rootDirectoryPath, projectConfig, line))
828
- .filter(Boolean) as CatalogHistoryEntity[];
829
- const filteredEntities = entities.filter((entity) => entity.type !== "test");
830
-
831
- if (filteredEntities.length > 0) {
832
- history.push({ commit, author, timestamp, entities: filteredEntities });
833
- }
834
- }
835
-
836
- return history;
989
+ return buildCatalogHistoryIndex(
990
+ await streamCatalogGitHistory(rootDirectoryPath, projectConfig),
991
+ );
837
992
  } catch (_error) {
838
- return [];
993
+ return createEmptyHistoryIndex();
839
994
  }
840
995
  }
841
996
 
@@ -946,24 +1101,13 @@ async function writeHistoryPages(directoryPath: string, history: CatalogHistoryE
946
1101
  }
947
1102
  }
948
1103
 
949
- function filterHistoryForEntity(
950
- history: CatalogHistoryEntry[],
1104
+ function getHistoryForEntity(
1105
+ historyIndex: CatalogHistoryIndex,
951
1106
  type: CatalogEntityType,
952
1107
  key: string,
953
1108
  set?: string,
954
1109
  ) {
955
- return history.filter((entry) =>
956
- entry.entities.some(
957
- (entity) =>
958
- entity.type === type &&
959
- entity.key === key &&
960
- (typeof set === "undefined" || entity.set === set),
961
- ),
962
- );
963
- }
964
-
965
- function filterHistoryForSet(history: CatalogHistoryEntry[], set: string) {
966
- return history.filter((entry) => entry.entities.some((entity) => entity.set === set));
1110
+ return historyIndex.byEntity[getHistoryEntityKey(type, key, set)] || [];
967
1111
  }
968
1112
 
969
1113
  function getSourceFileInfo(
@@ -1137,7 +1281,7 @@ async function buildSetCatalog(
1137
1281
  }
1138
1282
  }
1139
1283
 
1140
- const history = set ? filterHistoryForSet(context.fullHistory, set) : context.fullHistory;
1284
+ const history = set ? context.historyIndex.bySet[set] || [] : context.historyIndex.entries;
1141
1285
  const localeDirections = getLocaleDirections(locales);
1142
1286
  const duplicateResult = context.duplicateResultsBySet[getDuplicateSetKey(set)] || {
1143
1287
  set: set || null,
@@ -1225,11 +1369,11 @@ async function buildSetCatalog(
1225
1369
  context.runtime.resolveFormats(localeKey, locales, targets[targetKey]),
1226
1370
  ]),
1227
1371
  ),
1228
- lastModified: getLastModified(context.fullHistory, "locale", localeKey, set || undefined),
1372
+ lastModified: getLastModified(context.historyIndex, "locale", localeKey, set || undefined),
1229
1373
  };
1230
1374
 
1231
1375
  index.entities.locale.push(
1232
- getEntitySummary(locale, "locale", localeKey, context.fullHistory, set || undefined, {
1376
+ getEntitySummary(locale, "locale", localeKey, context.historyIndex, set || undefined, {
1233
1377
  targets: sortStrings(Array.from(localeTargets[localeKey] || [])),
1234
1378
  }),
1235
1379
  );
@@ -1243,7 +1387,7 @@ async function buildSetCatalog(
1243
1387
  );
1244
1388
  await writeHistoryPages(
1245
1389
  path.join(outputDirectoryPath, "history", "locale", encodeKey(localeKey)),
1246
- filterHistoryForEntity(context.fullHistory, "locale", localeKey, set || undefined),
1390
+ getHistoryForEntity(context.historyIndex, "locale", localeKey, set || undefined),
1247
1391
  );
1248
1392
  }
1249
1393
 
@@ -1305,7 +1449,7 @@ async function buildSetCatalog(
1305
1449
  resolveTranslationRow(override.translations, localeKey, locales),
1306
1450
  ),
1307
1451
  })),
1308
- lastModified: getLastModified(context.fullHistory, "message", messageKey, set || undefined),
1452
+ lastModified: getLastModified(context.historyIndex, "message", messageKey, set || undefined),
1309
1453
  };
1310
1454
 
1311
1455
  const directLocales = localeKeys.filter(
@@ -1334,7 +1478,7 @@ async function buildSetCatalog(
1334
1478
  }
1335
1479
 
1336
1480
  index.entities.message.push(
1337
- getEntitySummary(message, "message", messageKey, context.fullHistory, set || undefined, {
1481
+ getEntitySummary(message, "message", messageKey, context.historyIndex, set || undefined, {
1338
1482
  targets: sortStrings(messageTargets[messageKey] || []),
1339
1483
  ...(directLocales.length > 0 ? { locales: sortStrings(directLocales) } : {}),
1340
1484
  ...(overrideLocalesList.length > 0 ? { overrideLocales: overrideLocalesList } : {}),
@@ -1346,7 +1490,7 @@ async function buildSetCatalog(
1346
1490
  );
1347
1491
  await writeHistoryPages(
1348
1492
  path.join(outputDirectoryPath, "history", "message", encodeKey(messageKey)),
1349
- filterHistoryForEntity(context.fullHistory, "message", messageKey, set || undefined),
1493
+ getHistoryForEntity(context.historyIndex, "message", messageKey, set || undefined),
1350
1494
  );
1351
1495
  }
1352
1496
 
@@ -1378,7 +1522,7 @@ async function buildSetCatalog(
1378
1522
  messages: sortStrings(Array.from(attributesUsedInMessages[attributeKey] || [])),
1379
1523
  },
1380
1524
  lastModified: getLastModified(
1381
- context.fullHistory,
1525
+ context.historyIndex,
1382
1526
  "attribute",
1383
1527
  attributeKey,
1384
1528
  set || undefined,
@@ -1390,7 +1534,7 @@ async function buildSetCatalog(
1390
1534
  attribute,
1391
1535
  "attribute",
1392
1536
  attributeKey,
1393
- context.fullHistory,
1537
+ context.historyIndex,
1394
1538
  set || undefined,
1395
1539
  {
1396
1540
  targets: sortStrings(Array.from(attributeTargets[attributeKey] || [])),
@@ -1403,7 +1547,7 @@ async function buildSetCatalog(
1403
1547
  );
1404
1548
  await writeHistoryPages(
1405
1549
  path.join(outputDirectoryPath, "history", "attribute", encodeKey(attributeKey)),
1406
- filterHistoryForEntity(context.fullHistory, "attribute", attributeKey, set || undefined),
1550
+ getHistoryForEntity(context.historyIndex, "attribute", attributeKey, set || undefined),
1407
1551
  );
1408
1552
  }
1409
1553
 
@@ -1428,11 +1572,11 @@ async function buildSetCatalog(
1428
1572
  attributes: sortStrings(Array.from(usedAttributes)),
1429
1573
  messages: sortStrings(Array.from(segmentsUsedInMessages[segmentKey] || [])),
1430
1574
  },
1431
- lastModified: getLastModified(context.fullHistory, "segment", segmentKey, set || undefined),
1575
+ lastModified: getLastModified(context.historyIndex, "segment", segmentKey, set || undefined),
1432
1576
  };
1433
1577
 
1434
1578
  index.entities.segment.push(
1435
- getEntitySummary(segment, "segment", segmentKey, context.fullHistory, set || undefined, {
1579
+ getEntitySummary(segment, "segment", segmentKey, context.historyIndex, set || undefined, {
1436
1580
  targets: sortStrings(Array.from(segmentTargets[segmentKey] || [])),
1437
1581
  }),
1438
1582
  );
@@ -1442,7 +1586,7 @@ async function buildSetCatalog(
1442
1586
  );
1443
1587
  await writeHistoryPages(
1444
1588
  path.join(outputDirectoryPath, "history", "segment", encodeKey(segmentKey)),
1445
- filterHistoryForEntity(context.fullHistory, "segment", segmentKey, set || undefined),
1589
+ getHistoryForEntity(context.historyIndex, "segment", segmentKey, set || undefined),
1446
1590
  );
1447
1591
  }
1448
1592
 
@@ -1474,11 +1618,11 @@ async function buildSetCatalog(
1474
1618
  formatsByLocale,
1475
1619
  formatRowsByLocale,
1476
1620
  messages: targetMessages[targetKey],
1477
- lastModified: getLastModified(context.fullHistory, "target", targetKey, set || undefined),
1621
+ lastModified: getLastModified(context.historyIndex, "target", targetKey, set || undefined),
1478
1622
  };
1479
1623
 
1480
1624
  index.entities.target.push(
1481
- getEntitySummary(target, "target", targetKey, context.fullHistory, set || undefined, {
1625
+ getEntitySummary(target, "target", targetKey, context.historyIndex, set || undefined, {
1482
1626
  messageCount: targetMessages[targetKey].length,
1483
1627
  }),
1484
1628
  );
@@ -1488,7 +1632,7 @@ async function buildSetCatalog(
1488
1632
  );
1489
1633
  await writeHistoryPages(
1490
1634
  path.join(outputDirectoryPath, "history", "target", encodeKey(targetKey)),
1491
- filterHistoryForEntity(context.fullHistory, "target", targetKey, set || undefined),
1635
+ getHistoryForEntity(context.historyIndex, "target", targetKey, set || undefined),
1492
1636
  );
1493
1637
  }
1494
1638
 
@@ -1543,7 +1687,7 @@ export async function exportCatalog(
1543
1687
  }
1544
1688
 
1545
1689
  const devEditors = options.dev ? options.devEditors || detectDevEditors() : [];
1546
- const fullHistory = getGitHistory(rootDirectoryPath, projectConfig);
1690
+ const historyIndex = await getGitHistoryIndex(rootDirectoryPath, projectConfig);
1547
1691
  const duplicateTranslations = await runtime.findDuplicateTranslations(projectConfig, datasource);
1548
1692
  const duplicateResultsBySet = Object.fromEntries(
1549
1693
  duplicateTranslations.results.map((result) => [getDuplicateSetKey(result.set), result]),
@@ -1553,7 +1697,7 @@ export async function exportCatalog(
1553
1697
  repositoryRootDirectoryPath: getRepositoryRootDirectoryPath(rootDirectoryPath),
1554
1698
  outputDirectoryPath,
1555
1699
  dataDirectoryPath,
1556
- fullHistory,
1700
+ historyIndex,
1557
1701
  runtime,
1558
1702
  devEditors,
1559
1703
  duplicateResultsBySet,
@@ -1561,7 +1705,7 @@ export async function exportCatalog(
1561
1705
  const executions = await runtime.getProjectSetExecutions(projectConfig, datasource);
1562
1706
  const setIndexes: Record<string, CatalogSetIndex> = {};
1563
1707
 
1564
- await writeHistoryPages(path.join(dataDirectoryPath, "project", "history"), fullHistory);
1708
+ await writeHistoryPages(path.join(dataDirectoryPath, "project", "history"), historyIndex.entries);
1565
1709
 
1566
1710
  for (const execution of executions) {
1567
1711
  const outputRelativeDirectory = projectConfig.sets ? path.join("sets", execution.set) : "root";
@@ -1 +0,0 @@
1
- *,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.static{position:static}.absolute{position:absolute}.relative{position:relative}.right-0{right:0}.right-2{right:.5rem}.right-3{right:.75rem}.top-1\/2{top:50%}.top-full{top:100%}.z-20{z-index:20}.m-8{margin:2rem}.mx-6{margin-left:1.5rem;margin-right:1.5rem}.mx-auto{margin-left:auto;margin-right:auto}.-ml-px{margin-left:-1px}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-6{margin-bottom:1.5rem}.ml-3{margin-left:.75rem}.ml-auto{margin-left:auto}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-px{margin-top:1px}.box-border{box-sizing:border-box}.\!block{display:block!important}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-\[46px\]{height:46px}.h-auto{height:auto}.h-full{height:100%}.max-h-4{max-height:1rem}.min-h-0{min-height:0px}.min-h-screen{min-height:100vh}.w-1\/2{width:50%}.w-1\/3{width:33.333333%}.w-16{width:4rem}.w-2\/5{width:40%}.w-28{width:7rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-8{width:2rem}.w-\[10\%\]{width:10%}.w-\[12\%\]{width:12%}.w-\[14\%\]{width:14%}.w-\[16\%\]{width:16%}.w-\[18\%\]{width:18%}.w-\[20\%\]{width:20%}.w-\[22\%\]{width:22%}.w-\[28\%\]{width:28%}.w-\[30\%\]{width:30%}.w-\[32\%\]{width:32%}.w-\[34\%\]{width:34%}.w-\[36\%\]{width:36%}.w-\[38\%\]{width:38%}.w-\[40\%\]{width:40%}.w-\[42\%\]{width:42%}.w-\[70\%\]{width:70%}.w-auto{width:auto}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.min-w-0{min-width:0px}.min-w-28{min-width:7rem}.min-w-48{min-width:12rem}.min-w-\[40rem\]{min-width:40rem}.max-w-44{max-width:11rem}.max-w-5xl{max-width:64rem}.max-w-full{max-width:100%}.max-w-none{max-width:none}.flex-1{flex:1 1 0%}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.basis-\[min\(100\%\,22rem\)\]{flex-basis:min(100%,22rem)}.table-fixed{table-layout:fixed}.border-collapse{border-collapse:collapse}.-translate-y-1\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-pointer{cursor:pointer}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-rows-\[0fr\]{grid-template-rows:0fr}.grid-rows-\[1fr\]{grid-template-rows:1fr}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-stretch{align-items:stretch}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0{gap:0px}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-2\.5{gap:.625rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.gap-x-4{-moz-column-gap:1rem;column-gap:1rem}.gap-y-1\.5{row-gap:.375rem}.gap-y-3{row-gap:.75rem}.gap-y-8{row-gap:2rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-border>:not([hidden])~:not([hidden]){border-color:var(--mv-color-border)}.self-start{align-self:flex-start}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.break-words{overflow-wrap:break-word}.rounded{border-radius:8px}.rounded-\[3px\]{border-radius:3px}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-xl{border-radius:.75rem}.rounded-l{border-top-left-radius:8px;border-bottom-left-radius:8px}.rounded-r{border-top-right-radius:8px;border-bottom-right-radius:8px}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l{border-left-width:1px}.border-r{border-right-width:1px}.border-border{border-color:var(--mv-color-border)}.border-danger-outline{border-color:var(--mv-color-danger-outline)}.border-pill{border-color:var(--mv-color-pill)}.border-primary{border-color:var(--mv-color-primary)}.border-success-outline{border-color:var(--mv-color-success-outline)}.border-transparent{border-color:transparent}.border-warning-outline{border-color:var(--mv-color-warning-outline)}.bg-amber-100{--tw-bg-opacity: 1;background-color:rgb(254 243 199 / var(--tw-bg-opacity, 1))}.bg-background{background-color:var(--mv-color-background)}.bg-danger-surface{background-color:var(--mv-color-danger-surface)}.bg-elevated{background-color:var(--mv-color-elevated)}.bg-header{background-color:var(--mv-color-header)}.bg-header-active{background-color:var(--mv-color-header-active)}.bg-pill{background-color:var(--mv-color-pill)}.bg-success-surface{background-color:var(--mv-color-success-surface)}.bg-surface{background-color:var(--mv-color-surface)}.bg-transparent{background-color:transparent}.bg-warning-surface{background-color:var(--mv-color-warning-surface)}.object-contain{-o-object-fit:contain;object-fit:contain}.object-left{-o-object-position:left;object-position:left}.p-1{padding:.25rem}.p-4{padding:1rem}.p-8{padding:2rem}.p-px{padding:1px}.px-0\.5{padding-left:.125rem;padding-right:.125rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0{padding-top:0;padding-bottom:0}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-px{padding-top:1px;padding-bottom:1px}.pb-2{padding-bottom:.5rem}.pb-4{padding-bottom:1rem}.pb-5{padding-bottom:1.25rem}.pb-6{padding-bottom:1.5rem}.pl-1{padding-left:.25rem}.pl-2{padding-left:.5rem}.pl-4{padding-left:1rem}.pl-5{padding-left:1.25rem}.pr-10{padding-right:2.5rem}.pr-2{padding-right:.5rem}.pr-3{padding-right:.75rem}.pr-7{padding-right:1.75rem}.pt-1{padding-top:.25rem}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.pt-8{padding-top:2rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-top{vertical-align:top}.align-middle{vertical-align:middle}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-black{font-weight:900}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.leading-4{line-height:1rem}.leading-5{line-height:1.25rem}.leading-snug{line-height:1.375}.tracking-wide{letter-spacing:.025em}.text-danger{color:var(--mv-color-danger)}.text-faint{color:var(--mv-color-faint)}.text-header{color:var(--mv-color-header)}.text-header-text{color:var(--mv-color-header-text)}.text-inherit{color:inherit}.text-muted{color:var(--mv-color-muted)}.text-pill{color:var(--mv-color-pill)}.text-primary{color:var(--mv-color-primary)}.text-text{color:var(--mv-color-text)}.opacity-0{opacity:0}.shadow{--tw-shadow: var(--mv-shadow);--tw-shadow-colored: var(--mv-shadow);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[inset_0_-2px_0_0_rgba\(251\,191\,36\,0\.35\)\]{--tw-shadow: inset 0 -2px 0 0 rgba(251,191,36,.35);--tw-shadow-colored: inset 0 -2px 0 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow: var(--mv-shadow-md);--tw-shadow-colored: var(--mv-shadow-md);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: var(--mv-shadow-sm);--tw-shadow-colored: var(--mv-shadow-sm);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.ring{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-1{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-inset{--tw-ring-inset: inset}.ring-amber-400\/25{--tw-ring-color: rgb(251 191 36 / .25)}.ring-black\/5{--tw-ring-color: rgb(0 0 0 / .05)}.ring-offset-2{--tw-ring-offset-width: 2px}.ring-offset-header{--tw-ring-offset-color: var(--mv-color-header)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition-\[background-color\,box-shadow\]{transition-property:background-color,box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-150{transition-duration:.15s}.duration-200{transition-duration:.2s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.\[overflow-wrap\:anywhere\]{overflow-wrap:anywhere}:root{color-scheme:light;--mv-color-background: #e5e7eb;--mv-color-surface: #ffffff;--mv-color-elevated: #f8fafc;--mv-color-border: #e5e7eb;--mv-color-text: #374151;--mv-color-muted: #6b7280;--mv-color-primary: #475569;--mv-color-success: #16a34a;--mv-color-warning: #ea580c;--mv-color-danger: #dc2626;--mv-color-header: #1f2937;--mv-color-header-active: #374151;--mv-color-header-text: #f9fafb;--mv-color-pill: #cbd5e1;--mv-color-faint: #9ca3af;--mv-color-placeholder: #9ca3af;--mv-color-success-surface: #bbf7d0;--mv-color-success-outline: #86efac;--mv-color-warning-surface: #fed7aa;--mv-color-warning-outline: #fdba74;--mv-color-danger-surface: #fee2e2;--mv-color-danger-outline: #fca5a5;--mv-color-ring: rgb(71 85 105 / .45);--mv-shadow-sm: 0 1px 2px 0 rgb(15 23 42 / .06);--mv-shadow-md: 0 4px 6px -1px rgb(15 23 42 / .08), 0 2px 4px -2px rgb(15 23 42 / .06);--mv-shadow: 0 1px 3px 0 rgb(15 23 42 / .1), 0 1px 2px -1px rgb(15 23 42 / .08);--mv-shadow-soft: 0 10px 30px rgb(15 23 42 / .08)}body{margin:0;background:var(--mv-color-background);color:var(--mv-color-text);font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}a{color:inherit}.placeholder\:text-xs::-moz-placeholder{font-size:.75rem;line-height:1rem}.placeholder\:text-xs::placeholder{font-size:.75rem;line-height:1rem}.placeholder\:leading-snug::-moz-placeholder{line-height:1.375}.placeholder\:leading-snug::placeholder{line-height:1.375}.placeholder\:text-muted::-moz-placeholder{color:var(--mv-color-muted)}.placeholder\:text-muted::placeholder{color:var(--mv-color-muted)}.placeholder\:text-placeholder::-moz-placeholder{color:var(--mv-color-placeholder)}.placeholder\:text-placeholder::placeholder{color:var(--mv-color-placeholder)}.hover\:border-border:hover{border-color:var(--mv-color-border)}.hover\:border-primary:hover{border-color:var(--mv-color-primary)}.hover\:bg-background:hover{background-color:var(--mv-color-background)}.hover\:bg-elevated:hover{background-color:var(--mv-color-elevated)}.hover\:bg-header-active:hover{background-color:var(--mv-color-header-active)}.hover\:text-primary:hover{color:var(--mv-color-primary)}.hover\:text-text:hover{color:var(--mv-color-text)}.hover\:underline:hover{text-decoration-line:underline}.focus\:border-primary:focus{border-color:var(--mv-color-primary)}.focus-visible\:opacity-100:focus-visible{opacity:1}.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-header-text:focus-visible{--tw-ring-color: var(--mv-color-header-text)}.focus-visible\:ring-ring:focus-visible{--tw-ring-color: var(--mv-color-ring)}.focus-visible\:ring-offset-2:focus-visible{--tw-ring-offset-width: 2px}.focus-visible\:ring-offset-background:focus-visible{--tw-ring-offset-color: var(--mv-color-background)}.group:hover .group-hover\:opacity-100{opacity:1}@media(min-width:640px){.sm\:px-4{padding-left:1rem;padding-right:1rem}}@media(min-width:768px){.md\:col-span-2{grid-column:span 2 / span 2}.md\:flex{display:flex}.md\:w-56{width:14rem}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-\[minmax\(0\,1fr\)_auto\]{grid-template-columns:minmax(0,1fr) auto}.md\:flex-row{flex-direction:row}.md\:items-start{align-items:flex-start}.md\:items-center{align-items:center}.md\:justify-between{justify-content:space-between}.md\:justify-self-end{justify-self:end}.md\:text-right{text-align:right}}.\[\&_code\]\:rounded-md code{border-radius:.375rem}.\[\&_code\]\:border code{border-width:1px}.\[\&_code\]\:border-faint code{border-color:var(--mv-color-faint)}.\[\&_code\]\:bg-elevated code{background-color:var(--mv-color-elevated)}.\[\&_code\]\:px-1\.5 code{padding-left:.375rem;padding-right:.375rem}.\[\&_code\]\:py-0\.5 code{padding-top:.125rem;padding-bottom:.125rem}.\[\&_code\]\:font-mono code{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.\[\&_code\]\:text-\[0\.8125rem\] code{font-size:.8125rem}.\[\&_code\]\:font-medium code{font-weight:500}.\[\&_code\]\:text-text code{color:var(--mv-color-text)}.\[\&_pre\]\:my-3 pre{margin-top:.75rem;margin-bottom:.75rem}.\[\&_pre\]\:rounded-xl pre{border-radius:.75rem}.\[\&_pre\]\:border pre{border-width:1px}.\[\&_pre\]\:border-faint pre{border-color:var(--mv-color-faint)}.\[\&_pre\]\:bg-elevated pre{background-color:var(--mv-color-elevated)}.\[\&_pre\]\:p-4 pre{padding:1rem}.\[\&_pre\]\:shadow-sm pre{--tw-shadow: var(--mv-shadow-sm);--tw-shadow-colored: var(--mv-shadow-sm);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.\[\&_pre_code\]\:m-0 pre code{margin:0}.\[\&_pre_code\]\:block pre code{display:block}.\[\&_pre_code\]\:w-full pre code{width:100%}.\[\&_pre_code\]\:rounded-none pre code{border-radius:0}.\[\&_pre_code\]\:border-0 pre code{border-width:0px}.\[\&_pre_code\]\:bg-transparent pre code{background-color:transparent}.\[\&_pre_code\]\:p-0 pre code{padding:0}.\[\&_pre_code\]\:text-xs pre code{font-size:.75rem;line-height:1rem}.\[\&_pre_code\]\:font-normal pre code{font-weight:400}.\[\&_pre_code\]\:leading-relaxed pre code{line-height:1.625}.\[\&_pre_code\]\:shadow-none pre code{--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}