mosaic-headless 1.5.0 → 1.6.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/sites/_moksa.py CHANGED
@@ -323,6 +323,17 @@ STACK = [
323
323
 
324
324
  # the clause index, fixed to the left margin. One entry per section, and the entry
325
325
  # lights up while its section is on screen - see the named view timelines below.
326
+ # What the boot screen reports while it works. Real steps in this page's own
327
+ # construction rather than decoration: the faces it loads, the tokens it resolves,
328
+ # the breakpoints it compiles, the clauses it mounts.
329
+ BOOT_LOG = [
330
+ "LOADING TYPEFACES — IBM PLEX MONO / SPACE GROTESK / NOTO SANS TC",
331
+ "RESOLVING DESIGN TOKENS — 8 COLLECTION VARIABLES",
332
+ "COMPILING BREAKPOINTS — 1440 / 1079 / 767",
333
+ "MOUNTING CLAUSES §01–§07",
334
+ ]
335
+ RULER_TICKS = 13
336
+
326
337
  CLAUSES = [
327
338
  ("01", "SERVICES", "#services", "--mk-s1"),
328
339
  ("02", "PROCESS", "#process", "--mk-s2"),
@@ -346,6 +357,9 @@ REVEALS = [
346
357
  ("mk-work-0", 1), ("mk-work-1", 1), ("mk-work-2", 2), ("mk-work-3", 2),
347
358
  ("mk-work-4", 3), ("mk-work-5", 3), ("mk-work-6", 4), ("mk-work-7", 4),
348
359
  ("mk-work-8", 5),
360
+ ("mk-plate-num", 0), ("mk-plate-t", 1),
361
+ ("mk-spec2-head", 0), ("mk-spec2-r-0", 1), ("mk-spec2-r-1", 2),
362
+ ("mk-spec2-r-2", 3), ("mk-spec2-r-3", 4),
349
363
  ("mk-stack-head", 0), ("mk-stack-0", 1), ("mk-stack-1", 2), ("mk-stack-2", 3),
350
364
  ("mk-stack-3", 4), ("mk-stack-4", 5),
351
365
  ("mk-prod-head", 0), ("mk-prod-0", 1), ("mk-prod-1", 2),
@@ -376,10 +390,17 @@ def motion_css():
376
390
  for i, (_g, items) in enumerate(STACK)
377
391
  for j in range(len(items)))
378
392
  marks = ",".join("#mk-mark-%d" % i for i in range(4))
379
- # the boot list lights one clause at a time
393
+ # the boot sequence, phase by phase: the clauses report in, the log writes
394
+ # itself out a line at a time, and the ruler ticks up the left margin
380
395
  boot_stagger = "\n".join(
381
- " #mk-boot-c%d{animation-delay:%dms}" % (i, 260 + i * 120)
396
+ " #mk-boot-c%d{animation-delay:%dms}" % (i, 700 + i * 200)
382
397
  for i in range(len(CLAUSES)))
398
+ log_stagger = "\n".join(
399
+ " #mk-boot-l%d{animation-delay:%dms}" % (i, 550 + i * 380)
400
+ for i in range(len(BOOT_LOG)))
401
+ ruler_stagger = "\n".join(
402
+ " #mk-boot-t%d{animation-delay:%dms}" % (i, 120 + i * 26)
403
+ for i in range(RULER_TICKS))
383
404
  # a named view timeline per section, declared on the section and consumed by its
384
405
  # index entry - `timeline-scope` on #mk-doc is what lets the name cross between
385
406
  # two elements that are not ancestor and descendant
@@ -472,6 +493,7 @@ def motion_css():
472
493
  # the blinking caret under the headline: the one piece of ornament, and it
473
494
  # belongs to a page set in a terminal face
474
495
  "#mk-caret{width:13px;height:19px;background:rgb(255,90,54)}",
496
+ "#mk-plate-dash{width:34px;height:1px;background:rgb(191,68,40)}",
475
497
  "#mk-mast-rule,#mk-spec-rule{height:1px;background:" + RULE + ";"
476
498
  "transform:scaleX(0);transform-origin:0 50%}",
477
499
  digits + "{display:block;transform:translateY(105%)}",
@@ -559,23 +581,35 @@ def motion_css():
559
581
  "@keyframes mk-boot-scan{from{transform:translateY(0)}"
560
582
  "to{transform:translateY(100vh)}}",
561
583
  "@keyframes mk-boot-fade{from{opacity:0}to{opacity:1}}",
584
+ # a log line arriving: clipped from the left, like a terminal writing it
585
+ "@keyframes mk-boot-type{from{clip-path:inset(0 100% 0 0);opacity:.3}"
586
+ "to{clip-path:inset(0 0 0 0);opacity:1}}",
587
+ "@keyframes mk-boot-caret{0%,49%{opacity:1}50%,99%{opacity:0}}",
588
+ # the corner crosshairs draw themselves in
589
+ "@keyframes mk-boot-cross{from{opacity:0;transform:scale(.55)}"
590
+ "to{opacity:1;transform:scale(1)}}",
591
+ "@keyframes mk-boot-tick{from{opacity:0;transform:scaleX(.2)}"
592
+ "to{opacity:1;transform:scaleX(1)}}",
593
+ # the stamp lands hard, the way a stamp does
594
+ "@keyframes mk-boot-stamp{0%{opacity:0;transform:scale(1.35)}"
595
+ "55%{opacity:1;transform:scale(.97)}100%{opacity:1;transform:scale(1)}}",
562
596
 
563
597
  # ── motion, all of it opt-out-able ───────────────────────────────────
564
598
  "@media (prefers-reduced-motion:no-preference){",
565
599
  " #mk-boot{display:grid;position:fixed;inset:0;z-index:999;"
566
600
  "background:rgb(250,250,247);align-content:center;justify-items:center;"
567
- "row-gap:22px;overflow:hidden;"
568
- "animation:mk-boot-out .5s cubic-bezier(.7,0,.3,1) 1.55s forwards}",
601
+ "row-gap:20px;overflow:hidden;"
602
+ "animation:mk-boot-out .62s cubic-bezier(.7,0,.3,1) 2.95s forwards}",
569
603
  " #mk-boot-head,#mk-boot-foot{position:absolute;left:40px;right:40px;"
570
604
  "display:flex;justify-content:space-between;font-family:" + MONO + ";"
571
605
  "font-size:10px;letter-spacing:.2em;color:rgb(107,109,113);"
572
606
  "animation:mk-boot-fade .4s ease both}",
573
607
  " #mk-boot-head{top:34px}",
574
608
  " #mk-boot-foot{bottom:30px;animation-delay:.1s}",
575
- " #mk-boot-num{font-family:" + MONO + ";font-size:96px;font-weight:500;"
609
+ " #mk-boot-num{font-family:" + MONO + ";font-size:104px;font-weight:500;"
576
610
  "line-height:1;letter-spacing:-.04em;color:rgb(22,24,28);"
577
611
  "font-variant-numeric:tabular-nums;min-width:3ch;text-align:right;"
578
- "animation:mk-count 1.2s cubic-bezier(.3,0,0,1) .12s both}",
612
+ "animation:mk-count 2.05s linear .3s both}",
579
613
  ' #mk-boot-num::after{counter-reset:n var(--mk-n);content:counter(n)}',
580
614
  " #mk-boot-row{display:flex;align-items:flex-end;column-gap:8px;"
581
615
  "line-height:1}",
@@ -588,12 +622,17 @@ def motion_css():
588
622
  "background:rgba(22,24,28,.14);position:relative}",
589
623
  " #mk-boot-fill{position:absolute;inset:0;background:rgb(255,90,54);"
590
624
  "transform-origin:0 50%;"
591
- "animation:mk-boot-fill 1.2s cubic-bezier(.3,0,0,1) .12s both}",
625
+ "animation:mk-boot-fill 2.05s linear .3s both}",
626
+ # ticks along the rule, so the bar reads as a measure rather than a bar
627
+ ' #mk-boot-track::after{content:"";position:absolute;left:0;right:0;'
628
+ "top:-3px;height:3px;background:repeating-linear-gradient(90deg,"
629
+ "rgba(22,24,28,.22) 0 1px,transparent 1px 42px);"
630
+ "animation:mk-boot-fade .5s ease .15s both}",
592
631
  " #mk-boot-list{display:flex;column-gap:18px;row-gap:8px;"
593
632
  "flex-wrap:wrap;justify-content:center;font-family:" + MONO + ";"
594
633
  "font-size:10px;letter-spacing:.18em}",
595
634
  " #mk-boot-list>*{opacity:.14;"
596
- "animation:mk-boot-line .5s ease both}",
635
+ "animation:mk-boot-line .62s ease both}",
597
636
  boot_stagger,
598
637
  " #mk-boot::before{content:\"\";position:absolute;inset:0;"
599
638
  "background:"
@@ -604,22 +643,59 @@ def motion_css():
604
643
  "animation:mk-boot-fade .5s ease both}",
605
644
  " #mk-boot-scan{position:absolute;left:0;right:0;top:0;height:1px;"
606
645
  "background:linear-gradient(90deg,rgba(255,90,54,0),rgba(255,90,54,.55),"
607
- "rgba(255,90,54,0));animation:mk-boot-scan 1.6s linear .1s both}",
646
+ "rgba(255,90,54,0));"
647
+ "animation:mk-boot-scan 1.45s linear .15s 2 both}",
648
+
649
+ # corner crosshairs: the veil is a plate, and a plate has trim marks
650
+ " #mk-boot .mk-x,#mk-boot-x0,#mk-boot-x1,#mk-boot-x2,#mk-boot-x3{"
651
+ "position:absolute;width:14px;height:14px;"
652
+ "animation:mk-boot-cross .5s cubic-bezier(.16,1,.3,1) both}",
653
+ " #mk-boot-x0{top:64px;left:40px;border-left:1px solid " + RULE_INK
654
+ + ";border-top:1px solid " + RULE_INK + ";animation-delay:.08s}",
655
+ " #mk-boot-x1{top:64px;right:40px;border-right:1px solid " + RULE_INK
656
+ + ";border-top:1px solid " + RULE_INK + ";animation-delay:.16s}",
657
+ " #mk-boot-x2{bottom:56px;left:40px;border-left:1px solid " + RULE_INK
658
+ + ";border-bottom:1px solid " + RULE_INK + ";animation-delay:.24s}",
659
+ " #mk-boot-x3{bottom:56px;right:40px;border-right:1px solid " + RULE_INK
660
+ + ";border-bottom:1px solid " + RULE_INK + ";animation-delay:.32s}",
661
+
662
+ # a ruler down the left margin, because this is a measured object
663
+ " #mk-boot-ruler{position:absolute;left:40px;top:50%;"
664
+ "transform:translateY(-50%);display:grid;row-gap:9px}",
665
+ " #mk-boot-ruler>*{width:9px;height:1px;background:" + RULE_INK + ";"
666
+ "transform-origin:0 50%;animation:mk-boot-tick .3s ease both}",
667
+ ruler_stagger,
668
+ " @media (max-width:1023px){#mk-boot-ruler{display:none}}",
669
+
670
+ # the log: four lines, each written out left to right
671
+ " #mk-boot-log{display:grid;row-gap:7px;justify-items:start;"
672
+ "font-family:" + MONO + ";font-size:10px;letter-spacing:.16em;"
673
+ "color:rgb(107,109,113);min-height:64px}",
674
+ " #mk-boot-log>*{animation:mk-boot-type .42s steps(24,end) both}",
675
+ log_stagger,
676
+ " #mk-boot-cursor{width:7px;height:11px;background:rgb(255,90,54);"
677
+ "animation:mk-boot-caret .62s steps(1,end) .5s infinite}",
678
+
679
+ # the stamp that says the document is complete
680
+ " #mk-boot-ready{border:1px solid rgb(191,68,40);padding:5px 12px;"
681
+ "font-family:" + MONO + ";font-size:10px;letter-spacing:.24em;"
682
+ "color:rgb(191,68,40);opacity:0;"
683
+ "animation:mk-boot-stamp .42s cubic-bezier(.16,1,.3,1) 2.42s both}",
608
684
  " @media (max-width:767px){#mk-boot-num{font-size:62px}"
609
685
  "#mk-boot-head,#mk-boot-foot{left:18px;right:18px}}",
610
686
  " #mk-hl1-mask>*,#mk-hl2-mask>*{transform:translateY(112%);"
611
687
  "animation:mk-linein .95s cubic-bezier(.16,1,.3,1) forwards}",
612
- " #mk-hl1-mask>*{animation-delay:1.72s}",
613
- " #mk-hl2-mask>*{animation-delay:1.84s}",
688
+ " #mk-hl1-mask>*{animation-delay:3.16s}",
689
+ " #mk-hl2-mask>*{animation-delay:3.28s}",
614
690
  " #mk-mast-meta,#mk-mast-lede,#mk-mast-cta{opacity:0;"
615
691
  "animation:mk-softin .8s cubic-bezier(.16,1,.3,1) forwards}",
616
- " #mk-mast-meta{animation-delay:1.62s}",
617
- " #mk-mast-lede{animation-delay:2.10s}",
618
- " #mk-mast-cta{animation-delay:2.22s}",
692
+ " #mk-mast-meta{animation-delay:3.06s}",
693
+ " #mk-mast-lede{animation-delay:3.54s}",
694
+ " #mk-mast-cta{animation-delay:3.66s}",
619
695
  " #mk-caret{animation:mk-caret 1.15s steps(1,end) infinite;"
620
- "animation-delay:2.4s}",
696
+ "animation-delay:3.84s}",
621
697
  " #mk-mast-rule{animation:mk-drawx .9s cubic-bezier(.2,.7,.3,1) forwards;"
622
- "animation-delay:1.96s}",
698
+ "animation-delay:3.40s}",
623
699
  " #mk-spec-rule{animation:mk-drawx .9s cubic-bezier(.2,.7,.3,1) forwards;"
624
700
  "animation-delay:.9s}",
625
701
  " #mk-cue{opacity:0;animation:mk-softin .8s ease forwards;"
@@ -1261,6 +1337,102 @@ CONTACT = section("contact", [wrap("mk-contact-in", [
1261
1337
  ]),
1262
1338
  ])])
1263
1339
 
1340
+ # ── PLATE 01: a statement ─────────────────────────────────────────────────────
1341
+ # Every clause on this page has the same rhythm - a numbered head, then hairline
1342
+ # rows. That is correct for a specification and monotonous for a page. A document
1343
+ # also has PLATES: unnumbered, full-bleed, one idea at a scale nothing else gets.
1344
+ # This one changes the ground, the measure and the type size all at once, so the
1345
+ # reader feels a chapter break rather than another row.
1346
+ PLATE = section("plate", [wrap("mk-plate-in", [
1347
+ box("mk-plate-pad",
1348
+ {"paddingTop": "104px", "paddingBottom": "104px",
1349
+ "display": "grid", "gridCols": "auto 1fr", "columnGap": "56px",
1350
+ "alignItems": "start"},
1351
+ _t={"columnGap": "36px"},
1352
+ _m={"gridCols": "repeat(1, 1fr)", "rowGap": "22px",
1353
+ "paddingTop": "62px", "paddingBottom": "62px"},
1354
+ children=[
1355
+ # the plate number, set as a hollow numeral - the one place on the page
1356
+ # where type is used as a shape rather than as reading matter
1357
+ box("mk-plate-num", {},
1358
+ [T("p", "01", fontFamily=DISPLAY, fontSize="132px",
1359
+ fontWeight="600", lineHeight=".82", letterSpacing="-0.05em",
1360
+ color="rgba(0,0,0,0)",
1361
+ customStyles="-webkit-text-stroke:1px " + RULE_INK + ";",
1362
+ _t={"fontSize": "104px"}, _m={"fontSize": "68px"})]),
1363
+ box("mk-plate-t", {}, [
1364
+ mono("PLATE 01 — POSITION", size="10px", color="--mk-accent-ink",
1365
+ track="0.22em"),
1366
+ ml("h2", "技術是拿來解決問題的,\n不是拿來炫耀的。",
1367
+ color={"token": "--mk-ink"}, fontSize="46px", fontWeight="600",
1368
+ letterSpacing="0.01em", lineHeight="1.42", fontFamily=DISPLAY,
1369
+ marginTop="22px",
1370
+ _t={"fontSize": "38px"}, _m={"fontSize": "26px"}),
1371
+ T("p", "每一個決定都要能被說明:為什麼用這個工具、"
1372
+ "為什麼是這個結構、為什麼值這個價錢。說不清楚的,就不做。",
1373
+ color={"token": "--mk-muted"}, fontSize="15px", lineHeight="2",
1374
+ marginTop="26px", maxWidth="34em", _m={"fontSize": "13.5px"}),
1375
+ box("mk-plate-sig",
1376
+ {"marginTop": "34px", "display": "flex", "columnGap": "12px",
1377
+ "alignItems": "center"},
1378
+ [box("mk-plate-dash", {}, []),
1379
+ mono("MOKSA WEB — TAICHUNG", size="10px", color="--mk-faint",
1380
+ track="0.2em")]),
1381
+ ]),
1382
+ ]),
1383
+ ])], bg="--mk-panel")
1384
+
1385
+
1386
+ # ── the type specimen ─────────────────────────────────────────────────────────
1387
+ # A studio that sets type should be willing to show the type. This is the system
1388
+ # itself on display - the scale it uses, the faces it pairs, the numerals it relies
1389
+ # on - inverted onto the ink ground so it reads as a plate rather than a section.
1390
+ SPECIMEN_ROWS = [
1391
+ ("Aa", "72 / SPACE GROTESK 600", "72px", "54px", "40px", DISPLAY, "600"),
1392
+ ("網站開發", "46 / NOTO SANS TC 500", "46px", "38px", "27px", CJK, "500"),
1393
+ ("0123456789", "34 / IBM PLEX MONO 500", "34px", "27px", "20px", MONO, "500"),
1394
+ ("automation", "22 / SPACE GROTESK 500", "22px", "19px", "16px", DISPLAY,
1395
+ "500"),
1396
+ ]
1397
+
1398
+ SPECIMEN = section("specimen", [wrap("mk-spec2-in", [
1399
+ box("mk-spec2-pad", {"paddingTop": "88px", "paddingBottom": "88px"},
1400
+ _m={"paddingTop": "58px", "paddingBottom": "58px"},
1401
+ children=[
1402
+ box("mk-spec2-head",
1403
+ {"display": "flex", "justifyContent": "space-between",
1404
+ "columnGap": "20px", "rowGap": "8px",
1405
+ "customStyles": "flex-wrap:wrap;"},
1406
+ [mono("TYPE SPECIMEN", size="10px", color="--mk-accent",
1407
+ track="0.22em"),
1408
+ mono("THREE FACES / ONE SCALE", size="10px",
1409
+ color="rgb(140,142,150)", track="0.2em")]),
1410
+ box("mk-spec2-rows", {"marginTop": "40px"},
1411
+ _m={"marginTop": "26px"},
1412
+ children=[
1413
+ box("mk-spec2-r-%d" % i,
1414
+ {"display": "grid", "gridCols": "1fr auto",
1415
+ "columnGap": "28px", "alignItems": "baseline",
1416
+ "paddingTop": "20px", "paddingBottom": "20px",
1417
+ "customStyles":
1418
+ "border-top:1px solid " + RULE_DARK + ";"},
1419
+ _m={"gridCols": "1fr", "rowGap": "6px",
1420
+ "paddingTop": "14px", "paddingBottom": "14px"},
1421
+ children=[
1422
+ T("p", glyphs, color={"token": "--mk-paper"},
1423
+ fontSize=size, fontFamily=face, fontWeight=weight,
1424
+ lineHeight="1.1", letterSpacing="0.01em",
1425
+ _t={"fontSize": tsize}, _m={"fontSize": msize}),
1426
+ mono(label, size="10px", color="rgb(140,142,150)",
1427
+ track="0.16em"),
1428
+ ])
1429
+ for i, (glyphs, label, size, tsize, msize, face, weight)
1430
+ in enumerate(SPECIMEN_ROWS)
1431
+ ]),
1432
+ ]),
1433
+ ])], bg="--mk-ink")
1434
+
1435
+
1264
1436
  # ── the entrance sequence ─────────────────────────────────────────────────────
1265
1437
  # A boot screen, because the page is a specification document and this is what one
1266
1438
  # looks like while it is being read off a machine. It is CSS only: a counter that is
@@ -1272,6 +1444,11 @@ CONTACT = section("contact", [wrap("mk-contact-in", [
1272
1444
  # of the page's life, which is the only window in which any of this exists.
1273
1445
  BOOT = box("mk-boot", {}, [
1274
1446
  box("mk-boot-scan", {}, []),
1447
+ # trim marks on the plate itself, drawn corner by corner
1448
+ *[box("mk-boot-x%d" % i, {}, []) for i in range(4)],
1449
+ # a ruler up the left margin: the veil is a measured object, not a splash
1450
+ box("mk-boot-ruler", {}, [box("mk-boot-t%d" % i, {}, [])
1451
+ for i in range(RULER_TICKS)]),
1275
1452
  box("mk-boot-head", {}, [
1276
1453
  mono("MOKSA WEB — STUDIO PROFILE", size="10px", color="--mk-faint",
1277
1454
  track="0.2em"),
@@ -1282,6 +1459,13 @@ BOOT = box("mk-boot", {}, [
1282
1459
  box("mk-boot-pct", {}, [T("p", "%")]),
1283
1460
  ]),
1284
1461
  box("mk-boot-track", {}, [box("mk-boot-fill", {}, [])]),
1462
+ # the log writes itself out a line at a time, with a cursor still blinking
1463
+ box("mk-boot-log", {},
1464
+ [box("mk-boot-l%d" % i, {}, [mono(line, size="10px", color="--mk-faint",
1465
+ track="0.16em")])
1466
+ for i, line in enumerate(BOOT_LOG)]
1467
+ + [box("mk-boot-l%d" % len(BOOT_LOG), {},
1468
+ [box("mk-boot-cursor", {}, [])])]),
1285
1469
  box("mk-boot-list", {},
1286
1470
  # each clause gets its own box because the id is what the stagger
1287
1471
  # targets, and `mono()` puts everything it is given into the style
@@ -1289,6 +1473,7 @@ BOOT = box("mk-boot", {}, [
1289
1473
  [mono("§" + num + " " + name, size="10px", color="--mk-faint",
1290
1474
  track="0.18em")])
1291
1475
  for i, (num, name, _h, _t) in enumerate(CLAUSES)]),
1476
+ box("mk-boot-ready", {}, [T("p", "PROFILE READY")]),
1292
1477
  box("mk-boot-foot", {}, [
1293
1478
  mono("INITIALISING", size="10px", color="--mk-faint", track="0.2em"),
1294
1479
  mono("TAICHUNG, TW", size="10px", color="--mk-faint", track="0.2em"),
@@ -1324,8 +1509,10 @@ CUE = box("mk-cue", {}, [
1324
1509
  HOME_TREE = {"type": "div", "data": {"attrID": "mk-home"},
1325
1510
  "children": [BOOT, box("mk-doc", {}, [
1326
1511
  MARKS, INDEX, CUE,
1327
- MASTHEAD, TICKER_BAND, SERVICE_SEC, PROCESS_SEC, WORK_SEC,
1328
- STACK_SEC, PRODUCT_SEC, VOICE_SEC, CONTACT,
1512
+ # paper, panel, paper, ink, paper, ink, paper - the page
1513
+ # changes ground five times so it reads as chapters
1514
+ MASTHEAD, TICKER_BAND, PLATE, SERVICE_SEC, PROCESS_SEC,
1515
+ WORK_SEC, SPECIMEN, STACK_SEC, PRODUCT_SEC, VOICE_SEC, CONTACT,
1329
1516
  ])]}
1330
1517
 
1331
1518
  SITE = {