| @@ -275,9 +275,13 @@ | ||
| 275 | 275 | background: var( |
| 276 | 276 | --os-media-tile-bg, |
| 277 | 277 | rgba( 0, 0, 0, 0.05 ) |
| 278 | 278 | ); |
| 279 | - box-shadow: inset 0 0 0 1px rgba( 0, 0, 0, 0.12 ); | |
| 279 | + /* The hairline was a flat 12%-alpha black — right on the pre-brand | |
| 280 | + * white canvas, and nothing at all on a dark one, where a black | |
| 281 | + * line over a near-black surface leaves the photo edgeless. It | |
| 282 | + * follows the border token now, so it inverts with the theme. */ | |
| 283 | + box-shadow: inset 0 0 0 1px var( --os-ui-border, rgba( 0, 0, 0, 0.12 ) ); | |
| 280 | 284 | } |
| 281 | 285 | |
| 282 | 286 | /* Banded list views. A section can split its tiles into labelled |
| 283 | 287 | * bands (WooCommerce Orders groups by status, needs-attention first) |
| @@ -406,9 +410,12 @@ | ||
| 406 | 410 | 0 1px 3px rgba( 0, 0, 0, 0.35 ); |
| 407 | 411 | pointer-events: none; |
| 408 | 412 | } |
| 409 | 413 | |
| 410 | -/* Tooltip lock banner — shown above the excerpt when present. */ | |
| 414 | +/* Hover-card lock banner — shown above the excerpt when present. The | |
| 415 | + * wash was a fixed 8%-alpha red, which on a dark card was a smear too | |
| 416 | + * faint to read as a banner at all; it follows the badge-danger token | |
| 417 | + * now, so it lands at the alpha the active theme picked. */ | |
| 411 | 418 | .os-my-wordpress__tooltip-lock { |
| 412 | 419 | display: flex; |
| 413 | 420 | align-items: center; |
| 414 | 421 | gap: 6px; |
| @@ -414,9 +421,12 @@ | ||
| 414 | 421 | gap: 6px; |
| 415 | 422 | margin: 0 0 8px; |
| 416 | 423 | padding: 6px 8px; |
| 417 | 424 | border-radius: 4px; |
| 418 | - background: rgba( 179, 45, 46, 0.08 ); | |
| 425 | + background: var( | |
| 426 | + --os-my-wordpress-card-lock-bg, | |
| 427 | + rgba( 179, 45, 46, 0.08 ) | |
| 428 | + ); | |
| 419 | 429 | color: var( --os-danger, var( --os-ui-danger, #b32d2e ) ); |
| 420 | 430 | font-size: 12px; |
| 421 | 431 | font-weight: 600; |
| 422 | 432 | } |
| @@ -701,9 +711,23 @@ | ||
| 701 | 711 | .os-my-wordpress__error { |
| 702 | 712 | color: var( --os-danger, var( --os-ui-danger, #b32d2e ) ); |
| 703 | 713 | } |
| 704 | 714 | |
| 705 | -/* ----- Hover tooltip (floats over body) ----- */ | |
| 715 | +/* ----- Hover card (floats over body) ----- | |
| 716 | + * | |
| 717 | + * The card is summoned from a tile and belongs to the window that | |
| 718 | + * tile is in, so it follows the active desktop theme rather than the | |
| 719 | + * shell's tooltip chip. Every colour chains | |
| 720 | + * `--os-my-wordpress-card-*` first — derived in `variables.css` from | |
| 721 | + * the window family, so a theme that repaints the window repaints the | |
| 722 | + * card with it — then the chip tokens, then the pre-brand literal. | |
| 723 | + * | |
| 724 | + * It is appended to `document.body`, not to the window, because it is | |
| 725 | + * `position: fixed` and a window with `overflow: hidden` would clip | |
| 726 | + * it. Theme tokens still reach it: a desktop theme declares on | |
| 727 | + * `body.os-desktop-theme-<slug>`, an ancestor of both. What does NOT | |
| 728 | + * reach it is anything scoped to `.desktop-mode-my-wordpress`, which | |
| 729 | + * is why the card family is declared at palette level. */ | |
| 706 | 730 | |
| 707 | 731 | .os-my-wordpress__tooltip { |
| 708 | 732 | position: fixed; |
| 709 | 733 | z-index: 100000; |
| @@ -708,19 +732,28 @@ | ||
| 708 | 732 | position: fixed; |
| 709 | 733 | z-index: 100000; |
| 710 | 734 | max-width: 320px; |
| 711 | 735 | background: var( |
| 712 | - --os-tooltip-bg, | |
| 713 | - var( --os-surface, var( --os-ui-surface, #fff ) ) | |
| 736 | + --os-my-wordpress-card-bg, | |
| 737 | + var( | |
| 738 | + --os-tooltip-bg, | |
| 739 | + var( --os-surface, var( --os-ui-surface, #fff ) ) | |
| 740 | + ) | |
| 714 | 741 | ); |
| 715 | 742 | color: var( |
| 716 | - --os-tooltip-fg, | |
| 717 | - var( --os-fg, #1d2327 ) | |
| 743 | + --os-my-wordpress-card-fg, | |
| 744 | + var( --os-tooltip-fg, var( --os-fg, #1d2327 ) ) | |
| 718 | 745 | ); |
| 719 | - border: 1px solid var( --os-ui-border, #dcdcde ); | |
| 746 | + /* The card lands on the same colour as the window under it — the | |
| 747 | + * border and the shadow are the only reason it reads as a separate | |
| 748 | + * object, so neither is decoration. */ | |
| 749 | + border: 1px solid var( --os-my-wordpress-card-border, #dcdcde ); | |
| 720 | 750 | border-radius: 6px; |
| 721 | 751 | padding: 12px; |
| 722 | - box-shadow: 0 6px 24px rgba( 0, 0, 0, 0.18 ); | |
| 752 | + box-shadow: var( | |
| 753 | + --os-my-wordpress-card-shadow, | |
| 754 | + 0 6px 24px rgba( 0, 0, 0, 0.18 ) | |
| 755 | + ); | |
| 723 | 756 | font-size: 12px; |
| 724 | 757 | pointer-events: none; |
| 725 | 758 | } |
| 726 | 759 | |
| @@ -729,8 +762,12 @@ | ||
| 729 | 762 | margin-bottom: 6px; |
| 730 | 763 | font-size: 13px; |
| 731 | 764 | } |
| 732 | 765 | |
| 766 | +/* Same neutral well the entry and media tiles give their thumbnails: | |
| 767 | + * a transparent PNG or a still-loading image would otherwise show the | |
| 768 | + * card straight through, and a photo whose edge matches the card | |
| 769 | + * would have no boundary. */ | |
| 733 | 770 | .os-my-wordpress__tooltip-thumb { |
| 734 | 771 | display: block; |
| 735 | 772 | max-width: 100%; |
| 736 | 773 | height: auto; |
| @@ -735,13 +772,18 @@ | ||
| 735 | 772 | max-width: 100%; |
| 736 | 773 | height: auto; |
| 737 | 774 | border-radius: 4px; |
| 738 | 775 | margin: 6px 0; |
| 776 | + background: var( --os-my-wordpress-card-thumb-bg, rgba( 0, 0, 0, 0.05 ) ); | |
| 777 | + box-shadow: inset 0 0 0 1px var( | |
| 778 | + --os-my-wordpress-card-border, | |
| 779 | + #dcdcde | |
| 780 | + ); | |
| 739 | 781 | } |
| 740 | 782 | |
| 741 | 783 | .os-my-wordpress__tooltip-excerpt { |
| 742 | 784 | margin: 0; |
| 743 | - color: var( --os-ui-fg-muted, #50575e ); | |
| 785 | + color: var( --os-my-wordpress-card-fg-muted, #50575e ); | |
| 744 | 786 | line-height: 1.4; |
| 745 | 787 | } |
| 746 | 788 | |
| 747 | 789 | /* ----- Context menu host ----- */ |
| @@ -804,9 +846,9 @@ | ||
| 804 | 846 | font-size: 11px; |
| 805 | 847 | font-weight: 600; |
| 806 | 848 | text-transform: uppercase; |
| 807 | 849 | letter-spacing: 0.04em; |
| 808 | - background: rgba( 34, 113, 177, 0.12 ); | |
| 850 | + background: color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 12%, transparent ); | |
| 809 | 851 | color: var( --wp-admin-theme-color, #2271b1 ); |
| 810 | 852 | } |
| 811 | 853 | |
| 812 | 854 | .os-my-wordpress__user-links { |
| @@ -909,9 +951,9 @@ | ||
| 909 | 951 | .os-my-wordpress__user-spark-bar { |
| 910 | 952 | background: linear-gradient( |
| 911 | 953 | 180deg, |
| 912 | 954 | var( --wp-admin-theme-color, #2271b1 ) 0%, |
| 913 | - rgba( 34, 113, 177, 0.55 ) 100% | |
| 955 | + color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 55%, transparent ) 100% | |
| 914 | 956 | ); |
| 915 | 957 | border-radius: 3px 3px 0 0; |
| 916 | 958 | min-height: 2px; |
| 917 | 959 | transition: height 0.3s ease; |
| @@ -1045,9 +1087,9 @@ | ||
| 1045 | 1087 | } |
| 1046 | 1088 | |
| 1047 | 1089 | .os-my-wordpress__term-icon--category { |
| 1048 | 1090 | background: linear-gradient( 135deg, var( --os-ui-accent, #2271b1 ) 0%, var( --os-ui-accent-strong, #135e96 ) 100% ); |
| 1049 | - box-shadow: 0 4px 12px rgba( 34, 113, 177, 0.32 ); | |
| 1091 | + box-shadow: 0 4px 12px color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 32%, transparent ); | |
| 1050 | 1092 | } |
| 1051 | 1093 | |
| 1052 | 1094 | .os-my-wordpress__term-icon--tag { |
| 1053 | 1095 | background: linear-gradient( 135deg, #7c3aed 0%, #5b21b6 100% ); |
| @@ -1054,9 +1096,9 @@ | ||
| 1054 | 1096 | box-shadow: 0 4px 12px rgba( 124, 58, 237, 0.32 ); |
| 1055 | 1097 | } |
| 1056 | 1098 | |
| 1057 | 1099 | .os-my-wordpress__user-role--category { |
| 1058 | - background: rgba( 34, 113, 177, 0.12 ); | |
| 1100 | + background: color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 12%, transparent ); | |
| 1059 | 1101 | color: var( --os-ui-accent-strong, #135e96 ); |
| 1060 | 1102 | } |
| 1061 | 1103 | |
| 1062 | 1104 | .os-my-wordpress__user-role--tag { |
| @@ -1116,9 +1158,9 @@ | ||
| 1116 | 1158 | * for users with moderate_comments. |
| 1117 | 1159 | * --------------------------------------------------------------- */ |
| 1118 | 1160 | |
| 1119 | 1161 | .os-my-wordpress__comment-status--approved { |
| 1120 | - background: rgba( 34, 113, 177, 0.12 ); | |
| 1162 | + background: color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 12%, transparent ); | |
| 1121 | 1163 | color: var( --os-ui-accent-strong, #135e96 ); |
| 1122 | 1164 | } |
| 1123 | 1165 | |
| 1124 | 1166 | .os-my-wordpress__comment-status--pending { |
| @@ -1149,9 +1191,9 @@ | ||
| 1149 | 1191 | .os-my-wordpress__comment-quote { |
| 1150 | 1192 | margin: 0 0 16px; |
| 1151 | 1193 | padding: 10px 14px; |
| 1152 | 1194 | border-left: 3px solid var( --wp-admin-theme-color, #2271b1 ); |
| 1153 | - background: rgba( 34, 113, 177, 0.06 ); | |
| 1195 | + background: color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 6%, transparent ); | |
| 1154 | 1196 | border-radius: 0 6px 6px 0; |
| 1155 | 1197 | font-size: 13px; |
| 1156 | 1198 | } |
| 1157 | 1199 | |
| @@ -1294,10 +1336,10 @@ | ||
| 1294 | 1336 | border-radius: 50%; |
| 1295 | 1337 | overflow: hidden; |
| 1296 | 1338 | background: linear-gradient( |
| 1297 | 1339 | 135deg, |
| 1298 | - rgba( 34, 113, 177, 0.18 ), | |
| 1299 | - rgba( 34, 113, 177, 0.04 ) | |
| 1340 | + color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 18%, transparent ), | |
| 1341 | + color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 4%, transparent ) | |
| 1300 | 1342 | ); |
| 1301 | 1343 | box-shadow: |
| 1302 | 1344 | inset 0 0 0 1px rgba( 0, 0, 0, 0.08 ), |
| 1303 | 1345 | 0 2px 6px rgba( 0, 0, 0, 0.08 ); |
| @@ -1418,10 +1460,10 @@ | ||
| 1418 | 1460 | padding: 24px; |
| 1419 | 1461 | border-radius: 16px; |
| 1420 | 1462 | background: linear-gradient( |
| 1421 | 1463 | 135deg, |
| 1422 | - rgba( 34, 113, 177, 0.10 ) 0%, | |
| 1423 | - rgba( 34, 113, 177, 0.02 ) 60%, | |
| 1464 | + color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 10%, transparent ) 0%, | |
| 1465 | + color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 2%, transparent ) 60%, | |
| 1424 | 1466 | transparent 100% |
| 1425 | 1467 | ); |
| 1426 | 1468 | border: 1px solid var( --os-ui-border, #dcdcde ); |
| 1427 | 1469 | } |
| @@ -1436,10 +1478,10 @@ | ||
| 1436 | 1478 | inset 0 0 0 2px rgba( 255, 255, 255, 0.8 ), |
| 1437 | 1479 | 0 6px 24px rgba( 0, 0, 0, 0.14 ); |
| 1438 | 1480 | background: linear-gradient( |
| 1439 | 1481 | 135deg, |
| 1440 | - rgba( 34, 113, 177, 0.18 ), | |
| 1441 | - rgba( 34, 113, 177, 0.04 ) | |
| 1482 | + color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 18%, transparent ), | |
| 1483 | + color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 4%, transparent ) | |
| 1442 | 1484 | ); |
| 1443 | 1485 | display: inline-flex; |
| 1444 | 1486 | align-items: center; |
| 1445 | 1487 | justify-content: center; |
| @@ -1571,17 +1613,17 @@ | ||
| 1571 | 1613 | background: var( --os-ui-hover, rgba( 0, 0, 0, 0.06 ) ); |
| 1572 | 1614 | } |
| 1573 | 1615 | |
| 1574 | 1616 | .os-my-wordpress__footprint-cell--l1 { |
| 1575 | - background: rgba( 34, 113, 177, 0.25 ); | |
| 1617 | + background: color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 25%, transparent ); | |
| 1576 | 1618 | } |
| 1577 | 1619 | |
| 1578 | 1620 | .os-my-wordpress__footprint-cell--l2 { |
| 1579 | - background: rgba( 34, 113, 177, 0.5 ); | |
| 1621 | + background: color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 50%, transparent ); | |
| 1580 | 1622 | } |
| 1581 | 1623 | |
| 1582 | 1624 | .os-my-wordpress__footprint-cell--l3 { |
| 1583 | - background: rgba( 34, 113, 177, 0.75 ); | |
| 1625 | + background: color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 75%, transparent ); | |
| 1584 | 1626 | } |
| 1585 | 1627 | |
| 1586 | 1628 | .os-my-wordpress__footprint-cell--l4 { |
| 1587 | 1629 | background: var( --wp-admin-theme-color, #2271b1 ); |
| @@ -1651,9 +1693,9 @@ | ||
| 1651 | 1693 | .os-my-wordpress__footprint-bar { |
| 1652 | 1694 | background: linear-gradient( |
| 1653 | 1695 | 180deg, |
| 1654 | 1696 | var( --wp-admin-theme-color, #2271b1 ) 0%, |
| 1655 | - rgba( 34, 113, 177, 0.55 ) 100% | |
| 1697 | + color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 55%, transparent ) 100% | |
| 1656 | 1698 | ); |
| 1657 | 1699 | border-radius: 3px 3px 0 0; |
| 1658 | 1700 | min-height: 2px; |
| 1659 | 1701 | transition: opacity 0.2s ease; |
| @@ -1685,10 +1727,10 @@ | ||
| 1685 | 1727 | text-align: center; |
| 1686 | 1728 | padding: 20px 24px; |
| 1687 | 1729 | background: linear-gradient( |
| 1688 | 1730 | 135deg, |
| 1689 | - rgba( 34, 113, 177, 0.10 ), | |
| 1690 | - rgba( 34, 113, 177, 0.02 ) | |
| 1731 | + color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 10%, transparent ), | |
| 1732 | + color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 2%, transparent ) | |
| 1691 | 1733 | ); |
| 1692 | 1734 | } |
| 1693 | 1735 | |
| 1694 | 1736 | .os-my-wordpress__footprint-callout-label { |
| @@ -2113,17 +2155,8 @@ | ||
| 2113 | 2155 | overflow: hidden; |
| 2114 | 2156 | box-sizing: border-box; |
| 2115 | 2157 | } |
| 2116 | 2158 | |
| 2117 | -/* The framework is opt-in but the section is always listed, so with | |
| 2118 | - the option off the surface paints inert rather than vanishing. | |
| 2119 | - Only the sidebar dims: the detail pane holds the empty state | |
| 2120 | - explaining why, and the one button that undoes it — dimming the way | |
| 2121 | - out along with everything else is how a disabled screen becomes a | |
| 2122 | - dead end. */ | |
| 2123 | -.dm-agents.is-disabled .dm-agents__sidebar { | |
| 2124 | - opacity: 0.6; | |
| 2125 | -} | |
| 2126 | 2159 | |
| 2127 | 2160 | /* Section-level loading — same scale curve as the My WordPress |
| 2128 | 2161 | preview loader and the window-loading overlay, instead of the bare |
| 2129 | 2162 | 48px component default. */ |
| @@ -2138,103 +2171,8 @@ | ||
| 2138 | 2171 | .dm-agents__loading os-spinner { |
| 2139 | 2172 | --os-ui-spinner-size: clamp( 96px, 14vw, 192px ); |
| 2140 | 2173 | } |
| 2141 | 2174 | |
| 2142 | -.dm-agents__layout { | |
| 2143 | - display: flex; | |
| 2144 | - flex: 1; | |
| 2145 | - min-height: 0; | |
| 2146 | - gap: 12px; | |
| 2147 | -} | |
| 2148 | - | |
| 2149 | -/* Sidebar column: a fixed "Create agent" header over the scrolling | |
| 2150 | - list. The button used to be the list's last child, which put it out | |
| 2151 | - of reach on any site with enough agents to need it. */ | |
| 2152 | -.dm-agents__sidebar { | |
| 2153 | - display: flex; | |
| 2154 | - flex-direction: column; | |
| 2155 | - flex: 0 0 260px; | |
| 2156 | - /* `min-width: auto` on a flex item resolves to its min-content | |
| 2157 | - width, and the rows carry long `white-space: nowrap` descriptions | |
| 2158 | - — without this the column ignores its 260px basis and eats the | |
| 2159 | - detail pane. The scroll container used to be this item, whose | |
| 2160 | - non-visible overflow zeroed the minimum for free. */ | |
| 2161 | - min-width: 0; | |
| 2162 | - min-height: 0; | |
| 2163 | - border-inline-end: 1px solid var( --os-border, rgba( 0, 0, 0, 0.08 ) ); | |
| 2164 | -} | |
| 2165 | - | |
| 2166 | -.dm-agents__list-toolbar { | |
| 2167 | - flex: none; | |
| 2168 | - display: flex; | |
| 2169 | - padding-block-end: 8px; | |
| 2170 | - padding-inline-end: 8px; | |
| 2171 | -} | |
| 2172 | - | |
| 2173 | -.dm-agents__list-toolbar .dm-agents__create { | |
| 2174 | - flex: 1; | |
| 2175 | -} | |
| 2176 | - | |
| 2177 | -.dm-agents__list { | |
| 2178 | - display: flex; | |
| 2179 | - flex-direction: column; | |
| 2180 | - gap: 4px; | |
| 2181 | - flex: 1; | |
| 2182 | - min-height: 0; | |
| 2183 | - overflow-y: auto; | |
| 2184 | - padding-inline-end: 4px; | |
| 2185 | -} | |
| 2186 | - | |
| 2187 | -.dm-agents__row { | |
| 2188 | - display: flex; | |
| 2189 | - align-items: center; | |
| 2190 | - gap: 8px; | |
| 2191 | - padding: 8px; | |
| 2192 | - border-radius: 8px; | |
| 2193 | - cursor: pointer; | |
| 2194 | -} | |
| 2195 | - | |
| 2196 | -.dm-agents__row:hover { | |
| 2197 | - background: var( --os-hover, rgba( 0, 0, 0, 0.06 ) ); | |
| 2198 | -} | |
| 2199 | - | |
| 2200 | -.dm-agents__row.is-selected { | |
| 2201 | - background: var( --os-selected, rgba( 0, 0, 0, 0.1 ) ); | |
| 2202 | -} | |
| 2203 | - | |
| 2204 | -.dm-agents__row-avatar { | |
| 2205 | - width: 32px; | |
| 2206 | - height: 32px; | |
| 2207 | - border-radius: 50%; | |
| 2208 | - /* Placeholder behind the avatar image while it loads — follows the | |
| 2209 | - palette so it isn't a white disc on a dark station. */ | |
| 2210 | - background: var( --os-ui-surface-elevated, #fff ); | |
| 2211 | - flex: none; | |
| 2212 | -} | |
| 2213 | - | |
| 2214 | -.dm-agents__row-text { | |
| 2215 | - display: flex; | |
| 2216 | - flex-direction: column; | |
| 2217 | - min-width: 0; | |
| 2218 | - flex: 1; | |
| 2219 | -} | |
| 2220 | - | |
| 2221 | -.dm-agents__row-name { | |
| 2222 | - font-weight: 600; | |
| 2223 | - white-space: nowrap; | |
| 2224 | - overflow: hidden; | |
| 2225 | - text-overflow: ellipsis; | |
| 2226 | -} | |
| 2227 | - | |
| 2228 | -.dm-agents__row-desc { | |
| 2229 | - font-size: 12px; | |
| 2230 | - opacity: 0.65; | |
| 2231 | - white-space: nowrap; | |
| 2232 | - overflow: hidden; | |
| 2233 | - text-overflow: ellipsis; | |
| 2234 | -} | |
| 2235 | - | |
| 2236 | - | |
| 2237 | 2175 | .dm-agents__detail { |
| 2238 | 2176 | flex: 1; |
| 2239 | 2177 | min-width: 0; |
| 2240 | 2178 | overflow-y: auto; |
| @@ -2343,31 +2281,156 @@ | ||
| 2343 | 2281 | font-size: 12px; |
| 2344 | 2282 | opacity: 0.7; |
| 2345 | 2283 | } |
| 2346 | 2284 | |
| 2285 | +/* Role first: least privilege is the decision, so the control holds | |
| 2286 | + the mockup's width instead of stretching into a landing strip. */ | |
| 2287 | +.dm-agents__role-select { | |
| 2288 | + max-width: 280px; | |
| 2289 | +} | |
| 2290 | + | |
| 2291 | +/* The ability filter. Sized like the role select rather than the | |
| 2292 | + full pane: it sits above a list of rules, and a search box as wide | |
| 2293 | + as the rules reads as another one of them. */ | |
| 2294 | +.dm-agents__ability-search { | |
| 2295 | + display: block; | |
| 2296 | + max-width: 320px; | |
| 2297 | + margin: 12px 0 4px; | |
| 2298 | +} | |
| 2299 | + | |
| 2300 | +/* Each category is a native disclosure. `<details>` because the | |
| 2301 | + behaviour is exactly what it is for: keyboard, screen-reader | |
| 2302 | + semantics and the open/closed state all arrive for free, and the | |
| 2303 | + only thing left to write is the costume. */ | |
| 2304 | +.dm-agents__ability-group { | |
| 2305 | + border-bottom: 1px solid var( --os-border, rgba( 0, 0, 0, 0.08 ) ); | |
| 2306 | +} | |
| 2307 | + | |
| 2308 | +.dm-agents__ability-group:last-of-type { | |
| 2309 | + border-bottom: 0; | |
| 2310 | +} | |
| 2311 | + | |
| 2347 | 2312 | .dm-agents__category { |
| 2348 | - margin: 8px 0 0; | |
| 2349 | - font-size: 12px; | |
| 2313 | + margin: 18px 0 2px; | |
| 2314 | + font-family: var( --os-ui-font-mono, ui-monospace, monospace ); | |
| 2315 | + font-size: 11px; | |
| 2316 | + font-weight: 500; | |
| 2350 | 2317 | text-transform: uppercase; |
| 2351 | - letter-spacing: 0.04em; | |
| 2352 | - opacity: 0.6; | |
| 2318 | + letter-spacing: 0.08em; | |
| 2319 | + color: var( --os-ui-fg-muted, #646970 ); | |
| 2353 | 2320 | } |
| 2354 | 2321 | |
| 2322 | +/* A `<summary>` is a button, so it gets a button's affordances: a | |
| 2323 | + pointer, a hover, and a focus ring that is visible on the dark | |
| 2324 | + surface the section is drawn on. */ | |
| 2325 | +summary.dm-agents__category { | |
| 2326 | + display: flex; | |
| 2327 | + align-items: center; | |
| 2328 | + gap: 8px; | |
| 2329 | + margin: 0; | |
| 2330 | + padding: 10px 0; | |
| 2331 | + cursor: pointer; | |
| 2332 | + list-style: none; | |
| 2333 | + user-select: none; | |
| 2334 | +} | |
| 2335 | + | |
| 2336 | +summary.dm-agents__category::-webkit-details-marker { | |
| 2337 | + display: none; | |
| 2338 | +} | |
| 2339 | + | |
| 2340 | +/* The marker is drawn here rather than left to the UA so it can be | |
| 2341 | + the same triangle in every browser and turn with the disclosure. | |
| 2342 | + Rotation only: a transform, so opening a group of forty rows | |
| 2343 | + costs no layout. */ | |
| 2344 | +summary.dm-agents__category::before { | |
| 2345 | + content: ''; | |
| 2346 | + flex: none; | |
| 2347 | + width: 0; | |
| 2348 | + height: 0; | |
| 2349 | + border-inline-start: 5px solid currentcolor; | |
| 2350 | + border-block: 4px solid transparent; | |
| 2351 | + transition: transform 120ms ease; | |
| 2352 | +} | |
| 2353 | + | |
| 2354 | +.dm-agents__ability-group[ open ] > summary.dm-agents__category::before { | |
| 2355 | + transform: rotate( 90deg ); | |
| 2356 | +} | |
| 2357 | + | |
| 2358 | +@media ( prefers-reduced-motion: reduce ) { | |
| 2359 | + summary.dm-agents__category::before { | |
| 2360 | + transition: none; | |
| 2361 | + } | |
| 2362 | +} | |
| 2363 | + | |
| 2364 | +summary.dm-agents__category:hover { | |
| 2365 | + color: var( --os-ui-fg, #1e1e1e ); | |
| 2366 | +} | |
| 2367 | + | |
| 2368 | +summary.dm-agents__category:focus-visible { | |
| 2369 | + outline: 2px solid var( --os-ui-accent, #3858e9 ); | |
| 2370 | + outline-offset: 2px; | |
| 2371 | + border-radius: 4px; | |
| 2372 | +} | |
| 2373 | + | |
| 2374 | +.dm-agents__category-name { | |
| 2375 | + flex: 1 1 auto; | |
| 2376 | +} | |
| 2377 | + | |
| 2378 | +/* "3 of 12" when some are ticked, otherwise just the size of the | |
| 2379 | + group. The count is why a closed group is still informative: | |
| 2380 | + collapsing must not hide the fact that something in there is | |
| 2381 | + switched on. */ | |
| 2382 | +.dm-agents__category-count { | |
| 2383 | + flex: none; | |
| 2384 | + font-variant-numeric: tabular-nums; | |
| 2385 | + opacity: 0.75; | |
| 2386 | +} | |
| 2387 | + | |
| 2388 | +/* One ability per row, ruled like the mockup: tick and name on the | |
| 2389 | + left, badge on the right, the description indented under the name | |
| 2390 | + (the checkbox column is the control's own 26px). */ | |
| 2355 | 2391 | .dm-agents__ability { |
| 2356 | 2392 | display: grid; |
| 2357 | 2393 | grid-template-columns: 1fr auto; |
| 2358 | - gap: 2px 8px; | |
| 2359 | - align-items: center; | |
| 2360 | - padding: 4px 0; | |
| 2394 | + gap: 2px 10px; | |
| 2395 | + align-items: start; | |
| 2396 | + padding: 11px 0; | |
| 2397 | + border-bottom: 1px solid var( --os-border, rgba( 0, 0, 0, 0.08 ) ); | |
| 2361 | 2398 | } |
| 2362 | 2399 | |
| 2400 | +.dm-agents__ability:last-of-type { | |
| 2401 | + border-bottom: 0; | |
| 2402 | +} | |
| 2403 | + | |
| 2363 | 2404 | .dm-agents__ability-desc { |
| 2364 | 2405 | grid-column: 1 / -1; |
| 2365 | 2406 | margin: 0; |
| 2366 | - font-size: 12px; | |
| 2367 | - opacity: 0.6; | |
| 2407 | + padding-inline-start: 26px; | |
| 2408 | + font-size: 12.5px; | |
| 2409 | + color: var( --os-ui-fg-muted, #646970 ); | |
| 2368 | 2410 | } |
| 2369 | 2411 | |
| 2412 | +/* Access badges in the instrument voice. The palette's own warning | |
| 2413 | + tokens carry the pale-yellow "can modify"; all this changes is the | |
| 2414 | + costume: mono, uppercase, an outline instead of a wash. */ | |
| 2415 | +.dm-agents__ability os-badge { | |
| 2416 | + --os-ui-badge-font: 500 10px/1.6 var( --os-ui-font-mono, ui-monospace, monospace ); | |
| 2417 | + --os-ui-badge-dot-size: 0; | |
| 2418 | + --os-ui-badge-gap: 0; | |
| 2419 | + --os-ui-badge-padding: 3px 8px; | |
| 2420 | + --os-ui-badge-bg: transparent; | |
| 2421 | + --os-ui-badge-border: 1px solid var( --os-border, rgba( 0, 0, 0, 0.12 ) ); | |
| 2422 | + text-transform: uppercase; | |
| 2423 | + letter-spacing: 0.06em; | |
| 2424 | + white-space: nowrap; | |
| 2425 | + margin-top: 2px; | |
| 2426 | +} | |
| 2427 | + | |
| 2428 | +.dm-agents__ability os-badge[ tone='warning' ] { | |
| 2429 | + --os-ui-badge-border: 1px solid | |
| 2430 | + var( --os-ui-warning-border, rgba( 154, 103, 0, 0.4 ) ); | |
| 2431 | +} | |
| 2432 | + | |
| 2370 | 2433 | .dm-agents__trigger { |
| 2371 | 2434 | border: 1px solid var( --os-border, rgba( 0, 0, 0, 0.08 ) ); |
| 2372 | 2435 | border-radius: 8px; |
| 2373 | 2436 | padding: 8px 10px; |
| @@ -2381,15 +2444,12 @@ | ||
| 2381 | 2444 | align-items: center; |
| 2382 | 2445 | gap: 8px; |
| 2383 | 2446 | } |
| 2384 | 2447 | |
| 2385 | -.dm-agents__trigger-summary { | |
| 2386 | - flex: 1; | |
| 2448 | +.dm-agents__trigger-desc { | |
| 2449 | + margin: 0; | |
| 2387 | 2450 | font-size: 12px; |
| 2388 | - opacity: 0.65; | |
| 2389 | - white-space: nowrap; | |
| 2390 | - overflow: hidden; | |
| 2391 | - text-overflow: ellipsis; | |
| 2451 | + opacity: 0.75; | |
| 2392 | 2452 | } |
| 2393 | 2453 | |
| 2394 | 2454 | .dm-agents__trigger-config { |
| 2395 | 2455 | display: flex; |
| @@ -2399,5 +2459,496 @@ | ||
| 2399 | 2459 | |
| 2400 | 2460 | .dm-agents__actions { |
| 2401 | 2461 | display: flex; |
| 2402 | 2462 | gap: 8px; |
| 2463 | + align-items: center; | |
| 2464 | + flex-wrap: wrap; | |
| 2465 | + margin-block-start: 12px; | |
| 2466 | +} | |
| 2467 | + | |
| 2468 | +/* --------------------------------------------------------------------- | |
| 2469 | + The cast | |
| 2470 | + ------------------------------------------------------------------ */ | |
| 2471 | + | |
| 2472 | +/* One view at a time: the grid, an agent, or the wizard. A sidebar of | |
| 2473 | + faces next to a detail form would leave neither enough room, and the | |
| 2474 | + whole point of the grid is that the faces are big enough to tell | |
| 2475 | + apart. */ | |
| 2476 | +.dm-agents__view { | |
| 2477 | + display: flex; | |
| 2478 | + flex-direction: column; | |
| 2479 | + flex: 1; | |
| 2480 | + min-height: 0; | |
| 2481 | + overflow-y: auto; | |
| 2482 | + gap: 12px; | |
| 2483 | +} | |
| 2484 | + | |
| 2485 | +.dm-agents__cast-head { | |
| 2486 | + display: flex; | |
| 2487 | + align-items: baseline; | |
| 2488 | + gap: 8px; | |
| 2489 | +} | |
| 2490 | + | |
| 2491 | +.dm-agents__cast-head h3 { | |
| 2492 | + margin: 0; | |
| 2493 | +} | |
| 2494 | + | |
| 2495 | +.dm-agents__cast-count { | |
| 2496 | + font-family: var( --os-ui-font-mono, ui-monospace, monospace ); | |
| 2497 | + font-size: 12px; | |
| 2498 | + color: var( --os-ui-fg-muted, #646970 ); | |
| 2499 | +} | |
| 2500 | + | |
| 2501 | +.dm-agents__cast { | |
| 2502 | + display: grid; | |
| 2503 | + gap: 16px; | |
| 2504 | + grid-template-columns: repeat( auto-fill, minmax( 288px, 1fr ) ); | |
| 2505 | + align-content: start; | |
| 2506 | +} | |
| 2507 | + | |
| 2508 | +/* The card reacts like the mockup's: a lift and a brighter edge. | |
| 2509 | + Transform and border-color only — both cheap, and the same pair the | |
| 2510 | + mockup transitions. Document styles win over the component's own | |
| 2511 | + :host rules, which is the sanctioned way to restyle a host. */ | |
| 2512 | +.dm-agents__cast-card, | |
| 2513 | +.dm-agents__cast-new { | |
| 2514 | + --os-ui-card-padding: 20px 18px 16px; | |
| 2515 | + transition: border-color 0.18s ease, transform 0.18s ease; | |
| 2516 | +} | |
| 2517 | + | |
| 2518 | +.dm-agents__cast-card:hover, | |
| 2519 | +.dm-agents__cast-card:focus-within { | |
| 2520 | + border-color: var( --os-ui-border-strong, #8c8f94 ); | |
| 2521 | + transform: translateY( -2px ); | |
| 2522 | +} | |
| 2523 | + | |
| 2524 | +/* The dashed door, same as the mockup's crew-new card. */ | |
| 2525 | +.dm-agents__cast-new { | |
| 2526 | + border-style: dashed; | |
| 2527 | + --os-ui-card-bg: var( --os-ui-surface-subtle, transparent ); | |
| 2528 | +} | |
| 2529 | + | |
| 2530 | +/* The crew breathes. Transform only, staggered so five faces do not | |
| 2531 | + bob in lockstep, and gone entirely under reduced motion. */ | |
| 2532 | +@media ( prefers-reduced-motion: no-preference ) { | |
| 2533 | + .dm-agents__cast-card .dm-agents__cast-face { | |
| 2534 | + animation: dm-agents-bob 6s ease-in-out infinite; | |
| 2535 | + } | |
| 2536 | + .dm-agents__cast-card:nth-child( 2n ) .dm-agents__cast-face { | |
| 2537 | + animation-duration: 7.2s; | |
| 2538 | + animation-delay: -1.4s; | |
| 2539 | + } | |
| 2540 | + .dm-agents__cast-card:nth-child( 3n ) .dm-agents__cast-face { | |
| 2541 | + animation-duration: 6.6s; | |
| 2542 | + animation-delay: -2.8s; | |
| 2543 | + } | |
| 2544 | +} | |
| 2545 | + | |
| 2546 | +@keyframes dm-agents-bob { | |
| 2547 | + 0%, | |
| 2548 | + 100% { | |
| 2549 | + transform: translateY( 0 ); | |
| 2550 | + } | |
| 2551 | + 50% { | |
| 2552 | + transform: translateY( -4px ); | |
| 2553 | + } | |
| 2554 | +} | |
| 2555 | + | |
| 2556 | +/* The column lives on a wrapper we own, not on the host: the slotted | |
| 2557 | + children sit inside the card's own container, so a flex rule on the | |
| 2558 | + host never reaches them and the role badges land wherever the | |
| 2559 | + description's line count leaves them. */ | |
| 2560 | +.dm-agents__cast-inner { | |
| 2561 | + display: flex; | |
| 2562 | + flex-direction: column; | |
| 2563 | + align-items: center; | |
| 2564 | + text-align: center; | |
| 2565 | + gap: 2px; | |
| 2566 | + height: 100%; | |
| 2567 | +} | |
| 2568 | + | |
| 2569 | +/* The faces are the loud part of this surface, and deliberately so: | |
| 2570 | + agent identity is the one place the station spends the mesh budget | |
| 2571 | + on something other than a hero CTA. A cast has to be legible at a | |
| 2572 | + glance, which is exactly what a flat accent cannot do. */ | |
| 2573 | +.dm-agents__cast-face { | |
| 2574 | + width: 118px; | |
| 2575 | + height: 118px; | |
| 2576 | + margin: -10px 0 6px; | |
| 2577 | + flex: none; | |
| 2578 | +} | |
| 2579 | + | |
| 2580 | +.dm-agents__cast-name { | |
| 2581 | + font-size: 17px; | |
| 2582 | + font-weight: 600; | |
| 2583 | + color: var( --os-ui-fg, #1d2327 ); | |
| 2584 | +} | |
| 2585 | + | |
| 2586 | +/* The voice line, in the instrument register: this is metadata about | |
| 2587 | + the agent, not prose from it. */ | |
| 2588 | +.dm-agents__cast-vibes { | |
| 2589 | + font-family: var( --os-ui-font-mono, ui-monospace, monospace ); | |
| 2590 | + font-size: 11.5px; | |
| 2591 | + color: var( --os-ui-accent-strong, #2271b1 ); | |
| 2592 | +} | |
| 2593 | + | |
| 2594 | +.dm-agents__cast-good { | |
| 2595 | + font-size: 13px; | |
| 2596 | + color: var( --os-ui-fg-muted, #646970 ); | |
| 2597 | + margin-block: 4px 14px; | |
| 2598 | + flex: 1; | |
| 2599 | +} | |
| 2600 | + | |
| 2601 | +/* The role pill in the instrument voice: mono, uppercase, no status | |
| 2602 | + dot — this is a fact about the agent, not a state to monitor. The | |
| 2603 | + custom properties are the component's own theming hooks; the | |
| 2604 | + inherited text properties flow into its shadow label. */ | |
| 2605 | +.dm-agents__cast-card os-badge { | |
| 2606 | + --os-ui-badge-font: 500 11px/1.6 var( --os-ui-font-mono, ui-monospace, monospace ); | |
| 2607 | + --os-ui-badge-dot-size: 0; | |
| 2608 | + --os-ui-badge-gap: 0; | |
| 2609 | + --os-ui-badge-padding: 3px 10px; | |
| 2610 | + text-transform: uppercase; | |
| 2611 | + letter-spacing: 0.08em; | |
| 2612 | +} | |
| 2613 | + | |
| 2614 | +/* The framework-off bar: the section's status and its one action, on | |
| 2615 | + one line above the crew it would hire. It is deliberately not an | |
| 2616 | + `os-empty-state` — that block is centred, icon-led and paragraph- | |
| 2617 | + shaped, which is exactly the wall of text the cast replaced, and at | |
| 2618 | + five cards tall it would push the button that undoes the situation | |
| 2619 | + off the bottom of the window. `flex: none` because `.dm-agents__view` | |
| 2620 | + is a scrolling flex column and the bar must not absorb the slack. */ | |
| 2621 | +.dm-agents__off-head { | |
| 2622 | + display: flex; | |
| 2623 | + align-items: center; | |
| 2624 | + justify-content: space-between; | |
| 2625 | + flex-wrap: wrap; | |
| 2626 | + flex: none; | |
| 2627 | + gap: 8px 16px; | |
| 2628 | + padding: 12px 14px; | |
| 2629 | + border-radius: 10px; | |
| 2630 | + background: var( --os-ui-surface-elevated, #fff ); | |
| 2631 | + border: 1px solid var( --os-border, rgba( 0, 0, 0, 0.08 ) ); | |
| 2632 | +} | |
| 2633 | + | |
| 2634 | +.dm-agents__off-copy { | |
| 2635 | + min-width: 0; | |
| 2636 | +} | |
| 2637 | + | |
| 2638 | +.dm-agents__off-copy h3 { | |
| 2639 | + margin: 0; | |
| 2640 | +} | |
| 2641 | + | |
| 2642 | +.dm-agents__off-copy p { | |
| 2643 | + margin: 2px 0 0; | |
| 2644 | + font-size: 13px; | |
| 2645 | + color: var( --os-ui-fg-muted, #646970 ); | |
| 2646 | +} | |
| 2647 | + | |
| 2648 | +/* The cast the site would get, drawn while the framework is off. | |
| 2649 | + Dimmed as a whole rather than desaturated: the five hues ARE the | |
| 2650 | + argument this state is making, and a greyscale filter would flatten | |
| 2651 | + the crew into five identical blobs on the way to saying "not yet". | |
| 2652 | + Opacity says inactive and leaves the faces telling each other apart. | |
| 2653 | + | |
| 2654 | + `pointer-events` is belt and braces — the cards are rendered without | |
| 2655 | + `interactive` and without a click handler, so there is nothing to | |
| 2656 | + press. It exists so a hover state cannot promise otherwise. */ | |
| 2657 | +.dm-agents__cast--preview { | |
| 2658 | + opacity: 0.6; | |
| 2659 | + pointer-events: none; | |
| 2660 | +} | |
| 2661 | + | |
| 2662 | +.dm-agents__cast-new .dm-agents__cast-plus { | |
| 2663 | + display: grid; | |
| 2664 | + place-items: center; | |
| 2665 | + width: 118px; | |
| 2666 | + height: 118px; | |
| 2667 | + margin: -10px 0 6px; | |
| 2668 | + border-radius: 50%; | |
| 2669 | + border: 1.5px dashed var( --os-ui-border-strong, #8c8f94 ); | |
| 2670 | + font-size: 30px; | |
| 2671 | + font-weight: 300; | |
| 2672 | + line-height: 1; | |
| 2673 | + color: var( --os-ui-fg-muted, #646970 ); | |
| 2674 | +} | |
| 2675 | + | |
| 2676 | +/* --------------------------------------------------------------------- | |
| 2677 | + The wizard | |
| 2678 | + ------------------------------------------------------------------ */ | |
| 2679 | + | |
| 2680 | +.dm-agents__wizard { | |
| 2681 | + display: flex; | |
| 2682 | + flex-direction: column; | |
| 2683 | + gap: 10px; | |
| 2684 | +} | |
| 2685 | + | |
| 2686 | +.dm-agents__wiz-head { | |
| 2687 | + display: flex; | |
| 2688 | + align-items: center; | |
| 2689 | + justify-content: space-between; | |
| 2690 | + gap: 8px 12px; | |
| 2691 | + flex-wrap: wrap; | |
| 2692 | +} | |
| 2693 | + | |
| 2694 | +.dm-agents__wiz-head h3 { | |
| 2695 | + margin: 0; | |
| 2696 | +} | |
| 2697 | + | |
| 2698 | +/* The trail wears the instrument voice: mono uppercase labels, 22px | |
| 2699 | + dots, a thin rule between stations. All of it goes through the | |
| 2700 | + component's own theming hooks; the host elements live in this light | |
| 2701 | + DOM, so the per-state overrides below can select them directly. */ | |
| 2702 | +.dm-agents__trail { | |
| 2703 | + margin-block: 6px 14px; | |
| 2704 | + --os-ui-steps-gap: 10px; | |
| 2705 | + --os-ui-step-gap: 7px; | |
| 2706 | + --os-ui-step-chip-size: 22px; | |
| 2707 | + --os-ui-step-chip-font-size: 11px; | |
| 2708 | + --os-ui-step-chip-family: var( --os-ui-font-mono, ui-monospace, monospace ); | |
| 2709 | + --os-ui-step-title-size: 11px; | |
| 2710 | + --os-ui-step-title-family: var( --os-ui-font-mono, ui-monospace, monospace ); | |
| 2711 | + --os-ui-step-title-transform: uppercase; | |
| 2712 | + --os-ui-step-title-spacing: 0.08em; | |
| 2713 | +} | |
| 2714 | + | |
| 2715 | +/* A station you have not reached is an outline, not a filled dot: the | |
| 2716 | + mesh chip is where you ARE, and it only reads that way if it is the | |
| 2717 | + only one lit. */ | |
| 2718 | +.dm-agents__trail os-step:not( [ done ] ):not( [ current ] ) { | |
| 2719 | + --os-ui-step-chip-bg: transparent; | |
| 2720 | + --os-ui-step-chip-border: 1px solid var( --os-ui-border-strong, #8c8f94 ); | |
| 2721 | + --os-ui-step-chip-fg: var( --os-ui-fg-muted, #646970 ); | |
| 2722 | +} | |
| 2723 | + | |
| 2724 | +/* Done is quiet: a filled tick on the elevated surface, muted like its | |
| 2725 | + label. It reads as history, not as a second highlight. */ | |
| 2726 | +.dm-agents__trail os-step[ done ] { | |
| 2727 | + --os-ui-step-chip-done-bg: var( --os-ui-surface-elevated, #f0f0f1 ); | |
| 2728 | + --os-ui-step-chip-fg: var( --os-ui-fg-muted, #646970 ); | |
| 2729 | +} | |
| 2730 | + | |
| 2731 | +.dm-agents__wiz-heading { | |
| 2732 | + margin: 12px 0 2px; | |
| 2733 | + font-size: 16px; | |
| 2734 | + font-weight: 600; | |
| 2735 | + color: var( --os-ui-fg, #1d2327 ); | |
| 2736 | +} | |
| 2737 | + | |
| 2738 | +/* The door. Five complete agents already ship with the plugin, and | |
| 2739 | + until now the create flow showed them to nobody. */ | |
| 2740 | +.dm-agents__starters { | |
| 2741 | + display: grid; | |
| 2742 | + gap: 12px; | |
| 2743 | + grid-template-columns: repeat( auto-fill, minmax( 148px, 1fr ) ); | |
| 2744 | + margin-block: 8px 16px; | |
| 2745 | +} | |
| 2746 | + | |
| 2747 | +.dm-agents__starter { | |
| 2748 | + display: flex; | |
| 2749 | + flex-direction: column; | |
| 2750 | + align-items: center; | |
| 2751 | + text-align: center; | |
| 2752 | + gap: 3px; | |
| 2753 | + --os-ui-card-padding: 16px 14px; | |
| 2754 | + --os-ui-card-radius: 10px; | |
| 2755 | + --os-ui-card-bg: var( --os-ui-surface-subtle, transparent ); | |
| 2756 | + transition: border-color 0.18s ease; | |
| 2757 | +} | |
| 2758 | + | |
| 2759 | +.dm-agents__starter:hover, | |
| 2760 | +.dm-agents__starter:focus-within { | |
| 2761 | + border-color: var( --os-ui-border-strong, #8c8f94 ); | |
| 2762 | +} | |
| 2763 | + | |
| 2764 | +.dm-agents__starter-face { | |
| 2765 | + width: 76px; | |
| 2766 | + height: 76px; | |
| 2767 | + margin: -8px 0 4px; | |
| 2768 | + flex: none; | |
| 2769 | +} | |
| 2770 | + | |
| 2771 | +.dm-agents__starter-name { | |
| 2772 | + font-size: 14px; | |
| 2773 | + font-weight: 500; | |
| 2774 | + color: var( --os-ui-fg, #1d2327 ); | |
| 2775 | +} | |
| 2776 | + | |
| 2777 | +.dm-agents__starter-vibes { | |
| 2778 | + font-family: var( --os-ui-font-mono, ui-monospace, monospace ); | |
| 2779 | + font-size: 11.5px; | |
| 2780 | + color: var( --os-ui-fg-muted, #646970 ); | |
| 2781 | +} | |
| 2782 | + | |
| 2783 | +/* Meet: the portrait beside the fields, so the thing being named is | |
| 2784 | + visible while it is being named. */ | |
| 2785 | +.dm-agents__meet { | |
| 2786 | + display: grid; | |
| 2787 | + gap: 20px; | |
| 2788 | + grid-template-columns: 220px 1fr; | |
| 2789 | + align-items: start; | |
| 2790 | +} | |
| 2791 | + | |
| 2792 | +/* The character card. Sunken rather than subtle: the portrait is the | |
| 2793 | + hero of this step, and the mockup floats it on the darkest surface | |
| 2794 | + so the face's own glow does the framing. */ | |
| 2795 | +.dm-agents__portrait { | |
| 2796 | + display: flex; | |
| 2797 | + flex-direction: column; | |
| 2798 | + align-items: center; | |
| 2799 | + gap: 10px; | |
| 2800 | + padding: 20px 14px 14px; | |
| 2801 | + border: 1px solid var( --os-border, rgba( 0, 0, 0, 0.08 ) ); | |
| 2802 | + border-radius: var( --os-ui-card-radius, 10px ); | |
| 2803 | + background: var( --os-ui-surface-sunken, #f6f7f7 ); | |
| 2804 | +} | |
| 2805 | + | |
| 2806 | +.dm-agents__portrait-face { | |
| 2807 | + width: 176px; | |
| 2808 | + height: 176px; | |
| 2809 | + max-width: 100%; | |
| 2810 | + margin-top: -12px; | |
| 2811 | +} | |
| 2812 | + | |
| 2813 | +/* What this face is, in two words. */ | |
| 2814 | +.dm-agents__portrait-chips { | |
| 2815 | + display: flex; | |
| 2816 | + gap: 6px; | |
| 2817 | + flex-wrap: wrap; | |
| 2818 | + justify-content: center; | |
| 2819 | +} | |
| 2820 | + | |
| 2821 | +.dm-agents__faces { | |
| 2822 | + display: grid; | |
| 2823 | + grid-template-columns: repeat( 6, 1fr ); | |
| 2824 | + gap: 2px; | |
| 2825 | + width: 100%; | |
| 2826 | +} | |
| 2827 | + | |
| 2828 | +.dm-agents__face-pick { | |
| 2829 | + display: grid; | |
| 2830 | + place-items: center; | |
| 2831 | + padding: 2px; | |
| 2832 | + border: 1px solid transparent; | |
| 2833 | + border-radius: 8px; | |
| 2834 | + background: none; | |
| 2835 | + cursor: pointer; | |
| 2836 | +} | |
| 2837 | + | |
| 2838 | +.dm-agents__face-pick img { | |
| 2839 | + width: 100%; | |
| 2840 | + height: auto; | |
| 2841 | + display: block; | |
| 2842 | +} | |
| 2843 | + | |
| 2844 | +.dm-agents__face-pick:hover { | |
| 2845 | + border-color: var( --os-ui-border-strong, #8c8f94 ); | |
| 2846 | +} | |
| 2847 | + | |
| 2848 | +.dm-agents__face-pick.is-picked { | |
| 2849 | + border-color: var( --os-ui-accent, #2271b1 ); | |
| 2850 | +} | |
| 2851 | + | |
| 2852 | +.dm-agents__face-pick:focus-visible { | |
| 2853 | + outline: var( --os-ui-focus-ring, 2px solid #2271b1 ); | |
| 2854 | + outline-offset: 1px; | |
| 2855 | +} | |
| 2856 | + | |
| 2857 | +.dm-agents__meet-fields { | |
| 2858 | + display: flex; | |
| 2859 | + flex-direction: column; | |
| 2860 | + gap: 10px; | |
| 2861 | + min-width: 0; | |
| 2862 | +} | |
| 2863 | + | |
| 2864 | +/* Launch: one card, the brand's card radius, floating on the darkest | |
| 2865 | + surface like the portrait it echoes. */ | |
| 2866 | +.dm-agents__summary { | |
| 2867 | + display: grid; | |
| 2868 | + grid-template-columns: 106px 1fr; | |
| 2869 | + gap: 18px; | |
| 2870 | + align-items: start; | |
| 2871 | + --os-ui-card-padding: 18px; | |
| 2872 | + --os-ui-card-radius: 10px; | |
| 2873 | + --os-ui-card-bg: var( --os-ui-surface-sunken, #f6f7f7 ); | |
| 2874 | +} | |
| 2875 | + | |
| 2876 | +.dm-agents__summary-face { | |
| 2877 | + width: 106px; | |
| 2878 | + height: 106px; | |
| 2879 | + flex: none; | |
| 2880 | +} | |
| 2881 | + | |
| 2882 | +.dm-agents__summary-text h4 { | |
| 2883 | + margin: 0 0 2px; | |
| 2884 | + font-size: 17px; | |
| 2885 | +} | |
| 2886 | + | |
| 2887 | +.dm-agents__summary-vibes { | |
| 2888 | + font-family: var( --os-ui-font-mono, ui-monospace, monospace ); | |
| 2889 | + font-size: 11.5px; | |
| 2890 | + color: var( --os-ui-accent-strong, #2271b1 ); | |
| 2891 | + margin: 0 0 6px; | |
| 2892 | +} | |
| 2893 | + | |
| 2894 | +.dm-agents__summary-desc { | |
| 2895 | + margin: 0; | |
| 2896 | + font-size: 13px; | |
| 2897 | + color: var( --os-ui-fg-muted, #646970 ); | |
| 2898 | +} | |
| 2899 | + | |
| 2900 | +.dm-agents__chips { | |
| 2901 | + display: flex; | |
| 2902 | + flex-wrap: wrap; | |
| 2903 | + gap: 6px; | |
| 2904 | + margin-block-start: 10px; | |
| 2905 | +} | |
| 2906 | + | |
| 2907 | +/* What the agent will actually be told, under the chips. Clamped: a | |
| 2908 | + summary card quotes the instructions, it does not host them. */ | |
| 2909 | +.dm-agents__summary-instr { | |
| 2910 | + margin: 10px 0 0; | |
| 2911 | + font-size: 13px; | |
| 2912 | + color: var( --os-ui-fg-muted, #646970 ); | |
| 2913 | + display: -webkit-box; | |
| 2914 | + -webkit-line-clamp: 3; | |
| 2915 | + -webkit-box-orient: vertical; | |
| 2916 | + overflow: hidden; | |
| 2917 | +} | |
| 2918 | + | |
| 2919 | +/* Identity chips — role, abilities, silhouette, hue — all wear the | |
| 2920 | + instrument voice: these are facts about the character, stamped | |
| 2921 | + rather than said. */ | |
| 2922 | +.dm-agents__chips os-chip, | |
| 2923 | +.dm-agents__portrait-chips os-chip { | |
| 2924 | + --os-ui-chip-font-size: 10.5px; | |
| 2925 | + --os-ui-chip-font-weight: 500; | |
| 2926 | + --os-ui-chip-bg: transparent; | |
| 2927 | + --os-ui-chip-fg: var( --os-ui-fg-muted, #646970 ); | |
| 2928 | + --os-ui-chip-border: 1px solid var( --os-border, rgba( 0, 0, 0, 0.12 ) ); | |
| 2929 | + font-family: var( --os-ui-font-mono, ui-monospace, monospace ); | |
| 2930 | + text-transform: uppercase; | |
| 2931 | + letter-spacing: 0.06em; | |
| 2932 | +} | |
| 2933 | + | |
| 2934 | +.dm-agents__spacer { | |
| 2935 | + flex: 1; | |
| 2936 | +} | |
| 2937 | + | |
| 2938 | +@media ( max-width: 640px ) { | |
| 2939 | + .dm-agents__meet, | |
| 2940 | + .dm-agents__summary { | |
| 2941 | + grid-template-columns: 1fr; | |
| 2942 | + } | |
| 2943 | + .dm-agents__portrait-face { | |
| 2944 | + width: 128px; | |
| 2945 | + height: 128px; | |
| 2946 | + } | |
| 2947 | +} | |
| 2948 | + | |
| 2949 | +/* The way back to the grid. The window's own breadcrumb goes UP to the | |
| 2950 | + folder, which is a different journey: this one returns to the cast. */ | |
| 2951 | +.dm-agents__back { | |
| 2952 | + align-self: flex-start; | |
| 2953 | + margin-block-end: 4px; | |
| 2403 | 2954 | } |