| @@ -34,9 +34,14 @@ | ||
| 34 | 34 | position: absolute; |
| 35 | 35 | display: flex; |
| 36 | 36 | flex-direction: column; |
| 37 | 37 | background: var(--os-window-bg); |
| 38 | - border: 1px solid var(--os-window-border); | |
| 38 | + /* | |
| 39 | + * The border width is a token so a WINDOW_FRAME texture can be | |
| 40 | + * thicker than a hairline: border-image paints in the border area, | |
| 41 | + * and content starts inside it, so a 4px bevel needs a 4px border. | |
| 42 | + */ | |
| 43 | + border: var(--os-window-border-width, 1px) solid var(--os-window-border); | |
| 39 | 44 | border-radius: var(--os-window-radius); |
| 40 | 45 | box-shadow: var(--os-window-shadow); |
| 41 | 46 | /* |
| 42 | 47 | * Desktop-theme window frame (WINDOW_FRAME texture slot). All |
| @@ -146,9 +151,9 @@ | ||
| 146 | 151 | z-index: 21; |
| 147 | 152 | display: flex; |
| 148 | 153 | align-items: center; |
| 149 | 154 | height: var(--os-titlebar-height); |
| 150 | - padding: 0 8px; | |
| 155 | + padding: var(--os-titlebar-padding, 0 8px); | |
| 151 | 156 | background-color: var(--os-titlebar-bg); |
| 152 | 157 | /* |
| 153 | 158 | * Desktop-theme title-bar texture (TITLEBAR slot). `none` when |
| 154 | 159 | * unset, so the background-color above is the whole story for |
| @@ -175,9 +180,18 @@ | ||
| 175 | 180 | ); |
| 176 | 181 | cursor: default; |
| 177 | 182 | user-select: none; |
| 178 | 183 | flex-shrink: 0; |
| 179 | - gap: 8px; | |
| 184 | + gap: var(--os-titlebar-gap, 8px); | |
| 185 | + /* | |
| 186 | + * Title-bar controls are sized here rather than in | |
| 187 | + * `<os-window-button>`, because the same component also draws | |
| 188 | + * buttons outside the title bar that a theme does not mean to resize. | |
| 189 | + */ | |
| 190 | + --os-ui-btn-width: var(--os-titlebar-btn-width, 30px); | |
| 191 | + --os-ui-btn-height: var(--os-titlebar-btn-height, 30px); | |
| 192 | + --os-ui-btn-icon-size: var(--os-titlebar-btn-icon-size, 14px); | |
| 193 | + --os-ui-btn-press-transform: var(--os-titlebar-btn-press-transform, scale( 0.9 )); | |
| 180 | 194 | } |
| 181 | 195 | |
| 182 | 196 | .os-window--focused .os-window__titlebar { |
| 183 | 197 | background-color: var(--os-titlebar-bg-focused); |
| @@ -255,9 +269,10 @@ | ||
| 255 | 269 | */ |
| 256 | 270 | --os-ui-save-status-ring-color: var(--os-titlebar-activity-color, #2271b1); |
| 257 | 271 | --os-ui-save-status-saved-bg: var(--os-titlebar-activity-saved-color, #2271b1); |
| 258 | 272 | --os-ui-save-status-failed-bg: var(--os-titlebar-activity-failed-color, #d63638); |
| 259 | - display: inline-flex; | |
| 273 | + /* `none` for an era whose title bar had no such mark. */ | |
| 274 | + display: var(--os-titlebar-activity-display, inline-flex); | |
| 260 | 275 | align-items: center; |
| 261 | 276 | flex-shrink: 0; |
| 262 | 277 | } |
| 263 | 278 | |
| @@ -306,17 +321,35 @@ | ||
| 306 | 321 | margin-inline-end: 4px; |
| 307 | 322 | color: var(--wp-admin-theme-color, #2271b1); |
| 308 | 323 | } |
| 309 | 324 | |
| 310 | -/* Window title text. */ | |
| 325 | +/* | |
| 326 | + * Window title text. | |
| 327 | + * | |
| 328 | + * Every knob a classic title bar needs: size, weight and alignment of | |
| 329 | + * the text, and a plate behind it for a bar whose artwork runs under | |
| 330 | + * the title (stripes that stop either side of it). A title centred on | |
| 331 | + * the whole bar rather than on the space the controls leave it is | |
| 332 | + * `position: absolute` with `left: 50%` and a `-50%` translate, all | |
| 333 | + * from tokens; the bar is the positioned ancestor. Unset, every | |
| 334 | + * property resolves to what this rule always said. | |
| 335 | + */ | |
| 311 | 336 | .os-window__title { |
| 312 | 337 | flex: 1; |
| 313 | 338 | overflow: hidden; |
| 314 | 339 | text-overflow: ellipsis; |
| 315 | 340 | white-space: nowrap; |
| 316 | - font-size: 14px; | |
| 317 | - font-weight: 500; | |
| 341 | + font-size: var(--os-titlebar-font-size, 14px); | |
| 342 | + font-weight: var(--os-titlebar-font-weight, 500); | |
| 343 | + letter-spacing: var(--os-titlebar-letter-spacing, normal); | |
| 344 | + text-align: var(--os-titlebar-title-align, start); | |
| 318 | 345 | line-height: var(--os-titlebar-height); |
| 346 | + position: var(--os-titlebar-title-position, static); | |
| 347 | + left: var(--os-titlebar-title-left, auto); | |
| 348 | + translate: var(--os-titlebar-title-translate, none); | |
| 349 | + max-width: var(--os-titlebar-title-max-width, none); | |
| 350 | + padding-inline: var(--os-titlebar-title-padding, 0); | |
| 351 | + background: var(--os-titlebar-title-bg, transparent); | |
| 319 | 352 | } |
| 320 | 353 | |
| 321 | 354 | /* |
| 322 | 355 | * Window control buttons container. |
| @@ -338,8 +371,10 @@ | ||
| 338 | 371 | * @since 0.9.8 |
| 339 | 372 | */ |
| 340 | 373 | .os-window__controls { |
| 341 | 374 | display: flex; |
| 375 | + /* `-1` puts the cluster at the leading edge of the bar. */ | |
| 376 | + order: var( --os-titlebar-controls-order, 0 ); | |
| 342 | 377 | gap: var( --os-titlebar-controls-gap, 4px ); |
| 343 | 378 | align-items: center; |
| 344 | 379 | flex-shrink: 0; |
| 345 | 380 | padding-inline: var( --os-titlebar-controls-padding, 0 ); |
| @@ -350,9 +385,38 @@ | ||
| 350 | 385 | background-size: var( --os-titlebar-controls-image-size, auto ); |
| 351 | 386 | background-position: var( --os-titlebar-controls-image-position, center ); |
| 352 | 387 | } |
| 353 | 388 | |
| 389 | +/* A window that asked for `appearance.controls.placement: 'left'`. */ | |
| 390 | +.os-window__controls--left { | |
| 391 | + order: -1; | |
| 392 | +} | |
| 393 | + | |
| 354 | 394 | /* |
| 395 | + * Per-control order and visibility, for a theme drawing an era whose | |
| 396 | + * title bar had a different set: a close box first and nothing else, | |
| 397 | + * or three buttons with a gap before the last. Hiding a control takes | |
| 398 | + * a way to reach that action off the bar, so it is the theme's | |
| 399 | + * explicit choice and never a default. | |
| 400 | + */ | |
| 401 | +.os-window__controls .os-window__btn--minimize { | |
| 402 | + order: var( --os-titlebar-minimize-order, 0 ); | |
| 403 | + display: var( --os-titlebar-minimize-display, inline-flex ); | |
| 404 | +} | |
| 405 | +.os-window__controls .os-window__btn--maximize { | |
| 406 | + order: var( --os-titlebar-maximize-order, 0 ); | |
| 407 | + display: var( --os-titlebar-maximize-display, inline-flex ); | |
| 408 | +} | |
| 409 | +.os-window__controls .os-window__btn--focus-tab { | |
| 410 | + order: var( --os-titlebar-fullscreen-order, 0 ); | |
| 411 | + display: var( --os-titlebar-fullscreen-display, inline-flex ); | |
| 412 | +} | |
| 413 | +.os-window__controls .os-window__btn--close { | |
| 414 | + order: var( --os-titlebar-close-order, 0 ); | |
| 415 | + margin-inline-start: var( --os-titlebar-close-gap, 0 ); | |
| 416 | +} | |
| 417 | + | |
| 418 | +/* | |
| 355 | 419 | * Same treatment for the Screen Options / Help cluster, so a theme |
| 356 | 420 | * that plates one can plate the other and keep them consistent. |
| 357 | 421 | * Falls through to the controls tokens, so setting the pair above is |
| 358 | 422 | * enough for both. |
| @@ -460,10 +524,12 @@ | ||
| 460 | 524 | * addressed the same way. Every one is UNDECLARED and falls back to |
| 461 | 525 | * the literal it replaced, so an unthemed shell paints exactly what |
| 462 | 526 | * it painted before. |
| 463 | 527 | * |
| 464 | - * There is no `-danger-hover` twin: destructive red is semantic, not | |
| 465 | - * chrome, and both halves already resolve it through `--os-ui-danger`. | |
| 528 | + * The close button's hover is the danger red in both halves, through | |
| 529 | + * `--os-ui-danger`. `--os-titlebar-close-bg-hover` and | |
| 530 | + * `-color-hover` re-point it for a title bar whose era drew its close | |
| 531 | + * button another way, without moving every other danger surface. | |
| 466 | 532 | */ |
| 467 | 533 | .os-window--focused { |
| 468 | 534 | --os-ui-btn-color: var( --os-titlebar-btn-focused-color, rgba( 255, 255, 255, 0.7 ) ); |
| 469 | 535 | --os-ui-btn-color-hover: var( --os-titlebar-btn-focused-color-hover, #fff ); |
| @@ -469,9 +535,10 @@ | ||
| 469 | 535 | --os-ui-btn-color-hover: var( --os-titlebar-btn-focused-color-hover, #fff ); |
| 470 | 536 | --os-ui-btn-bg-hover: var( --os-titlebar-btn-focused-bg-hover, rgba( 255, 255, 255, 0.18 ) ); |
| 471 | 537 | --os-ui-btn-bg-active: var( --os-titlebar-btn-focused-bg-active, rgba( 255, 255, 255, 0.25 ) ); |
| 472 | 538 | --os-ui-btn-outline: var( --os-titlebar-btn-focused-outline, rgba( 255, 255, 255, 0.65 ) ); |
| 473 | - --os-ui-btn-danger-hover: var( --os-ui-danger, #d63638 ); | |
| 539 | + --os-ui-btn-danger-hover: var( --os-titlebar-close-bg-hover, var( --os-ui-danger, #d63638 ) ); | |
| 540 | + --os-ui-btn-danger-color-hover: var( --os-titlebar-close-color-hover, var( --os-ui-fg-on-accent, #fff ) ); | |
| 474 | 541 | } |
| 475 | 542 | |
| 476 | 543 | .os-window:not( .os-window--focused ) { |
| 477 | 544 | --os-ui-btn-color: var( --os-titlebar-btn-color, rgba( 0, 0, 0, 0.45 ) ); |
| @@ -478,9 +545,10 @@ | ||
| 478 | 545 | --os-ui-btn-color-hover: var( --os-titlebar-btn-color-hover, rgba( 0, 0, 0, 0.85 ) ); |
| 479 | 546 | --os-ui-btn-bg-hover: var( --os-titlebar-btn-bg-hover, rgba( 0, 0, 0, 0.08 ) ); |
| 480 | 547 | --os-ui-btn-bg-active: var( --os-titlebar-btn-bg-active, rgba( 0, 0, 0, 0.12 ) ); |
| 481 | 548 | --os-ui-btn-outline: var( --wp-admin-theme-color, #2271b1 ); |
| 482 | - --os-ui-btn-danger-hover: var( --os-ui-danger, #d63638 ); | |
| 549 | + --os-ui-btn-danger-hover: var( --os-titlebar-close-bg-hover, var( --os-ui-danger, #d63638 ) ); | |
| 550 | + --os-ui-btn-danger-color-hover: var( --os-titlebar-close-color-hover, var( --os-ui-fg-on-accent, #fff ) ); | |
| 483 | 551 | } |
| 484 | 552 | |
| 485 | 553 | /* |
| 486 | 554 | * Unfocused control glyphs under an active desktop theme. |
| @@ -578,8 +646,49 @@ | ||
| 578 | 646 | z-index: 2; |
| 579 | 647 | } |
| 580 | 648 | |
| 581 | 649 | /* |
| 650 | + * "Copy link" confirms in its own row: the label becomes "Link copied" | |
| 651 | + * with a tick that pops in, then the row reverts and the menu closes | |
| 652 | + * unless it is still hovered. The tick sits in the slotted label, so it | |
| 653 | + * is styled here rather than in the menu's shadow root. Transform and | |
| 654 | + * opacity only. | |
| 655 | + * | |
| 656 | + * The tick wears the row's own ink, not the accent: it is feedback, not | |
| 657 | + * the thing you are on, and the words already say what happened (see | |
| 658 | + * "The accent marks state; it never decorates" in AGENTS.md). | |
| 659 | + */ | |
| 660 | +.os-window__menu-copied-icon { | |
| 661 | + /* Hangs in the gutter so "Link copied" stays aligned with the | |
| 662 | + other labels. Out of flow, so the label's overflow clip, whose | |
| 663 | + box is not this icon's containing block, does not cut it off. */ | |
| 664 | + position: absolute; | |
| 665 | + translate: -28px -1px; | |
| 666 | + animation: os-menu-copied-pop 0.24s cubic-bezier( 0.34, 1.56, 0.64, 1 ) both; | |
| 667 | +} | |
| 668 | + | |
| 669 | +.os-window__menu-copied-icon:dir( rtl ) { | |
| 670 | + translate: 28px -1px; | |
| 671 | +} | |
| 672 | + | |
| 673 | +@keyframes os-menu-copied-pop { | |
| 674 | + from { | |
| 675 | + opacity: 0; | |
| 676 | + transform: scale( 0.4 ); | |
| 677 | + } | |
| 678 | + to { | |
| 679 | + opacity: 1; | |
| 680 | + transform: scale( 1 ); | |
| 681 | + } | |
| 682 | +} | |
| 683 | + | |
| 684 | +@media ( prefers-reduced-motion: reduce ) { | |
| 685 | + .os-window__menu-copied-icon { | |
| 686 | + animation: none; | |
| 687 | + } | |
| 688 | +} | |
| 689 | + | |
| 690 | +/* | |
| 582 | 691 | * "Related" dropdown — opened by the related-entities title-bar |
| 583 | 692 | * button (`src/related-entities/`). The panel ALSO carries |
| 584 | 693 | * `.os-window__menu-panel` (positioning + the drag-tracker |
| 585 | 694 | * exclusion come from there); this class only layers the related-menu |
| @@ -634,22 +743,37 @@ | ||
| 634 | 743 | .os-window__meta-btn { |
| 635 | 744 | display: flex; |
| 636 | 745 | align-items: center; |
| 637 | 746 | justify-content: center; |
| 638 | - width: 28px; | |
| 639 | - height: 28px; | |
| 747 | + width: var( --os-titlebar-btn-width, 28px ); | |
| 748 | + height: var( --os-titlebar-btn-height, 28px ); | |
| 640 | 749 | border: none; |
| 641 | - border-radius: 6px; | |
| 750 | + border-radius: var( --os-titlebar-meta-btn-radius, 6px ); | |
| 642 | 751 | cursor: pointer; |
| 643 | 752 | padding: 0; |
| 644 | - background: transparent; | |
| 753 | + /* The same face as the window controls beside them, when a theme | |
| 754 | + * gives those one (TITLEBAR_BUTTON). Every state below changes the | |
| 755 | + * colour only, so the face survives hover and press. */ | |
| 756 | + background-color: var( --os-ui-btn-bg, transparent ); | |
| 757 | + background-image: var( --os-ui-btn-bg-image, none ); | |
| 758 | + background-repeat: var( --os-ui-btn-bg-image-repeat, no-repeat ); | |
| 759 | + background-size: var( --os-ui-btn-bg-image-size, auto ); | |
| 760 | + background-position: var( --os-ui-btn-bg-image-position, center ); | |
| 645 | 761 | transition: background-color 0.15s ease, color 0.15s ease; |
| 646 | 762 | } |
| 647 | 763 | |
| 764 | +.os-window__meta-btn:active, | |
| 765 | +.os-window__meta-btn--active { | |
| 766 | + background-image: var( | |
| 767 | + --os-ui-btn-bg-image-pressed, | |
| 768 | + var( --os-ui-btn-bg-image, none ) | |
| 769 | + ); | |
| 770 | +} | |
| 771 | + | |
| 648 | 772 | .os-window__meta-btn .dashicons { |
| 649 | - font-size: 18px; | |
| 650 | - width: 18px; | |
| 651 | - height: 18px; | |
| 773 | + font-size: var( --os-titlebar-meta-icon-size, 18px ); | |
| 774 | + width: var( --os-titlebar-meta-icon-size, 18px ); | |
| 775 | + height: var( --os-titlebar-meta-icon-size, 18px ); | |
| 652 | 776 | } |
| 653 | 777 | /* The flex-centring override for the dashicon glyph currently lives |
| 654 | 778 | * in `windows.css`. That placement was a cache workaround from when |
| 655 | 779 | * this file was an `@import` sub-sheet with no `?ver=` of its own; |
| @@ -671,19 +795,19 @@ | ||
| 671 | 795 | color: var( --os-titlebar-btn-focused-color, rgba(255, 255, 255, 0.65) ); |
| 672 | 796 | } |
| 673 | 797 | .os-window--focused .os-window__meta-btn:hover { |
| 674 | 798 | color: var( --os-titlebar-btn-focused-color-hover, var( --os-ui-fg-on-accent, #fff ) ); |
| 675 | - background: var( --os-titlebar-btn-focused-bg-hover, rgba(255, 255, 255, 0.18) ); | |
| 799 | + background-color: var( --os-titlebar-btn-focused-bg-hover, rgba(255, 255, 255, 0.18) ); | |
| 676 | 800 | } |
| 677 | 801 | .os-window--focused .os-window__meta-btn:focus-visible { |
| 678 | 802 | color: var( --os-titlebar-btn-focused-color-hover, var( --os-ui-fg-on-accent, #fff ) ); |
| 679 | - background: var( --os-titlebar-btn-focused-bg-hover, rgba(255, 255, 255, 0.18) ); | |
| 803 | + background-color: var( --os-titlebar-btn-focused-bg-hover, rgba(255, 255, 255, 0.18) ); | |
| 680 | 804 | outline: 2px solid var( --os-titlebar-btn-focused-outline, rgba(255, 255, 255, 0.6) ); |
| 681 | 805 | outline-offset: 1px; |
| 682 | 806 | } |
| 683 | 807 | .os-window--focused .os-window__meta-btn--active { |
| 684 | 808 | color: var( --os-titlebar-btn-focused-color-hover, var( --os-ui-fg-on-accent, #fff ) ); |
| 685 | - background: var( --os-titlebar-btn-focused-bg-active, rgba(255, 255, 255, 0.25) ); | |
| 809 | + background-color: var( --os-titlebar-btn-focused-bg-active, rgba(255, 255, 255, 0.25) ); | |
| 686 | 810 | } |
| 687 | 811 | |
| 688 | 812 | /* Unfocused window: divider and buttons adapt to light title bar. */ |
| 689 | 813 | .os-window:not(.os-window--focused) .os-window__screen-meta { |
| @@ -703,13 +827,13 @@ | ||
| 703 | 827 | color: var( --os-titlebar-btn-color, rgba(0, 0, 0, 0.3) ); |
| 704 | 828 | } |
| 705 | 829 | .os-window:not(.os-window--focused) .os-window__meta-btn:hover { |
| 706 | 830 | color: var( --os-titlebar-btn-color-hover, rgba(0, 0, 0, 0.6) ); |
| 707 | - background: var( --os-ui-hover, rgba(0, 0, 0, 0.08) ); | |
| 831 | + background-color: var( --os-ui-hover, rgba(0, 0, 0, 0.08) ); | |
| 708 | 832 | } |
| 709 | 833 | .os-window:not(.os-window--focused) .os-window__meta-btn--active { |
| 710 | 834 | color: var( --os-titlebar-btn-color-hover, rgba(0, 0, 0, 0.6) ); |
| 711 | - background: rgba(0, 0, 0, 0.12); | |
| 835 | + background-color: rgba(0, 0, 0, 0.12); | |
| 712 | 836 | } |
| 713 | 837 | |
| 714 | 838 | /* --------------------------------------------------------------- |
| 715 | 839 | * Tab strip — submenu navigation rendered in the parent shell, just |
| @@ -739,9 +863,9 @@ | ||
| 739 | 863 | * kink where the tab meets the floor. One alias, read by both. |
| 740 | 864 | */ |
| 741 | 865 | --_tab-radius: var( --os-tabs-radius, 8px ); |
| 742 | 866 | /* Tab height, shared with the plate that has to sit exactly on it. */ |
| 743 | - --_tab-h: 30px; | |
| 867 | + --_tab-h: var( --os-tabs-tab-height, 30px ); | |
| 744 | 868 | /* Weight of the rail that traces the silhouette. */ |
| 745 | 869 | --_tab-stroke: var( --os-tabs-rail-width, 2px ); |
| 746 | 870 | /* |
| 747 | 871 | * How far each straight run of the rail overlaps the arc it hands |
| @@ -754,9 +878,9 @@ | ||
| 754 | 878 | display: flex; |
| 755 | 879 | /* Tabs sit ON the floor of the track, not centred in it. */ |
| 756 | 880 | align-items: flex-end; |
| 757 | 881 | flex-shrink: 0; |
| 758 | - gap: 2px; | |
| 882 | + gap: var( --os-tabs-gap, 2px ); | |
| 759 | 883 | /* |
| 760 | 884 | * Horizontal padding is a floor as well as a breathing space. The |
| 761 | 885 | * ring reaches one radius plus one stroke (10px at the shipped |
| 762 | 886 | * values) past the plate on each side, so a first or last tab |
| @@ -762,9 +886,9 @@ | ||
| 762 | 886 | * values) past the plate on each side, so a first or last tab |
| 763 | 887 | * under a smaller padding would have its outer corner clipped by |
| 764 | 888 | * the `overflow` rule below. |
| 765 | 889 | */ |
| 766 | - padding: 8px 12px 0; | |
| 890 | + padding: var( --os-tabs-padding, 8px 12px 0 ); | |
| 767 | 891 | background-color: var( --os-tabs-bg, var( --os-ui-surface-elevated, #f6f7f7 ) ); |
| 768 | 892 | /* TABBAR texture slot — layered over the strip's own colour. */ |
| 769 | 893 | background-image: var( --os-tabs-image, none ); |
| 770 | 894 | background-repeat: var( --os-tabs-image-repeat, repeat ); |
| @@ -866,8 +990,10 @@ | ||
| 866 | 990 | * `tabs.ts` publishes the target geometry as `--_tab-plate-x` and |
| 867 | 991 | * `--_tab-plate-w` on this element; everything else is CSS. |
| 868 | 992 | * --------------------------------------------------------------- */ |
| 869 | 993 | .os-window__tab-plate { |
| 994 | + /* `none` for a theme whose tabs draw their own faces. */ | |
| 995 | + display: var( --os-tabs-plate-display, block ); | |
| 870 | 996 | position: absolute; |
| 871 | 997 | bottom: 0; |
| 872 | 998 | left: 0; |
| 873 | 999 | height: var( --_tab-h ); |
| @@ -1037,8 +1163,11 @@ | ||
| 1037 | 1163 | right: 0; |
| 1038 | 1164 | bottom: 0; |
| 1039 | 1165 | height: var( --_tab-stroke ); |
| 1040 | 1166 | background-image: var( --os-tabs-rail, none ); |
| 1167 | + /* The rail's colour is derived from the accent; how much of it | |
| 1168 | + shows is a literal the palette answers. 1 is the earlier look. */ | |
| 1169 | + opacity: var( --os-tabs-rail-opacity, 1 ); | |
| 1041 | 1170 | background-size: var( --_tab-strip-w, 100% ) 100%; |
| 1042 | 1171 | background-repeat: no-repeat; |
| 1043 | 1172 | pointer-events: none; |
| 1044 | 1173 | /* |
| @@ -1126,8 +1255,11 @@ | ||
| 1126 | 1255 | calc( var( --_tab-stroke ) * -1 ) |
| 1127 | 1256 | calc( ( var( --_tab-radius ) + var( --_tab-stroke ) ) * -1 ) |
| 1128 | 1257 | 0; |
| 1129 | 1258 | background-image: var( --os-tabs-rail, none ); |
| 1259 | + /* The rail's colour is derived from the accent; how much of it | |
| 1260 | + shows is a literal the palette answers. 1 is the earlier look. */ | |
| 1261 | + opacity: var( --os-tabs-rail-opacity, 1 ); | |
| 1130 | 1262 | background-size: var( --_tab-strip-w, 100% ) 100%; |
| 1131 | 1263 | background-position: |
| 1132 | 1264 | calc( |
| 1133 | 1265 | var( --_tab-radius ) + var( --_tab-stroke ) - |
| @@ -1289,16 +1421,23 @@ | ||
| 1289 | 1421 | position: relative; |
| 1290 | 1422 | flex-shrink: 0; |
| 1291 | 1423 | display: inline-flex; |
| 1292 | 1424 | align-items: center; |
| 1293 | - height: 30px; | |
| 1294 | - padding: 0 14px; | |
| 1425 | + height: var( --_tab-h ); | |
| 1426 | + margin: var( --os-tabs-tab-margin, 0 ); | |
| 1427 | + padding: var( --os-tabs-tab-padding, 0 14px ); | |
| 1295 | 1428 | border: none; |
| 1296 | 1429 | border-radius: var( --_tab-radius ) var( --_tab-radius ) 0 0; |
| 1297 | - background: transparent; | |
| 1430 | + /* | |
| 1431 | + * A tab paints no face of its own by default: the plate is the | |
| 1432 | + * surface. A theme that draws every tab as a key gives each one a | |
| 1433 | + * face and an edge here, and turns the plate off. | |
| 1434 | + */ | |
| 1435 | + background: var( --os-tabs-tab-bg, transparent ); | |
| 1436 | + box-shadow: var( --os-tabs-tab-shadow, none ); | |
| 1298 | 1437 | color: var( --os-tabs-color, var( --os-ui-fg-muted, #50575e ) ); |
| 1299 | 1438 | font: inherit; |
| 1300 | - font-size: 12px; | |
| 1439 | + font-size: var( --os-tabs-font-size, 12px ); | |
| 1301 | 1440 | line-height: 1; |
| 1302 | 1441 | cursor: pointer; |
| 1303 | 1442 | white-space: nowrap; |
| 1304 | 1443 | transition: color 0.15s ease, background-color 0.15s ease; |
| @@ -1304,10 +1443,10 @@ | ||
| 1304 | 1443 | transition: color 0.15s ease, background-color 0.15s ease; |
| 1305 | 1444 | } |
| 1306 | 1445 | |
| 1307 | 1446 | .os-window__tab:hover { |
| 1308 | - color: var(--wp-admin-theme-color, #2271b1); | |
| 1309 | - background: var( --os-ui-hover, rgba(0, 0, 0, 0.03) ); | |
| 1447 | + color: var( --os-tabs-hover-color, var(--wp-admin-theme-color, #2271b1) ); | |
| 1448 | + background: var( --os-tabs-hover-bg, var( --os-ui-hover, rgba(0, 0, 0, 0.03) ) ); | |
| 1310 | 1449 | } |
| 1311 | 1450 | |
| 1312 | 1451 | .os-window__tab:focus-visible { |
| 1313 | 1452 | outline: 2px solid var(--wp-admin-theme-color, #2271b1); |
| @@ -1324,10 +1463,16 @@ | ||
| 1324 | 1463 | * ring. A tab that is both a distinct surface AND coloured is saying |
| 1325 | 1464 | * the same thing twice. |
| 1326 | 1465 | */ |
| 1327 | 1466 | .os-window__tab--active { |
| 1467 | + /* Above its neighbours, for a theme whose active tab grows over them. */ | |
| 1468 | + z-index: 1; | |
| 1469 | + height: var( --os-tabs-active-height, var( --_tab-h ) ); | |
| 1470 | + margin: var( --os-tabs-active-margin, var( --os-tabs-tab-margin, 0 ) ); | |
| 1471 | + background: var( --os-tabs-active-tab-bg, transparent ); | |
| 1472 | + box-shadow: var( --os-tabs-active-shadow, none ); | |
| 1328 | 1473 | color: var( --os-tabs-active-color, #1d2327 ); |
| 1329 | - font-weight: 600; | |
| 1474 | + font-weight: var( --os-tabs-active-weight, 600 ); | |
| 1330 | 1475 | /* |
| 1331 | 1476 | * Anything nested in an active tab (the external tab's detach and |
| 1332 | 1477 | * close chips) is now sitting on a light fill inside dark chrome, |
| 1333 | 1478 | * so the two tones it reads have to flip with the tab. Both are |
| @@ -1344,9 +1489,9 @@ | ||
| 1344 | 1489 | |
| 1345 | 1490 | /* An active tab has the plate under it; a hover wash on top of that |
| 1346 | 1491 | * would double-paint the surface. */ |
| 1347 | 1492 | .os-window__tab--active:hover { |
| 1348 | - background: transparent; | |
| 1493 | + background: var( --os-tabs-active-tab-bg, transparent ); | |
| 1349 | 1494 | color: var( --os-tabs-active-color, #1d2327 ); |
| 1350 | 1495 | } |
| 1351 | 1496 | |
| 1352 | 1497 | /* |
| @@ -1410,8 +1555,28 @@ | ||
| 1410 | 1555 | display: block; |
| 1411 | 1556 | background: var(--os-window-bg); |
| 1412 | 1557 | opacity: 1; |
| 1413 | 1558 | transition: opacity 0.25s ease; |
| 1559 | +} | |
| 1560 | + | |
| 1561 | +/* | |
| 1562 | + * A window with tabs can sit its page in a panel the tabs stand on, | |
| 1563 | + * for a theme that draws its tabs as keys: padding and edges on the | |
| 1564 | + * body, and a frame around the page. The defaults leave the page | |
| 1565 | + * flush under the strip. A buffer iframe is placed absolutely, so it | |
| 1566 | + * keeps to the same padding. | |
| 1567 | + */ | |
| 1568 | +.os-window:has( .os-window__tab ) > .os-window__body { | |
| 1569 | + padding: var( --os-tabs-panel-padding, 0 ); | |
| 1570 | + box-shadow: var( --os-tabs-panel-shadow, none ); | |
| 1571 | +} | |
| 1572 | + | |
| 1573 | +.os-window:has( .os-window__tab ) > .os-window__body > .os-window__iframe { | |
| 1574 | + box-shadow: var( --os-tabs-page-shadow, none ); | |
| 1575 | +} | |
| 1576 | + | |
| 1577 | +.os-window:has( .os-window__tab ) > .os-window__body > .os-window__iframe--buffer { | |
| 1578 | + inset: var( --os-tabs-panel-padding, 0 ); | |
| 1414 | 1579 | } |
| 1415 | 1580 | |
| 1416 | 1581 | /* |
| 1417 | 1582 | * Headings inside native window bodies. |