mnfst 0.5.231 → 0.5.233

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/lib/manifest.css CHANGED
@@ -2922,142 +2922,139 @@
2922
2922
 
2923
2923
  @layer base, components, utilities;
2924
2924
 
2925
- /* Self-contained: every rule the plugin needs lives here, so this stylesheet works
2926
- on its own. Authors override without specificity battles — rules are :where()
2927
- wrapped and keyed off data-edit-* attributes, including the injected affordances
2928
- (handles, overlay, live region, toolbar, menu). No class names to collide with. */
2925
+ /* Rules are :where()-wrapped and keyed off data-edit-* attributes, so authors
2926
+ override without specificity battles. Visuals are on for every area;
2927
+ x-edit.bare (data-edit-area="bare") keeps the behaviour and draws none of them. */
2929
2928
 
2930
2929
  @layer utilities {
2931
2930
 
2932
- /* ---- Editing UI scope ----
2933
- ALL chrome — cursors, movable/text outlines, size-handle hairlines, drop
2934
- targets, the floating toolbar — lives under ONE scope: [data-edit-ui], on
2935
- the region itself or any ancestor (e.g. <body data-edit-ui> for a whole
2936
- editor view). The plugin sets it on `.authoring` regions automatically;
2937
- everything else opts in with the attribute. A region outside the scope is
2938
- just as editable — it simply carries no visual cues. */
2939
-
2940
- /* ---- Editable area (armed) ---- */
2941
- :where([data-edit-armed]) {
2942
- position: relative;
2943
- }
2944
-
2945
- /* No default region boundary or label: a page being edited should look
2946
- like the page, not a diagram of its regions. The hooks remain for a real
2947
- editor product to draw its own — [data-edit-authoring] marks the region
2948
- and data-edit-label carries "key · regime". */
2949
-
2950
- /* ---- Reorder (pointer + keyboard; touch-action:none lets touch-drag beat scroll) ---- */
2951
- :where([data-edit-sortable]) {
2931
+ /* ---- Pieces ---- */
2932
+ :where([data-edit-piece]) {
2952
2933
  cursor: grab;
2953
2934
  touch-action: none;
2954
2935
  transition: opacity 0.12s ease, outline-color 0.12s ease;
2955
2936
  }
2956
2937
 
2957
- /* No injected grip: the row itself is the handle (grab cursor), while text
2958
- inside stays a text surface (text cursor, below). Rows that are pure text
2959
- still reorder by keyboard (Alt/Option + arrows). */
2960
-
2961
- /* Hover hint in the UI scope; quiet while a drag is in progress. */
2962
- :where([data-edit-ui] [data-edit-sortable], [data-edit-ui][data-edit-sortable]):where(:hover):where(:not([data-edit-dragging], [data-edit-ghost], [data-edit-dragging-in] [data-edit-sortable])) {
2938
+ :where([data-edit-piece]):where(:hover):where(:not([data-edit-area="bare"], [data-edit-area="bare"] *, [data-edit-dragging], [data-edit-ghost], :has([data-edit-dragging]) *)) {
2963
2939
  outline: 1px solid color-mix(in oklch, var(--edit-accent, var(--color-brand-content)) 45%, transparent);
2964
2940
  outline-offset: 3px;
2965
2941
  }
2966
2942
 
2967
- :where([data-edit-sortable], [data-edit-movable]):focus-visible {
2943
+ :where([data-edit-piece]):focus-visible:where(:not([data-edit-area="bare"], [data-edit-area="bare"] *)) {
2968
2944
  outline: 2px solid var(--edit-accent, var(--color-brand-content));
2969
2945
  outline-offset: 3px;
2970
2946
  }
2971
2947
 
2972
- /* Lifted out of the flow and following the pointer. */
2973
- :where([data-edit-sortable][data-edit-dragging]) {
2948
+ /* Grip: drags a text piece; sits at its inline-start edge */
2949
+ :where([data-edit-grip]) {
2950
+ position: fixed;
2951
+ z-index: 1001;
2952
+ width: var(--edit-grip-size, 0.75rem);
2953
+ height: calc(var(--edit-grip-size, 0.75rem) * 1.5);
2954
+ translate: calc(-100% - var(--edit-grip-offset, 0.25rem)) 0;
2955
+ border-radius: 3px;
2956
+ color: var(--edit-accent, var(--color-brand-content));
2957
+ background: radial-gradient(circle, currentColor 1px, transparent 1.5px) center / 6px 6px;
2958
+ opacity: 0.6;
2959
+ cursor: grab;
2960
+ touch-action: none;
2961
+ user-select: none;
2962
+
2963
+ &:hover {
2964
+ opacity: 1;
2965
+ }
2966
+ }
2967
+
2968
+ :where([data-edit-grip]:dir(rtl)) {
2969
+ translate: var(--edit-grip-offset, 0.25rem) 0;
2970
+ }
2971
+
2972
+ :where([data-edit-grip][hidden]) {
2973
+ display: none;
2974
+ }
2975
+
2976
+ /* Lifted, following the pointer */
2977
+ :where([data-edit-dragging=""]) {
2974
2978
  z-index: 1000;
2975
2979
  cursor: grabbing;
2980
+ }
2981
+
2982
+ :where([data-edit-dragging=""]):where(:not([data-edit-area="bare"], [data-edit-area="bare"] *)) {
2976
2983
  box-shadow: 0 8px 24px rgb(0 0 0 / 0.18);
2977
2984
  }
2978
2985
 
2979
- /* The stand-in holding the slot the drop would land in — a translucent copy of
2980
- the element by default, because the clearest preview of where it lands is the
2981
- thing itself. Restyle it freely: hide its contents for an empty outlined slot,
2982
- give it a background, animate it. */
2986
+ /* Grabbed from the keyboard */
2987
+ :where([data-edit-dragging="keyboard"]):where(:not([data-edit-area="bare"], [data-edit-area="bare"] *)) {
2988
+ outline: 2px dashed var(--edit-accent, var(--color-brand-content));
2989
+ outline-offset: 3px;
2990
+ }
2991
+
2992
+ /* The stand-in holding the slot the drop would land in */
2983
2993
  :where([data-edit-ghost]) {
2984
2994
  opacity: var(--edit-ghost-opacity, 0.4);
2985
2995
  pointer-events: none;
2986
2996
  }
2987
2997
 
2988
- /* Valid cross-region destinations during a drag: a dashed invitation, and
2989
- enough height that an EMPTY region can be dropped onto at all. */
2990
- :where([data-edit-drop-target]) {
2998
+ :where([data-edit-area="bare"] [data-edit-ghost]) {
2999
+ opacity: 0;
3000
+ }
3001
+
3002
+ /* The container the drop would land in */
3003
+ :where(:has(> [data-edit-ghost])):where(:not([data-edit-area="bare"], [data-edit-area="bare"] *)) {
2991
3004
  outline: 1px dashed color-mix(in oklch, var(--edit-accent, var(--color-brand-content)) 55%, transparent);
2992
3005
  outline-offset: 4px;
3006
+ }
3007
+
3008
+ /* Other areas a drag can land in; an empty one still has a surface */
3009
+ :where([data-edit-drop-target]):where(:not([data-edit-area="bare"])) {
3010
+ min-height: 2.5rem;
3011
+ outline: 1px dashed color-mix(in oklch, var(--edit-accent, var(--color-brand-content)) 55%, transparent);
3012
+ outline-offset: 4px;
3013
+ }
3014
+
3015
+ /* While dragging: empty containers can be dropped into, nothing else reacts */
3016
+ :where([data-edit-area]:not([data-edit-area="bare"]):has([data-edit-dragging=""])) :where(:empty:not(img, input, br, hr, svg, video, canvas, iframe, textarea, [data-edit-ghost], [data-edit-handle], [data-edit-area="bare"], [data-edit-area="bare"] *)) {
2993
3017
  min-height: 2.5rem;
2994
3018
  }
2995
3019
 
2996
- /* Nothing else should react while a drag is in progress */
2997
- :where([data-edit-dragging-in]) {
3020
+ :where([data-edit-area]:has([data-edit-dragging=""])) {
2998
3021
  cursor: grabbing;
2999
3022
  user-select: none;
3000
3023
 
3001
- & :where([data-edit-sortable]:not([data-edit-dragging])) {
3024
+ & :where([data-edit-piece]:not([data-edit-dragging])) {
3002
3025
  cursor: grabbing;
3003
3026
  }
3004
3027
  }
3005
3028
 
3006
- :where([data-edit-grabbed]) {
3007
- outline: 2px dashed var(--edit-accent, var(--color-brand-content));
3008
- outline-offset: 3px;
3009
- }
3010
-
3011
- /* ---- Move (positioned children) ---- */
3012
- :where([data-edit-movable]) {
3013
- cursor: move;
3014
- touch-action: none;
3015
- }
3016
-
3017
- :where([data-edit-ui] [data-edit-movable], [data-edit-ui][data-edit-movable]):hover {
3018
- outline: 1px solid var(--edit-accent, var(--color-brand-content));
3019
- outline-offset: 2px;
3020
- }
3021
-
3022
- /* ---- Inline text ----
3023
- One weight everywhere: hover hints and the focused caret both use the same
3024
- 1px line, so focusing doesn't make the page jump a weight class. */
3025
- :where([data-edit-ui]) :where([data-edit-armed]) [contenteditable="true"],
3026
- :where([data-edit-ui])[data-edit-armed] [contenteditable="true"] {
3029
+ /* ---- Inline text ---- */
3030
+ :where([data-edit-area]:not([data-edit-area="bare"])) :where([contenteditable="true"], [data-edit-text]):where(:not([data-edit-area="bare"] *)),
3031
+ :where([data-edit-area]:is([contenteditable="true"], [data-edit-text]):not([data-edit-area="bare"])) {
3027
3032
  cursor: text;
3028
3033
  outline: 1px solid transparent;
3029
3034
  outline-offset: 2px;
3030
3035
  border-radius: 3px;
3031
3036
  transition: outline-color 0.12s ease;
3032
- }
3033
3037
 
3034
- :where([data-edit-ui]) :where([data-edit-armed]) [contenteditable="true"]:hover,
3035
- :where([data-edit-ui])[data-edit-armed] [contenteditable="true"]:hover {
3036
- outline-color: color-mix(in oklch, var(--edit-accent, var(--color-brand-content)) 45%, transparent);
3037
- }
3038
+ &:hover {
3039
+ outline-color: color-mix(in oklch, var(--edit-accent, var(--color-brand-content)) 45%, transparent);
3040
+ }
3038
3041
 
3039
- :where([data-edit-ui]) :where([data-edit-armed]) [contenteditable="true"]:focus,
3040
- :where([data-edit-ui])[data-edit-armed] [contenteditable="true"]:focus {
3041
- outline-color: var(--edit-accent, var(--color-brand-content));
3042
+ &:focus {
3043
+ outline-color: var(--edit-accent, var(--color-brand-content));
3044
+ }
3042
3045
  }
3043
3046
 
3044
- /* ---- Size handles ----
3045
- Injected as siblings of the element's own markup, so its native :hover and
3046
- :focus still fire and its body stays interactive. */
3047
- :where([data-edit-sizable]) {
3047
+ /* ---- Size handles ---- */
3048
+ :where(:has(> [data-edit-handle])) {
3048
3049
  position: relative;
3049
3050
  }
3050
3051
 
3051
- /* Handles reveal on approach rather than sitting on the element permanently.
3052
- The hairline is chrome, so it follows the [data-edit-ui] scope like every
3053
- other affordance; outside the scope the handles still work (hit areas and
3054
- resize cursors stay), they just draw nothing. */
3055
- :where([data-edit-sizable]) :where([data-edit-handle])::before {
3052
+ :where([data-edit-handle])::before {
3056
3053
  opacity: 0;
3057
3054
  transition: opacity 0.12s ease, background-color 0.15s ease;
3058
3055
  }
3059
3056
 
3060
- :where([data-edit-ui] [data-edit-sizable], [data-edit-ui][data-edit-sizable]):is(:hover, :focus-within) :where([data-edit-handle])::before {
3057
+ :where(:has(> [data-edit-handle])):is(:hover, :focus-within):where(:not([data-edit-area="bare"], [data-edit-area="bare"] *)) > :where([data-edit-handle])::before {
3061
3058
  opacity: 1;
3062
3059
  }
3063
3060
 
@@ -3065,9 +3062,9 @@
3065
3062
  position: absolute;
3066
3063
  z-index: 100;
3067
3064
  background: transparent;
3065
+ touch-action: none;
3068
3066
  --h: var(--edit-size-handle, 1rem);
3069
3067
 
3070
- /* Hairline, revealed on hover */
3071
3068
  &::before {
3072
3069
  content: '';
3073
3070
  position: absolute;
@@ -3087,11 +3084,10 @@
3087
3084
  }
3088
3085
  }
3089
3086
 
3090
- :where([data-edit-handle]):focus-visible {
3087
+ :where([data-edit-handle]):focus-visible:where(:not([data-edit-area="bare"], [data-edit-area="bare"] *)) {
3091
3088
  outline: 2px solid var(--edit-accent, var(--color-brand-content));
3092
3089
  }
3093
3090
 
3094
- /* Edges span their axis; corners are square. A corner value contains a hyphen. */
3095
3091
  :where([data-edit-handle="top"], [data-edit-handle="bottom"]) {
3096
3092
  left: 0;
3097
3093
  width: 100%;
@@ -3119,8 +3115,6 @@
3119
3115
  height: var(--h);
3120
3116
  }
3121
3117
 
3122
- /* Inset — each handle straddles its edge; a corner matches one rule per axis.
3123
- inset-inline-* carries the logical start/end values, so they flip for RTL. */
3124
3118
  :where([data-edit-handle^="top"]) {
3125
3119
  top: calc(var(--h) * -0.5);
3126
3120
  }
@@ -3145,7 +3139,6 @@
3145
3139
  inset-inline-end: calc(var(--h) * -0.5);
3146
3140
  }
3147
3141
 
3148
- /* Corner cursors; the logical pair flips with direction. */
3149
3142
  :where([data-edit-handle="top-left"], [data-edit-handle="bottom-right"], [data-edit-handle="top-start"], [data-edit-handle="bottom-end"]) {
3150
3143
  cursor: nwse-resize;
3151
3144
  }
@@ -3162,12 +3155,12 @@
3162
3155
  cursor: nwse-resize;
3163
3156
  }
3164
3157
 
3165
- /* Collapsed past --edit-size-collapse-* — authors restyle freely */
3166
- :where([data-edit-collapsed]) {
3167
- opacity: 0.45;
3158
+ /* Bare: handles keep their hit areas and cursors, draw nothing */
3159
+ :where([data-edit-area="bare"] [data-edit-handle])::before {
3160
+ content: none;
3168
3161
  }
3169
3162
 
3170
- /* Full-viewport capture layer during a size or move drag */
3163
+ /* Pointer capture layer during a resize */
3171
3164
  :where([data-edit-overlay]) {
3172
3165
  position: fixed;
3173
3166
  inset: 0;
@@ -3175,7 +3168,7 @@
3175
3168
  background: transparent;
3176
3169
  }
3177
3170
 
3178
- /* Screen-reader announcements (keyboard grab / move / drop) */
3171
+ /* Screen-reader announcements */
3179
3172
  :where([data-edit-live]) {
3180
3173
  position: absolute;
3181
3174
  width: 1px;
@@ -3190,69 +3183,13 @@
3190
3183
 
3191
3184
  @media (prefers-reduced-motion: reduce) {
3192
3185
 
3193
- :where([data-edit-armed]) > [draggable="true"],
3186
+ :where([data-edit-piece]),
3194
3187
  :where([data-edit-handle])::before {
3195
3188
  transition: none;
3196
3189
  }
3197
3190
  }
3198
3191
  }
3199
3192
 
3200
- /* ---- Authoring chrome (toolbar + class/scope menu) ---- */
3201
- @layer components {
3202
-
3203
- /* Presence is script's business — it knows which route is on screen. Whether it
3204
- is seen is not, so the toolbar is styled and revealed here. */
3205
- :where([data-edit-toolbar]) {
3206
- display: none;
3207
- position: fixed;
3208
- inset-block-end: 1rem;
3209
- inset-inline-end: 1rem;
3210
- z-index: 9999;
3211
- gap: 0.5rem;
3212
- align-items: center;
3213
-
3214
- & button[disabled] {
3215
- opacity: 0.35;
3216
- pointer-events: none;
3217
- }
3218
- }
3219
-
3220
- /* --edit-toolbar: none (any scope up to :root) suppresses it — e.g. a site
3221
- that demos .authoring regions but has its own publish flow. */
3222
- :root[data-edit-active] :where([data-edit-toolbar]) {
3223
- display: var(--edit-toolbar, flex);
3224
- }
3225
-
3226
- /* A popover: the top layer sits above every stacking context, so no handle,
3227
- overlay or z-index anywhere on the page can paint over it. */
3228
- :where([data-edit-menu]) {
3229
- position: fixed;
3230
- margin: 0;
3231
- width: 16rem;
3232
- padding: 0.6rem;
3233
- display: flex;
3234
- flex-direction: column;
3235
- gap: 0.4rem;
3236
- background: var(--color-surface-1);
3237
- border: 1px solid var(--color-line);
3238
- border-radius: var(--radius);
3239
- box-shadow: 0 8px 30px rgb(0 0 0 / 0.2);
3240
-
3241
- & input {
3242
- width: 100%;
3243
- font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
3244
- font-size: 0.75rem;
3245
- }
3246
-
3247
- & small {
3248
- font-size: 0.7rem;
3249
- text-transform: uppercase;
3250
- letter-spacing: 0.05em;
3251
- color: var(--color-content-subtle);
3252
- }
3253
- }
3254
- }
3255
-
3256
3193
  /* Manifest Forms */
3257
3194
 
3258
3195
  @layer base, components, utilities;
@@ -3917,6 +3854,260 @@
3917
3854
  }
3918
3855
  }
3919
3856
 
3857
+ /* Manifest Rich Text */
3858
+
3859
+ @layer base, components, utilities;
3860
+
3861
+ @layer components {
3862
+
3863
+ :where([data-rich-text]:not([data-edit-text])) {
3864
+ position: relative;
3865
+ overflow-y: auto;
3866
+ max-height: var(--rich-text-max-height, none);
3867
+ outline: none;
3868
+
3869
+ /* Document-wide styles (.all controls, $rich.all) */
3870
+ font-family: var(--rich-text-font, inherit);
3871
+ font-size: var(--rich-text-size, inherit);
3872
+ line-height: var(--rich-text-leading, inherit);
3873
+ text-align: var(--rich-text-align, start);
3874
+ color: var(--rich-text-color, inherit);
3875
+
3876
+ /* Placeholder overlays the first line */
3877
+ &[data-rich-text-empty]::before {
3878
+ content: attr(placeholder);
3879
+ position: absolute;
3880
+ inset-block-start: var(--rich-text-padding, 0.75rem);
3881
+ inset-inline: var(--rich-text-padding, 0.75rem);
3882
+ color: var(--color-content-subtle);
3883
+ pointer-events: none;
3884
+ }
3885
+ }
3886
+
3887
+ /* .all background on an unstyled area */
3888
+ :where([data-rich-text].unstyle[style*="--rich-text-background"]) {
3889
+ background: var(--rich-text-background);
3890
+ }
3891
+
3892
+ /* Unstyled: placeholder hugs the line */
3893
+ :where([data-rich-text].unstyle)[data-rich-text-empty]::before {
3894
+ inset-block-start: 0;
3895
+ inset-inline: 0;
3896
+ }
3897
+
3898
+ /* Field look; .unstyle drops it */
3899
+ :where([data-rich-text]:not(.unstyle, [data-edit-text])) {
3900
+ min-height: var(--rich-text-min-height, 8rem);
3901
+ padding: var(--rich-text-padding, 0.75rem);
3902
+ background: var(--rich-text-background, var(--color-surface-1));
3903
+ border: 1px solid var(--color-line);
3904
+ border-radius: var(--radius);
3905
+
3906
+ /* Held while a focus-taking control acts on the area */
3907
+ &:focus,
3908
+ &[data-rich-text-focused] {
3909
+ border-color: var(--color-content-subtle);
3910
+ }
3911
+ }
3912
+
3913
+ /* Single-line (.inline) */
3914
+ :where([data-rich-text-inline]:not(.unstyle, [data-edit-text])) {
3915
+ min-height: var(--rich-text-min-height, auto);
3916
+ }
3917
+
3918
+ /* ---- Selection menu (x-rich-text-menu) ---- */
3919
+ :where([data-rich-text-menu]) {
3920
+ position: fixed;
3921
+ margin: 0;
3922
+ inset: auto;
3923
+ left: var(--rich-text-selection-center);
3924
+ top: var(--rich-text-selection-y);
3925
+ transform: translate(-50%, calc(-100% - 0.5rem));
3926
+ gap: 0.25rem;
3927
+ align-items: center;
3928
+ padding: 0.25rem;
3929
+ background: var(--color-surface-1);
3930
+ border: 1px solid var(--color-line);
3931
+ border-radius: var(--radius);
3932
+ box-shadow: 0 8px 30px rgb(0 0 0 / 0.2);
3933
+ }
3934
+
3935
+ /* Display only while open */
3936
+ :where([data-rich-text-menu]:popover-open) {
3937
+ display: flex;
3938
+ }
3939
+
3940
+ /* No Popover API: hidden */
3941
+ @supports not selector(:popover-open) {
3942
+ :where([data-rich-text-menu]) {
3943
+ display: none;
3944
+ }
3945
+ }
3946
+
3947
+ /* ---- Controls ---- */
3948
+ :where([data-rich-text-control]) {
3949
+ &[data-rich-text-active] {
3950
+ background: color-mix(in oklch, var(--color-content-stark) 10%, transparent);
3951
+ color: var(--color-content-stark);
3952
+ }
3953
+
3954
+ & > svg {
3955
+ width: 1rem;
3956
+ height: 1rem;
3957
+ }
3958
+ }
3959
+
3960
+ /* Icon-only buttons */
3961
+ :where(button[data-rich-text-control]:has(> svg:only-child)) {
3962
+ padding: 0.35rem;
3963
+ line-height: 0;
3964
+ }
3965
+
3966
+ /* Disabled controls still catch the click, so the area keeps focus */
3967
+ :where([data-rich-text-control][aria-disabled=true]) {
3968
+ pointer-events: auto;
3969
+ }
3970
+
3971
+ /* ---- Editable content ---- */
3972
+ :where([data-rich-text]:not([data-edit-text])) {
3973
+
3974
+ & > * + * {
3975
+ margin-block-start: 0.75em;
3976
+ }
3977
+
3978
+ & :where(h1, h2, h3, h4, h5, h6) {
3979
+ font-weight: 600;
3980
+ line-height: 1.25;
3981
+ }
3982
+
3983
+ & h1 { font-size: 1.6em }
3984
+ & h2 { font-size: 1.35em }
3985
+ & h3 { font-size: 1.15em }
3986
+
3987
+ & :where(ul, ol) {
3988
+ padding-inline-start: 1.5em;
3989
+ }
3990
+
3991
+ & li {
3992
+ list-style: revert;
3993
+ }
3994
+
3995
+ & blockquote {
3996
+ padding-inline-start: 0.85em;
3997
+ border-inline-start: 2px solid var(--color-line);
3998
+ color: var(--color-content-neutral);
3999
+ }
4000
+
4001
+ & code {
4002
+ padding: 0.1em 0.3em;
4003
+ border-radius: 4px;
4004
+ font-size: 0.9em;
4005
+ background: color-mix(in oklch, var(--color-content-stark) 8%, transparent);
4006
+ }
4007
+
4008
+ & pre {
4009
+ padding: 0.75em;
4010
+ border-radius: var(--radius);
4011
+ overflow-x: auto;
4012
+ background: color-mix(in oklch, var(--color-content-stark) 8%, transparent);
4013
+
4014
+ & code {
4015
+ padding: 0;
4016
+ background: none;
4017
+ }
4018
+ }
4019
+
4020
+ & a {
4021
+ color: var(--color-brand-content);
4022
+ text-decoration: underline;
4023
+ }
4024
+
4025
+ & hr {
4026
+ margin-block: 1em;
4027
+ }
4028
+
4029
+ & img {
4030
+ max-width: 100%;
4031
+ }
4032
+
4033
+ & table {
4034
+ width: 100%;
4035
+ table-layout: fixed;
4036
+
4037
+ & :where(td, th) {
4038
+ padding: 0.35em 0.5em;
4039
+ border: 1px solid var(--color-line);
4040
+ vertical-align: top;
4041
+ }
4042
+
4043
+ & th {
4044
+ font-weight: 600;
4045
+ text-align: start;
4046
+ background: var(--color-surface-2);
4047
+ }
4048
+ }
4049
+
4050
+ /* Cell block selection */
4051
+ & :where(td, th)[data-rich-text-cell] {
4052
+ background: color-mix(in oklch, var(--color-brand-content) 18%, transparent);
4053
+ }
4054
+
4055
+ /* Table border resizing */
4056
+ &[data-rich-text-border="x"] { cursor: col-resize }
4057
+ &[data-rich-text-border="y"] { cursor: row-resize }
4058
+ &[data-rich-text-resizing] { user-select: none }
4059
+ &[data-rich-text-resizing="x"] { cursor: col-resize }
4060
+ &[data-rich-text-resizing="y"] { cursor: row-resize }
4061
+
4062
+ /* Task lists */
4063
+ & :where(ul[data-checklist]) {
4064
+ padding-inline-start: 0.25em;
4065
+ list-style: none;
4066
+
4067
+ & li {
4068
+ display: flex;
4069
+ align-items: baseline;
4070
+ gap: 0.5em;
4071
+ list-style: none;
4072
+ }
4073
+ }
4074
+
4075
+ & :where(dt) {
4076
+ font-weight: 600;
4077
+ }
4078
+
4079
+ & :where(dd) {
4080
+ margin-inline-start: 1.5em;
4081
+ }
4082
+
4083
+ & :where(kbd) {
4084
+ padding: 0.1em 0.35em;
4085
+ border: 1px solid var(--color-line);
4086
+ border-radius: 4px;
4087
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
4088
+ font-size: 0.85em;
4089
+ }
4090
+
4091
+ & :where(mark) {
4092
+ background: color-mix(in oklch, var(--color-brand-content) 25%, transparent);
4093
+ color: inherit;
4094
+ }
4095
+
4096
+ & :where(small) {
4097
+ font-size: 0.8em;
4098
+ }
4099
+
4100
+ & :where(figcaption) {
4101
+ font-size: 0.8em;
4102
+ color: var(--color-content-neutral);
4103
+ }
4104
+
4105
+ & :where(abbr, dfn) {
4106
+ text-decoration: underline dotted;
4107
+ }
4108
+ }
4109
+ }
4110
+
3920
4111
  /* Manifest Sidebars */
3921
4112
 
3922
4113
  @layer base, components, utilities;
@@ -4213,280 +4404,6 @@
4213
4404
  }
4214
4405
  }
4215
4406
 
4216
- /* Manifest Text Edit */
4217
-
4218
- @layer base, components, utilities;
4219
-
4220
- /* Self-contained. The editable area is a field first — it borrows the tokens inputs
4221
- and textareas use, so it sits in a form without looking bolted on. Controls are
4222
- styled where they are, not by where they sit, because they can be anywhere. */
4223
-
4224
- @layer components {
4225
-
4226
- :where([data-text-edit]) {
4227
- position: relative;
4228
- overflow-y: auto;
4229
- max-height: var(--text-edit-max-height, none);
4230
- outline: none;
4231
-
4232
- /* Page-level styling — set by .page controls, read back by $text.page.
4233
- Presentation, so it lives here rather than inside the stored markup. */
4234
- font-family: var(--text-edit-font, inherit);
4235
- font-size: var(--text-edit-size, inherit);
4236
- line-height: var(--text-edit-leading, inherit);
4237
- text-align: var(--text-edit-align, start);
4238
- color: var(--text-edit-color, inherit);
4239
-
4240
- /* Flagged from script: :empty never matches the <br> a contenteditable
4241
- keeps, and the tag holding it is not predictable after a wipe. The
4242
- placeholder OVERLAYS the first line (it is not a line of its own), so
4243
- the caret sits on top of it and nothing jumps when typing starts. */
4244
- &[data-text-edit-empty]::before {
4245
- content: attr(placeholder);
4246
- position: absolute;
4247
- inset-block-start: var(--text-edit-padding, 0.75rem);
4248
- inset-inline: var(--text-edit-padding, 0.75rem);
4249
- color: var(--color-content-subtle);
4250
- pointer-events: none;
4251
- }
4252
- }
4253
-
4254
- /* A .page background applies to an unstyled area too. */
4255
- :where([data-text-edit].unstyle[style*="--text-edit-background"]) {
4256
- background: var(--text-edit-background);
4257
- }
4258
-
4259
- /* An unstyled area has no field padding, so its placeholder hugs the line. */
4260
- :where([data-text-edit].unstyle)[data-text-edit-empty]::before {
4261
- inset-block-start: 0;
4262
- inset-inline: 0;
4263
- }
4264
-
4265
- /* The FIELD look. `.unstyle` drops it so an area can sit seamlessly in a
4266
- page — a WYSIWYG document inherits its element's own type and colours;
4267
- everything above (caret custody, placeholder, commands) still works. */
4268
- :where([data-text-edit]:not(.unstyle)) {
4269
- min-height: var(--text-edit-min-height, 8rem);
4270
- padding: var(--text-edit-padding, 0.75rem);
4271
- background: var(--text-edit-background, var(--color-surface-1));
4272
- border: 1px solid var(--color-line);
4273
- border-radius: var(--radius);
4274
-
4275
- /* Held while the area owns the editing session — a <select> or colour
4276
- control takes NATIVE focus by design, and the ring must not flicker
4277
- off while the writer is mid-command. */
4278
- &:focus,
4279
- &[data-text-edit-focused] {
4280
- border-color: var(--color-content-subtle);
4281
- }
4282
- }
4283
-
4284
- /* ---- Selection menu (x-text-edit-menu) ----
4285
- Positioned by the --text-edit-selection-* variables the plugin writes to
4286
- :root, so the default needs no script; restyle or reposition freely. */
4287
- :where([data-text-edit-menu]) {
4288
- position: fixed;
4289
- margin: 0;
4290
- inset: auto;
4291
- left: var(--text-edit-selection-center);
4292
- top: var(--text-edit-selection-y);
4293
- transform: translate(-50%, calc(-100% - 0.5rem));
4294
- gap: 0.25rem;
4295
- align-items: center;
4296
- padding: 0.25rem;
4297
- background: var(--color-surface-1);
4298
- border: 1px solid var(--color-line);
4299
- border-radius: var(--radius);
4300
- box-shadow: 0 8px 30px rgb(0 0 0 / 0.2);
4301
- }
4302
-
4303
- /* display only while OPEN: an author display on the base rule would beat
4304
- the UA's closed-popover display:none, leaving the menu floating fixed
4305
- over the page before any selection exists. */
4306
- :where([data-text-edit-menu]:popover-open) {
4307
- display: flex;
4308
- }
4309
-
4310
- /* Without the Popover API the attribute is inert and the menu would render
4311
- permanently fixed on the page — hide it there; the bubble is progressive
4312
- enhancement. (In supporting browsers a closed popover is hidden natively.) */
4313
- @supports not selector(:popover-open) {
4314
- :where([data-text-edit-menu]) {
4315
- display: none;
4316
- }
4317
- }
4318
-
4319
- /* ---- Controls ----
4320
- A control is marked wherever it lives, so a toolbar is optional markup and
4321
- never a requirement. The reset already dims [aria-disabled=true]. */
4322
- :where([data-text-edit-control]) {
4323
- &[data-text-edit-active] {
4324
- background: color-mix(in oklch, var(--color-content-stark) 10%, transparent);
4325
- color: var(--color-content-stark);
4326
- }
4327
-
4328
- & > svg {
4329
- width: 1rem;
4330
- height: 1rem;
4331
- }
4332
- }
4333
-
4334
- /* Icon-only buttons; text buttons keep the house padding. */
4335
- :where(button[data-text-edit-control]:has(> svg:only-child)) {
4336
- padding: 0.35rem;
4337
- line-height: 0;
4338
- }
4339
-
4340
- /* The reset drops pointer events on disabled elements; a click would fall
4341
- through and blur the area. The plugin ignores it instead. */
4342
- :where([data-text-edit-control][aria-disabled=true]) {
4343
- pointer-events: auto;
4344
- }
4345
-
4346
- /* ---- Editable content ----
4347
- The editor authors real block elements, so style them as elements. Deliberately
4348
- lighter than the .prose class, which sets a reading measure this field can't use. */
4349
- :where([data-text-edit]) {
4350
-
4351
- & > * + * {
4352
- margin-block-start: 0.75em;
4353
- }
4354
-
4355
- & :where(h1, h2, h3, h4, h5, h6) {
4356
- font-weight: 600;
4357
- line-height: 1.25;
4358
- }
4359
-
4360
- & h1 { font-size: 1.6em }
4361
- & h2 { font-size: 1.35em }
4362
- & h3 { font-size: 1.15em }
4363
-
4364
- & :where(ul, ol) {
4365
- padding-inline-start: 1.5em;
4366
- }
4367
-
4368
- & li {
4369
- list-style: revert;
4370
- }
4371
-
4372
- & blockquote {
4373
- padding-inline-start: 0.85em;
4374
- border-inline-start: 2px solid var(--color-line);
4375
- color: var(--color-content-neutral);
4376
- }
4377
-
4378
- & code {
4379
- padding: 0.1em 0.3em;
4380
- border-radius: 4px;
4381
- font-size: 0.9em;
4382
- background: color-mix(in oklch, var(--color-content-stark) 8%, transparent);
4383
- }
4384
-
4385
- & pre {
4386
- padding: 0.75em;
4387
- border-radius: var(--radius);
4388
- overflow-x: auto;
4389
- background: color-mix(in oklch, var(--color-content-stark) 8%, transparent);
4390
-
4391
- & code {
4392
- padding: 0;
4393
- background: none;
4394
- }
4395
- }
4396
-
4397
- & a {
4398
- color: var(--color-brand-content);
4399
- text-decoration: underline;
4400
- }
4401
-
4402
- & hr {
4403
- margin-block: 1em;
4404
- }
4405
-
4406
- & img {
4407
- max-width: 100%;
4408
- }
4409
-
4410
- & table {
4411
- width: 100%;
4412
- table-layout: fixed;
4413
-
4414
- & :where(td, th) {
4415
- padding: 0.35em 0.5em;
4416
- border: 1px solid var(--color-line);
4417
- vertical-align: top;
4418
- }
4419
-
4420
- & th {
4421
- font-weight: 600;
4422
- text-align: start;
4423
- background: var(--color-surface-2);
4424
- }
4425
- }
4426
-
4427
- /* A block selection across cells. The browser can only highlight text, so an
4428
- empty cell shows nothing — this is what makes a spreadsheet-style
4429
- selection visible. */
4430
- & :where(td, th)[data-text-edit-cell] {
4431
- background: color-mix(in oklch, var(--color-brand-content) 18%, transparent);
4432
- }
4433
-
4434
- /* Borders read as grabbable only when the pointer is on one */
4435
- &[data-text-edit-border="x"] { cursor: col-resize }
4436
- &[data-text-edit-border="y"] { cursor: row-resize }
4437
- &[data-text-edit-resizing] { user-select: none }
4438
- &[data-text-edit-resizing="x"] { cursor: col-resize }
4439
- &[data-text-edit-resizing="y"] { cursor: row-resize }
4440
-
4441
- /* Task lists — the checkbox replaces the marker */
4442
- & :where(ul[data-checklist]) {
4443
- padding-inline-start: 0.25em;
4444
- list-style: none;
4445
-
4446
- & li {
4447
- display: flex;
4448
- align-items: baseline;
4449
- gap: 0.5em;
4450
- list-style: none;
4451
- }
4452
- }
4453
-
4454
- & :where(dt) {
4455
- font-weight: 600;
4456
- }
4457
-
4458
- & :where(dd) {
4459
- margin-inline-start: 1.5em;
4460
- }
4461
-
4462
- & :where(kbd) {
4463
- padding: 0.1em 0.35em;
4464
- border: 1px solid var(--color-line);
4465
- border-radius: 4px;
4466
- font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
4467
- font-size: 0.85em;
4468
- }
4469
-
4470
- & :where(mark) {
4471
- background: color-mix(in oklch, var(--color-brand-content) 25%, transparent);
4472
- color: inherit;
4473
- }
4474
-
4475
- & :where(small) {
4476
- font-size: 0.8em;
4477
- }
4478
-
4479
- & :where(figcaption) {
4480
- font-size: 0.8em;
4481
- color: var(--color-content-neutral);
4482
- }
4483
-
4484
- & :where(abbr, dfn) {
4485
- text-decoration: underline dotted;
4486
- }
4487
- }
4488
- }
4489
-
4490
4407
  /* ManifestToasts */
4491
4408
 
4492
4409
  @layer base, components, utilities;