@jossuealcala/madre 0.6.0 → 0.7.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/public/styles.css CHANGED
@@ -29,7 +29,7 @@
29
29
  --user-ink: var(--phosphor-ink);
30
30
 
31
31
  --danger: #ff7b72;
32
- --warn: #ffd166;
32
+ --warn: #ffd166; --warn-ink: #1a1403;
33
33
  --crit: #ff8a7a;
34
34
  --terror: #ff2a1f; /* MOTHER, when she stops being polite */
35
35
  --shadow: 0 1px 0 rgba(255,255,255,.03) inset, 0 12px 40px rgba(0,0,0,.45);
@@ -70,15 +70,15 @@
70
70
  --line-2: rgba(0, 0, 0, .13);
71
71
  --text: #121512;
72
72
  --text-2: #5a615a;
73
- --text-3: #8b928a;
73
+ --text-3: #767d75;
74
74
  --phosphor: #2f8a1c;
75
75
  --brew: #178f0c;
76
76
  --brew-ink: #ffffff;
77
77
  --phosphor-ink: #ffffff;
78
- --bubble: #e9ebe6;
78
+ --bubble: #dde0d7;
79
79
  --bubble-ink: #121512;
80
80
  --danger: #b3261e;
81
- --warn: #8a6a00;
81
+ --warn: #8a6a00; --warn-ink: #ffffff;
82
82
  --crit: #a1301f;
83
83
  --shadow: 0 12px 40px rgba(0,0,0,.08);
84
84
  --mode-0: #6f786e; --mode-0-ink: #ffffff;
@@ -103,15 +103,15 @@
103
103
  --line-2: rgba(0, 0, 0, .13);
104
104
  --text: #121512;
105
105
  --text-2: #5a615a;
106
- --text-3: #8b928a;
106
+ --text-3: #767d75;
107
107
  --phosphor: #2f8a1c;
108
108
  --brew: #178f0c;
109
109
  --brew-ink: #ffffff;
110
110
  --phosphor-ink: #ffffff;
111
- --bubble: #e9ebe6;
111
+ --bubble: #dde0d7;
112
112
  --bubble-ink: #121512;
113
113
  --danger: #b3261e;
114
- --warn: #8a6a00;
114
+ --warn: #8a6a00; --warn-ink: #ffffff;
115
115
  --crit: #a1301f;
116
116
  --shadow: 0 12px 40px rgba(0,0,0,.08);
117
117
  }
@@ -228,6 +228,22 @@ body {
228
228
  .avatar.gradient { background: var(--agent-gradient, var(--agent)); color: #fff; }
229
229
  .agents .avatar { cursor: default; }
230
230
 
231
+ /* The spheres, in light mode. A tint of the agent's colour works on a near-black page because the
232
+ colour is the only light in the circle; over a near-white page the same mix just walks back to
233
+ the page. Measured: at 17% over #f4f5f2 the brightest agents came out at 1.06:1 and 1.03:1 —
234
+ the disc was not faint, it was absent. Raising the percentage does not fix it either, because
235
+ mixing a bright yellow into white stays white (40% only reached 1.17:1).
236
+
237
+ So on light the disc keeps its tint and gains an edge and a glyph in the agent's colour taken
238
+ DOWN instead of up. One colour, two directions, and every agent reads at its own hue. */
239
+ :root:not([data-theme="dark"]) .avatar:not(.gradient):not(.offline):not(.detected),
240
+ :root[data-theme="light"] .avatar:not(.gradient):not(.offline):not(.detected) {
241
+ --agent-ink: color-mix(in srgb, var(--agent) 58%, #11210f);
242
+ background: color-mix(in srgb, var(--agent) 22%, transparent);
243
+ box-shadow: inset 0 0 0 1.5px var(--agent-ink);
244
+ color: var(--agent-ink);
245
+ }
246
+
231
247
  /* ================= thread ================= */
232
248
  .thread {
233
249
  overflow-y: auto;
@@ -320,14 +336,26 @@ code { font-family: var(--mono); font-size: .9em; color: var(--phosphor); backgr
320
336
  /* The panel is a screen, not a column. Sections pair up once there is room for two, and the
321
337
  ones that carry a table or a full-width strip keep the whole width to themselves. */
322
338
  #economy-body { display: grid; grid-template-columns: 1fr; gap: 0 56px; align-content: start; }
323
- @media (min-width: 1180px) { #economy-body { grid-template-columns: 1fr 1fr; } #economy-body > .wide, #economy-body > .economy-strip { grid-column: 1 / -1; } }
339
+ @media (min-width: 1180px) { #economy-body { grid-template-columns: 1fr 1fr; gap: 16px; } #economy-body > .wide, #economy-body > .economy-strip { grid-column: 1 / -1; } }
324
340
  .economy .card-block { display: grid; gap: 10px; align-content: start; }
325
- .economy .card-block { margin-top: 40px; padding-top: 24px; border-top: 1px solid var(--ph-faint); }
326
- .economy .card-block:first-of-type { margin-top: 0; padding-top: 0; border-top: 0; }
341
+ .economy .card-block {
342
+ margin: 0; padding: 20px 22px 22px;
343
+ border: 1px solid var(--ph-faint); border-radius: 12px;
344
+ background: color-mix(in srgb, var(--ph) 3%, transparent);
345
+ }
346
+ .economy .card-block:first-of-type { margin: 0; }
347
+ .economy .card-head { display: flex; align-items: center; gap: 8px; margin: 0 0 4px; }
348
+ .card-icon { width: 12px; height: 12px; opacity: .85; }
349
+ /* The unit, said once per card instead of stamped on every row. */
350
+ .economy .unit-note { margin: -2px 0 6px; font-family: var(--mono); font-size: 9px; letter-spacing: .14em; text-transform: uppercase; color: var(--ph-dim); }
327
351
 
328
352
  /* The room in six figures, read across before anything is read down. */
329
- .economy-strip { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 20px 32px; margin: 4px 0 8px; padding-bottom: 26px; border-bottom: 1px solid var(--ph-dim); }
330
- .economy-stat { display: grid; gap: 5px; align-content: start; min-width: 0; }
353
+ .economy-strip { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; margin: 0 0 4px; padding: 0; border: 0; }
354
+ .economy-stat {
355
+ display: grid; gap: 5px; align-content: start; min-width: 0;
356
+ padding: 14px 16px; border: 1px solid var(--ph-faint); border-radius: 10px;
357
+ background: color-mix(in srgb, var(--ph) 4%, transparent);
358
+ }
331
359
  .economy-stat b { font-family: var(--mono); font-size: 22px; font-weight: 600; line-height: 1.1; color: var(--ph); }
332
360
  .economy-stat span { font-family: var(--mono); font-size: 8.5px; letter-spacing: .18em; color: var(--ph-dim); }
333
361
 
@@ -392,7 +420,7 @@ code { font-family: var(--mono); font-size: .9em; color: var(--phosphor); backgr
392
420
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase;
393
421
  color: var(--text-3); line-height: 1.7;
394
422
  }
395
- .system > b:first-child { display: block; margin-bottom: 3px; color: var(--text-3); letter-spacing: .2em; }
423
+ .system > b:first-child:not(.inline) { display: block; margin-bottom: 3px; color: var(--text-3); letter-spacing: .2em; }
396
424
  /* Everything after the heading is one sentence and has to wrap as one: a code chip that becomes
397
425
  a block breaks the line in front of it and leaves the agent's name stranded. */
398
426
  .system code { display: inline-block; vertical-align: baseline; }
@@ -729,11 +757,13 @@ textarea::placeholder { color: var(--text-3); }
729
757
  .field button[type="submit"]:hover { filter: brightness(1.06); }
730
758
  .field button[type="submit"]:disabled { opacity: .4; cursor: default; box-shadow: none; }
731
759
  .pick-label .pick-note { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; font-family: var(--mono); font-size: 9px; letter-spacing: .14em; text-transform: uppercase; color: var(--text-3); white-space: nowrap; }
732
- .safety { max-width: min(100%, 150ch); margin: 8px auto 4px; color: var(--text-3); font-family: var(--mono); font-size: 8.5px; line-height: 1.5; letter-spacing: .06em; text-transform: uppercase; text-align: center; opacity: .85; }
760
+ .safety { max-width: min(100%, 150ch); margin: 8px auto 4px; color: var(--text-2); font-family: var(--mono); font-size: 8.5px; line-height: 1.5; letter-spacing: .06em; text-transform: uppercase; text-align: center; opacity: .9; }
733
761
  /* The signature, in the corner it belongs in: last in the page's order, and out of the way of
734
762
  everything that is actually used. */
735
- .colophon { position: fixed; right: 14px; bottom: 10px; z-index: 2; font-family: var(--mono); font-size: 8.5px; letter-spacing: .1em; color: var(--text-3); opacity: .5; pointer-events: none; user-select: none; transition: opacity .2s; }
736
- .colophon:hover { opacity: .9; }
763
+ .colophon { position: fixed; right: 14px; bottom: 10px; z-index: 2; font-family: var(--mono); font-size: 8.5px; letter-spacing: .1em; color: var(--brew); opacity: .68; pointer-events: none; user-select: none; transition: opacity .2s; }
764
+ .colophon:hover { opacity: 1; }
765
+ .colophon-back { pointer-events: auto; color: inherit; text-decoration: none; border-bottom: 1px solid currentColor; padding-bottom: 1px; }
766
+ .colophon-back:hover { color: var(--brew); opacity: 1; }
737
767
  @media (max-width: 720px) { .colophon { display: none; } }
738
768
  .shell.with-browser .colophon { display: none; }
739
769
 
@@ -816,20 +846,35 @@ dialog.mother::backdrop { background: rgba(0, 0, 0, .82); backdrop-filter: blur(
816
846
  .mother-section { margin-top: 34px; }
817
847
  .mother-section h3:not(:first-child) { margin-top: 40px; padding-top: 22px; border-top: 1px solid var(--ph-faint); }
818
848
  .mother-section h3.toggle:not(:first-child) { margin-top: 40px; }
819
- .settings .room-form, .settings .conn-grid, .settings .mother-grid { margin-bottom: 8px; }
849
+ :is(.settings, .memory-panel) .room-form, .settings .conn-grid, .settings .mother-grid { margin-bottom: 8px; }
820
850
  .mother-section h3::before { content: "▌ "; color: var(--ph); }
851
+ /* A folding block carries its own glyph, so the generic bar would be a second mark saying the
852
+ same thing. And the rule above it goes with it: a line and an icon are two ways of announcing
853
+ «a new block starts here», and one of them is enough. */
854
+ .mother-section .fold > summary h3::before { content: none; }
855
+ .mother-section .fold > summary h3 { font-size: 11px; letter-spacing: .22em; color: var(--ph); }
856
+ .mother-section .fold[open] > summary h3 { color: var(--ph); }
857
+ /* No frame around it: a badge was a second box saying what the drawing already says. Crisp edges
858
+ because a pixel that gets antialiased into a curve stops being a pixel. */
859
+ .pixel-icon { flex: none; display: block; line-height: 0; color: var(--ph); }
860
+ .pixel-icon svg { display: block; width: 100%; height: 100%; shape-rendering: crispEdges; }
861
+ .fold-icon { width: 13px; height: 13px; opacity: .8; transition: opacity .15s; }
862
+ .mother-section .fold > summary:hover .fold-icon { opacity: 1; }
863
+ .mother-section .fold { padding-top: 26px; margin-top: 10px; border-top: 1px solid var(--ph-faint); }
864
+ .mother-section .fold:first-of-type { border-top: 0; padding-top: 0; }
821
865
 
822
866
  /* A section that folds. The summary carries the same header it always had, plus a mark on the
823
867
  right when there is something behind it worth opening. */
824
868
  .mother-section .fold { margin: 0; }
825
869
  .mother-section .fold + .fold { margin-top: 26px; }
826
- .mother-section .fold > summary { display: flex; align-items: baseline; gap: 10px; cursor: pointer; list-style: none; }
870
+ .mother-section .fold > summary { display: flex; align-items: center; gap: 9px; cursor: pointer; list-style: none; }
827
871
  .mother-section .fold > summary::-webkit-details-marker { display: none; }
828
872
  /* The button is a word, not a glyph: the panel already said EXPAND and COLLAPSE elsewhere. */
829
873
  .mother-section .fold > summary .caret { margin-left: auto; font-family: var(--mono); font-size: 9px; letter-spacing: .18em; color: var(--ph); white-space: nowrap; }
830
874
  .mother-section .fold > summary:hover h3 { color: var(--ph); }
831
- .mother-section .fold > summary h3 { margin: 0 0 12px; }
875
+ .mother-section .fold > summary h3 { margin: 0; }
832
876
  .mother-section .fold > summary h3:not(:first-child) { margin-top: 0; padding-top: 0; border-top: 0; }
877
+ .mother-section .fold > .fold-body { padding-top: 14px; }
833
878
  .fold-badge { font-family: var(--mono); font-size: 9px; letter-spacing: .12em; padding: 2px 7px; border-radius: 999px; border: 1px solid var(--ph-dim); color: var(--ph-dim); white-space: nowrap; }
834
879
  /* Red, and only red, when there is something new: that is the whole message. */
835
880
  .fold-badge.urgent { border-color: var(--danger); background: var(--danger); color: #fff; }
@@ -1010,22 +1055,22 @@ dialog.mother::backdrop { background: rgba(0, 0, 0, .82); backdrop-filter: blur(
1010
1055
  .conn-card .session.busy { color: #ffd166; border-color: #ffd166; animation: blink 1s infinite; }
1011
1056
  .conn-card .meta { font-size: 11px; line-height: 1.6; color: rgba(210, 255, 190, .8); text-shadow: none; }
1012
1057
  .conn-card .row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
1013
- .conn-card button, .settings .room-form button { border: 1px solid var(--ph-dim); background: transparent; color: var(--ph); font: inherit; font-size: 9.5px; letter-spacing: .16em; padding: 6px 10px; cursor: pointer; }
1014
- .conn-card button.primary, .settings .room-form button.primary { background: var(--ph); color: #041004; text-shadow: none; border-color: var(--ph); }
1015
- .conn-card button:disabled, .settings .room-form button:disabled { opacity: .4; cursor: default; }
1016
- .conn-card label, .settings .room-form label { display: grid; gap: 4px; font-size: 9.5px; letter-spacing: .16em; color: var(--ph-dim); }
1058
+ .conn-card button, :is(.settings, .memory-panel) .room-form button { border: 1px solid var(--ph-dim); background: transparent; color: var(--ph); font: inherit; font-size: 9.5px; letter-spacing: .16em; padding: 6px 10px; cursor: pointer; }
1059
+ .conn-card button.primary, :is(.settings, .memory-panel) .room-form button.primary { background: var(--ph); color: #041004; text-shadow: none; border-color: var(--ph); }
1060
+ .conn-card button:disabled, :is(.settings, .memory-panel) .room-form button:disabled { opacity: .4; cursor: default; }
1061
+ .conn-card label, :is(.settings, .memory-panel) .room-form label { display: grid; gap: 4px; font-size: 9.5px; letter-spacing: .16em; color: var(--ph-dim); }
1017
1062
  /* A textarea is a field like any other here. It was left out of this rule, so what you typed
1018
1063
  into it was drawn in the page's own colour: invisible on this ground. */
1019
- .conn-card input, .conn-card select, .settings .room-form input, .settings .room-form select, .settings .room-form textarea { border: 1px solid var(--ph-dim); background: #000; color: var(--ph); font: inherit; font-size: 12px; padding: 6px 8px; letter-spacing: .04em; min-width: 0; }
1020
- .settings .room-form textarea::placeholder { color: var(--ph-dim); }
1021
- .conn-card input:focus, .settings .room-form input:focus, .settings .room-form textarea:focus { outline: 1px solid var(--ph); }
1064
+ .conn-card input, .conn-card select, :is(.settings, .memory-panel) .room-form input, :is(.settings, .memory-panel) .room-form select, :is(.settings, .memory-panel) .room-form textarea { border: 1px solid var(--ph-dim); background: #000; color: var(--ph); font: inherit; font-size: 12px; padding: 6px 8px; letter-spacing: .04em; min-width: 0; }
1065
+ :is(.settings, .memory-panel) .room-form textarea::placeholder { color: var(--ph-dim); }
1066
+ .conn-card input:focus, :is(.settings, .memory-panel) .room-form input:focus, :is(.settings, .memory-panel) .room-form textarea:focus { outline: 1px solid var(--ph); }
1022
1067
  .conn-card .login-log { max-height: 140px; overflow-y: auto; border: 1px solid var(--ph-faint); background: #000; padding: 8px 10px; font-size: 11px; line-height: 1.5; white-space: pre-wrap; overflow-wrap: anywhere; }
1023
1068
  .conn-card .login-log a { color: var(--ph); }
1024
- .settings .room-form { border: 1px solid var(--ph-dim); padding: 14px 16px; display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); align-items: end; }
1025
- .settings .room-form .full { grid-column: 1 / -1; display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
1026
- .settings .room-form .toggle { display: flex; align-items: center; gap: 8px; font-size: 10px; letter-spacing: .16em; color: var(--ph); cursor: pointer; }
1027
- .settings .room-form .toggle input { width: auto; accent-color: var(--brew); }
1028
- .settings .note { font-size: 10px; letter-spacing: .1em; color: var(--ph-dim); }
1069
+ :is(.settings, .memory-panel) .room-form { border: 1px solid var(--ph-dim); padding: 14px 16px; display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); align-items: end; }
1070
+ :is(.settings, .memory-panel) .room-form .full { grid-column: 1 / -1; display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
1071
+ :is(.settings, .memory-panel) .room-form .toggle { display: flex; align-items: center; gap: 8px; font-size: 10px; letter-spacing: .16em; color: var(--ph); cursor: pointer; }
1072
+ :is(.settings, .memory-panel) .room-form .toggle input { width: auto; accent-color: var(--brew); }
1073
+ :is(.settings, .memory-panel) .note { font-size: 10px; letter-spacing: .1em; color: var(--ph-dim); }
1029
1074
  .system.login { color: var(--phosphor); }
1030
1075
  .system.login.failed { color: var(--danger); }
1031
1076
 
@@ -1241,6 +1286,10 @@ dialog.viewer { border: 0; padding: 0; width: min(1100px, 96vw); max-width: 96vw
1241
1286
  /* The composer has the same disease: its parts have to be allowed to give. */
1242
1287
  .composer .field { min-width: 0; }
1243
1288
  .composer .editor { min-width: 0; }
1289
+ /* The field grows with the text to a workable page and then scrolls on its own, so a long brief
1290
+ is written in one piece instead of through a three-line window — and the thread above it never
1291
+ disappears, because what is being written is usually written against it. */
1292
+ .composer .editor textarea { scrollbar-width: thin; }
1244
1293
  .composer .crew-label { flex: none; }
1245
1294
 
1246
1295
  /* The browser docks beside the conversation; it does not take the screen from it. The point of
@@ -1664,13 +1713,27 @@ dialog.viewer::backdrop { background: rgba(0,0,0,.7); backdrop-filter: blur(4px)
1664
1713
  .ports-row b { font-family: var(--mono); font-size: 12.5px; color: var(--phosphor); }
1665
1714
  .ports-row span { font-size: 11.5px; color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1666
1715
  .ports-row:hover { background: color-mix(in srgb, var(--phosphor) 12%, transparent); }
1716
+ /* Found and not offered: it is there, and it is not something this room will frame. */
1717
+ .ports-row.wider { cursor: default; opacity: .62; }
1718
+ .ports-row.wider:hover { background: transparent; }
1719
+ .ports-row.wider b { color: var(--text-3); }
1667
1720
  .ports-note { padding: 6px 10px 7px; font-family: var(--mono); font-size: 9px; line-height: 1.6; letter-spacing: .1em; color: var(--text-3); }
1668
1721
 
1669
1722
  /* The way up, beside the agent asking to climb it. Quiet: it is a door, not an alarm. */
1670
- .mode-ask { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 8px 12px 0; padding: 7px 12px; border: 1px dashed color-mix(in srgb, var(--warn, #e2a022) 46%, transparent); border-radius: 10px; background: color-mix(in srgb, var(--warn, #e2a022) 6%, transparent); }
1723
+ /* An agent asking for a rung. The box used to be drawn around the whole thing — a dashed frame
1724
+ and a tinted ground behind a sentence that is not clickable — so the eye read a panel and had
1725
+ to find the button inside it. The sentence is a sentence now; only the thing you can press
1726
+ looks pressable, and it looks it properly: filled, not outlined. */
1727
+ .mode-ask { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin: 10px 12px 2px; padding: 0; border: 0; background: none; }
1671
1728
  .mode-what { flex: 1; min-width: 0; font-family: var(--mono); font-size: 10.5px; letter-spacing: .06em; color: var(--text-2); }
1672
- .mode-go { flex: none; border: 1px solid color-mix(in srgb, var(--warn, #e2a022) 60%, transparent); background: transparent; color: var(--warn, #e2a022); font-family: var(--mono); font-size: 10px; font-weight: 600; letter-spacing: .12em; padding: 5px 12px; border-radius: 7px; cursor: pointer; }
1673
- .mode-go:hover { background: color-mix(in srgb, var(--warn, #e2a022) 16%, transparent); }
1729
+ .mode-go {
1730
+ flex: none; border: 0; border-radius: 7px; cursor: pointer;
1731
+ background: var(--warn, #e2a022); color: var(--warn-ink, #1a1403);
1732
+ font-family: var(--mono); font-size: 10px; font-weight: 700; letter-spacing: .12em; padding: 6px 13px;
1733
+ box-shadow: 0 1px 0 color-mix(in srgb, #000 22%, transparent);
1734
+ }
1735
+ .mode-go:hover { background: color-mix(in srgb, var(--warn, #e2a022) 86%, #fff); }
1736
+ .mode-go:active { transform: translateY(1px); box-shadow: none; }
1674
1737
 
1675
1738
  /* A decision handed back, in the agent's colour: read at a glance, answered with one press. */
1676
1739
  .choice { margin: 10px 12px 2px; padding: 12px 14px; border: 1px solid color-mix(in srgb, var(--agent, var(--text-3)) 32%, transparent); border-radius: 14px; background: color-mix(in srgb, var(--agent, var(--text-3)) 5%, transparent); }
@@ -1757,6 +1820,25 @@ dialog.viewer::backdrop { background: rgba(0,0,0,.7); backdrop-filter: blur(4px)
1757
1820
  .tree-menu button { border: 0; background: transparent; color: var(--text); font: inherit; font-size: 12px; text-align: left; padding: 7px 10px; border-radius: 7px; cursor: pointer; }
1758
1821
  .tree-menu button:hover { background: color-mix(in srgb, var(--phosphor) 12%, transparent); }
1759
1822
  .tree-menu .guarded { color: var(--warn); }
1823
+ /* A zone is a state, not a category: the one that still travels wears the room's own green, the
1824
+ one that does not is dimmed to the colour of everything the archive keeps and never serves. */
1825
+ .nostromo-card .zone { font-family: var(--mono); font-size: 10px; letter-spacing: .12em; }
1826
+ .nostromo-card .zone.underway { color: var(--phosphor); }
1827
+ .nostromo-card .zone.archived { color: var(--text-3); opacity: .75; }
1828
+ .nostromo-card .zone.archived::after { content: ' ·'; }
1829
+
1830
+ /* The brake for one answer, in the row of the answer it stops. Quiet until the turn is worth
1831
+ stopping — which is when the human is already looking at it. */
1832
+ .stop-turn {
1833
+ margin-left: 10px; padding: 2px 9px; border: 1px solid var(--line-2); border-radius: 999px;
1834
+ background: transparent; color: var(--text-3);
1835
+ font-family: var(--mono); font-size: 9px; letter-spacing: .14em; cursor: pointer;
1836
+ opacity: .5; transition: opacity .15s, color .15s, border-color .15s;
1837
+ }
1838
+ .row.thinking:hover .stop-turn, .stop-turn:focus-visible { opacity: 1; }
1839
+ .stop-turn:hover { color: var(--terror); border-color: var(--terror); }
1840
+ .stop-turn:disabled { opacity: .7; cursor: default; color: var(--text-3); border-color: var(--line-2); }
1841
+
1760
1842
  .tree-menu .note { padding: 5px 10px 6px; font-family: var(--mono); font-size: 8.5px; letter-spacing: .1em; color: var(--text-3); }
1761
1843
 
1762
1844
  @keyframes tree-in { from { opacity: 0; transform: translateX(8px); } to { opacity: 1; transform: none; } }
@@ -1823,6 +1905,10 @@ dialog.viewer::backdrop { background: rgba(0,0,0,.7); backdrop-filter: blur(4px)
1823
1905
  .bubble-actions .act:hover { color: var(--text); background: color-mix(in srgb, var(--text) 8%, transparent); }
1824
1906
  .bubble-actions .act.good.on { color: var(--phosphor); }
1825
1907
  .bubble-actions .act.bad.on { color: var(--terror); }
1908
+ .bubble-actions .act.prefer.on { color: var(--phosphor); }
1909
+ .bubble-actions .act.never.on { color: var(--terror); }
1910
+ /* Shown only once the verdict they escalate is in: at rest the bubble carries no extra chrome. */
1911
+ .bubble-actions .act.prefer[hidden], .bubble-actions .act.never[hidden] { display: none; }
1826
1912
  .bubble-actions .act.done { color: var(--phosphor); }
1827
1913
  .reply-menu { width: min(280px, calc(100vw - 24px)); padding: 8px; }
1828
1914
  .reply-menu .model-menu-title { margin: 4px 8px 6px; }
@@ -1862,10 +1948,10 @@ dialog.viewer::backdrop { background: rgba(0,0,0,.7); backdrop-filter: blur(4px)
1862
1948
  .mother-section.sentinel button, .mother-section.update button { border: 1px solid var(--ph-dim); background: transparent; color: var(--ph); font: inherit; font-size: 9.5px; letter-spacing: .16em; padding: 6px 10px; cursor: pointer; }
1863
1949
  .mother-section.sentinel button:hover, .mother-section.update button:hover { background: var(--ph-faint); }
1864
1950
  .mother-section.sentinel .sentinel-report.sent { opacity: .65; }
1865
- .settings .memory-form .toggle { display: inline-flex; align-items: center; gap: 6px; margin-right: 14px; font-size: 9.5px; letter-spacing: .14em; color: var(--ph-dim); cursor: pointer; text-transform: uppercase; }
1866
- .settings .memory-form .toggle input { accent-color: var(--brew); width: auto; }
1867
- .settings .memory-form .full .note { margin-right: 12px; }
1868
- .settings .memory-form .dataset-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; padding-top: 8px; border-top: 1px solid var(--ph-faint); }
1951
+ :is(.settings, .memory-panel) .memory-form .toggle { display: inline-flex; align-items: center; gap: 6px; margin-right: 14px; font-size: 9.5px; letter-spacing: .14em; color: var(--ph-dim); cursor: pointer; text-transform: uppercase; }
1952
+ :is(.settings, .memory-panel) .memory-form .toggle input { accent-color: var(--brew); width: auto; }
1953
+ :is(.settings, .memory-panel) .memory-form .full .note { margin-right: 12px; }
1954
+ :is(.settings, .memory-panel) .memory-form .dataset-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; padding-top: 8px; border-top: 1px solid var(--ph-faint); }
1869
1955
  .module-card .ollama-status { margin: 0; display: grid; grid-template-columns: auto 1fr; gap: 3px 12px; font-size: 10px; letter-spacing: .1em; }
1870
1956
  .module-card .ollama-status dt { color: var(--ph-dim); } .module-card .ollama-status dd { margin: 0; color: rgba(210, 255, 190, .85); overflow-wrap: anywhere; }
1871
1957
  .module-card .actions .toggle { display: inline-flex; align-items: center; gap: 6px; font-size: 9.5px; letter-spacing: .14em; color: var(--ph-dim); cursor: pointer; }
@@ -1888,16 +1974,6 @@ dialog.viewer::backdrop { background: rgba(0,0,0,.7); backdrop-filter: blur(4px)
1888
1974
  .dev-row a.mother-close { text-decoration: none; display: inline-flex; align-items: center; }
1889
1975
  .dev-fail { color: var(--warn); } .dev-fail code { color: var(--warn); background: color-mix(in srgb, var(--warn) 12%, transparent); padding: 1px 5px; }
1890
1976
  .tour-button { min-width: 30px; padding: 6px 0; text-align: center; font-weight: 700; }
1891
- .tour-frame { width: min(620px, 92vw); padding: 26px 30px 22px; }
1892
- .tour-body { min-height: 190px; padding: 12px 0 6px; }
1893
- .tour-step h3 { margin: 6px 0 14px; font-size: 11px; letter-spacing: .28em; color: var(--ph); font-weight: 700; }
1894
- .tour-step p { margin: 0 0 10px; font-size: 12.5px; line-height: 1.7; letter-spacing: .03em; color: var(--ph); text-transform: none; }
1895
- .tour-foot { display: flex; align-items: center; justify-content: space-between; gap: 14px; padding-top: 14px; border-top: 1px solid var(--ph-dim); }
1896
- .tour-dots { display: inline-flex; gap: 8px; }
1897
- .tour-dots .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--ph-faint); border: 1px solid var(--ph-dim); transition: background-color .22s ease; }
1898
- .tour-dots .dot.on { background: var(--ph); box-shadow: 0 0 8px rgba(155, 255, 102, .5); }
1899
- .tour-nav { display: inline-flex; gap: 8px; }
1900
- .tour .mother-close.primary { background: var(--ph-faint); }
1901
1977
 
1902
1978
  /* DEV modules and proposals */
1903
1979
  .module-card .dev-tag { font-family: var(--mono); font-size: 8.5px; letter-spacing: .18em; color: var(--warn); border: 1px solid color-mix(in srgb, var(--warn) 55%, transparent); padding: 2px 7px; margin-left: 8px; align-self: center; }
@@ -2062,26 +2138,7 @@ dialog.viewer::backdrop { background: rgba(0,0,0,.7); backdrop-filter: blur(4px)
2062
2138
  .exams button.primary { background: var(--ph); color: #041004; text-shadow: none; }
2063
2139
  .exams button:disabled { opacity: .4; cursor: default; }
2064
2140
 
2065
- .maturity { display: grid; gap: 10px; margin: 12px 0 4px; }
2066
- .maturity > .card-fold { border-top: 1px solid var(--ph-faint); padding-top: 10px; }
2067
- .maturity .maturity-next { margin: 0; font-family: var(--mono); font-size: 10.5px; line-height: 1.8; letter-spacing: .1em; text-transform: uppercase; color: #eaffdf; text-shadow: 0 0 6px rgba(155, 255, 102, .18); padding: 11px 13px; border: 1px solid var(--ph); border-left-width: 4px; background: var(--ph-faint); }
2068
- .maturity .maturity-next b { font-size: 9px; letter-spacing: .22em; color: var(--ph); margin-right: 10px; }
2069
- .maturity .maturity-next .where { font-size: 9px; letter-spacing: .16em; color: var(--ph); white-space: nowrap; }
2070
- .maturity-head { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
2071
- .maturity-head b { font-family: var(--mono); font-size: 11px; letter-spacing: .24em; }
2072
- .maturity-head span { font-family: var(--mono); font-size: 9.5px; letter-spacing: .12em; line-height: 1.7; text-transform: uppercase; color: var(--ph-dim); }
2073
- .maturity-head b.stage.empty, .maturity-head b.stage.sparse { color: var(--ph-dim); }
2074
- .maturity-head b.stage.forming { color: var(--ph-dim); }
2075
- .maturity-head b.stage.working, .maturity-head b.stage.mature { color: var(--ph); }
2076
- .maturity-row { display: grid; grid-template-columns: 210px 90px 1fr; gap: 12px; align-items: center; }
2077
- .maturity-row b { font-family: var(--mono); font-size: 9px; letter-spacing: .14em; color: var(--ph-dim); font-weight: 400; }
2078
- .maturity-row i { height: 5px; background: var(--ph-faint); position: relative; }
2079
- .maturity-row i::after { content: ''; position: absolute; inset: 0 auto 0 0; width: var(--fill, 0%); background: var(--ph-dim); }
2080
- .maturity-row.weakest i::after { background: var(--ph); }
2081
- .maturity-row.weakest b { color: var(--ph); }
2082
- .maturity-row span { font-family: var(--mono); font-size: 9px; letter-spacing: .08em; color: var(--ph-dim); opacity: .8; }
2083
2141
  .maturity-next { color: var(--ph); }
2084
- @media (max-width: 860px) { .maturity-row { grid-template-columns: 1fr; gap: 2px; } .maturity-row i { display: none; } }
2085
2142
 
2086
2143
  /* A record you have dealt with: the way out sits at the end of its own row. */
2087
2144
  .mother-record .drop { justify-self: end; background: none; border: 0; color: var(--ph-faint); cursor: pointer; font: inherit; font-size: 14px; padding: 0; line-height: 1; }
@@ -2106,3 +2163,289 @@ dialog.viewer::backdrop { background: rgba(0,0,0,.7); backdrop-filter: blur(4px)
2106
2163
  .viewer .code .t-literal { color: var(--syn-literal); }
2107
2164
  .viewer .code .t-regex { color: var(--syn-regex); }
2108
2165
  .viewer-lang { color: var(--ph-dim); font-size: 9.5px; letter-spacing: .16em; text-transform: uppercase; }
2166
+
2167
+ /* A connector's key: a password field that is never filled back in, what MADRE knows about it
2168
+ (its length, never its value), and the way to take it out again. */
2169
+ .module-card .card-secret { display: flex; flex-wrap: wrap; gap: 10px 14px; align-items: center; }
2170
+ .module-card .card-secret .control { display: inline-flex; align-items: center; gap: 8px; font-size: 9.5px; letter-spacing: .14em; color: var(--ph-dim); }
2171
+ .module-card .card-secret .control input { border: 1px solid var(--ph-dim); background: #000; color: var(--ph); font: inherit; font-size: 10.5px; letter-spacing: .18em; padding: 5px 8px; min-width: 190px; }
2172
+ .module-card .card-secret button.ghost { background: none; border: 1px solid var(--ph-dim); color: var(--ph-dim); font: inherit; font-size: 8.5px; letter-spacing: .18em; padding: 5px 9px; cursor: pointer; }
2173
+ .module-card .card-secret button.ghost:hover { color: var(--ph); border-color: var(--ph); }
2174
+ .module-card .card-block > .note { margin: 0; font-size: 10px; line-height: 1.7; letter-spacing: .08em; color: var(--ph-dim); }
2175
+ .module-card .card-block > a.note { justify-self: start; color: var(--brew); text-decoration: none; letter-spacing: .18em; font-size: 8.5px; }
2176
+ .module-card .card-block > a.note:hover { text-decoration: underline; }
2177
+
2178
+ /* A starter under /module: an instruction to edit, not a command to run. Dimmer key, so the
2179
+ command above it still reads as the command. */
2180
+ .slash-menu .item.starter .key { color: var(--text-3); font-size: 11px; }
2181
+ .slash-menu .item.starter .what { color: var(--text-2); }
2182
+ .dev-card .dev-ask { margin: 0; font-size: 12px; line-height: 1.7; color: var(--ph-dim); }
2183
+ .dev-card .dev-ask code { font-family: var(--mono); font-size: 11.5px; color: var(--brew); }
2184
+
2185
+ /* EXPAND ALL, taken out of the bar. The bar is a row of destinations — CONNECTIONS, MEMORY,
2186
+ NOSTROMO — and this is not one: it acts on the canvas underneath it. A frame made it a rival
2187
+ of those buttons, so it has none: it speaks like the ▸ OPEN of each fold, dim, at the same right
2188
+ edge, over the column of carets it moves all at once. */
2189
+ .fold-all-row { display: flex; justify-content: flex-end; margin: 14px 0 6px; }
2190
+ .fold-all {
2191
+ display: inline-flex; align-items: center; gap: 7px;
2192
+ border: 0; border-radius: 0; background: transparent; color: var(--ph-dim);
2193
+ font-family: var(--mono); font-size: 9px; letter-spacing: .18em; padding: 4px 0; cursor: pointer;
2194
+ }
2195
+ .fold-all:hover, .fold-all:focus-visible { color: var(--ph); }
2196
+ .fold-all:focus-visible { outline: 1px solid var(--ph-dim); outline-offset: 3px; }
2197
+ .fold-all .pixel-icon { width: 9px; height: 9px; display: block; color: currentColor; }
2198
+ .fold-all .pixel-icon svg { width: 100%; height: 100%; shape-rendering: crispEdges; display: block; }
2199
+
2200
+ /* ---------- MEMORY · the dashboard ----------
2201
+ The same phosphor as the rest of MU/TH/UR: hairline frames, one green, the brighter ink only
2202
+ for the figures. A chart here is boxes with heights, so it stays crisp at any width. */
2203
+ .mem-dash { display: grid; gap: 14px; margin-bottom: 8px; transition: opacity .2s; }
2204
+ .mem-dash.loading { opacity: .45; }
2205
+ .mem-dash-head { display: flex; align-items: baseline; justify-content: flex-end; gap: 14px; flex-wrap: wrap; margin-top: -4px; }
2206
+ .mem-dash-head .when { font-size: 9px; letter-spacing: .16em; color: var(--ph-dim); }
2207
+ .mem-dash button { border: 1px solid var(--ph-dim); background: transparent; color: var(--ph); font: inherit; font-size: 9.5px; letter-spacing: .16em; padding: 6px 10px; cursor: pointer; }
2208
+ .mem-dash button:hover { background: var(--ph-faint); }
2209
+ .mem-dash button.primary { background: var(--ph); color: #041004; text-shadow: none; border-color: var(--ph); }
2210
+ .mem-dash button:disabled { opacity: .4; cursor: default; }
2211
+ .mem-dash .note { margin: 0; font-size: 9.5px; letter-spacing: .12em; line-height: 1.7; color: var(--ph-dim); }
2212
+
2213
+ .mem-kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 10px; }
2214
+ .mem-tile { display: grid; align-content: start; gap: 6px; padding: 14px 16px 12px; border: 1px solid var(--ph-faint); background: rgba(40, 254, 20, .025); min-width: 0; }
2215
+ .mem-tile .label { font-size: 9px; letter-spacing: .2em; color: var(--ph-dim); }
2216
+ .mem-tile .value { font-size: clamp(26px, 3vw, 34px); font-weight: 700; letter-spacing: .04em; line-height: 1.05; color: #eaffdf; text-shadow: 0 0 10px rgba(155, 255, 102, .35); }
2217
+ .mem-tile .sub { font-size: 9px; letter-spacing: .14em; line-height: 1.6; color: var(--ph); text-transform: uppercase; }
2218
+ .mem-tile .mem-cols.spark { height: 22px; margin-top: 4px; }
2219
+ .mem-tile .mem-meter { margin-top: 8px; }
2220
+
2221
+ .mem-verdict { display: grid; gap: 8px; }
2222
+ .mem-verdict .says { margin: 0; font-size: 10.5px; letter-spacing: .1em; line-height: 1.7; text-transform: uppercase; color: rgba(210, 255, 190, .9); }
2223
+ .mem-verdict .says b { font-size: 10px; letter-spacing: .24em; color: var(--ph); margin-right: 8px; }
2224
+ .mem-verdict .maturity-next { margin: 0; font-family: var(--mono); font-size: 10.5px; line-height: 1.8; letter-spacing: .1em; text-transform: uppercase; color: #eaffdf; text-shadow: 0 0 6px rgba(155, 255, 102, .18); padding: 11px 13px; border: 1px solid var(--ph); background: var(--ph-faint); }
2225
+ .mem-verdict .maturity-next b { font-size: 9px; letter-spacing: .22em; color: var(--ph); margin-right: 10px; }
2226
+ .mem-verdict .maturity-next .where { font-size: 9px; letter-spacing: .16em; color: var(--ph); white-space: nowrap; }
2227
+
2228
+ .mem-grid { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 14px; }
2229
+ .mem-card { grid-column: span 6; display: grid; align-content: start; gap: 12px; padding: 14px 16px 16px; border: 1px solid var(--ph-faint); min-width: 0; }
2230
+ .mem-card.span-3 { grid-column: span 3; }
2231
+ .mem-card.span-5 { grid-column: span 5; }
2232
+ .mem-card.span-7 { grid-column: span 7; }
2233
+ .mem-card.span-12 { grid-column: 1 / -1; }
2234
+ .mem-card > h4 { margin: 0; font-size: 9.5px; font-weight: 400; letter-spacing: .24em; color: var(--ph); }
2235
+ .mem-card .detail { font-size: 8.5px; letter-spacing: .1em; line-height: 1.6; color: var(--ph-dim); text-transform: uppercase; }
2236
+ @media (max-width: 1180px) { .mem-card.span-3 { grid-column: span 6; } .mem-card.span-5, .mem-card.span-7 { grid-column: 1 / -1; } }
2237
+ @media (max-width: 640px) { .mem-card.span-3 { grid-column: 1 / -1; } }
2238
+
2239
+ /* Columns from one baseline: 4px rounded ends, square at the floor, 2px of black between them. */
2240
+ .mem-cols { display: flex; align-items: flex-end; gap: 2px; height: 46px; border-bottom: 1px solid var(--ph-faint); }
2241
+ .mem-cols i { flex: 1; min-width: 0; max-width: 24px; height: var(--h, 0); background: var(--ph-dim); border-radius: 2px 2px 0 0; }
2242
+ .mem-cols i.zero { height: 1px; background: var(--ph-faint); border-radius: 0; }
2243
+ .mem-cols i.now { background: var(--ph); }
2244
+ .mem-cols i.on { background: #eaffdf; box-shadow: 0 0 8px rgba(155, 255, 102, .5); }
2245
+ .mem-cols.big i { max-width: none; border-radius: 4px 4px 0 0; }
2246
+ .mem-cols.spark { border-bottom: 0; }
2247
+ .mem-cols.spark i { border-radius: 1px 1px 0 0; }
2248
+
2249
+ .mem-activity { position: relative; display: grid; gap: 12px; outline: none; cursor: crosshair; }
2250
+ .mem-activity:focus-visible { outline: 1px solid var(--ph-dim); outline-offset: 6px; }
2251
+ .mem-strip { display: grid; gap: 6px; }
2252
+ .mem-strip-head { display: flex; align-items: baseline; gap: 10px; }
2253
+ .mem-strip-head b { font-size: 9px; font-weight: 400; letter-spacing: .18em; color: rgba(210, 255, 190, .9); }
2254
+ .mem-strip-head span { margin-left: auto; font-size: 8.5px; letter-spacing: .14em; color: var(--ph-dim); }
2255
+ .mem-axis { display: flex; justify-content: space-between; font-size: 8.5px; letter-spacing: .14em; color: var(--ph-dim); margin-top: -4px; }
2256
+ .mem-cross { position: absolute; top: 0; bottom: 14px; width: 1px; background: var(--ph-dim); pointer-events: none; }
2257
+ .mem-tip { position: absolute; top: 18px; z-index: 2; display: grid; gap: 4px; min-width: 150px; padding: 9px 11px; background: #020402; border: 1px solid var(--ph); pointer-events: none; box-shadow: 0 6px 24px rgba(0, 0, 0, .6); }
2258
+ .mem-tip .when { font-size: 9px; font-weight: 400; letter-spacing: .2em; color: var(--ph-dim); }
2259
+ .mem-tip div { display: flex; align-items: baseline; gap: 8px; }
2260
+ .mem-tip strong { min-width: 28px; font-size: 13px; color: #eaffdf; font-variant-numeric: tabular-nums; }
2261
+ .mem-tip span { font-size: 8.5px; letter-spacing: .14em; color: var(--ph); }
2262
+
2263
+ .mem-table { width: 100%; border-collapse: collapse; font-size: 9.5px; letter-spacing: .1em; }
2264
+ .mem-table th { text-align: right; font-weight: 400; font-size: 8.5px; letter-spacing: .16em; color: var(--ph-dim); padding: 4px 6px; border-bottom: 1px solid var(--ph-faint); }
2265
+ .mem-table td { text-align: right; padding: 4px 6px; color: var(--ph); font-variant-numeric: tabular-nums; border-bottom: 1px solid rgba(40, 254, 20, .06); }
2266
+ .mem-table th:first-child, .mem-table td:first-child { text-align: left; }
2267
+
2268
+ /* A meter: the fill against its own track, with an optional mark where it has to reach. */
2269
+ .mem-meter { position: relative; display: block; height: 6px; background: var(--ph-faint); }
2270
+ .mem-meter > i { position: absolute; inset: 0 auto 0 0; background: var(--ph-dim); border-radius: 0 3px 3px 0; }
2271
+ .mem-meter > .mark { position: absolute; top: -4px; bottom: -4px; width: 2px; margin-left: -1px; background: #eaffdf; }
2272
+ .mem-tile .mem-meter > i, .mem-signal.weakest .mem-meter > i { background: var(--ph); }
2273
+ .mem-signal { display: grid; gap: 5px; }
2274
+ .mem-signal .top { display: flex; align-items: baseline; gap: 10px; }
2275
+ .mem-signal .top b { font-size: 9px; font-weight: 400; letter-spacing: .14em; color: rgba(210, 255, 190, .9); }
2276
+ .mem-signal .top span { margin-left: auto; font-size: 10px; letter-spacing: .08em; color: #eaffdf; font-variant-numeric: tabular-nums; }
2277
+ .mem-signal.weakest .top b { color: var(--ph); }
2278
+ .mem-signal.weakest .top b::after { content: " ◂"; }
2279
+
2280
+ .mem-bars { display: grid; gap: 9px; }
2281
+ .mem-bar { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 4px 10px; align-items: center; }
2282
+ .mem-bar .name { display: flex; align-items: center; gap: 7px; font-size: 9px; letter-spacing: .14em; color: rgba(210, 255, 190, .9); min-width: 0; overflow-wrap: anywhere; }
2283
+ .mem-bar .swatch { flex: none; width: 8px; height: 8px; box-shadow: 0 0 6px currentColor; }
2284
+ .mem-bar .value { font-size: 9px; letter-spacing: .08em; color: var(--ph-dim); font-variant-numeric: tabular-nums; white-space: nowrap; }
2285
+ .mem-bar .track { grid-column: 1 / -1; display: block; height: 8px; }
2286
+ .mem-bar .track i { display: block; height: 100%; min-width: 2px; background: var(--ph-dim); border-radius: 0 4px 4px 0; }
2287
+ .mem-bar:first-child .track i { background: var(--ph); }
2288
+
2289
+ .mem-split { display: flex; gap: 2px; height: 12px; }
2290
+ .mem-split i { flex-basis: 0; min-width: 2px; }
2291
+ .mem-split i.search { background: var(--ph); border-radius: 0; }
2292
+ .mem-split i.cascade { background: var(--ph-dim); border-radius: 0 4px 4px 0; }
2293
+ .mem-legend { display: flex; flex-wrap: wrap; gap: 6px 16px; }
2294
+ .mem-legend .k { display: inline-flex; align-items: center; gap: 6px; font-size: 9px; letter-spacing: .14em; color: rgba(210, 255, 190, .9); }
2295
+ .mem-legend .k i { width: 10px; height: 10px; }
2296
+ .mem-legend .k.search i { background: var(--ph); }
2297
+ .mem-legend .k.cascade i { background: var(--ph-dim); }
2298
+ .mem-legend .k b { font-weight: 400; color: var(--ph-dim); font-variant-numeric: tabular-nums; }
2299
+
2300
+ /* The three tests, side by side on a wide screen, each with its rate against the line it has to reach. */
2301
+ .mem-dash .exams { margin: 0; grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: start; }
2302
+ @media (max-width: 900px) { .mem-dash .exams { grid-template-columns: minmax(0, 1fr); } }
2303
+ .mem-dash .exams > .note, .mem-dash .exams > button { grid-column: 1 / -1; justify-self: start; }
2304
+ /* One hairline all round: the verdict and the bar already say passed or not, so no coloured edge. */
2305
+ .mem-dash .exams .exam, .mem-dash .exams .exam.passed, .mem-dash .exams .exam.failed { align-content: start; height: 100%; box-sizing: border-box; border: 1px solid var(--ph-faint); }
2306
+ .mem-dash .exams .said { font-family: var(--mono); font-size: 11px; letter-spacing: .04em; line-height: 1.65; }
2307
+ .exam-bullet { display: grid; gap: 6px; margin: 2px 0; }
2308
+ .exam-bullet .mem-meter { height: 8px; }
2309
+ .exam-bullet .mem-meter > i { background: var(--ph); }
2310
+ .exams .exam.failed .exam-bullet .mem-meter > i { background: var(--warn); }
2311
+ .exam-bullet span { font-size: 9px; letter-spacing: .14em; color: var(--ph-dim); }
2312
+ .exams .exam .actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
2313
+
2314
+ /* The two folds under the dashboard: same frame as everywhere else in MU/TH/UR. */
2315
+ .memory-panel > .fold { border-top: 1px solid var(--ph-faint); padding-top: 22px; }
2316
+ .memory-panel .memory-form .train-card { border-top: 1px solid var(--ph-faint); padding-top: 12px; }
2317
+ .memory-panel .train-head { color: var(--ph); }
2318
+ .memory-panel .train-step-label { color: var(--ph-dim); }
2319
+ .memory-panel .update-command { border: 1px solid var(--ph-faint); border-radius: 0; background: rgba(0, 0, 0, .4); }
2320
+ .memory-panel .update-command code { color: var(--ph); }
2321
+ .memory-panel .update-command button { border-color: var(--ph-dim); color: var(--ph); background: transparent; border-radius: 0; }
2322
+ /* A command is one long line that scrolls inside its own box; it must never widen the screen. */
2323
+ .memory-panel .memory-form .train-card { display: block; min-width: 0; }
2324
+ .memory-panel .train-steps, .memory-panel .train-steps li, .memory-panel .update-command { min-width: 0; }
2325
+
2326
+ /* ---------- What's new ----------
2327
+ The sheet an app shows after it updates: the room's own ground and type, not MU/TH/UR's
2328
+ terminal, because this is the product talking to its person and not the console. One column,
2329
+ a big plain title, each thing with its 8-bit mark in the room's green, and one button. */
2330
+ /* The window scrolls, not the sheet: a long sheet keeps its rounded edges whole and the scrollbar
2331
+ sits at the edge of the screen, outside the card, where a scrollbar belongs. */
2332
+ dialog.whats-new { position: fixed; inset: 0; width: 100vw; height: 100dvh; max-width: none; max-height: none; margin: 0; border: 0; padding: 24px 16px; box-sizing: border-box; background: transparent; color: var(--text); overflow-y: auto; }
2333
+ dialog.whats-new[open] { display: flex; flex-direction: column; align-items: center; }
2334
+ dialog.whats-new::backdrop { background: rgba(0, 0, 0, .55); backdrop-filter: blur(10px); }
2335
+ .wn-sheet {
2336
+ width: min(560px, 100%); margin: auto 0; flex: none; box-sizing: border-box;
2337
+ padding: 40px 40px 28px; border-radius: 26px; background: var(--panel); border: 1px solid var(--line-2);
2338
+ box-shadow: 0 30px 90px rgba(0, 0, 0, .45); animation: wn-in .45s cubic-bezier(.2, .8, .2, 1);
2339
+ }
2340
+ @keyframes wn-in { from { opacity: 0; transform: translateY(18px) scale(.98); } to { opacity: 1; transform: none; } }
2341
+ @media (prefers-reduced-motion: reduce) { .wn-sheet { animation: none; } }
2342
+ .wn-head { text-align: center; margin-bottom: 26px; }
2343
+ .wn-badge { display: inline-block; font-family: var(--mono); font-size: 10px; letter-spacing: .2em; color: var(--text-2); padding: 4px 10px; border: 1px solid var(--line-2); border-radius: 999px; }
2344
+ .wn-head h2 { margin: 14px 0 10px; font-size: clamp(26px, 5vw, 34px); font-weight: 700; letter-spacing: -.01em; line-height: 1.1; }
2345
+ .wn-intro { margin: 0 auto; max-width: 42ch; font-size: 14.5px; line-height: 1.55; color: var(--text-2); }
2346
+ .wn-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 20px; }
2347
+ .wn-item, .wn-more { display: grid; grid-template-columns: 40px minmax(0, 1fr); gap: 16px; align-items: start; }
2348
+ .wn-icon { width: 30px; height: 30px; margin: 3px 5px 0; color: var(--brew); filter: drop-shadow(0 0 6px color-mix(in srgb, var(--brew) 45%, transparent)); }
2349
+ :root[data-scheme="light"] .wn-icon { color: #178f0c; filter: none; }
2350
+ .wn-words h3 { margin: 0 0 4px; font-size: 15.5px; font-weight: 650; line-height: 1.3; }
2351
+ .wn-words p { margin: 0; font-size: 14px; line-height: 1.55; color: var(--text-2); }
2352
+ .wn-words .wn-where { margin-top: 6px; font-family: var(--mono); font-size: 11px; letter-spacing: .04em; color: var(--text-2); }
2353
+ .wn-where .k { font-size: 9.5px; letter-spacing: .18em; text-transform: uppercase; color: var(--text-3); margin-right: 4px; }
2354
+ .wn-more { margin-top: 26px; padding: 18px 18px 18px 14px; border-radius: 16px; border: 1px dashed var(--line-2); background: color-mix(in srgb, var(--bg) 40%, transparent); }
2355
+ .wn-more .wn-icon { color: var(--module-electric); filter: drop-shadow(0 0 6px color-mix(in srgb, var(--module-electric) 50%, transparent)); }
2356
+ :root[data-scheme="light"] .wn-more .wn-icon { color: var(--module-electric); filter: none; }
2357
+ .wn-more h3 { font-style: italic; }
2358
+ .wn-foot { display: grid; justify-items: center; gap: 14px; margin-top: 30px; }
2359
+ .wn-continue { width: min(320px, 100%); padding: 13px 18px; border: 0; border-radius: 14px; background: var(--accent); color: var(--accent-ink); font: inherit; font-size: 15px; font-weight: 650; cursor: pointer; }
2360
+ .wn-continue:hover { filter: brightness(1.06); }
2361
+ .wn-continue:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
2362
+ .wn-changes { font-size: 13px; color: var(--text-2); text-decoration: none; }
2363
+ .wn-changes:hover { color: var(--text); text-decoration: underline; }
2364
+ @media (max-width: 520px) { .wn-sheet { padding: 30px 22px 22px; border-radius: 22px; } }
2365
+
2366
+ /* ---------- First contact: the tour on the room itself ----------
2367
+ The dialog covers the window and is transparent; the spot is a hole of light in a dark veil,
2368
+ drawn as the spot's own shadow, and it glides from one stop to the next. The card is the same
2369
+ sheet as What's new: the product speaking, in the room's own ground and type. */
2370
+ dialog.tour { position: fixed; inset: 0; width: 100vw; height: 100dvh; max-width: none; max-height: none; margin: 0; padding: 0; border: 0; background: transparent; overflow: hidden; color: var(--text); }
2371
+ dialog.tour::backdrop { background: transparent; }
2372
+ .tour-spot {
2373
+ position: absolute; border-radius: 16px; pointer-events: none;
2374
+ box-shadow: 0 0 0 9999px rgba(0, 0, 0, .62), 0 0 0 2px var(--accent), 0 0 24px color-mix(in srgb, var(--accent) 45%, transparent);
2375
+ transition: left .45s cubic-bezier(.2, .8, .2, 1), top .45s cubic-bezier(.2, .8, .2, 1), width .45s cubic-bezier(.2, .8, .2, 1), height .45s cubic-bezier(.2, .8, .2, 1), opacity .25s;
2376
+ }
2377
+ .tour-spot.none { left: 50% !important; top: 50% !important; width: 0 !important; height: 0 !important; box-shadow: 0 0 0 9999px rgba(0, 0, 0, .62); }
2378
+ .tour-card {
2379
+ position: absolute; width: min(360px, calc(100vw - 32px)); box-sizing: border-box; padding: 22px 22px 16px;
2380
+ border-radius: 20px; background: var(--panel); border: 1px solid var(--line-2); box-shadow: 0 24px 70px rgba(0, 0, 0, .45);
2381
+ transition: left .45s cubic-bezier(.2, .8, .2, 1), top .45s cubic-bezier(.2, .8, .2, 1);
2382
+ }
2383
+ @media (prefers-reduced-motion: reduce) { .tour-spot, .tour-card { transition: none; } }
2384
+ .tour-count { font-family: var(--mono); font-size: 10px; letter-spacing: .2em; color: var(--text-3); text-transform: uppercase; }
2385
+ .tour-card h3 { margin: 8px 0 8px; font-size: 18px; font-weight: 700; line-height: 1.25; }
2386
+ .tour-card p { margin: 0; font-size: 14px; line-height: 1.55; color: var(--text-2); }
2387
+ .tour-card .tour-note { margin-top: 10px; font-size: 12.5px; color: var(--text-3); }
2388
+ .tour-foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 18px; }
2389
+ .tour-nav { display: inline-flex; gap: 8px; }
2390
+ .tour-card button { font: inherit; font-size: 13.5px; border-radius: 11px; cursor: pointer; padding: 8px 14px; }
2391
+ .tour-skip { border: 0; background: transparent; color: var(--text-3); padding-left: 0 !important; }
2392
+ .tour-skip:hover { color: var(--text); }
2393
+ .tour-back { border: 1px solid var(--line-2); background: transparent; color: var(--text); }
2394
+ .tour-next { border: 0; background: var(--accent); color: var(--accent-ink); font-weight: 650 !important; }
2395
+ .tour-next:focus-visible, .tour-back:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
2396
+
2397
+ /* The modes, in order and in their own colours: the same chip the composer wears. */
2398
+ .tour-modes { list-style: none; margin: 12px 0 0; padding: 0; display: grid; gap: 8px; }
2399
+ .tour-modes li { display: grid; grid-template-columns: 104px minmax(0, 1fr); gap: 10px; align-items: start; }
2400
+ .tour-mode { display: inline-flex; align-items: center; gap: 5px; justify-self: start; padding: 3px 8px; border-radius: 999px; font-family: var(--mono); font-size: 10.5px; letter-spacing: .08em; white-space: nowrap; }
2401
+ .tour-mode b { font-weight: 700; }
2402
+ .tour-mode.m0 { background: var(--mode-0); color: var(--mode-0-ink); }
2403
+ .tour-mode.m1 { background: var(--mode-1); color: var(--mode-1-ink); }
2404
+ .tour-mode.m2 { background: var(--mode-2); color: var(--mode-2-ink); }
2405
+ .tour-mode.m3 { background: var(--mode-3); color: var(--mode-3-ink); }
2406
+ .tour-mode.m4 { background: var(--mode-4); color: var(--mode-4-ink); }
2407
+ .tour-modes .what { font-size: 12.5px; line-height: 1.45; color: var(--text-2); }
2408
+ .tour-modes li.start .what { color: var(--text); }
2409
+
2410
+ /* First touch: a card under a button that has never been pressed, saying what it opens. */
2411
+ .hint-card {
2412
+ position: fixed; z-index: 2147483000; width: min(320px, calc(100vw - 24px)); box-sizing: border-box; padding: 16px 18px 14px;
2413
+ border-radius: 16px; background: var(--panel); color: var(--text); border: 1px solid var(--line-2);
2414
+ box-shadow: 0 18px 50px rgba(0, 0, 0, .4); animation: wn-in .3s cubic-bezier(.2, .8, .2, 1);
2415
+ }
2416
+ .hint-card.beside::before { content: none; }
2417
+ .hint-card::before {
2418
+ content: ''; position: absolute; top: -7px; left: calc(var(--arrow, 24px) - 6px); width: 12px; height: 12px;
2419
+ background: var(--panel); border-left: 1px solid var(--line-2); border-top: 1px solid var(--line-2); transform: rotate(45deg);
2420
+ }
2421
+ @media (prefers-reduced-motion: reduce) { .hint-card { animation: none; } }
2422
+ .hint-card h3 { margin: 0 0 6px; font-size: 15px; font-weight: 700; }
2423
+ .hint-card p { margin: 0; font-size: 13.5px; line-height: 1.5; color: var(--text-2); }
2424
+ .hint-ok { margin-top: 12px; border: 0; border-radius: 10px; padding: 7px 14px; background: var(--accent); color: var(--accent-ink); font: inherit; font-size: 13px; font-weight: 650; cursor: pointer; }
2425
+ .hint-ok:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
2426
+
2427
+ /* A link inside a fold's header: text in the header's own voice, a step dimmer, that does
2428
+ something without opening or closing the fold. */
2429
+ .mother-section .fold > summary .fold-link { border: 0; background: transparent; padding: 2px 0 2px 10px; margin-left: 2px; border-left: 1px solid var(--ph-faint); font-family: var(--mono); font-size: 10px; letter-spacing: .2em; color: var(--ph-dim); cursor: pointer; }
2430
+ .mother-section .fold > summary .fold-link:hover, .mother-section .fold > summary .fold-link:focus-visible { color: var(--ph); }
2431
+
2432
+ /* /module's ideas: a grid of small cards under the command, each with its mark and the shape of
2433
+ module it would be, in that shape's colour. The command row and the hint keep the full width. */
2434
+ .slash-menu.with-starters { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; min-width: min(560px, 92vw); }
2435
+ .slash-menu.with-starters > .item:not(.starter), .slash-menu.with-starters > .hint { grid-column: 1 / -1; }
2436
+ .slash-menu .item.starter {
2437
+ display: grid; grid-template-columns: 22px minmax(0, 1fr); grid-template-rows: auto auto; gap: 6px 10px; align-items: start;
2438
+ padding: 10px 12px; border-radius: 12px; border: 1px solid var(--line); background: color-mix(in srgb, var(--bg) 35%, transparent);
2439
+ --shape: var(--phosphor);
2440
+ }
2441
+ .slash-menu .item.starter[aria-selected="true"], .slash-menu .item.starter:hover { border-color: color-mix(in srgb, var(--shape) 55%, transparent); background: color-mix(in srgb, var(--shape) 10%, transparent); }
2442
+ .slash-menu .item.starter .starter-icon { grid-row: 1 / 3; width: 18px; height: 18px; margin-top: 2px; color: var(--shape); }
2443
+ .slash-menu .item.starter .idea { font-size: 12.5px; line-height: 1.4; color: var(--text); text-align: left; }
2444
+ .slash-menu .item.starter .shape { justify-self: start; font-family: var(--mono); font-size: 9.5px; letter-spacing: .12em; text-transform: uppercase; padding: 2px 7px; border-radius: 999px; color: var(--shape); border: 1px solid color-mix(in srgb, var(--shape) 45%, transparent); }
2445
+ .slash-menu .item.starter:has(.shape.connector) { --shape: var(--module-electric); }
2446
+ .slash-menu .item.starter:has(.shape.sends) { --shape: var(--mode-4); }
2447
+ .slash-menu .item.starter:has(.shape.card) { --shape: var(--mode-2); }
2448
+ :root[data-scheme="light"] .slash-menu .item.starter:has(.shape.command) { --shape: #178f0c; }
2449
+ :root[data-scheme="light"] .slash-menu .item.starter:has(.shape.sends) { --shape: #1f6f9e; }
2450
+ :root[data-scheme="light"] .slash-menu .item.starter:has(.shape.card) { --shape: #9a6400; }
2451
+ @media (max-width: 560px) { .slash-menu.with-starters { grid-template-columns: minmax(0, 1fr); } }