@conduction/docusaurus-preset 3.34.0 → 3.35.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.
Files changed (24) hide show
  1. package/ANIMATION_ROADMAP.md +129 -0
  2. package/MISSING_COMPONENTS.md +11 -2
  3. package/package.json +3 -2
  4. package/src/components/AppMock/AppMock.module.css +1263 -0
  5. package/src/components/AppMock/__tests__/AppMock.render.test.js +148 -0
  6. package/src/components/AppMock/variants/DeciDeskMock.jsx +46 -5
  7. package/src/components/AppMock/variants/DocuDeskMock.jsx +39 -9
  8. package/src/components/AppMock/variants/DoriathMock.jsx +28 -13
  9. package/src/components/AppMock/variants/HermiqMock.jsx +35 -15
  10. package/src/components/AppMock/variants/HrmqMock.jsx +46 -28
  11. package/src/components/AppMock/variants/LarpingAppMock.jsx +13 -3
  12. package/src/components/AppMock/variants/OpenBuildMock.jsx +20 -5
  13. package/src/components/AppMock/variants/OpenCatalogiMock.jsx +23 -4
  14. package/src/components/AppMock/variants/OpenConnectorMock.jsx +25 -3
  15. package/src/components/AppMock/variants/OpenRegisterMock.jsx +13 -2
  16. package/src/components/AppMock/variants/ProcestMock.jsx +34 -7
  17. package/src/components/AppMock/variants/ShillinqMock.jsx +33 -17
  18. package/src/components/AppMock/variants/SoftwareCatalogMock.jsx +15 -5
  19. package/src/components/AppMock/variants/ZaakAfhandelAppMock.jsx +19 -4
  20. package/src/components/SidebarMock/SidebarMock.jsx +29 -2
  21. package/src/components/SidebarMock/__tests__/SidebarMock.render.test.js +115 -0
  22. package/src/components/WidgetMock/WidgetMock.jsx +35 -14
  23. package/src/components/WidgetMock/__tests__/WidgetMock.render.test.js +125 -0
  24. package/src/components/WidgetMock/variants/DocuDeskAnonymise.jsx +6 -1
@@ -1062,6 +1062,1087 @@
1062
1062
  97%, 100% { transform: scaleX(1); }
1063
1063
  }
1064
1064
 
1065
+ /* ======================================================================
1066
+ Wave 2 — storytelling variant animations
1067
+ ====================================================================== */
1068
+
1069
+ /* ---- DocuDesk — the anonymiser blacks out the marked (PII) words
1070
+ one by one across the open document list. Base = redacted end
1071
+ state (cobalt-900 blocks); the amDdMark keyframes replay the
1072
+ text-look before-state and the black-out, one word per slot.
1073
+ The drop-zone shares the `.zoneLive` treatment below. ---- */
1074
+
1075
+ .am .docudesk { --am-dur: 9s; }
1076
+ /* The drop-zone widget absorbs the column's remaining height so the
1077
+ frame has no dead white band under the two widgets. */
1078
+ .am .docudesk .w-upload { flex: 1; }
1079
+ .am .docudesk .words {
1080
+ flex: 1;
1081
+ display: flex;
1082
+ align-items: center;
1083
+ gap: 3px;
1084
+ min-width: 0;
1085
+ }
1086
+ .am .docudesk .word {
1087
+ height: 3px;
1088
+ background: var(--c-cobalt-300);
1089
+ border-radius: 1px;
1090
+ flex-shrink: 0;
1091
+ }
1092
+ .am .docudesk .word.mark { height: 5px; background: var(--c-cobalt-900); }
1093
+ .am .docudesk .word.mark-1 { animation: amDdMark1 var(--am-dur) linear infinite both; }
1094
+ .am .docudesk .word.mark-2 { animation: amDdMark2 var(--am-dur) linear infinite both; }
1095
+ .am .docudesk .word.mark-3 { animation: amDdMark3 var(--am-dur) linear infinite both; }
1096
+ .am .docudesk .word.mark-4 { animation: amDdMark4 var(--am-dur) linear infinite both; }
1097
+ .am .docudesk .word.mark-5 { animation: amDdMark5 var(--am-dur) linear infinite both; }
1098
+
1099
+ @keyframes amDdMark1 {
1100
+ 0%, 12% { background: var(--c-cobalt-300); transform: scaleY(0.6); }
1101
+ 15%, 93% { background: var(--c-cobalt-900); transform: scaleY(1); }
1102
+ 98%, 100% { background: var(--c-cobalt-300); transform: scaleY(0.6); }
1103
+ }
1104
+ @keyframes amDdMark2 {
1105
+ 0%, 24% { background: var(--c-cobalt-300); transform: scaleY(0.6); }
1106
+ 27%, 93% { background: var(--c-cobalt-900); transform: scaleY(1); }
1107
+ 98%, 100% { background: var(--c-cobalt-300); transform: scaleY(0.6); }
1108
+ }
1109
+ @keyframes amDdMark3 {
1110
+ 0%, 36% { background: var(--c-cobalt-300); transform: scaleY(0.6); }
1111
+ 39%, 93% { background: var(--c-cobalt-900); transform: scaleY(1); }
1112
+ 98%, 100% { background: var(--c-cobalt-300); transform: scaleY(0.6); }
1113
+ }
1114
+ @keyframes amDdMark4 {
1115
+ 0%, 48% { background: var(--c-cobalt-300); transform: scaleY(0.6); }
1116
+ 51%, 93% { background: var(--c-cobalt-900); transform: scaleY(1); }
1117
+ 98%, 100% { background: var(--c-cobalt-300); transform: scaleY(0.6); }
1118
+ }
1119
+ @keyframes amDdMark5 {
1120
+ 0%, 60% { background: var(--c-cobalt-300); transform: scaleY(0.6); }
1121
+ 63%, 93% { background: var(--c-cobalt-900); transform: scaleY(1); }
1122
+ 98%, 100% { background: var(--c-cobalt-300); transform: scaleY(0.6); }
1123
+ }
1124
+
1125
+ /* ---- Shillinq — a bank statement line slides down onto invoice
1126
+ row 3, both tick mint, the totals line and the first KPI grow.
1127
+ Base = reconciled end state (row-3 tick mint, bank line gone). ---- */
1128
+
1129
+ .am .shillinq { --am-dur: 8s; }
1130
+ .am .shillinq .kpi .ico.terra { background: var(--c-terracotta-500); }
1131
+ .am .shillinq .kpi .ico.terraSoft { background: var(--c-terracotta-300); }
1132
+ .am .shillinq .ledger { flex: 1; position: relative; }
1133
+ .am .shillinq .inv .doc {
1134
+ width: 11px; height: 13px;
1135
+ clip-path: var(--hex-pointy-top);
1136
+ background: var(--c-terracotta-300);
1137
+ flex-shrink: 0;
1138
+ }
1139
+ .am .shillinq .inv .net { height: 4px; background: var(--c-cobalt-700); border-radius: 1px; flex-shrink: 0; }
1140
+ .am .shillinq .inv .vat { height: 4px; background: var(--c-cobalt-300); border-radius: 1px; flex-shrink: 0; }
1141
+ .am .shillinq .inv .tick {
1142
+ width: 9px; height: 10px;
1143
+ clip-path: var(--hex-pointy-top);
1144
+ background: var(--c-mint-500);
1145
+ flex-shrink: 0;
1146
+ }
1147
+ .am .shillinq .inv .tick.open { background: var(--c-cobalt-200); }
1148
+ .am .shillinq .totals {
1149
+ display: flex;
1150
+ justify-content: flex-end;
1151
+ gap: 6px;
1152
+ padding-top: 4px;
1153
+ border-top: 1px solid var(--c-cobalt-100);
1154
+ }
1155
+ .am .shillinq .totNet { width: 32px; height: 6px; background: var(--c-cobalt-900); border-radius: 1px; transform-origin: right center; }
1156
+ .am .shillinq .totVat { width: 20px; height: 6px; background: var(--c-cobalt-400); border-radius: 1px; }
1157
+
1158
+ /* The travelling bank line. Hidden at rest and in static frames. */
1159
+ .am .shillinq .bankLine {
1160
+ position: absolute;
1161
+ top: 24px;
1162
+ right: 12px;
1163
+ width: 45%;
1164
+ display: flex;
1165
+ align-items: center;
1166
+ gap: 4px;
1167
+ padding: 3px 4px;
1168
+ background: var(--c-cobalt-50);
1169
+ border: 1px solid var(--c-cobalt-200);
1170
+ border-radius: 2px;
1171
+ opacity: 0;
1172
+ pointer-events: none;
1173
+ animation: amShqBank var(--am-dur) ease-in-out infinite both;
1174
+ }
1175
+ .am .shillinq .bankLine .bIco { width: 8px; height: 9px; clip-path: var(--hex-pointy-top); background: var(--c-forest-500); flex-shrink: 0; }
1176
+ .am .shillinq .bankLine .bBar { flex: 1; height: 3px; background: var(--c-cobalt-400); border-radius: 1px; }
1177
+ .am .shillinq .bankLine .bAmt { width: 18px; height: 4px; background: var(--c-cobalt-700); border-radius: 1px; flex-shrink: 0; }
1178
+
1179
+ @keyframes amShqBank {
1180
+ 0%, 6% { opacity: 0; transform: translateY(-8px); }
1181
+ 12%, 22% { opacity: 1; transform: translateY(0); }
1182
+ 36% { opacity: 1; transform: translateY(52px); }
1183
+ 42%, 100% { opacity: 0; transform: translateY(52px); }
1184
+ }
1185
+
1186
+ .am .shillinq .inv.reconciling .tick { animation: amShqTick var(--am-dur) linear infinite both; }
1187
+ @keyframes amShqTick {
1188
+ 0%, 38% { background: var(--c-cobalt-200); transform: scale(1); }
1189
+ 42% { background: var(--c-mint-500); transform: scale(1.35); }
1190
+ 46%, 93% { background: var(--c-mint-500); transform: scale(1); }
1191
+ 98%, 100% { background: var(--c-cobalt-200); transform: scale(1); }
1192
+ }
1193
+
1194
+ .am .shillinq .totNet { animation: amShqTotal var(--am-dur) ease-in-out infinite; }
1195
+ @keyframes amShqTotal {
1196
+ 0%, 44% { transform: scaleX(1); }
1197
+ 52%, 90% { transform: scaleX(1.18); }
1198
+ 97%, 100% { transform: scaleX(1); }
1199
+ }
1200
+
1201
+ /* ---- Doriath — the key turns, the mask dots unmask, the value
1202
+ wipes in, the mint countdown hairline runs out, and the entry
1203
+ auto-relocks. Base = revealed state (what static frames show). ---- */
1204
+
1205
+ .am .doriath { --am-dur: 10s; }
1206
+ .am .doriath .keyChip {
1207
+ width: 10px; height: 11px;
1208
+ clip-path: var(--hex-pointy-top);
1209
+ background: var(--c-lavender-500);
1210
+ flex-shrink: 0;
1211
+ }
1212
+ .am .doriath .maskDots { display: flex; gap: 2px; flex-shrink: 0; }
1213
+ .am .doriath .dot { width: 3px; height: 3px; border-radius: 50%; background: var(--c-cobalt-400); flex-shrink: 0; }
1214
+ .am .doriath .vaultCard { background: var(--c-cobalt-900); border-color: var(--c-cobalt-900); }
1215
+ .am .doriath .vHead { display: flex; align-items: center; gap: 5px; }
1216
+ .am .doriath .keyHex {
1217
+ width: 12px; height: 14px;
1218
+ clip-path: var(--hex-pointy-top);
1219
+ background: var(--c-lavender-300);
1220
+ flex-shrink: 0;
1221
+ animation: amDorKey var(--am-dur) ease-in-out infinite;
1222
+ }
1223
+ .am .doriath .vTitle { height: 6px; width: 45%; background: var(--c-lavender-300); border-radius: 1px; }
1224
+ .am .doriath .vMeta { height: 3px; width: 60%; background: rgba(255, 255, 255, 0.25); border-radius: 1px; }
1225
+ .am .doriath .vMetaShort { height: 3px; width: 50%; background: rgba(255, 255, 255, 0.25); border-radius: 1px; }
1226
+ .am .doriath .vSecret { position: relative; height: 10px; }
1227
+ .am .doriath .vMask {
1228
+ position: absolute;
1229
+ inset: 0;
1230
+ display: flex;
1231
+ align-items: center;
1232
+ gap: 2px;
1233
+ opacity: 0;
1234
+ animation: amDorMask var(--am-dur) linear infinite both;
1235
+ }
1236
+ .am .doriath .vMask .dot { background: rgba(255, 255, 255, 0.45); }
1237
+ .am .doriath .vValue {
1238
+ position: absolute;
1239
+ inset: 0 15% 0 0;
1240
+ background: rgba(255, 255, 255, 0.9);
1241
+ border-radius: 2px;
1242
+ transform-origin: left center;
1243
+ animation: amDorValue var(--am-dur) linear infinite both;
1244
+ }
1245
+ .am .doriath .vCountdown {
1246
+ height: 2px;
1247
+ background: var(--c-mint-500);
1248
+ border-radius: 1px;
1249
+ transform-origin: left center;
1250
+ animation: amDorCount var(--am-dur) linear infinite both;
1251
+ }
1252
+
1253
+ @keyframes amDorKey {
1254
+ 0% { transform: rotate(-35deg); }
1255
+ 10%, 82% { transform: rotate(0deg); }
1256
+ 90%, 100% { transform: rotate(-35deg); }
1257
+ }
1258
+ @keyframes amDorMask {
1259
+ 0%, 14% { opacity: 1; }
1260
+ 20%, 82% { opacity: 0; }
1261
+ 88%, 100% { opacity: 1; }
1262
+ }
1263
+ @keyframes amDorValue {
1264
+ 0%, 16% { opacity: 0; transform: scaleX(0); }
1265
+ 26%, 80% { opacity: 1; transform: scaleX(1); }
1266
+ 86%, 100% { opacity: 0; transform: scaleX(1); }
1267
+ }
1268
+ @keyframes amDorCount {
1269
+ 0%, 24% { opacity: 0; transform: scaleX(1); }
1270
+ 27% { opacity: 1; transform: scaleX(1); }
1271
+ 76% { opacity: 1; transform: scaleX(0.02); }
1272
+ 80%, 100% { opacity: 0; transform: scaleX(0.02); }
1273
+ }
1274
+
1275
+ /* ---- OpenCatalogi — a query types into the federated search bar,
1276
+ the grid dims, the three matches snap back and their pills tick.
1277
+ Base = filtered end state (non-matches dimmed, query present). ---- */
1278
+
1279
+ .am .opencatalogi { --am-dur: 8s; }
1280
+ .am .opencatalogi .col > .head {
1281
+ display: flex;
1282
+ align-items: center;
1283
+ justify-content: space-between;
1284
+ gap: 6px;
1285
+ }
1286
+ .am .opencatalogi .search {
1287
+ flex: 1;
1288
+ max-width: 38%;
1289
+ height: 14px;
1290
+ display: flex;
1291
+ align-items: center;
1292
+ gap: 3px;
1293
+ padding: 0 5px;
1294
+ background: white;
1295
+ border: 1px solid var(--c-cobalt-200);
1296
+ border-radius: 999px;
1297
+ animation: amOcFocus var(--am-dur) linear infinite;
1298
+ }
1299
+ .am .opencatalogi .search .sIco { width: 6px; height: 6px; border-radius: 50%; border: 1px solid var(--c-cobalt-400); flex-shrink: 0; }
1300
+ .am .opencatalogi .search .q {
1301
+ height: 3px;
1302
+ width: 55%;
1303
+ background: var(--c-cobalt-700);
1304
+ border-radius: 1px;
1305
+ transform-origin: left center;
1306
+ animation: amOcQuery var(--am-dur) linear infinite both;
1307
+ }
1308
+ .am .opencatalogi .card.dim { opacity: 0.38; animation: amOcDim var(--am-dur) linear infinite both; }
1309
+ .am .opencatalogi .card.match { animation: amOcMatch var(--am-dur) ease-in-out infinite; }
1310
+ .am .opencatalogi .card.match .statusPill .h { animation: amOcPill var(--am-dur) ease-in-out infinite; }
1311
+
1312
+ @keyframes amOcFocus {
1313
+ 0%, 2% { border-color: var(--c-cobalt-200); box-shadow: 0 0 0 0 rgba(31, 68, 156, 0); }
1314
+ 5%, 20% { border-color: var(--c-blue-cobalt); box-shadow: 0 0 0 2px var(--c-cobalt-100); }
1315
+ 24%, 100% { border-color: var(--c-cobalt-200); box-shadow: 0 0 0 0 rgba(31, 68, 156, 0); }
1316
+ }
1317
+ @keyframes amOcQuery {
1318
+ 0%, 4% { transform: scaleX(0); opacity: 1; }
1319
+ 18%, 93% { transform: scaleX(1); opacity: 1; }
1320
+ 98% { transform: scaleX(1); opacity: 0; }
1321
+ 100% { transform: scaleX(0); opacity: 0; }
1322
+ }
1323
+ @keyframes amOcDim {
1324
+ 0%, 20% { opacity: 1; }
1325
+ 30%, 90% { opacity: 0.38; }
1326
+ 97%, 100% { opacity: 1; }
1327
+ }
1328
+ @keyframes amOcMatch {
1329
+ 0%, 26% { transform: scale(1); }
1330
+ 32% { transform: scale(1.04); }
1331
+ 38%, 100% { transform: scale(1); }
1332
+ }
1333
+ @keyframes amOcPill {
1334
+ 0%, 32% { transform: scale(1); }
1335
+ 38% { transform: scale(1.5); }
1336
+ 44%, 100% { transform: scale(1); }
1337
+ }
1338
+
1339
+ /* ---- OpenConnector — a record dot travels the pipeline: lavender
1340
+ leg source → connector, forest leg connector → target (the mapping
1341
+ made visible), then the new run row inserts and ticks mint.
1342
+ Base = completed end state (run row present, tick mint). ---- */
1343
+
1344
+ .am .openconnector { --am-dur: 7s; }
1345
+ .am .openconnector .stage .arrow { overflow: visible; }
1346
+ .am .openconnector .travelDotA,
1347
+ .am .openconnector .travelDotB {
1348
+ position: absolute;
1349
+ top: 50%;
1350
+ left: 0;
1351
+ width: 6px; height: 6px;
1352
+ margin-top: -3px;
1353
+ border-radius: 50%;
1354
+ opacity: 0;
1355
+ pointer-events: none;
1356
+ }
1357
+ .am .openconnector .travelDotA { background: var(--c-lavender-500); animation: amOxDotA var(--am-dur) linear infinite both; }
1358
+ .am .openconnector .travelDotB { background: var(--c-forest-500); animation: amOxDotB var(--am-dur) linear infinite both; }
1359
+ .am .openconnector .stage .conn { animation: amOxConn var(--am-dur) ease-in-out infinite; }
1360
+
1361
+ @keyframes amOxDotA {
1362
+ 0%, 5% { left: 0%; opacity: 0; }
1363
+ 8% { left: 4%; opacity: 1; }
1364
+ 24% { left: 92%; opacity: 1; }
1365
+ 27%, 100% { left: 100%; opacity: 0; }
1366
+ }
1367
+ @keyframes amOxDotB {
1368
+ 0%, 30% { left: 0%; opacity: 0; }
1369
+ 33% { left: 6%; opacity: 1; }
1370
+ 47% { left: 92%; opacity: 1; }
1371
+ 50%, 100% { left: 100%; opacity: 0; }
1372
+ }
1373
+ @keyframes amOxConn {
1374
+ 0%, 24% { transform: scale(1); }
1375
+ 28% { transform: scale(1.05); }
1376
+ 32%, 100% { transform: scale(1); }
1377
+ }
1378
+
1379
+ .am .openconnector .newRun { animation: amOxRun var(--am-dur) ease-out infinite both; }
1380
+ @keyframes amOxRun {
1381
+ 0%, 52% { opacity: 0; transform: translateY(-5px); }
1382
+ 58%, 93% { opacity: 1; transform: none; }
1383
+ 98%, 100% { opacity: 0; transform: none; }
1384
+ }
1385
+ .am .openconnector .newRun .runTick {
1386
+ width: 10px; height: 11px;
1387
+ clip-path: var(--hex-pointy-top);
1388
+ background: var(--c-mint-500);
1389
+ flex-shrink: 0;
1390
+ animation: amOxTick var(--am-dur) ease-in-out infinite both;
1391
+ }
1392
+ @keyframes amOxTick {
1393
+ 0%, 58% { opacity: 0; transform: scale(0.5); }
1394
+ 63% { opacity: 1; transform: scale(1.3); }
1395
+ 67%, 93% { opacity: 1; transform: scale(1); }
1396
+ 98%, 100% { opacity: 0; transform: scale(1); }
1397
+ }
1398
+
1399
+ /* ---- Procest — the case advances one stage. Ghost hexes overlaid
1400
+ on steps 2+3 replay the before-state (step 2 orange-active, step 3
1401
+ to-do) and fade to reveal the advanced base; the advanced case's
1402
+ row re-sorts to the top of the list. Base = advanced end state. ---- */
1403
+
1404
+ .am .procest { --am-dur: 7s; }
1405
+ .am .procest .timeline .step .ghost {
1406
+ position: absolute;
1407
+ top: 0;
1408
+ left: 50%;
1409
+ margin-left: -9px;
1410
+ width: 18px; height: 21px;
1411
+ clip-path: var(--hex-pointy-top);
1412
+ opacity: 0;
1413
+ pointer-events: none;
1414
+ animation: amPcGhost var(--am-dur) linear infinite both;
1415
+ }
1416
+ .am .procest .timeline .step .ghost.ghostNow { background: var(--c-orange-knvb); }
1417
+ .am .procest .timeline .step .ghost.ghostTodo { background: var(--c-cobalt-100); }
1418
+ @keyframes amPcGhost {
1419
+ 0%, 30% { opacity: 1; }
1420
+ 40%, 92% { opacity: 0; }
1421
+ 97%, 100% { opacity: 1; }
1422
+ }
1423
+ .am .procest .stack .sortUp { animation: amPcSortUp var(--am-dur) ease-in-out infinite both; }
1424
+ .am .procest .stack .sortDown { animation: amPcSortDown var(--am-dur) ease-in-out infinite both; }
1425
+ @keyframes amPcSortUp {
1426
+ 0% { opacity: 0; transform: translateY(28px); }
1427
+ 4%, 48% { opacity: 1; transform: translateY(28px); }
1428
+ 60%, 92% { opacity: 1; transform: none; }
1429
+ 97% { opacity: 0; transform: none; }
1430
+ 100% { opacity: 0; transform: translateY(28px); }
1431
+ }
1432
+ @keyframes amPcSortDown {
1433
+ 0% { opacity: 0; transform: translateY(-28px); }
1434
+ 4%, 48% { opacity: 1; transform: translateY(-28px); }
1435
+ 60%, 92% { opacity: 1; transform: none; }
1436
+ 97% { opacity: 0; transform: none; }
1437
+ 100% { opacity: 0; transform: translateY(-28px); }
1438
+ }
1439
+
1440
+ /* ---- OpenRegister — a new object row lands in the "Objects by
1441
+ Register" table, the first KPI widens, the right-rail statistics
1442
+ repaint in a stagger. Base = landed end state. ---- */
1443
+
1444
+ .am .openregister { --am-dur: 7s; }
1445
+ .am .openregister .newObj { animation: amOrLand var(--am-dur) ease-out infinite both; }
1446
+ @keyframes amOrLand {
1447
+ 0%, 44% { opacity: 0; transform: translateY(-5px); }
1448
+ 51%, 93% { opacity: 1; transform: none; }
1449
+ 98%, 100% { opacity: 0; transform: none; }
1450
+ }
1451
+ .am .openregister .detail > .row { animation: amOrRail var(--am-dur) linear infinite; }
1452
+ .am .openregister .detail > .row:nth-child(2) { animation-delay: calc(var(--am-dur) * 0.015); }
1453
+ .am .openregister .detail > .row:nth-child(3) { animation-delay: calc(var(--am-dur) * 0.03); }
1454
+ .am .openregister .detail > .row:nth-child(4) { animation-delay: calc(var(--am-dur) * 0.045); }
1455
+ .am .openregister .detail > .row:nth-child(6) { animation-delay: calc(var(--am-dur) * 0.06); }
1456
+ .am .openregister .detail > .row:nth-child(7) { animation-delay: calc(var(--am-dur) * 0.075); }
1457
+ .am .openregister .detail > .row:nth-child(8) { animation-delay: calc(var(--am-dur) * 0.09); }
1458
+ .am .openregister .detail > .row:nth-child(9) { animation-delay: calc(var(--am-dur) * 0.105); }
1459
+ .am .openregister .detail > .row:nth-child(10) { animation-delay: calc(var(--am-dur) * 0.12); }
1460
+ .am .openregister .detail > .row:nth-child(11) { animation-delay: calc(var(--am-dur) * 0.135); }
1461
+ .am .openregister .detail > .row:nth-child(12) { animation-delay: calc(var(--am-dur) * 0.15); }
1462
+ @keyframes amOrRail {
1463
+ 0%, 56% { opacity: 1; }
1464
+ 60% { opacity: 0.25; }
1465
+ 66%, 100% { opacity: 1; }
1466
+ }
1467
+
1468
+ /* Shared KPI-widen pulse — the .kpiGrow cell's number stretches as a
1469
+ count absorbs the new arrival (OpenRegister, OpenBuild, Shillinq). */
1470
+ .am .kpiGrow .num {
1471
+ transform-origin: left center;
1472
+ animation: amKpiGrow var(--am-dur) ease-in-out infinite;
1473
+ }
1474
+ @keyframes amKpiGrow {
1475
+ 0%, 50% { transform: scaleX(1); }
1476
+ 58%, 88% { transform: scaleX(1.25); }
1477
+ 96%, 100% { transform: scaleX(1); }
1478
+ }
1479
+
1480
+ /* ======================================================================
1481
+ Wave 4 — content reworks, animated
1482
+ ====================================================================== */
1483
+
1484
+ /* ---- DeciDesk — the vote tally fills, the "for" bar crosses the
1485
+ quorum line (which ticks mint), and the decision pill flips
1486
+ pending → adopted. Base = adopted end state. ---- */
1487
+
1488
+ .am .decidesk { --am-dur: 8s; }
1489
+ .am .decidesk .tallyRow { display: flex; align-items: center; gap: 6px; }
1490
+ .am .decidesk .tallyRow .tLabel { width: 22px; height: 3px; background: var(--c-cobalt-400); border-radius: 1px; flex-shrink: 0; }
1491
+ .am .decidesk .tallyRow .track {
1492
+ flex: 1;
1493
+ height: 6px;
1494
+ background: var(--c-cobalt-100);
1495
+ border-radius: 2px;
1496
+ position: relative;
1497
+ }
1498
+ .am .decidesk .tallyRow .fill {
1499
+ height: 6px;
1500
+ border-radius: 2px;
1501
+ transform-origin: left center;
1502
+ animation: amDkFill var(--am-dur) cubic-bezier(0.2, 0.7, 0.3, 1) infinite both;
1503
+ }
1504
+ .am .decidesk .tallyRow.for .fill { background: var(--c-mint-500); }
1505
+ .am .decidesk .tallyRow.against .fill { background: var(--c-cobalt-400); animation-delay: calc(var(--am-dur) * 0.04); }
1506
+ .am .decidesk .tallyRow.abstain .fill { background: var(--c-cobalt-200); animation-delay: calc(var(--am-dur) * 0.08); }
1507
+ @keyframes amDkFill {
1508
+ 0%, 8% { transform: scaleX(0); opacity: 1; }
1509
+ 30%, 93% { transform: scaleX(1); opacity: 1; }
1510
+ 98% { transform: scaleX(1); opacity: 0; }
1511
+ 100% { transform: scaleX(0); opacity: 0; }
1512
+ }
1513
+ .am .decidesk .tallyRow .quorum {
1514
+ position: absolute;
1515
+ left: 55%;
1516
+ top: -2px;
1517
+ width: 2px;
1518
+ height: 10px;
1519
+ border-radius: 1px;
1520
+ background: var(--c-mint-500);
1521
+ animation: amDkQuorum var(--am-dur) linear infinite both;
1522
+ }
1523
+ @keyframes amDkQuorum {
1524
+ 0%, 22% { background: var(--c-cobalt-400); transform: scaleY(1); }
1525
+ 26% { background: var(--c-mint-500); transform: scaleY(1.4); }
1526
+ 30%, 93% { background: var(--c-mint-500); transform: scaleY(1); }
1527
+ 98%, 100% { background: var(--c-cobalt-400); transform: scaleY(1); }
1528
+ }
1529
+ .am .decidesk .decisionRow .dIco {
1530
+ width: 11px; height: 13px;
1531
+ clip-path: var(--hex-pointy-top);
1532
+ background: var(--c-lavender-300);
1533
+ flex-shrink: 0;
1534
+ }
1535
+ /* Pending → adopted flip. The pill rides the shared beta (coral +
1536
+ orange) styling transiently as the pending phase, landing mint. */
1537
+ .am .decidesk .adoptFlip { animation: amDkPill var(--am-dur) linear infinite both; }
1538
+ .am .decidesk .adoptFlip .h { animation: amDkPillH var(--am-dur) linear infinite both; }
1539
+ .am .decidesk .adoptFlip .t { animation: amDkPillT var(--am-dur) linear infinite both; }
1540
+ @keyframes amDkPill {
1541
+ 0% { background: var(--c-coral-300); opacity: 0; }
1542
+ 6%, 38% { background: var(--c-coral-300); opacity: 1; }
1543
+ 44%, 92% { background: var(--c-mint-300); opacity: 1; }
1544
+ 98% { background: var(--c-mint-300); opacity: 0; }
1545
+ 100% { background: var(--c-coral-300); opacity: 0; }
1546
+ }
1547
+ @keyframes amDkPillH {
1548
+ 0%, 38% { background: var(--c-orange-knvb); transform: scale(1); }
1549
+ 44% { background: var(--c-mint-500); transform: scale(1.4); }
1550
+ 50%, 100% { background: var(--c-mint-500); transform: scale(1); }
1551
+ }
1552
+ @keyframes amDkPillT {
1553
+ 0%, 38% { background: var(--c-coral-500); }
1554
+ 44%, 100% { background: var(--c-mint-500); }
1555
+ }
1556
+
1557
+ /* ---- HRMQ — the week's hour bars fill, the sheet is submitted, the
1558
+ approval pip ticks mint, and the payroll counter widens.
1559
+ Base = approved end state. ---- */
1560
+
1561
+ .am .hrmq { --am-dur: 8s; }
1562
+ .am .hrmq .week {
1563
+ flex-shrink: 0;
1564
+ height: 72px;
1565
+ display: flex;
1566
+ align-items: stretch;
1567
+ gap: 6px;
1568
+ padding: 2px 4px 0;
1569
+ }
1570
+ .am .hrmq .dayCol {
1571
+ flex: 1;
1572
+ display: flex;
1573
+ flex-direction: column;
1574
+ align-items: center;
1575
+ justify-content: flex-end;
1576
+ gap: 3px;
1577
+ }
1578
+ .am .hrmq .dayBar {
1579
+ width: 70%;
1580
+ background: var(--c-mint-300);
1581
+ border-radius: 2px 2px 0 0;
1582
+ transform-origin: bottom center;
1583
+ animation: amHrBar var(--am-dur) cubic-bezier(0.2, 0.7, 0.3, 1) infinite both;
1584
+ }
1585
+ .am .hrmq .dayCol:nth-child(2) .dayBar { animation-delay: calc(var(--am-dur) * 0.03); }
1586
+ .am .hrmq .dayCol:nth-child(3) .dayBar { animation-delay: calc(var(--am-dur) * 0.06); }
1587
+ .am .hrmq .dayCol:nth-child(4) .dayBar { animation-delay: calc(var(--am-dur) * 0.09); }
1588
+ .am .hrmq .dayCol:nth-child(5) .dayBar { animation-delay: calc(var(--am-dur) * 0.12); }
1589
+ @keyframes amHrBar {
1590
+ 0%, 4% { transform: scaleY(0); opacity: 1; }
1591
+ 22%, 92% { transform: scaleY(1); opacity: 1; }
1592
+ 97% { transform: scaleY(1); opacity: 0; }
1593
+ 100% { transform: scaleY(0); opacity: 0; }
1594
+ }
1595
+ .am .hrmq .dayLabel { width: 60%; height: 2px; background: var(--c-cobalt-200); border-radius: 1px; }
1596
+ .am .hrmq .sheetFoot { display: flex; align-items: center; justify-content: space-between; gap: 6px; }
1597
+ .am .hrmq .sheetSum { width: 30%; height: 5px; background: var(--c-cobalt-700); border-radius: 1px; }
1598
+ /* The submit button lives outside an .actions row, so it carries its
1599
+ own button paint. */
1600
+ .am .hrmq .submitBtn {
1601
+ width: 44px;
1602
+ height: 14px;
1603
+ border-radius: 3px;
1604
+ background: var(--c-blue-cobalt);
1605
+ animation: amHrSubmit var(--am-dur) ease-in-out infinite;
1606
+ }
1607
+ @keyframes amHrSubmit {
1608
+ 0%, 38% { transform: scale(1); }
1609
+ 41% { transform: scale(0.9); }
1610
+ 44%, 100% { transform: scale(1); }
1611
+ }
1612
+ .am .hrmq .approvePip,
1613
+ .am .hrmq .donePip {
1614
+ width: 8px; height: 8px;
1615
+ border-radius: 50%;
1616
+ background: var(--c-mint-500);
1617
+ flex-shrink: 0;
1618
+ }
1619
+ .am .hrmq .donePip { background: var(--c-mint-300); }
1620
+ .am .hrmq .approvePip { animation: amHrApprove var(--am-dur) linear infinite both; }
1621
+ @keyframes amHrApprove {
1622
+ 0%, 50% { background: var(--c-cobalt-200); transform: scale(1); }
1623
+ 55% { background: var(--c-mint-500); transform: scale(1.4); }
1624
+ 60%, 93% { background: var(--c-mint-500); transform: scale(1); }
1625
+ 98%, 100% { background: var(--c-cobalt-200); transform: scale(1); }
1626
+ }
1627
+ .am .hrmq .payroll {
1628
+ display: flex;
1629
+ flex-direction: column;
1630
+ gap: 3px;
1631
+ padding-top: 5px;
1632
+ border-top: 1px solid var(--c-cobalt-100);
1633
+ }
1634
+ .am .hrmq .payroll .pLabel { width: 40%; height: 3px; background: var(--c-cobalt-400); border-radius: 1px; }
1635
+ .am .hrmq .payroll .pNum {
1636
+ width: 34%; height: 8px;
1637
+ background: var(--c-cobalt-900);
1638
+ border-radius: 1px;
1639
+ transform-origin: left center;
1640
+ animation: amHrPay var(--am-dur) ease-in-out infinite;
1641
+ }
1642
+ @keyframes amHrPay {
1643
+ 0%, 62% { transform: scaleX(1); }
1644
+ 70%, 90% { transform: scaleX(1.3); }
1645
+ 97%, 100% { transform: scaleX(1); }
1646
+ }
1647
+
1648
+ /* ---- LarpingApp — the XP ripple: the second character card lifts,
1649
+ an XP hex token rises to the timeline's active stage, the stage
1650
+ absorbs it with a pulse, and every card's text rows grow in a
1651
+ stagger. Base = settled (post-XP) end state. ---- */
1652
+
1653
+ .am .larping { --am-dur: 8s; }
1654
+ .am .larping .col { position: relative; }
1655
+ .am .larping .card.xpSource { animation: amLrpLift var(--am-dur) ease-in-out infinite; }
1656
+ @keyframes amLrpLift {
1657
+ 0%, 4% { transform: none; box-shadow: none; }
1658
+ 10%, 26% { transform: translateY(-3px); box-shadow: 0 6px 14px -6px rgba(0, 0, 0, 0.25); }
1659
+ 34%, 100% { transform: none; box-shadow: none; }
1660
+ }
1661
+ .am .larping .xpToken {
1662
+ position: absolute;
1663
+ left: 48%;
1664
+ top: 52%;
1665
+ width: 10px; height: 11px;
1666
+ clip-path: var(--hex-pointy-top);
1667
+ background: var(--c-mint-500);
1668
+ opacity: 0;
1669
+ pointer-events: none;
1670
+ animation: amLrpToken var(--am-dur) ease-in-out infinite both;
1671
+ }
1672
+ @keyframes amLrpToken {
1673
+ 0%, 10% { left: 48%; top: 52%; opacity: 0; transform: scale(0.6); }
1674
+ 14% { left: 48%; top: 48%; opacity: 1; transform: scale(1); }
1675
+ 34% { left: 31%; top: 9%; opacity: 1; transform: scale(1); }
1676
+ 38%, 100% { left: 31%; top: 7%; opacity: 0; transform: scale(0.4); }
1677
+ }
1678
+ .am .larping .timeline .step.now .h { animation: amLrpStage var(--am-dur) ease-in-out infinite; }
1679
+ @keyframes amLrpStage {
1680
+ 0%, 34% { transform: scale(1); }
1681
+ 39% { transform: scale(1.25); }
1682
+ 44%, 100% { transform: scale(1); }
1683
+ }
1684
+ .am .larping .card .row {
1685
+ transform-origin: left center;
1686
+ animation: amLrpRow var(--am-dur) ease-in-out infinite;
1687
+ }
1688
+ .am .larping .card:nth-child(2) .row { animation-delay: calc(var(--am-dur) * 0.02); }
1689
+ .am .larping .card:nth-child(3) .row { animation-delay: calc(var(--am-dur) * 0.04); }
1690
+ .am .larping .card:nth-child(4) .row { animation-delay: calc(var(--am-dur) * 0.06); }
1691
+ .am .larping .card:nth-child(5) .row { animation-delay: calc(var(--am-dur) * 0.08); }
1692
+ .am .larping .card:nth-child(6) .row { animation-delay: calc(var(--am-dur) * 0.1); }
1693
+ @keyframes amLrpRow {
1694
+ 0%, 46% { transform: scaleX(0.82); }
1695
+ 58%, 100% { transform: scaleX(1); }
1696
+ }
1697
+
1698
+ /* ---- SoftwareCatalog — the CVE scan: a band sweeps down the app
1699
+ list, row 4's pip flips red as it passes, and the CVE chart bar
1700
+ surges in vermillion (red family — the chart keeps its single
1701
+ KNVB-orange accent). Base = post-scan end state. ---- */
1702
+
1703
+ .am .swc { --am-dur: 8s; }
1704
+ .am .swc .scanPanel { position: relative; overflow: hidden; }
1705
+ .am .swc .scanBand {
1706
+ position: absolute;
1707
+ left: 0;
1708
+ right: 0;
1709
+ top: 0;
1710
+ height: 12px;
1711
+ background: linear-gradient(180deg, transparent 0%, var(--c-cobalt-100) 50%, transparent 100%);
1712
+ opacity: 0;
1713
+ pointer-events: none;
1714
+ animation: amSwcScan var(--am-dur) linear infinite both;
1715
+ }
1716
+ @keyframes amSwcScan {
1717
+ 0%, 6% { transform: translateY(-12px); opacity: 0; }
1718
+ 10% { transform: translateY(0); opacity: 0.9; }
1719
+ 44% { transform: translateY(88px); opacity: 0.9; }
1720
+ 50%, 100% { transform: translateY(100px); opacity: 0; }
1721
+ }
1722
+ .am .swc .item.cveHit .pip { animation: amSwcPip var(--am-dur) linear infinite both; }
1723
+ @keyframes amSwcPip {
1724
+ 0%, 28% { background: var(--c-cobalt-200); transform: scale(1); }
1725
+ 33% { background: var(--c-red-vermillion); transform: scale(1.4); }
1726
+ 38%, 93% { background: var(--c-red-vermillion); transform: scale(1); }
1727
+ 98%, 100% { background: var(--c-cobalt-200); transform: scale(1); }
1728
+ }
1729
+ .am .swc .bar.cve {
1730
+ background: var(--c-red-vermillion);
1731
+ transform-origin: bottom center;
1732
+ animation: amSwcBar var(--am-dur) ease-in-out infinite both;
1733
+ }
1734
+ @keyframes amSwcBar {
1735
+ 0%, 36% { transform: scaleY(0.45); }
1736
+ 48% { transform: scaleY(1.08); }
1737
+ 54%, 93% { transform: scaleY(1); }
1738
+ 98%, 100% { transform: scaleY(0.45); }
1739
+ }
1740
+
1741
+ /* ---- ZaakAfhandelApp — a citizen submission travels up into the
1742
+ werkvoorraad and gains its stage hex + assignee avatar; the late
1743
+ row's red pip pulses once as the SLA reminder. Base = assigned
1744
+ end state. ---- */
1745
+
1746
+ .am .zaak { --am-dur: 8s; }
1747
+ .am .zaak .col { position: relative; }
1748
+ .am .zaak .zkGhost {
1749
+ position: absolute;
1750
+ left: 28%;
1751
+ top: 76%;
1752
+ width: 40%;
1753
+ display: flex;
1754
+ align-items: center;
1755
+ gap: 4px;
1756
+ padding: 3px 4px;
1757
+ background: white;
1758
+ border: 1px solid var(--c-cobalt-200);
1759
+ border-radius: 2px;
1760
+ opacity: 0;
1761
+ pointer-events: none;
1762
+ animation: amZkGhost var(--am-dur) ease-in-out infinite both;
1763
+ }
1764
+ .am .zaak .zkGhost .src { width: 14px; height: 3px; background: var(--c-cobalt-400); border-radius: 1px; flex-shrink: 0; }
1765
+ .am .zaak .zkGhost .gBar { flex: 1; height: 3px; background: var(--c-cobalt-700); border-radius: 1px; }
1766
+ @keyframes amZkGhost {
1767
+ 0%, 8% { top: 76%; opacity: 0; }
1768
+ 13% { top: 74%; opacity: 1; }
1769
+ 36% { top: 27%; opacity: 1; }
1770
+ 42%, 100% { top: 25%; opacity: 0; }
1771
+ }
1772
+ .am .zaak .zkNew .stage { animation: amZkStage var(--am-dur) linear infinite both; }
1773
+ @keyframes amZkStage {
1774
+ 0%, 42% { background: var(--c-cobalt-100); transform: scale(1); }
1775
+ 47% { background: var(--c-lavender-300); transform: scale(1.3); }
1776
+ 52%, 100% { background: var(--c-lavender-300); transform: scale(1); }
1777
+ }
1778
+ .am .zaak .zkNew .av { animation: amZkAv var(--am-dur) linear infinite both; }
1779
+ @keyframes amZkAv {
1780
+ 0%, 44% { opacity: 0.25; }
1781
+ 52%, 100% { opacity: 1; }
1782
+ }
1783
+ .am .zaak .zkNew .l1 {
1784
+ transform-origin: left center;
1785
+ animation: amZkLine var(--am-dur) ease-out infinite both;
1786
+ }
1787
+ @keyframes amZkLine {
1788
+ 0%, 40% { transform: scaleX(0.55); }
1789
+ 52%, 100% { transform: scaleX(1); }
1790
+ }
1791
+ .am .zaak .zkSent { animation: amZkSent var(--am-dur) linear infinite; }
1792
+ @keyframes amZkSent {
1793
+ 0%, 10% { opacity: 1; }
1794
+ 16%, 40% { opacity: 0.35; }
1795
+ 50%, 100% { opacity: 1; }
1796
+ }
1797
+ .am .zaak .item.late .stage { animation: amZkLate var(--am-dur) ease-in-out infinite; }
1798
+ @keyframes amZkLate {
1799
+ 0%, 60% { transform: scale(1); }
1800
+ 64% { transform: scale(1.35); }
1801
+ 68%, 100% { transform: scale(1); }
1802
+ }
1803
+
1804
+ /* ---- Hermiq — the conversation plays: the user asks, the typing
1805
+ indicator blinks, the agent answers, the tool chips light L→R,
1806
+ the approval chip (the variant's single orange while pending)
1807
+ ticks mint, the tool result lands, the user follows up.
1808
+ Base = approved end state (all chips lit, approval mint). ---- */
1809
+
1810
+ .am .hermiq { --am-dur: 10s; }
1811
+ .am .hermiq .nav .item .ico.round { border-radius: 50%; }
1812
+ .am .hermiq .convo { flex: 1; gap: 8px; justify-content: flex-end; }
1813
+ .am .hermiq .bubble { flex-shrink: 0; }
1814
+ .am .hermiq .bubble.user {
1815
+ align-self: flex-end;
1816
+ width: 42%;
1817
+ height: 12px;
1818
+ border-radius: 8px 2px 8px 8px;
1819
+ background: var(--c-workspaceblue-300);
1820
+ }
1821
+ .am .hermiq .bubble.user.narrow { width: 34%; }
1822
+ .am .hermiq .bubble.agent {
1823
+ align-self: flex-start;
1824
+ width: 58%;
1825
+ height: 18px;
1826
+ border-radius: 2px 8px 8px 8px;
1827
+ background: var(--c-cobalt-50);
1828
+ border: 1px solid var(--c-cobalt-100);
1829
+ }
1830
+ .am .hermiq .bubble.agent.tall { width: 64%; height: 24px; }
1831
+ .am .hermiq .typing {
1832
+ align-self: flex-start;
1833
+ display: flex;
1834
+ align-items: center;
1835
+ gap: 2px;
1836
+ padding: 3px 6px;
1837
+ background: var(--c-cobalt-50);
1838
+ border: 1px solid var(--c-cobalt-100);
1839
+ border-radius: 2px 8px 8px 8px;
1840
+ opacity: 0;
1841
+ animation: amHqTyping var(--am-dur) linear infinite both;
1842
+ }
1843
+ .am .hermiq .typing .tDot {
1844
+ width: 3px; height: 3px;
1845
+ border-radius: 50%;
1846
+ background: var(--c-cobalt-400);
1847
+ animation: amHqDot 0.9s ease-in-out infinite;
1848
+ }
1849
+ .am .hermiq .typing .tDot:nth-child(2) { animation-delay: 0.2s; }
1850
+ .am .hermiq .typing .tDot:nth-child(3) { animation-delay: 0.4s; }
1851
+ @keyframes amHqTyping {
1852
+ 0%, 7% { opacity: 0; }
1853
+ 10%, 20% { opacity: 1; }
1854
+ 23%, 100% { opacity: 0; }
1855
+ }
1856
+ @keyframes amHqDot {
1857
+ 0%, 100% { opacity: 0.35; transform: translateY(0); }
1858
+ 50% { opacity: 1; transform: translateY(-1px); }
1859
+ }
1860
+ .am .hermiq .chips { display: flex; align-items: center; gap: 4px; flex-shrink: 0; }
1861
+ .am .hermiq .chip { width: 34px; height: 9px; border-radius: 999px; background: var(--c-cobalt-300); }
1862
+ .am .hermiq .chip.chip3 { width: 26px; }
1863
+ .am .hermiq .bubble.turn1 { animation: amHqTurn1 var(--am-dur) ease-out infinite both; }
1864
+ .am .hermiq .bubble.turn2 { animation: amHqTurn2 var(--am-dur) ease-out infinite both; }
1865
+ .am .hermiq .bubble.turn3 { animation: amHqTurn3 var(--am-dur) ease-out infinite both; }
1866
+ .am .hermiq .bubble.turn4 { animation: amHqTurn4 var(--am-dur) ease-out infinite both; }
1867
+ @keyframes amHqTurn1 {
1868
+ 0%, 2% { opacity: 0; transform: translateY(4px); }
1869
+ 6%, 93% { opacity: 1; transform: none; }
1870
+ 98%, 100% { opacity: 0; transform: none; }
1871
+ }
1872
+ @keyframes amHqTurn2 {
1873
+ 0%, 22% { opacity: 0; transform: translateY(4px); }
1874
+ 27%, 93% { opacity: 1; transform: none; }
1875
+ 98%, 100% { opacity: 0; transform: none; }
1876
+ }
1877
+ @keyframes amHqTurn3 {
1878
+ 0%, 62% { opacity: 0; transform: translateY(4px); }
1879
+ 68%, 93% { opacity: 1; transform: none; }
1880
+ 98%, 100% { opacity: 0; transform: none; }
1881
+ }
1882
+ @keyframes amHqTurn4 {
1883
+ 0%, 74% { opacity: 0; transform: translateY(4px); }
1884
+ 79%, 93% { opacity: 1; transform: none; }
1885
+ 98%, 100% { opacity: 0; transform: none; }
1886
+ }
1887
+ .am .hermiq .chips .chip1 { animation: amHqChip1 var(--am-dur) ease-out infinite both; }
1888
+ @keyframes amHqChip1 {
1889
+ 0%, 30% { opacity: 0; transform: scale(0.7); }
1890
+ 34%, 93% { opacity: 1; transform: scale(1); }
1891
+ 98%, 100% { opacity: 0; transform: scale(1); }
1892
+ }
1893
+ .am .hermiq .chip.chip2 { animation: amHqChip2 var(--am-dur) linear infinite both; }
1894
+ @keyframes amHqChip2 {
1895
+ 0%, 36% { background: var(--c-cobalt-100); }
1896
+ 40%, 93% { background: var(--c-cobalt-300); }
1897
+ 98%, 100% { background: var(--c-cobalt-100); }
1898
+ }
1899
+ .am .hermiq .chip.chip3 { animation: amHqChip3 var(--am-dur) linear infinite both; }
1900
+ @keyframes amHqChip3 {
1901
+ 0%, 42% { background: var(--c-cobalt-100); }
1902
+ 46%, 93% { background: var(--c-cobalt-300); }
1903
+ 98%, 100% { background: var(--c-cobalt-100); }
1904
+ }
1905
+ /* Approval chip — appears orange (pending, via the shared beta pill
1906
+ tokens), holds for the human moment, ticks mint on approval. */
1907
+ .am .hermiq .approveChip { animation: amHqAppr var(--am-dur) linear infinite both; }
1908
+ .am .hermiq .approveChip .h { animation: amHqApprH var(--am-dur) linear infinite both; }
1909
+ .am .hermiq .approveChip .t { animation: amHqApprT var(--am-dur) linear infinite both; }
1910
+ @keyframes amHqAppr {
1911
+ 0%, 46% { background: var(--c-coral-300); opacity: 0; }
1912
+ 50%, 58% { background: var(--c-coral-300); opacity: 1; }
1913
+ 62%, 93% { background: var(--c-mint-300); opacity: 1; }
1914
+ 98% { background: var(--c-mint-300); opacity: 0; }
1915
+ 100% { background: var(--c-coral-300); opacity: 0; }
1916
+ }
1917
+ @keyframes amHqApprH {
1918
+ 0%, 58% { background: var(--c-orange-knvb); transform: scale(1); }
1919
+ 62% { background: var(--c-mint-500); transform: scale(1.4); }
1920
+ 67%, 100% { background: var(--c-mint-500); transform: scale(1); }
1921
+ }
1922
+ @keyframes amHqApprT {
1923
+ 0%, 58% { background: var(--c-coral-500); }
1924
+ 62%, 100% { background: var(--c-mint-500); }
1925
+ }
1926
+ .am .hermiq .promptRow { align-items: center; }
1927
+ .am .hermiq .promptField {
1928
+ flex: 1;
1929
+ height: 16px;
1930
+ background: white;
1931
+ border: 1px solid var(--c-cobalt-200);
1932
+ border-radius: 8px;
1933
+ }
1934
+ .am .hermiq .sendBtn { width: 28px; animation: amHqSend var(--am-dur) ease-in-out infinite; }
1935
+ @keyframes amHqSend {
1936
+ 0% { transform: scale(1); }
1937
+ 1.5% { transform: scale(0.88); }
1938
+ 4%, 100% { transform: scale(1); }
1939
+ }
1940
+
1941
+ /* ---- OpenBuild — the top template row highlights, a ghost chip
1942
+ travels into the virtual-apps list, the new app row lands, the
1943
+ first KPI widens, the published KPI's hex pulses mint.
1944
+ Base = published end state. ---- */
1945
+
1946
+ .am .openbuild { --am-dur: 8s; }
1947
+ .am .openbuild .col { position: relative; }
1948
+ .am .openbuild .col .kpiRow { display: flex; gap: 6px; }
1949
+ .am .openbuild .col .panelRow { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; flex: 1; min-height: 0; }
1950
+ .am .openbuild .tplSource { animation: amObTpl var(--am-dur) linear infinite; }
1951
+ @keyframes amObTpl {
1952
+ 0%, 6% { background: transparent; }
1953
+ 10%, 22% { background: var(--c-cobalt-50); }
1954
+ 28%, 100% { background: transparent; }
1955
+ }
1956
+ .am .openbuild .buildGhost {
1957
+ position: absolute;
1958
+ left: 58%;
1959
+ top: 42%;
1960
+ width: 26px;
1961
+ height: 8px;
1962
+ border-radius: 2px;
1963
+ background: var(--c-lavender-300);
1964
+ opacity: 0;
1965
+ pointer-events: none;
1966
+ animation: amObGhost var(--am-dur) ease-in-out infinite both;
1967
+ }
1968
+ @keyframes amObGhost {
1969
+ 0%, 14% { left: 58%; top: 42%; opacity: 0; }
1970
+ 18% { left: 56%; top: 42%; opacity: 1; }
1971
+ 38% { left: 10%; top: 38%; opacity: 1; }
1972
+ 44%, 100% { left: 8%; top: 38%; opacity: 0; }
1973
+ }
1974
+ .am .openbuild .newApp { animation: amObLand var(--am-dur) ease-out infinite both; }
1975
+ @keyframes amObLand {
1976
+ 0%, 42% { opacity: 0; transform: translateY(-5px); }
1977
+ 49%, 93% { opacity: 1; transform: none; }
1978
+ 98%, 100% { opacity: 0; transform: none; }
1979
+ }
1980
+ .am .openbuild .publishedKpi .ico { animation: amObPublish var(--am-dur) ease-in-out infinite; }
1981
+ @keyframes amObPublish {
1982
+ 0%, 64% { background: var(--c-forest-300); transform: scale(1); }
1983
+ 70% { background: var(--c-mint-500); transform: scale(1.25); }
1984
+ 76%, 84% { background: var(--c-mint-500); transform: scale(1); }
1985
+ 92%, 100% { background: var(--c-forest-300); transform: scale(1); }
1986
+ }
1987
+
1988
+ /* ======================================================================
1989
+ Wave 5 — WidgetMock list-refresh primitive, anonymise dropzone,
1990
+ SidebarMock open/underline/stagger
1991
+ ====================================================================== */
1992
+
1993
+ /* Shared list-refresh — WidgetMock puts `.wmLive` (this module) on
1994
+ its frame for every list-shaped variant. A fresh row slides in at
1995
+ the top, the bottom row clips out, and the unread badge bumps.
1996
+ Transforms + opacity only, so the tile's height never jumps. */
1997
+
1998
+ .am .wmLive { --am-dur: 7s; position: relative; }
1999
+ .am .wmLive .w .list > *:first-child {
2000
+ transform-origin: top center;
2001
+ animation: amWmNew var(--am-dur) ease-out infinite both;
2002
+ }
2003
+ @keyframes amWmNew {
2004
+ 0%, 8% { opacity: 0; transform: translateY(-6px) scaleY(0.5); }
2005
+ 16%, 90% { opacity: 1; transform: none; }
2006
+ 96%, 100% { opacity: 0; transform: translateY(-6px) scaleY(0.5); }
2007
+ }
2008
+ .am .wmLive .w .list > *:last-child {
2009
+ transform-origin: bottom center;
2010
+ animation: amWmOld var(--am-dur) ease-in infinite both;
2011
+ }
2012
+ @keyframes amWmOld {
2013
+ 0%, 16% { opacity: 1; transform: none; }
2014
+ 26%, 88% { opacity: 0; transform: translateY(4px) scaleY(0.4); }
2015
+ 94%, 100% { opacity: 1; transform: none; }
2016
+ }
2017
+ /* Unread badge — pinned to the tile's top-right; bumps as the fresh
2018
+ row lands. Mint on the cobalt-900 dashboard surface. */
2019
+ .am .wmBadge {
2020
+ position: absolute;
2021
+ top: 8px;
2022
+ right: 8px;
2023
+ width: 14px;
2024
+ height: 8px;
2025
+ border-radius: 999px;
2026
+ background: var(--c-mint-500);
2027
+ z-index: 1;
2028
+ animation: amWmBadge var(--am-dur) ease-in-out infinite;
2029
+ }
2030
+ @keyframes amWmBadge {
2031
+ 0%, 12% { transform: scale(1); }
2032
+ 17% { transform: scale(1.45); }
2033
+ 24%, 100% { transform: scale(1); }
2034
+ }
2035
+
2036
+ /* Anonymise dropzone — marching-ants dashes, a file hex drops in,
2037
+ the zone flashes mint as the redacted copy is confirmed. Applied
2038
+ by the docudesk-anonymise widget variant and the DocuDesk app
2039
+ mock's own drop-zone (`.zoneLive` on the .w-upload block). */
2040
+
2041
+ .am .zoneLive { --am-dur: 5s; }
2042
+ .am .zoneLive .zone {
2043
+ position: relative;
2044
+ overflow: hidden;
2045
+ border-style: solid;
2046
+ border-color: transparent;
2047
+ background-image:
2048
+ repeating-linear-gradient(90deg, var(--c-cobalt-300) 0 4px, transparent 4px 8px),
2049
+ repeating-linear-gradient(90deg, var(--c-cobalt-300) 0 4px, transparent 4px 8px),
2050
+ repeating-linear-gradient(0deg, var(--c-cobalt-300) 0 4px, transparent 4px 8px),
2051
+ repeating-linear-gradient(0deg, var(--c-cobalt-300) 0 4px, transparent 4px 8px);
2052
+ background-size: 100% 1px, 100% 1px, 1px 100%, 1px 100%;
2053
+ background-position: 0 0, 0 100%, 0 0, 100% 0;
2054
+ background-repeat: no-repeat;
2055
+ animation:
2056
+ amZoneAnts 0.9s linear infinite,
2057
+ amZoneFlash var(--am-dur) ease-in-out infinite;
2058
+ }
2059
+ @keyframes amZoneAnts {
2060
+ to { background-position: 8px 0, -8px 100%, 0 -8px, 100% 8px; }
2061
+ }
2062
+ @keyframes amZoneFlash {
2063
+ 0%, 52% { background-color: var(--c-cobalt-50); }
2064
+ 58%, 66% { background-color: var(--c-mint-300); }
2065
+ 74%, 100% { background-color: var(--c-cobalt-50); }
2066
+ }
2067
+ .am .zoneLive .zoneFile {
2068
+ position: absolute;
2069
+ left: 50%;
2070
+ top: 50%;
2071
+ width: 12px;
2072
+ height: 14px;
2073
+ margin: -7px 0 0 -6px;
2074
+ clip-path: var(--hex-pointy-top);
2075
+ background: var(--c-terracotta-300);
2076
+ opacity: 0;
2077
+ pointer-events: none;
2078
+ animation: amZoneFile var(--am-dur) ease-in infinite both;
2079
+ }
2080
+ @keyframes amZoneFile {
2081
+ 0%, 26% { opacity: 0; transform: translateY(-26px); }
2082
+ 32% { opacity: 1; transform: translateY(-20px); }
2083
+ 48% { opacity: 1; transform: translateY(0); }
2084
+ 56%, 100% { opacity: 0; transform: translateY(0); }
2085
+ }
2086
+
2087
+ /* SidebarMock — the panel slides in from the right, the head wipes,
2088
+ the active-tab underline travels in from the neighbouring tab
2089
+ (positioned by --sb-ix / --sb-n from the component), and the body
2090
+ rows land in a stagger. Base = opened, settled panel. */
2091
+
2092
+ .am .sbLive { --am-dur: 7s; animation: amSbPanel var(--am-dur) ease-out infinite both; }
2093
+ @keyframes amSbPanel {
2094
+ 0% { opacity: 0; transform: translateX(14px); }
2095
+ 7%, 94% { opacity: 1; transform: none; }
2096
+ 99%, 100% { opacity: 0; transform: translateX(14px); }
2097
+ }
2098
+ .am .sbLive .sb-head .title {
2099
+ transform-origin: left center;
2100
+ animation: amSbTitle var(--am-dur) ease-out infinite both;
2101
+ }
2102
+ @keyframes amSbTitle {
2103
+ 0%, 8% { transform: scaleX(0); }
2104
+ 16%, 100% { transform: scaleX(1); }
2105
+ }
2106
+ .am .sbLive .sb-head .desc {
2107
+ transform-origin: left center;
2108
+ animation: amSbDesc var(--am-dur) ease-out infinite both;
2109
+ }
2110
+ @keyframes amSbDesc {
2111
+ 0%, 12% { transform: scaleX(0); }
2112
+ 22%, 100% { transform: scaleX(1); }
2113
+ }
2114
+ .am .sbLive .sb-tabs { position: relative; }
2115
+ /* The travelling underline replaces the static active border. */
2116
+ .am .sbLive .sb-tab.active { border-bottom-color: transparent; }
2117
+ .am .sbLive .sb-underline {
2118
+ position: absolute;
2119
+ bottom: -1px;
2120
+ height: 2px;
2121
+ border-radius: 1px;
2122
+ background: var(--c-blue-cobalt);
2123
+ left: calc(10px + (100% - 20px) * var(--sb-ix, 1) / var(--sb-n, 4));
2124
+ width: calc((100% - 20px) / var(--sb-n, 4));
2125
+ animation: amSbUnderline var(--am-dur) cubic-bezier(0.2, 0.7, 0.3, 1) infinite both;
2126
+ }
2127
+ @keyframes amSbUnderline {
2128
+ 0%, 18% { transform: translateX(var(--sb-from, -100%)); }
2129
+ 30%, 100% { transform: translateX(0); }
2130
+ }
2131
+ .am .sbLive .sb-body > * { animation: amSbRow var(--am-dur) ease-out infinite both; }
2132
+ .am .sbLive .sb-body > *:nth-child(2) { animation-delay: calc(var(--am-dur) * 0.018); }
2133
+ .am .sbLive .sb-body > *:nth-child(3) { animation-delay: calc(var(--am-dur) * 0.036); }
2134
+ .am .sbLive .sb-body > *:nth-child(4) { animation-delay: calc(var(--am-dur) * 0.054); }
2135
+ .am .sbLive .sb-body > *:nth-child(5) { animation-delay: calc(var(--am-dur) * 0.072); }
2136
+ .am .sbLive .sb-body > *:nth-child(6) { animation-delay: calc(var(--am-dur) * 0.09); }
2137
+ .am .sbLive .sb-body > *:nth-child(7) { animation-delay: calc(var(--am-dur) * 0.108); }
2138
+ .am .sbLive .sb-body > *:nth-child(8) { animation-delay: calc(var(--am-dur) * 0.126); }
2139
+ .am .sbLive .sb-body > *:nth-child(9) { animation-delay: calc(var(--am-dur) * 0.144); }
2140
+ .am .sbLive .sb-body > *:nth-child(10) { animation-delay: calc(var(--am-dur) * 0.162); }
2141
+ @keyframes amSbRow {
2142
+ 0%, 20% { opacity: 0; transform: translateY(4px); }
2143
+ 28%, 100% { opacity: 1; transform: none; }
2144
+ }
2145
+
1065
2146
  /* ======================================================================
1066
2147
  Static frames — running={false} adds `.static` next to `.am .frame`;
1067
2148
  the media query below mirrors it for prefers-reduced-motion. Selectors
@@ -1139,3 +2220,185 @@
1139
2220
  .am .lpBi .w-graph-line .stroke { stroke-dasharray: none; stroke-dashoffset: 0; }
1140
2221
  .am .plq .dealGone { display: none; }
1141
2222
  }
2223
+
2224
+ /* ======================================================================
2225
+ Static frames — waves 2, 4 and 5. Same convention as the block
2226
+ above: `.static` on the frame (AppMock), on the WidgetMock frame
2227
+ (`.wmLive.static`), or on the SidebarMock panel (`.sbLive.static`)
2228
+ freezes every keyframe onto its base — the meaningful end state.
2229
+ Transient travellers (ghosts, dots, sweeps, the typing indicator)
2230
+ have `opacity: 0` bases, so they simply stay hidden.
2231
+ ====================================================================== */
2232
+
2233
+ .am .static .docudesk .word.mark-1,
2234
+ .am .static .docudesk .word.mark-2,
2235
+ .am .static .docudesk .word.mark-3,
2236
+ .am .static .docudesk .word.mark-4,
2237
+ .am .static .docudesk .word.mark-5,
2238
+ .am .static .shillinq .bankLine,
2239
+ .am .static .shillinq .inv.reconciling .tick,
2240
+ .am .static .shillinq .totNet,
2241
+ .am .static .doriath .keyHex,
2242
+ .am .static .doriath .vMask,
2243
+ .am .static .doriath .vValue,
2244
+ .am .static .doriath .vCountdown,
2245
+ .am .static .opencatalogi .search,
2246
+ .am .static .opencatalogi .search .q,
2247
+ .am .static .opencatalogi .card.dim,
2248
+ .am .static .opencatalogi .card.match,
2249
+ .am .static .opencatalogi .card.match .statusPill .h,
2250
+ .am .static .openconnector .travelDotA,
2251
+ .am .static .openconnector .travelDotB,
2252
+ .am .static .openconnector .stage .conn,
2253
+ .am .static .openconnector .newRun,
2254
+ .am .static .openconnector .newRun .runTick,
2255
+ .am .static .procest .timeline .step .ghost,
2256
+ .am .static .procest .stack .sortUp,
2257
+ .am .static .procest .stack .sortDown,
2258
+ .am .static .openregister .newObj,
2259
+ .am .static .openregister .detail > .row,
2260
+ .am .static .kpiGrow .num,
2261
+ .am .static .decidesk .tallyRow .fill,
2262
+ .am .static .decidesk .tallyRow .quorum,
2263
+ .am .static .decidesk .adoptFlip,
2264
+ .am .static .decidesk .adoptFlip .h,
2265
+ .am .static .decidesk .adoptFlip .t,
2266
+ .am .static .hrmq .dayBar,
2267
+ .am .static .hrmq .submitBtn,
2268
+ .am .static .hrmq .approvePip,
2269
+ .am .static .hrmq .payroll .pNum,
2270
+ .am .static .larping .card.xpSource,
2271
+ .am .static .larping .xpToken,
2272
+ .am .static .larping .timeline .step.now .h,
2273
+ .am .static .larping .card .row,
2274
+ .am .static .swc .scanBand,
2275
+ .am .static .swc .item.cveHit .pip,
2276
+ .am .static .swc .bar.cve,
2277
+ .am .static .zaak .zkGhost,
2278
+ .am .static .zaak .zkNew .stage,
2279
+ .am .static .zaak .zkNew .av,
2280
+ .am .static .zaak .zkNew .l1,
2281
+ .am .static .zaak .zkSent,
2282
+ .am .static .zaak .item.late .stage,
2283
+ .am .static .hermiq .bubble,
2284
+ .am .static .hermiq .typing,
2285
+ .am .static .hermiq .typing .tDot,
2286
+ .am .static .hermiq .chips .chip1,
2287
+ .am .static .hermiq .chip.chip2,
2288
+ .am .static .hermiq .chip.chip3,
2289
+ .am .static .hermiq .approveChip,
2290
+ .am .static .hermiq .approveChip .h,
2291
+ .am .static .hermiq .approveChip .t,
2292
+ .am .static .hermiq .sendBtn,
2293
+ .am .static .openbuild .tplSource,
2294
+ .am .static .openbuild .buildGhost,
2295
+ .am .static .openbuild .newApp,
2296
+ .am .static .openbuild .publishedKpi .ico,
2297
+ .am .wmLive.static .w .list > *:first-child,
2298
+ .am .wmLive.static .w .list > *:last-child,
2299
+ .am .wmLive.static .wmBadge,
2300
+ .am .static .wmBadge,
2301
+ .am .static .zoneLive .zone,
2302
+ .am .zoneLive.static .zone,
2303
+ .am .static .zoneLive .zoneFile,
2304
+ .am .zoneLive.static .zoneFile,
2305
+ .am .sbLive.static,
2306
+ .am .static .sbLive,
2307
+ .am .sbLive.static .sb-head .title,
2308
+ .am .static .sbLive .sb-head .title,
2309
+ .am .sbLive.static .sb-head .desc,
2310
+ .am .static .sbLive .sb-head .desc,
2311
+ .am .sbLive.static .sb-underline,
2312
+ .am .static .sbLive .sb-underline,
2313
+ .am .sbLive.static .sb-body > *,
2314
+ .am .static .sbLive .sb-body > * {
2315
+ animation: none;
2316
+ }
2317
+ .am .static .zoneLive .zone,
2318
+ .am .zoneLive.static .zone {
2319
+ border: 1px dashed var(--c-cobalt-300);
2320
+ background-image: none;
2321
+ }
2322
+
2323
+ @media (prefers-reduced-motion: reduce) {
2324
+ .am .docudesk .word.mark-1,
2325
+ .am .docudesk .word.mark-2,
2326
+ .am .docudesk .word.mark-3,
2327
+ .am .docudesk .word.mark-4,
2328
+ .am .docudesk .word.mark-5,
2329
+ .am .shillinq .bankLine,
2330
+ .am .shillinq .inv.reconciling .tick,
2331
+ .am .shillinq .totNet,
2332
+ .am .doriath .keyHex,
2333
+ .am .doriath .vMask,
2334
+ .am .doriath .vValue,
2335
+ .am .doriath .vCountdown,
2336
+ .am .opencatalogi .search,
2337
+ .am .opencatalogi .search .q,
2338
+ .am .opencatalogi .card.dim,
2339
+ .am .opencatalogi .card.match,
2340
+ .am .opencatalogi .card.match .statusPill .h,
2341
+ .am .openconnector .travelDotA,
2342
+ .am .openconnector .travelDotB,
2343
+ .am .openconnector .stage .conn,
2344
+ .am .openconnector .newRun,
2345
+ .am .openconnector .newRun .runTick,
2346
+ .am .procest .timeline .step .ghost,
2347
+ .am .procest .stack .sortUp,
2348
+ .am .procest .stack .sortDown,
2349
+ .am .openregister .newObj,
2350
+ .am .openregister .detail > .row,
2351
+ .am .kpiGrow .num,
2352
+ .am .decidesk .tallyRow .fill,
2353
+ .am .decidesk .tallyRow .quorum,
2354
+ .am .decidesk .adoptFlip,
2355
+ .am .decidesk .adoptFlip .h,
2356
+ .am .decidesk .adoptFlip .t,
2357
+ .am .hrmq .dayBar,
2358
+ .am .hrmq .submitBtn,
2359
+ .am .hrmq .approvePip,
2360
+ .am .hrmq .payroll .pNum,
2361
+ .am .larping .card.xpSource,
2362
+ .am .larping .xpToken,
2363
+ .am .larping .timeline .step.now .h,
2364
+ .am .larping .card .row,
2365
+ .am .swc .scanBand,
2366
+ .am .swc .item.cveHit .pip,
2367
+ .am .swc .bar.cve,
2368
+ .am .zaak .zkGhost,
2369
+ .am .zaak .zkNew .stage,
2370
+ .am .zaak .zkNew .av,
2371
+ .am .zaak .zkNew .l1,
2372
+ .am .zaak .zkSent,
2373
+ .am .zaak .item.late .stage,
2374
+ .am .hermiq .bubble,
2375
+ .am .hermiq .typing,
2376
+ .am .hermiq .typing .tDot,
2377
+ .am .hermiq .chips .chip1,
2378
+ .am .hermiq .chip.chip2,
2379
+ .am .hermiq .chip.chip3,
2380
+ .am .hermiq .approveChip,
2381
+ .am .hermiq .approveChip .h,
2382
+ .am .hermiq .approveChip .t,
2383
+ .am .hermiq .sendBtn,
2384
+ .am .openbuild .tplSource,
2385
+ .am .openbuild .buildGhost,
2386
+ .am .openbuild .newApp,
2387
+ .am .openbuild .publishedKpi .ico,
2388
+ .am .wmLive .w .list > *:first-child,
2389
+ .am .wmLive .w .list > *:last-child,
2390
+ .am .wmBadge,
2391
+ .am .zoneLive .zone,
2392
+ .am .zoneLive .zoneFile,
2393
+ .am .sbLive,
2394
+ .am .sbLive .sb-head .title,
2395
+ .am .sbLive .sb-head .desc,
2396
+ .am .sbLive .sb-underline,
2397
+ .am .sbLive .sb-body > * {
2398
+ animation: none;
2399
+ }
2400
+ .am .zoneLive .zone {
2401
+ border: 1px dashed var(--c-cobalt-300);
2402
+ background-image: none;
2403
+ }
2404
+ }