efficient-web-builder 0.10.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +50 -367
- package/README.md +108 -261
- package/dist/components/AddBlockRow.d.ts +1 -0
- package/dist/components/AddBlockRow.js +1 -0
- package/dist/components/AddChildRow.d.ts +1 -0
- package/dist/components/AddChildRow.js +1 -0
- package/dist/components/AddSidePanel.d.ts +2 -0
- package/dist/components/AddSidePanel.js +1 -0
- package/dist/components/AnimatedStat.d.ts +6 -0
- package/dist/components/AnimatedStat.js +1 -0
- package/dist/components/ApplyCornersToSiblings.d.ts +9 -0
- package/dist/components/ApplyCornersToSiblings.js +1 -0
- package/dist/components/Banner.d.ts +12 -0
- package/dist/components/Banner.js +1 -0
- package/dist/components/BlockFrame.d.ts +15 -0
- package/dist/components/BlockFrame.js +1 -0
- package/dist/components/BlockGapField.d.ts +5 -0
- package/dist/components/BlockGapField.js +1 -0
- package/dist/components/BlogPostSource.d.ts +14 -0
- package/dist/components/BlogPostSource.js +1 -0
- package/dist/components/BoxSurfaceContext.d.ts +7 -0
- package/dist/components/BoxSurfaceContext.js +1 -0
- package/dist/components/BoxTabs.d.ts +6 -0
- package/dist/components/BoxTabs.js +1 -0
- package/dist/components/Breadcrumb.d.ts +10 -0
- package/dist/components/Breadcrumb.js +1 -0
- package/dist/components/Btn.d.ts +22 -0
- package/dist/components/Btn.js +1 -0
- package/dist/components/ButtonBlock.d.ts +13 -0
- package/dist/components/ButtonBlock.js +1 -0
- package/dist/components/CardShadowField.d.ts +6 -0
- package/dist/components/CardShadowField.js +1 -0
- package/dist/components/Cards.d.ts +15 -0
- package/dist/components/Cards.js +1 -0
- package/dist/components/CategoryBar.d.ts +16 -0
- package/dist/components/CategoryBar.js +1 -0
- package/dist/components/ChartSection.d.ts +16 -0
- package/dist/components/ChartSection.js +1 -0
- package/dist/components/ChatSettingsPanel.d.ts +1 -0
- package/dist/components/ChatSettingsPanel.js +1 -0
- package/dist/components/ClearColoursDialog.d.ts +5 -0
- package/dist/components/ClearColoursDialog.js +1 -0
- package/dist/components/ContactLocations.d.ts +17 -0
- package/dist/components/ContactLocations.js +73 -0
- package/dist/components/CornersField.d.ts +6 -0
- package/dist/components/CornersField.js +1 -0
- package/dist/components/CountUpText.d.ts +3 -0
- package/dist/components/CountUpText.js +1 -0
- package/dist/components/Divider.d.ts +9 -0
- package/dist/components/Divider.js +1 -0
- package/dist/components/DocBody.d.ts +13 -0
- package/dist/components/DocBody.js +7 -0
- package/dist/components/DocMasthead.d.ts +13 -0
- package/dist/components/DocMasthead.js +1 -0
- package/dist/components/DocMetaCards.d.ts +10 -0
- package/dist/components/DocMetaCards.js +1 -0
- package/dist/components/DocTabs.d.ts +12 -0
- package/dist/components/DocTabs.js +1 -0
- package/dist/components/DuplicateToPageMenu.d.ts +12 -0
- package/dist/components/DuplicateToPageMenu.js +1 -0
- package/dist/components/EditorScreenMount.d.ts +1 -0
- package/dist/components/EditorScreenMount.js +1 -0
- package/dist/components/EditorStoreProvider.d.ts +1 -0
- package/dist/components/EditorStoreProvider.js +1 -0
- package/dist/components/EditorialSectionHead.d.ts +11 -0
- package/dist/components/EditorialSectionHead.js +1 -0
- package/dist/components/Eyebrow.d.ts +9 -0
- package/dist/components/Eyebrow.js +1 -0
- package/dist/components/FAQ.d.ts +20 -0
- package/dist/components/FAQ.js +1 -0
- package/dist/components/FeaturedCover.d.ts +13 -0
- package/dist/components/FeaturedCover.js +1 -0
- package/dist/components/FieldGlyph.d.ts +12 -0
- package/dist/components/FieldGlyph.js +1 -0
- package/dist/components/Flex.d.ts +32 -0
- package/dist/components/Flex.js +1 -0
- package/dist/components/Footprint.d.ts +16 -0
- package/dist/components/Footprint.js +27 -0
- package/dist/components/Grid.d.ts +11 -0
- package/dist/components/Grid.js +1 -0
- package/dist/components/Heading.d.ts +11 -0
- package/dist/components/Heading.js +1 -0
- package/dist/components/HeadingAudit.d.ts +1 -0
- package/dist/components/HeadingAudit.js +1 -0
- package/dist/components/HeroArrows.d.ts +8 -0
- package/dist/components/HeroArrows.js +1 -0
- package/dist/components/HeroGroup.d.ts +20 -0
- package/dist/components/HeroGroup.js +1 -0
- package/dist/components/HeroHeldFrame.d.ts +8 -0
- package/dist/components/HeroHeldFrame.js +1 -0
- package/dist/components/HeroImageField.d.ts +6 -0
- package/dist/components/HeroImageField.js +1 -0
- package/dist/components/HeroPoster.d.ts +10 -0
- package/dist/components/HeroPoster.js +1 -0
- package/dist/components/HeroSection.d.ts +35 -0
- package/dist/components/HeroSection.js +11 -0
- package/dist/components/HeroSingle.d.ts +17 -0
- package/dist/components/HeroSingle.js +1 -0
- package/dist/components/HeroSlide.d.ts +30 -0
- package/dist/components/HeroSlide.js +1 -0
- package/dist/components/HoverEffectField.d.ts +6 -0
- package/dist/components/HoverEffectField.js +1 -0
- package/dist/components/ImageBlock.d.ts +18 -0
- package/dist/components/ImageBlock.js +1 -0
- package/dist/components/ImageFocusRow.d.ts +7 -0
- package/dist/components/ImageFocusRow.js +1 -0
- package/dist/components/IntegrationsSection.d.ts +14 -0
- package/dist/components/IntegrationsSection.js +1 -0
- package/dist/components/IntroBleed.d.ts +32 -0
- package/dist/components/IntroBleed.js +1 -0
- package/dist/components/KeepHint.d.ts +5 -0
- package/dist/components/KeepHint.js +1 -0
- package/dist/components/KeyFeatures.d.ts +14 -0
- package/dist/components/KeyFeatures.js +1 -0
- package/dist/components/LocationGroupHeader.d.ts +5 -0
- package/dist/components/LocationGroupHeader.js +1 -0
- package/dist/components/LocationsGroupedField.d.ts +5 -0
- package/dist/components/LocationsGroupedField.js +1 -0
- package/dist/components/LocationsTreeContext.d.ts +2 -0
- package/dist/components/LocationsTreeContext.js +1 -0
- package/dist/components/Logo.d.ts +27 -0
- package/dist/components/Logo.js +1 -0
- package/dist/components/LogoBlock.d.ts +8 -0
- package/dist/components/LogoBlock.js +1 -0
- package/dist/components/Logos.d.ts +15 -0
- package/dist/components/Logos.js +1 -0
- package/dist/components/LongRead.d.ts +20 -0
- package/dist/components/LongRead.js +1 -0
- package/dist/components/Manifesto.d.ts +14 -0
- package/dist/components/Manifesto.js +1 -0
- package/dist/components/Masthead.d.ts +16 -0
- package/dist/components/Masthead.js +1 -0
- package/dist/components/MediaSidePanel.d.ts +1 -0
- package/dist/components/MediaSidePanel.js +1 -0
- package/dist/components/MediaUploadField.d.ts +9 -0
- package/dist/components/MediaUploadField.js +1 -0
- package/dist/components/MockupSection.d.ts +59 -0
- package/dist/components/MockupSection.js +1 -0
- package/dist/components/MultiSelectField.d.ts +19 -0
- package/dist/components/MultiSelectField.js +1 -0
- package/dist/components/NodeContextMenu.d.ts +2 -0
- package/dist/components/NodeContextMenu.js +1 -0
- package/dist/components/OrderSummary.d.ts +17 -0
- package/dist/components/OrderSummary.js +1 -0
- package/dist/components/PageEditGuardNotices.d.ts +1 -0
- package/dist/components/PageEditGuardNotices.js +1 -0
- package/dist/components/PagesPanel.d.ts +8 -0
- package/dist/components/PagesPanel.js +1 -0
- package/dist/components/PanelToggleIcon.d.ts +1 -0
- package/dist/components/PanelToggleIcon.js +1 -0
- package/dist/components/ParagraphsA.d.ts +15 -0
- package/dist/components/ParagraphsA.js +1 -0
- package/dist/components/PartGlyphs.d.ts +7 -0
- package/dist/components/PartGlyphs.js +1 -0
- package/dist/components/PartInkControl.d.ts +7 -0
- package/dist/components/PartInkControl.js +1 -0
- package/dist/components/PartResetDot.d.ts +5 -0
- package/dist/components/PartResetDot.js +1 -0
- package/dist/components/PartSettingsPanel.d.ts +68 -0
- package/dist/components/PartSettingsPanel.js +1 -0
- package/dist/components/PartStyledText.d.ts +5 -0
- package/dist/components/PartStyledText.js +1 -0
- package/dist/components/PartTextBox.d.ts +20 -0
- package/dist/components/PartTextBox.js +1 -0
- package/dist/components/PaymentBadges.d.ts +14 -0
- package/dist/components/PaymentBadges.js +1 -0
- package/dist/components/PhoneMenuTools.d.ts +12 -0
- package/dist/components/PhoneMenuTools.js +1 -0
- package/dist/components/PhotographyField.d.ts +6 -0
- package/dist/components/PhotographyField.js +1 -0
- package/dist/components/Placeholder.d.ts +18 -0
- package/dist/components/Placeholder.js +1 -0
- package/dist/components/PostCard.d.ts +37 -0
- package/dist/components/PostCard.js +1 -0
- package/dist/components/PreviewChatContext.d.ts +23 -0
- package/dist/components/PreviewChatContext.js +1 -0
- package/dist/components/PreviewDeviceContext.d.ts +2 -0
- package/dist/components/PreviewDeviceContext.js +1 -0
- package/dist/components/PreviewFocusContext.d.ts +15 -0
- package/dist/components/PreviewFocusContext.js +1 -0
- package/dist/components/PreviewFooterContext.d.ts +17 -0
- package/dist/components/PreviewFooterContext.js +1 -0
- package/dist/components/PreviewHeaderContext.d.ts +97 -0
- package/dist/components/PreviewHeaderContext.js +1 -0
- package/dist/components/PreviewLocationPartContext.d.ts +10 -0
- package/dist/components/PreviewLocationPartContext.js +1 -0
- package/dist/components/PreviewPartAnchors.d.ts +16 -0
- package/dist/components/PreviewPartAnchors.js +1 -0
- package/dist/components/PreviewPartStyleContext.d.ts +21 -0
- package/dist/components/PreviewPartStyleContext.js +1 -0
- package/dist/components/PreviewPartsContext.d.ts +1 -0
- package/dist/components/PreviewPartsContext.js +1 -0
- package/dist/components/PreviewSocialContext.d.ts +30 -0
- package/dist/components/PreviewSocialContext.js +1 -0
- package/dist/components/PreviewSurfaceContext.d.ts +10 -0
- package/dist/components/PreviewSurfaceContext.js +1 -0
- package/dist/components/PreviewThemeFrame.d.ts +6 -0
- package/dist/components/PreviewThemeFrame.js +11 -0
- package/dist/components/PreviewTickerContext.d.ts +4 -0
- package/dist/components/PreviewTickerContext.js +1 -0
- package/dist/components/ProcessSteps.d.ts +32 -0
- package/dist/components/ProcessSteps.js +1 -0
- package/dist/components/Prose.d.ts +9 -0
- package/dist/components/Prose.js +1 -0
- package/dist/components/PublishedFooterContext.d.ts +11 -0
- package/dist/components/PublishedFooterContext.js +1 -0
- package/dist/components/PublishedPartStylesContext.d.ts +15 -0
- package/dist/components/PublishedPartStylesContext.js +1 -0
- package/dist/components/RMark.d.ts +6 -0
- package/dist/components/RMark.js +1 -0
- package/dist/components/Reel.d.ts +15 -0
- package/dist/components/Reel.js +1 -0
- package/dist/components/RuleLine.d.ts +1 -0
- package/dist/components/RuleLine.js +1 -0
- package/dist/components/SearchSelectField.d.ts +22 -0
- package/dist/components/SearchSelectField.js +1 -0
- package/dist/components/SectionAnimation.d.ts +7 -0
- package/dist/components/SectionAnimation.js +1 -0
- package/dist/components/SectionEditor.d.ts +63 -0
- package/dist/components/SectionEditor.js +1 -0
- package/dist/components/SectionEditorShell.d.ts +1 -0
- package/dist/components/SectionEditorShell.js +1 -0
- package/dist/components/SectionEyebrow.d.ts +10 -0
- package/dist/components/SectionEyebrow.js +1 -0
- package/dist/components/SectionHeader.d.ts +29 -0
- package/dist/components/SectionHeader.js +1 -0
- package/dist/components/SectionIcon.d.ts +5 -0
- package/dist/components/SectionIcon.js +1 -0
- package/dist/components/SectionTextEntries.d.ts +5 -0
- package/dist/components/SectionTextEntries.js +1 -0
- package/dist/components/SectionTextPartBridge.d.ts +6 -0
- package/dist/components/SectionTextPartBridge.js +1 -0
- package/dist/components/SectionThemePicker.d.ts +25 -0
- package/dist/components/SectionThemePicker.js +1 -0
- package/dist/components/SectionThumbnail.d.ts +3 -0
- package/dist/components/SectionThumbnail.js +1 -0
- package/dist/components/Series.d.ts +19 -0
- package/dist/components/Series.js +1 -0
- package/dist/components/ShadowColourField.d.ts +5 -0
- package/dist/components/ShadowColourField.js +1 -0
- package/dist/components/SidePanelHead.d.ts +1 -0
- package/dist/components/SidePanelHead.js +1 -0
- package/dist/components/SideSpaceField.d.ts +7 -0
- package/dist/components/SideSpaceField.js +1 -0
- package/dist/components/SiteEditorProvider.d.ts +3 -0
- package/dist/components/SiteEditorProvider.js +1 -0
- package/dist/components/SiteFields.d.ts +6 -0
- package/dist/components/SiteFields.js +1 -0
- package/dist/components/SiteGutterFrame.d.ts +9 -0
- package/dist/components/SiteGutterFrame.js +1 -0
- package/dist/components/SiteLogoContext.d.ts +25 -0
- package/dist/components/SiteLogoContext.js +1 -0
- package/dist/components/SitePhotographyContext.d.ts +8 -0
- package/dist/components/SitePhotographyContext.js +1 -0
- package/dist/components/SiteStyleUnset.d.ts +1 -0
- package/dist/components/SiteStyleUnset.js +1 -0
- package/dist/components/SiteWidthField.d.ts +7 -0
- package/dist/components/SiteWidthField.js +1 -0
- package/dist/components/SlotChildActionsContext.d.ts +2 -0
- package/dist/components/SlotChildActionsContext.js +1 -0
- package/dist/components/SlotChildRows.d.ts +16 -0
- package/dist/components/SlotChildRows.js +1 -0
- package/dist/components/SocialLinksPanel.d.ts +3 -0
- package/dist/components/SocialLinksPanel.js +1 -0
- package/dist/components/SourceStatus.d.ts +14 -0
- package/dist/components/SourceStatus.js +1 -0
- package/dist/components/Spacer.d.ts +6 -0
- package/dist/components/Spacer.js +1 -0
- package/dist/components/SpecStrip.d.ts +10 -0
- package/dist/components/SpecStrip.js +1 -0
- package/dist/components/Split.d.ts +33 -0
- package/dist/components/Split.js +1 -0
- package/dist/components/StandaloneSectionEditor.d.ts +19 -0
- package/dist/components/StandaloneSectionEditor.js +1 -0
- package/dist/components/Stats.d.ts +14 -0
- package/dist/components/Stats.js +1 -0
- package/dist/components/StatsParagraph.d.ts +21 -0
- package/dist/components/StatsParagraph.js +1 -0
- package/dist/components/StorefrontDocumentContext.d.ts +2 -0
- package/dist/components/StorefrontDocumentContext.js +1 -0
- package/dist/components/StorefrontEditor.d.ts +19 -0
- package/dist/components/StorefrontEditor.js +1 -0
- package/dist/components/StorefrontEditorChrome.d.ts +1 -0
- package/dist/components/StorefrontEditorChrome.js +1 -0
- package/dist/components/StorefrontLinkField.d.ts +19 -0
- package/dist/components/StorefrontLinkField.js +1 -0
- package/dist/components/StylesPanel.d.ts +11 -0
- package/dist/components/StylesPanel.js +1 -0
- package/dist/components/SwitchToBoxFooter.d.ts +1 -0
- package/dist/components/SwitchToBoxFooter.js +1 -0
- package/dist/components/TemplateGlyph.d.ts +6 -0
- package/dist/components/TemplateGlyph.js +1 -0
- package/dist/components/Testimonials.d.ts +16 -0
- package/dist/components/Testimonials.js +1 -0
- package/dist/components/Text.d.ts +11 -0
- package/dist/components/Text.js +1 -0
- package/dist/components/TextStyleRow.d.ts +13 -0
- package/dist/components/TextStyleRow.js +1 -0
- package/dist/components/TextStylesField.d.ts +17 -0
- package/dist/components/TextStylesField.js +1 -0
- package/dist/components/ThemeCard.d.ts +40 -0
- package/dist/components/ThemeCard.js +1 -0
- package/dist/components/ThemeColourField.d.ts +5 -0
- package/dist/components/ThemeColourField.js +1 -0
- package/dist/components/ThemeField.d.ts +8 -0
- package/dist/components/ThemeField.js +1 -0
- package/dist/components/Ticker.d.ts +18 -0
- package/dist/components/Ticker.js +1 -0
- package/dist/components/TickerSection.d.ts +18 -0
- package/dist/components/TickerSection.js +1 -0
- package/dist/components/TickerSettingsPanel.d.ts +3 -0
- package/dist/components/TickerSettingsPanel.js +1 -0
- package/dist/components/Timeline.d.ts +24 -0
- package/dist/components/Timeline.js +1 -0
- package/dist/components/TimelineTrack.d.ts +22 -0
- package/dist/components/TimelineTrack.js +1 -0
- package/dist/components/TitleWithButtons.d.ts +14 -0
- package/dist/components/TitleWithButtons.js +1 -0
- package/dist/components/UiIcon.d.ts +2 -0
- package/dist/components/UiIcon.js +1 -0
- package/dist/components/WebsiteScreenParts.d.ts +2 -0
- package/dist/components/WebsiteScreenParts.js +1 -0
- package/dist/components/WebsiteSettingsPanel.d.ts +46 -0
- package/dist/components/WebsiteSettingsPanel.js +1 -0
- package/dist/components/WidthFollowField.d.ts +10 -0
- package/dist/components/WidthFollowField.js +1 -0
- package/dist/components/cartGlyph.d.ts +1 -0
- package/dist/components/cartGlyph.js +1 -0
- package/dist/components/floating-editor/tokens.d.ts +27 -0
- package/dist/components/floating-editor/tokens.js +1 -0
- package/dist/components/goldPhrases.d.ts +7 -0
- package/dist/components/goldPhrases.js +2 -0
- package/dist/components/integrationIcons.d.ts +2 -0
- package/dist/components/integrationIcons.js +1 -0
- package/dist/components/panel-widths.d.ts +2 -0
- package/dist/components/panel-widths.js +1 -0
- package/dist/components/preview-devices.d.ts +3 -0
- package/dist/components/preview-devices.js +1 -0
- package/dist/components/socialIcons.d.ts +8 -0
- package/dist/components/socialIcons.js +1 -0
- package/dist/components/storefront-editor.css +4870 -0
- package/dist/components/useCountUp.d.ts +10 -0
- package/dist/components/useCountUp.js +1 -0
- package/dist/components/useFooterFocus.d.ts +2 -0
- package/dist/components/useFooterFocus.js +1 -0
- package/dist/components/useLocationsTree.d.ts +6 -0
- package/dist/components/useLocationsTree.js +1 -0
- package/dist/components/usePartBridge.d.ts +1 -0
- package/dist/components/usePartBridge.js +1 -0
- package/dist/components/usePinnedChromeSeed.d.ts +2 -0
- package/dist/components/usePinnedChromeSeed.js +1 -0
- package/dist/components/usePreviewHref.d.ts +5 -0
- package/dist/components/usePreviewHref.js +1 -0
- package/dist/components/useReducedMotion.d.ts +4 -0
- package/dist/components/useReducedMotion.js +1 -0
- package/dist/components/useSnapshotSource.d.ts +17 -0
- package/dist/components/useSnapshotSource.js +1 -0
- package/dist/components/useSocialSettings.d.ts +14 -0
- package/dist/components/useSocialSettings.js +1 -0
- package/dist/components/useStorefrontBlogPosts.d.ts +2 -0
- package/dist/components/useStorefrontBlogPosts.js +1 -0
- package/dist/lib/client-only.d.ts +1 -0
- package/dist/lib/client-only.js +1 -0
- package/dist/lib/content/authored-props.d.ts +4 -0
- package/dist/lib/content/authored-props.js +1 -0
- package/dist/lib/content/box-background.d.ts +31 -0
- package/dist/lib/content/box-background.js +1 -0
- package/dist/lib/content/box-layout.d.ts +78 -0
- package/dist/lib/content/box-layout.js +1 -0
- package/dist/lib/content/button-arrow.d.ts +2 -0
- package/dist/lib/content/button-arrow.js +1 -0
- package/dist/lib/content/card-corners.d.ts +12 -0
- package/dist/lib/content/card-corners.js +1 -0
- package/dist/lib/content/card-image-background.d.ts +11 -0
- package/dist/lib/content/card-image-background.js +1 -0
- package/dist/lib/content/card-image-shape.d.ts +5 -0
- package/dist/lib/content/card-image-shape.js +1 -0
- package/dist/lib/content/cart-drawer.d.ts +20 -0
- package/dist/lib/content/cart-drawer.js +1 -0
- package/dist/lib/content/contact.d.ts +79 -0
- package/dist/lib/content/contact.js +3 -0
- package/dist/lib/content/container-direction.d.ts +14 -0
- package/dist/lib/content/container-direction.js +1 -0
- package/dist/lib/content/container-gap.d.ts +31 -0
- package/dist/lib/content/container-gap.js +1 -0
- package/dist/lib/content/footer.d.ts +30 -0
- package/dist/lib/content/footer.js +1 -0
- package/dist/lib/content/footprint.d.ts +22 -0
- package/dist/lib/content/footprint.js +1 -0
- package/dist/lib/content/gallery-card-layout.d.ts +7 -0
- package/dist/lib/content/gallery-card-layout.js +1 -0
- package/dist/lib/content/gallery-layout.d.ts +154 -0
- package/dist/lib/content/gallery-layout.js +1 -0
- package/dist/lib/content/grid-span.d.ts +15 -0
- package/dist/lib/content/grid-span.js +1 -0
- package/dist/lib/content/image-corners.d.ts +7 -0
- package/dist/lib/content/image-corners.js +1 -0
- package/dist/lib/content/image-fit.d.ts +11 -0
- package/dist/lib/content/image-fit.js +1 -0
- package/dist/lib/content/image-treatment.d.ts +20 -0
- package/dist/lib/content/image-treatment.js +1 -0
- package/dist/lib/content/image-width.d.ts +9 -0
- package/dist/lib/content/image-width.js +1 -0
- package/dist/lib/content/page-background.d.ts +4 -0
- package/dist/lib/content/page-background.js +1 -0
- package/dist/lib/content/page-width.d.ts +63 -0
- package/dist/lib/content/page-width.js +1 -0
- package/dist/lib/content/product-page.d.ts +11 -0
- package/dist/lib/content/product-page.js +1 -0
- package/dist/lib/content/section-animation.d.ts +13 -0
- package/dist/lib/content/section-animation.js +1 -0
- package/dist/lib/content/section-background.d.ts +7 -0
- package/dist/lib/content/section-background.js +1 -0
- package/dist/lib/content/section-corners.d.ts +16 -0
- package/dist/lib/content/section-corners.js +1 -0
- package/dist/lib/content/section-height.d.ts +9 -0
- package/dist/lib/content/section-height.js +1 -0
- package/dist/lib/content/section-min-height.d.ts +60 -0
- package/dist/lib/content/section-min-height.js +1 -0
- package/dist/lib/content/section-padding.d.ts +33 -0
- package/dist/lib/content/section-padding.js +1 -0
- package/dist/lib/content/section-surface.d.ts +13 -0
- package/dist/lib/content/section-surface.js +1 -0
- package/dist/lib/content/section-type-size.d.ts +7 -0
- package/dist/lib/content/section-type-size.js +1 -0
- package/dist/lib/content/section-width.d.ts +19 -0
- package/dist/lib/content/section-width.js +1 -0
- package/dist/lib/content/site-gutter.d.ts +2 -0
- package/dist/lib/content/site-gutter.js +1 -0
- package/dist/lib/content/site-name.d.ts +2 -0
- package/dist/lib/content/site-name.js +1 -0
- package/dist/lib/content/social-links.d.ts +12 -0
- package/dist/lib/content/social-links.js +1 -0
- package/dist/lib/content/subscribe.d.ts +76 -0
- package/dist/lib/content/subscribe.js +2 -0
- package/dist/lib/content/view-tiers.d.ts +2 -0
- package/dist/lib/content/view-tiers.js +1 -0
- package/dist/lib/editor/preview-href.d.ts +6 -0
- package/dist/lib/editor/preview-href.js +1 -0
- package/dist/lib/editor-admin-bridge.d.ts +2 -0
- package/dist/lib/editor-admin-bridge.js +1 -0
- package/dist/lib/editor-auth.d.ts +3 -0
- package/dist/lib/editor-auth.js +1 -0
- package/dist/lib/editor-backend-error.d.ts +2 -0
- package/dist/lib/editor-backend-error.js +1 -0
- package/dist/lib/editor-block-metadata.d.ts +6 -0
- package/dist/lib/editor-block-metadata.js +1 -0
- package/dist/lib/editor-blocks.d.ts +20 -0
- package/dist/lib/editor-blocks.js +1 -0
- package/dist/lib/editor-canvas-styles.d.ts +12 -0
- package/dist/lib/editor-canvas-styles.js +1 -0
- package/dist/lib/editor-chrome.d.ts +2 -0
- package/dist/lib/editor-chrome.js +1 -0
- package/dist/lib/editor-document-adapter.d.ts +7 -0
- package/dist/lib/editor-document-adapter.js +1 -0
- package/dist/lib/editor-document-addressing.d.ts +2 -0
- package/dist/lib/editor-document-addressing.js +1 -0
- package/dist/lib/editor-document-contract.d.ts +1 -0
- package/dist/lib/editor-document-contract.js +0 -0
- package/dist/lib/editor-document-hooks.d.ts +1 -0
- package/dist/lib/editor-document-hooks.js +0 -0
- package/dist/lib/editor-document-switch.d.ts +2 -0
- package/dist/lib/editor-document-switch.js +1 -0
- package/dist/lib/editor-events.d.ts +8 -0
- package/dist/lib/editor-events.js +1 -0
- package/dist/lib/editor-failure.d.ts +1 -0
- package/dist/lib/editor-failure.js +1 -0
- package/dist/lib/editor-form-window.d.ts +21 -0
- package/dist/lib/editor-form-window.js +1 -0
- package/dist/lib/editor-host-inbound.d.ts +1 -0
- package/dist/lib/editor-host-inbound.js +1 -0
- package/dist/lib/editor-host.d.ts +2 -0
- package/dist/lib/editor-host.js +1 -0
- package/dist/lib/editor-key-scope.d.ts +1 -0
- package/dist/lib/editor-key-scope.js +1 -0
- package/dist/lib/editor-load-error.d.ts +1 -0
- package/dist/lib/editor-load-error.js +1 -0
- package/dist/lib/editor-media-panel.d.ts +2 -0
- package/dist/lib/editor-media-panel.js +1 -0
- package/dist/lib/editor-media-picker.d.ts +2 -0
- package/dist/lib/editor-media-picker.js +1 -0
- package/dist/lib/editor-page-lock.d.ts +1 -0
- package/dist/lib/editor-page-lock.js +1 -0
- package/dist/lib/editor-page-rows.d.ts +16 -0
- package/dist/lib/editor-page-rows.js +1 -0
- package/dist/lib/editor-screen.d.ts +2 -0
- package/dist/lib/editor-screen.js +1 -0
- package/dist/lib/editor-section-templates.d.ts +1 -0
- package/dist/lib/editor-section-templates.js +1 -0
- package/dist/lib/editor-session-context.d.ts +1 -0
- package/dist/lib/editor-session-context.js +1 -0
- package/dist/lib/editor-session-loader.d.ts +4 -0
- package/dist/lib/editor-session-loader.js +1 -0
- package/dist/lib/editor-session.d.ts +2 -0
- package/dist/lib/editor-session.js +1 -0
- package/dist/lib/editor-site-slug.d.ts +2 -0
- package/dist/lib/editor-site-slug.js +1 -0
- package/dist/lib/editor-site.d.ts +3 -0
- package/dist/lib/editor-site.js +1 -0
- package/dist/lib/editor-theme.d.ts +1 -0
- package/dist/lib/editor-theme.js +1 -0
- package/dist/lib/fit-words.d.ts +3 -0
- package/dist/lib/fit-words.js +220 -0
- package/dist/lib/fonts.d.ts +32 -0
- package/dist/lib/fonts.js +1 -0
- package/dist/lib/geocode.d.ts +6 -0
- package/dist/lib/geocode.js +1 -0
- package/dist/lib/hero-arrows.d.ts +23 -0
- package/dist/lib/hero-arrows.js +1 -0
- package/dist/lib/hero-group-placement.d.ts +46 -0
- package/dist/lib/hero-group-placement.js +1 -0
- package/dist/lib/hero-overlay-anchor.d.ts +6 -0
- package/dist/lib/hero-overlay-anchor.js +1 -0
- package/dist/lib/hero-phone-stack.d.ts +27 -0
- package/dist/lib/hero-phone-stack.js +1 -0
- package/dist/lib/hero-swipe.d.ts +16 -0
- package/dist/lib/hero-swipe.js +1 -0
- package/dist/lib/hero-texture.d.ts +4 -0
- package/dist/lib/hero-texture.js +1 -0
- package/dist/lib/hero-video-control.d.ts +13 -0
- package/dist/lib/hero-video-control.js +1 -0
- package/dist/lib/image-focus.d.ts +16 -0
- package/dist/lib/image-focus.js +1 -0
- package/dist/lib/links/link-filters.d.ts +1 -0
- package/dist/lib/links/link-filters.js +0 -0
- package/dist/lib/links/link-picker-setup.d.ts +29 -0
- package/dist/lib/links/link-picker-setup.js +1 -0
- package/dist/lib/links/page-link-rules.d.ts +22 -0
- package/dist/lib/links/page-link-rules.js +1 -0
- package/dist/lib/locations-grid.d.ts +10 -0
- package/dist/lib/locations-grid.js +1 -0
- package/dist/lib/logo/analyze-logo-client.d.ts +3 -0
- package/dist/lib/logo/analyze-logo-client.js +1 -0
- package/dist/lib/logo/reverse-svg.d.ts +9 -0
- package/dist/lib/logo/reverse-svg.js +1 -0
- package/dist/lib/map-styles.d.ts +30 -0
- package/dist/lib/map-styles.js +1 -0
- package/dist/lib/maps-config.d.ts +16 -0
- package/dist/lib/maps-config.js +1 -0
- package/dist/lib/maps-loader.d.ts +3 -0
- package/dist/lib/maps-loader.js +1 -0
- package/dist/lib/markup.d.ts +38 -0
- package/dist/lib/markup.js +2 -0
- package/dist/lib/media.d.ts +10 -0
- package/dist/lib/media.js +1 -0
- package/dist/lib/parse-option.d.ts +3 -0
- package/dist/lib/parse-option.js +1 -0
- package/dist/lib/popup/text-kinds.d.ts +11 -0
- package/dist/lib/popup/text-kinds.js +1 -0
- package/dist/lib/preview-header-settings.d.ts +39 -0
- package/dist/lib/preview-header-settings.js +0 -0
- package/dist/lib/puck/ColourControl.d.ts +11 -0
- package/dist/lib/puck/ColourControl.js +1 -0
- package/dist/lib/puck/MarkupToolbar.d.ts +13 -0
- package/dist/lib/puck/MarkupToolbar.js +1 -0
- package/dist/lib/puck/add-palette.d.ts +14 -0
- package/dist/lib/puck/add-palette.js +1 -0
- package/dist/lib/puck/add-target-types.d.ts +1 -0
- package/dist/lib/puck/add-target-types.js +0 -0
- package/dist/lib/puck/add-target.d.ts +3 -0
- package/dist/lib/puck/add-target.js +1 -0
- package/dist/lib/puck/apply-card-corners.d.ts +21 -0
- package/dist/lib/puck/apply-card-corners.js +1 -0
- package/dist/lib/puck/block-choice.d.ts +2 -0
- package/dist/lib/puck/block-choice.js +1 -0
- package/dist/lib/puck/block-offer.d.ts +10 -0
- package/dist/lib/puck/block-offer.js +1 -0
- package/dist/lib/puck/block-types-in.d.ts +1 -0
- package/dist/lib/puck/block-types-in.js +1 -0
- package/dist/lib/puck/blocks/block-types.d.ts +12 -0
- package/dist/lib/puck/blocks/block-types.js +1 -0
- package/dist/lib/puck/blocks/general/Banner/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Banner/fields.js +1 -0
- package/dist/lib/puck/blocks/general/Banner/render.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Banner/render.js +1 -0
- package/dist/lib/puck/blocks/general/Breadcrumb/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Breadcrumb/fields.js +1 -0
- package/dist/lib/puck/blocks/general/Breadcrumb/render.d.ts +5 -0
- package/dist/lib/puck/blocks/general/Breadcrumb/render.js +1 -0
- package/dist/lib/puck/blocks/general/ButtonBlock/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/ButtonBlock/fields.js +1 -0
- package/dist/lib/puck/blocks/general/ButtonBlock/render.d.ts +2 -0
- package/dist/lib/puck/blocks/general/ButtonBlock/render.js +1 -0
- package/dist/lib/puck/blocks/general/Cards/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Cards/fields.js +1 -0
- package/dist/lib/puck/blocks/general/Cards/render.d.ts +6 -0
- package/dist/lib/puck/blocks/general/Cards/render.js +1 -0
- package/dist/lib/puck/blocks/general/CategoryBar/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/CategoryBar/fields.js +1 -0
- package/dist/lib/puck/blocks/general/CategoryBar/render.d.ts +2 -0
- package/dist/lib/puck/blocks/general/CategoryBar/render.js +1 -0
- package/dist/lib/puck/blocks/general/Chart/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Chart/fields.js +1 -0
- package/dist/lib/puck/blocks/general/Chart/render.d.ts +6 -0
- package/dist/lib/puck/blocks/general/Chart/render.js +2 -0
- package/dist/lib/puck/blocks/general/ContactLocations/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/ContactLocations/fields.js +1 -0
- package/dist/lib/puck/blocks/general/ContactLocations/render.d.ts +2 -0
- package/dist/lib/puck/blocks/general/ContactLocations/render.js +1 -0
- package/dist/lib/puck/blocks/general/CustomHTML/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/CustomHTML/fields.js +1 -0
- package/dist/lib/puck/blocks/general/CustomHTML/render.d.ts +2 -0
- package/dist/lib/puck/blocks/general/CustomHTML/render.js +3 -0
- package/dist/lib/puck/blocks/general/Divider/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Divider/fields.js +1 -0
- package/dist/lib/puck/blocks/general/Divider/render.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Divider/render.js +1 -0
- package/dist/lib/puck/blocks/general/DocBody/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/DocBody/fields.js +1 -0
- package/dist/lib/puck/blocks/general/DocBody/render.d.ts +5 -0
- package/dist/lib/puck/blocks/general/DocBody/render.js +1 -0
- package/dist/lib/puck/blocks/general/DocMasthead/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/DocMasthead/fields.js +1 -0
- package/dist/lib/puck/blocks/general/DocMasthead/render.d.ts +7 -0
- package/dist/lib/puck/blocks/general/DocMasthead/render.js +1 -0
- package/dist/lib/puck/blocks/general/DocMetaCards/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/DocMetaCards/fields.js +1 -0
- package/dist/lib/puck/blocks/general/DocMetaCards/render.d.ts +4 -0
- package/dist/lib/puck/blocks/general/DocMetaCards/render.js +1 -0
- package/dist/lib/puck/blocks/general/DocTabs/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/DocTabs/fields.js +1 -0
- package/dist/lib/puck/blocks/general/DocTabs/render.d.ts +6 -0
- package/dist/lib/puck/blocks/general/DocTabs/render.js +1 -0
- package/dist/lib/puck/blocks/general/Eyebrow/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Eyebrow/fields.js +1 -0
- package/dist/lib/puck/blocks/general/Eyebrow/render.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Eyebrow/render.js +1 -0
- package/dist/lib/puck/blocks/general/FAQ/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/FAQ/fields.js +1 -0
- package/dist/lib/puck/blocks/general/FAQ/render.d.ts +7 -0
- package/dist/lib/puck/blocks/general/FAQ/render.js +1 -0
- package/dist/lib/puck/blocks/general/FeaturedCover/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/FeaturedCover/fields.js +1 -0
- package/dist/lib/puck/blocks/general/FeaturedCover/render.d.ts +13 -0
- package/dist/lib/puck/blocks/general/FeaturedCover/render.js +1 -0
- package/dist/lib/puck/blocks/general/Flex/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Flex/fields.js +1 -0
- package/dist/lib/puck/blocks/general/Flex/render.d.ts +7 -0
- package/dist/lib/puck/blocks/general/Flex/render.js +1 -0
- package/dist/lib/puck/blocks/general/Footprint/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Footprint/fields.js +1 -0
- package/dist/lib/puck/blocks/general/Footprint/render.d.ts +7 -0
- package/dist/lib/puck/blocks/general/Footprint/render.js +2 -0
- package/dist/lib/puck/blocks/general/Grid/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Grid/fields.js +1 -0
- package/dist/lib/puck/blocks/general/Grid/render.d.ts +7 -0
- package/dist/lib/puck/blocks/general/Grid/render.js +1 -0
- package/dist/lib/puck/blocks/general/Heading/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Heading/fields.js +1 -0
- package/dist/lib/puck/blocks/general/Heading/render.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Heading/render.js +1 -0
- package/dist/lib/puck/blocks/general/Hero/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Hero/fields.js +1 -0
- package/dist/lib/puck/blocks/general/Hero/render.d.ts +7 -0
- package/dist/lib/puck/blocks/general/Hero/render.js +1 -0
- package/dist/lib/puck/blocks/general/HeroGroup/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/HeroGroup/fields.js +1 -0
- package/dist/lib/puck/blocks/general/HeroGroup/render.d.ts +8 -0
- package/dist/lib/puck/blocks/general/HeroGroup/render.js +1 -0
- package/dist/lib/puck/blocks/general/HeroSingle/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/HeroSingle/fields.js +1 -0
- package/dist/lib/puck/blocks/general/HeroSingle/render.d.ts +8 -0
- package/dist/lib/puck/blocks/general/HeroSingle/render.js +1 -0
- package/dist/lib/puck/blocks/general/HeroSlide/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/HeroSlide/fields.js +1 -0
- package/dist/lib/puck/blocks/general/HeroSlide/render.d.ts +8 -0
- package/dist/lib/puck/blocks/general/HeroSlide/render.js +1 -0
- package/dist/lib/puck/blocks/general/ImageBlock/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/ImageBlock/fields.js +1 -0
- package/dist/lib/puck/blocks/general/ImageBlock/render.d.ts +2 -0
- package/dist/lib/puck/blocks/general/ImageBlock/render.js +1 -0
- package/dist/lib/puck/blocks/general/Integrations/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Integrations/fields.js +2 -0
- package/dist/lib/puck/blocks/general/Integrations/render.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Integrations/render.js +2 -0
- package/dist/lib/puck/blocks/general/IntroBleed/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/IntroBleed/fields.js +1 -0
- package/dist/lib/puck/blocks/general/IntroBleed/render.d.ts +7 -0
- package/dist/lib/puck/blocks/general/IntroBleed/render.js +2 -0
- package/dist/lib/puck/blocks/general/KeyFeatures/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/KeyFeatures/fields.js +1 -0
- package/dist/lib/puck/blocks/general/KeyFeatures/render.d.ts +6 -0
- package/dist/lib/puck/blocks/general/KeyFeatures/render.js +1 -0
- package/dist/lib/puck/blocks/general/LogoBlock/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/LogoBlock/fields.js +1 -0
- package/dist/lib/puck/blocks/general/LogoBlock/render.d.ts +2 -0
- package/dist/lib/puck/blocks/general/LogoBlock/render.js +1 -0
- package/dist/lib/puck/blocks/general/Logos/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Logos/fields.js +1 -0
- package/dist/lib/puck/blocks/general/Logos/render.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Logos/render.js +1 -0
- package/dist/lib/puck/blocks/general/LongRead/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/LongRead/fields.js +1 -0
- package/dist/lib/puck/blocks/general/LongRead/render.d.ts +19 -0
- package/dist/lib/puck/blocks/general/LongRead/render.js +1 -0
- package/dist/lib/puck/blocks/general/Manifesto/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Manifesto/fields.js +2 -0
- package/dist/lib/puck/blocks/general/Manifesto/render.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Manifesto/render.js +1 -0
- package/dist/lib/puck/blocks/general/Masthead/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Masthead/fields.js +1 -0
- package/dist/lib/puck/blocks/general/Masthead/render.d.ts +8 -0
- package/dist/lib/puck/blocks/general/Masthead/render.js +1 -0
- package/dist/lib/puck/blocks/general/Mockup/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Mockup/fields.js +2 -0
- package/dist/lib/puck/blocks/general/Mockup/render.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Mockup/render.js +2 -0
- package/dist/lib/puck/blocks/general/OrderSummary/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/OrderSummary/fields.js +1 -0
- package/dist/lib/puck/blocks/general/OrderSummary/render.d.ts +6 -0
- package/dist/lib/puck/blocks/general/OrderSummary/render.js +1 -0
- package/dist/lib/puck/blocks/general/ParagraphsA/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/ParagraphsA/fields.js +1 -0
- package/dist/lib/puck/blocks/general/ParagraphsA/render.d.ts +9 -0
- package/dist/lib/puck/blocks/general/ParagraphsA/render.js +1 -0
- package/dist/lib/puck/blocks/general/PaymentBadges/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/PaymentBadges/fields.js +1 -0
- package/dist/lib/puck/blocks/general/PaymentBadges/render.d.ts +5 -0
- package/dist/lib/puck/blocks/general/PaymentBadges/render.js +1 -0
- package/dist/lib/puck/blocks/general/PostCard/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/PostCard/fields.js +1 -0
- package/dist/lib/puck/blocks/general/PostCard/render.d.ts +9 -0
- package/dist/lib/puck/blocks/general/PostCard/render.js +1 -0
- package/dist/lib/puck/blocks/general/ProcessSteps/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/ProcessSteps/fields.js +1 -0
- package/dist/lib/puck/blocks/general/ProcessSteps/render.d.ts +13 -0
- package/dist/lib/puck/blocks/general/ProcessSteps/render.js +1 -0
- package/dist/lib/puck/blocks/general/Prose/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Prose/fields.js +1 -0
- package/dist/lib/puck/blocks/general/Prose/render.d.ts +7 -0
- package/dist/lib/puck/blocks/general/Prose/render.js +1 -0
- package/dist/lib/puck/blocks/general/SectionHeader/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/SectionHeader/fields.js +1 -0
- package/dist/lib/puck/blocks/general/SectionHeader/render.d.ts +2 -0
- package/dist/lib/puck/blocks/general/SectionHeader/render.js +1 -0
- package/dist/lib/puck/blocks/general/Series/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Series/fields.js +1 -0
- package/dist/lib/puck/blocks/general/Series/render.d.ts +8 -0
- package/dist/lib/puck/blocks/general/Series/render.js +1 -0
- package/dist/lib/puck/blocks/general/Spacer/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Spacer/fields.js +1 -0
- package/dist/lib/puck/blocks/general/Spacer/render.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Spacer/render.js +1 -0
- package/dist/lib/puck/blocks/general/SpecStrip/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/SpecStrip/fields.js +1 -0
- package/dist/lib/puck/blocks/general/SpecStrip/render.d.ts +2 -0
- package/dist/lib/puck/blocks/general/SpecStrip/render.js +1 -0
- package/dist/lib/puck/blocks/general/Split/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Split/fields.js +1 -0
- package/dist/lib/puck/blocks/general/Split/render.d.ts +10 -0
- package/dist/lib/puck/blocks/general/Split/render.js +2 -0
- package/dist/lib/puck/blocks/general/Stats/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Stats/fields.js +1 -0
- package/dist/lib/puck/blocks/general/Stats/render.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Stats/render.js +1 -0
- package/dist/lib/puck/blocks/general/StatsParagraph/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/StatsParagraph/fields.js +1 -0
- package/dist/lib/puck/blocks/general/StatsParagraph/render.d.ts +7 -0
- package/dist/lib/puck/blocks/general/StatsParagraph/render.js +1 -0
- package/dist/lib/puck/blocks/general/Testimonials/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Testimonials/fields.js +1 -0
- package/dist/lib/puck/blocks/general/Testimonials/render.d.ts +6 -0
- package/dist/lib/puck/blocks/general/Testimonials/render.js +1 -0
- package/dist/lib/puck/blocks/general/Text/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Text/fields.js +1 -0
- package/dist/lib/puck/blocks/general/Text/render.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Text/render.js +1 -0
- package/dist/lib/puck/blocks/general/Ticker/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Ticker/fields.js +1 -0
- package/dist/lib/puck/blocks/general/Ticker/render.d.ts +5 -0
- package/dist/lib/puck/blocks/general/Ticker/render.js +1 -0
- package/dist/lib/puck/blocks/general/Timeline/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/Timeline/fields.js +1 -0
- package/dist/lib/puck/blocks/general/Timeline/render.d.ts +10 -0
- package/dist/lib/puck/blocks/general/Timeline/render.js +2 -0
- package/dist/lib/puck/blocks/general/TimelineTrack/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/TimelineTrack/fields.js +1 -0
- package/dist/lib/puck/blocks/general/TimelineTrack/render.d.ts +8 -0
- package/dist/lib/puck/blocks/general/TimelineTrack/render.js +1 -0
- package/dist/lib/puck/blocks/general/TitleWithButtons/fields.d.ts +2 -0
- package/dist/lib/puck/blocks/general/TitleWithButtons/fields.js +1 -0
- package/dist/lib/puck/blocks/general/TitleWithButtons/render.d.ts +5 -0
- package/dist/lib/puck/blocks/general/TitleWithButtons/render.js +2 -0
- package/dist/lib/puck/blocks/general/index.d.ts +2 -0
- package/dist/lib/puck/blocks/general/index.js +1 -0
- package/dist/lib/puck/blocks/general/renders.d.ts +57 -0
- package/dist/lib/puck/blocks/general/renders.js +1 -0
- package/dist/lib/puck/blocks/general/section-bg-built-in.d.ts +6 -0
- package/dist/lib/puck/blocks/general/section-bg-built-in.js +1 -0
- package/dist/lib/puck/blocks/placeholders.d.ts +25 -0
- package/dist/lib/puck/blocks/placeholders.js +1 -0
- package/dist/lib/puck/blocks/scaffold.d.ts +22 -0
- package/dist/lib/puck/blocks/scaffold.js +1 -0
- package/dist/lib/puck/blocks/shared-fields.d.ts +14 -0
- package/dist/lib/puck/blocks/shared-fields.js +1 -0
- package/dist/lib/puck/booking-preview.d.ts +3 -0
- package/dist/lib/puck/booking-preview.js +1 -0
- package/dist/lib/puck/box-footer.d.ts +9 -0
- package/dist/lib/puck/box-footer.js +1 -0
- package/dist/lib/puck/build-config.d.ts +3 -0
- package/dist/lib/puck/build-config.js +1 -0
- package/dist/lib/puck/cap-hero-groups.d.ts +1 -0
- package/dist/lib/puck/cap-hero-groups.js +1 -0
- package/dist/lib/puck/container-blocks.d.ts +10 -0
- package/dist/lib/puck/container-blocks.js +1 -0
- package/dist/lib/puck/content-tree.d.ts +2 -0
- package/dist/lib/puck/content-tree.js +1 -0
- package/dist/lib/puck/controls.d.ts +335 -0
- package/dist/lib/puck/controls.js +1 -0
- package/dist/lib/puck/device-fields.d.ts +2 -0
- package/dist/lib/puck/device-fields.js +1 -0
- package/dist/lib/puck/editor-page-context.d.ts +6 -0
- package/dist/lib/puck/editor-page-context.js +1 -0
- package/dist/lib/puck/enclosing-section.d.ts +1 -0
- package/dist/lib/puck/enclosing-section.js +1 -0
- package/dist/lib/puck/field-buckets.d.ts +2 -0
- package/dist/lib/puck/field-buckets.js +1 -0
- package/dist/lib/puck/field-groups.d.ts +23 -0
- package/dist/lib/puck/field-groups.js +1 -0
- package/dist/lib/puck/field-markers.d.ts +2 -0
- package/dist/lib/puck/field-markers.js +1 -0
- package/dist/lib/puck/field-noun.d.ts +3 -0
- package/dist/lib/puck/field-noun.js +1 -0
- package/dist/lib/puck/footer-block-row-name.d.ts +4 -0
- package/dist/lib/puck/footer-block-row-name.js +1 -0
- package/dist/lib/puck/footer-blocks.d.ts +11 -0
- package/dist/lib/puck/footer-blocks.js +1 -0
- package/dist/lib/puck/footer-return.d.ts +3 -0
- package/dist/lib/puck/footer-return.js +1 -0
- package/dist/lib/puck/general-registry.d.ts +4 -0
- package/dist/lib/puck/general-registry.js +1 -0
- package/dist/lib/puck/geocode-resolve.d.ts +14 -0
- package/dist/lib/puck/geocode-resolve.js +1 -0
- package/dist/lib/puck/header-clearance.d.ts +49 -0
- package/dist/lib/puck/header-clearance.js +1 -0
- package/dist/lib/puck/header-ink.d.ts +16 -0
- package/dist/lib/puck/header-ink.js +1 -0
- package/dist/lib/puck/heading-outline.d.ts +7 -0
- package/dist/lib/puck/heading-outline.js +1 -0
- package/dist/lib/puck/hidable.d.ts +2 -0
- package/dist/lib/puck/hidable.js +1 -0
- package/dist/lib/puck/home-page.d.ts +1 -0
- package/dist/lib/puck/home-page.js +1 -0
- package/dist/lib/puck/left-view.d.ts +5 -0
- package/dist/lib/puck/left-view.js +1 -0
- package/dist/lib/puck/locations-focus.d.ts +22 -0
- package/dist/lib/puck/locations-focus.js +1 -0
- package/dist/lib/puck/locations-tree.d.ts +23 -0
- package/dist/lib/puck/locations-tree.js +2 -0
- package/dist/lib/puck/locked-blocks.d.ts +2 -0
- package/dist/lib/puck/locked-blocks.js +1 -0
- package/dist/lib/puck/media-manifest.json +138 -0
- package/dist/lib/puck/migrate-legacy.d.ts +2 -0
- package/dist/lib/puck/migrate-legacy.js +1 -0
- package/dist/lib/puck/mockup-variant-fields.d.ts +10 -0
- package/dist/lib/puck/mockup-variant-fields.js +1 -0
- package/dist/lib/puck/neutralization-contracts.d.ts +43 -0
- package/dist/lib/puck/neutralization-contracts.js +1 -0
- package/dist/lib/puck/one-h1.d.ts +3 -0
- package/dist/lib/puck/one-h1.js +1 -0
- package/dist/lib/puck/overlay-portal.d.ts +2 -0
- package/dist/lib/puck/overlay-portal.js +1 -0
- package/dist/lib/puck/overrides.d.ts +2 -0
- package/dist/lib/puck/overrides.js +1 -0
- package/dist/lib/puck/page-render.d.ts +5 -0
- package/dist/lib/puck/page-render.js +1 -0
- package/dist/lib/puck/page-root-fields.d.ts +29 -0
- package/dist/lib/puck/page-root-fields.js +1 -0
- package/dist/lib/puck/page-root.d.ts +55 -0
- package/dist/lib/puck/page-root.js +1 -0
- package/dist/lib/puck/palette-sections.d.ts +2 -0
- package/dist/lib/puck/palette-sections.js +1 -0
- package/dist/lib/puck/panel-drop-empty-headings.d.ts +3 -0
- package/dist/lib/puck/panel-drop-empty-headings.js +1 -0
- package/dist/lib/puck/panel-fields.d.ts +2 -0
- package/dist/lib/puck/panel-fields.js +1 -0
- package/dist/lib/puck/panel-heading-scope.d.ts +8 -0
- package/dist/lib/puck/panel-heading-scope.js +1 -0
- package/dist/lib/puck/panel-no-control-mark.d.ts +2 -0
- package/dist/lib/puck/panel-no-control-mark.js +1 -0
- package/dist/lib/puck/part-anchors.d.ts +23 -0
- package/dist/lib/puck/part-anchors.js +1 -0
- package/dist/lib/puck/part-id.d.ts +1 -0
- package/dist/lib/puck/part-id.js +1 -0
- package/dist/lib/puck/part-inks.d.ts +9 -0
- package/dist/lib/puck/part-inks.js +1 -0
- package/dist/lib/puck/part-key.d.ts +9 -0
- package/dist/lib/puck/part-key.js +1 -0
- package/dist/lib/puck/part-row-field.d.ts +2 -0
- package/dist/lib/puck/part-row-field.js +1 -0
- package/dist/lib/puck/part-rows.d.ts +15 -0
- package/dist/lib/puck/part-rows.js +1 -0
- package/dist/lib/puck/part-styles.d.ts +133 -0
- package/dist/lib/puck/part-styles.js +2 -0
- package/dist/lib/puck/part-text.d.ts +12 -0
- package/dist/lib/puck/part-text.js +1 -0
- package/dist/lib/puck/part-typing.d.ts +11 -0
- package/dist/lib/puck/part-typing.js +1 -0
- package/dist/lib/puck/passes/catalogue-labels.d.ts +2 -0
- package/dist/lib/puck/passes/catalogue-labels.js +1 -0
- package/dist/lib/puck/passes/cell-width.d.ts +2 -0
- package/dist/lib/puck/passes/cell-width.js +1 -0
- package/dist/lib/puck/passes/clickable-parts.d.ts +2 -0
- package/dist/lib/puck/passes/clickable-parts.js +1 -0
- package/dist/lib/puck/passes/corners.d.ts +3 -0
- package/dist/lib/puck/passes/corners.js +1 -0
- package/dist/lib/puck/passes/document-position.d.ts +16 -0
- package/dist/lib/puck/passes/document-position.js +1 -0
- package/dist/lib/puck/passes/empty-headings.d.ts +2 -0
- package/dist/lib/puck/passes/empty-headings.js +1 -0
- package/dist/lib/puck/passes/hidden-nodes.d.ts +2 -0
- package/dist/lib/puck/passes/hidden-nodes.js +1 -0
- package/dist/lib/puck/passes/index.d.ts +5 -0
- package/dist/lib/puck/passes/index.js +1 -0
- package/dist/lib/puck/passes/inspector.d.ts +2 -0
- package/dist/lib/puck/passes/inspector.js +1 -0
- package/dist/lib/puck/passes/registry-context.d.ts +2 -0
- package/dist/lib/puck/passes/registry-context.js +1 -0
- package/dist/lib/puck/passes/section-anchor.d.ts +2 -0
- package/dist/lib/puck/passes/section-anchor.js +1 -0
- package/dist/lib/puck/passes/section-animation.d.ts +2 -0
- package/dist/lib/puck/passes/section-animation.js +1 -0
- package/dist/lib/puck/passes/section-height.d.ts +2 -0
- package/dist/lib/puck/passes/section-height.js +1 -0
- package/dist/lib/puck/passes/section-padding.d.ts +8 -0
- package/dist/lib/puck/passes/section-padding.js +1 -0
- package/dist/lib/puck/passes/section-theme.d.ts +3 -0
- package/dist/lib/puck/passes/section-theme.js +1 -0
- package/dist/lib/puck/passes/section-width.d.ts +10 -0
- package/dist/lib/puck/passes/section-width.js +1 -0
- package/dist/lib/puck/passes/settings-groups.d.ts +3 -0
- package/dist/lib/puck/passes/settings-groups.js +1 -0
- package/dist/lib/puck/passes/slot-rules.d.ts +4 -0
- package/dist/lib/puck/passes/slot-rules.js +1 -0
- package/dist/lib/puck/passes/types.d.ts +51 -0
- package/dist/lib/puck/passes/types.js +0 -0
- package/dist/lib/puck/phone-override.d.ts +4 -0
- package/dist/lib/puck/phone-override.js +1 -0
- package/dist/lib/puck/pinned-seed-gate.d.ts +7 -0
- package/dist/lib/puck/pinned-seed-gate.js +1 -0
- package/dist/lib/puck/preview-click.d.ts +1 -0
- package/dist/lib/puck/preview-click.js +1 -0
- package/dist/lib/puck/preview-dom.d.ts +1 -0
- package/dist/lib/puck/preview-dom.js +1 -0
- package/dist/lib/puck/preview-events.d.ts +2 -0
- package/dist/lib/puck/preview-events.js +1 -0
- package/dist/lib/puck/preview-selection-context.d.ts +2 -0
- package/dist/lib/puck/preview-selection-context.js +1 -0
- package/dist/lib/puck/registry.d.ts +3 -0
- package/dist/lib/puck/registry.js +1 -0
- package/dist/lib/puck/renamed-props.d.ts +2 -0
- package/dist/lib/puck/renamed-props.js +1 -0
- package/dist/lib/puck/sanitize.d.ts +1 -0
- package/dist/lib/puck/sanitize.js +1 -0
- package/dist/lib/puck/section-catalog.d.ts +36 -0
- package/dist/lib/puck/section-catalog.js +1 -0
- package/dist/lib/puck/section-descriptions.d.ts +1 -0
- package/dist/lib/puck/section-descriptions.js +1 -0
- package/dist/lib/puck/section-doc.d.ts +1 -0
- package/dist/lib/puck/section-doc.js +1 -0
- package/dist/lib/puck/section-groups.d.ts +21 -0
- package/dist/lib/puck/section-groups.js +1 -0
- package/dist/lib/puck/section-text-suppress.d.ts +9 -0
- package/dist/lib/puck/section-text-suppress.js +1 -0
- package/dist/lib/puck/site-gap-fields.d.ts +2 -0
- package/dist/lib/puck/site-gap-fields.js +1 -0
- package/dist/lib/puck/slider-typing.d.ts +9 -0
- package/dist/lib/puck/slider-typing.js +1 -0
- package/dist/lib/puck/slot-child-name.d.ts +2 -0
- package/dist/lib/puck/slot-child-name.js +1 -0
- package/dist/lib/puck/slot-heal.d.ts +1 -0
- package/dist/lib/puck/slot-heal.js +1 -0
- package/dist/lib/puck/slot-section-spec.d.ts +1 -0
- package/dist/lib/puck/slot-section-spec.js +0 -0
- package/dist/lib/puck/slot-specs.d.ts +9 -0
- package/dist/lib/puck/slot-specs.js +1 -0
- package/dist/lib/puck/snapshot-contracts.d.ts +4 -0
- package/dist/lib/puck/snapshot-contracts.js +1 -0
- package/dist/lib/puck/source-bound-parts.d.ts +12 -0
- package/dist/lib/puck/source-bound-parts.js +1 -0
- package/dist/lib/puck/style-clipboard.d.ts +1 -0
- package/dist/lib/puck/style-clipboard.js +1 -0
- package/dist/lib/puck/templateFields.d.ts +2 -0
- package/dist/lib/puck/templateFields.js +1 -0
- package/dist/lib/puck/text-control-kinds.d.ts +2 -0
- package/dist/lib/puck/text-control-kinds.js +1 -0
- package/dist/lib/puck/text-parts.d.ts +30 -0
- package/dist/lib/puck/text-parts.js +1 -0
- package/dist/lib/puck/theme-swatches.d.ts +3 -0
- package/dist/lib/puck/theme-swatches.js +1 -0
- package/dist/lib/puck/tree-reveal.d.ts +1 -0
- package/dist/lib/puck/tree-reveal.js +1 -0
- package/dist/lib/puck/use-section-ops.d.ts +2 -0
- package/dist/lib/puck/use-section-ops.js +1 -0
- package/dist/lib/reel.d.ts +33 -0
- package/dist/lib/reel.js +1 -0
- package/dist/lib/safe-storage.d.ts +10 -0
- package/dist/lib/safe-storage.js +1 -0
- package/dist/lib/save-as-template-action.d.ts +29 -0
- package/dist/lib/save-as-template-action.js +1 -0
- package/dist/lib/section-template-types.d.ts +1 -0
- package/dist/lib/section-template-types.js +0 -0
- package/dist/lib/sections/card-cover-index.d.ts +7 -0
- package/dist/lib/sections/card-cover-index.js +1 -0
- package/dist/lib/sections/collection-card-text-regions.d.ts +4 -0
- package/dist/lib/sections/collection-card-text-regions.js +1 -0
- package/dist/lib/sections/divider-style.d.ts +12 -0
- package/dist/lib/sections/divider-style.js +1 -0
- package/dist/lib/sections/faq-text-regions.d.ts +4 -0
- package/dist/lib/sections/faq-text-regions.js +1 -0
- package/dist/lib/sections/hero-overlay.d.ts +10 -0
- package/dist/lib/sections/hero-overlay.js +1 -0
- package/dist/lib/sections/intro-bleed-layout.d.ts +15 -0
- package/dist/lib/sections/intro-bleed-layout.js +1 -0
- package/dist/lib/sections/new-section-node.d.ts +2 -0
- package/dist/lib/sections/new-section-node.js +1 -0
- package/dist/lib/sections/product-card-style.d.ts +18 -0
- package/dist/lib/sections/product-card-style.js +1 -0
- package/dist/lib/sections/section-eyebrow-look.d.ts +11 -0
- package/dist/lib/sections/section-eyebrow-look.js +1 -0
- package/dist/lib/sections/section-head-placement.d.ts +31 -0
- package/dist/lib/sections/section-head-placement.js +1 -0
- package/dist/lib/sections/section-head-style.d.ts +16 -0
- package/dist/lib/sections/section-head-style.js +1 -0
- package/dist/lib/sections/section-number-style.d.ts +10 -0
- package/dist/lib/sections/section-number-style.js +1 -0
- package/dist/lib/sections/section-presets.d.ts +9 -0
- package/dist/lib/sections/section-presets.js +1 -0
- package/dist/lib/sections/section-text-kinds.d.ts +8 -0
- package/dist/lib/sections/section-text-kinds.js +1 -0
- package/dist/lib/sections/section-text-regions.d.ts +3 -0
- package/dist/lib/sections/section-text-regions.js +1 -0
- package/dist/lib/sections/spec-table-regions.d.ts +11 -0
- package/dist/lib/sections/spec-table-regions.js +1 -0
- package/dist/lib/sections/text-regions.d.ts +21 -0
- package/dist/lib/sections/text-regions.js +1 -0
- package/dist/lib/sections/ticker-join.d.ts +9 -0
- package/dist/lib/sections/ticker-join.js +1 -0
- package/dist/lib/sections/ticker-scroll.d.ts +11 -0
- package/dist/lib/sections/ticker-scroll.js +1 -0
- package/dist/lib/sections/ticker-style.d.ts +17 -0
- package/dist/lib/sections/ticker-style.js +1 -0
- package/dist/lib/site-runtime.d.ts +28 -0
- package/dist/lib/site-runtime.js +1 -0
- package/dist/lib/site-theme-row.d.ts +52 -0
- package/dist/lib/site-theme-row.js +0 -0
- package/dist/lib/slugify.d.ts +1 -0
- package/dist/lib/slugify.js +1 -0
- package/dist/lib/source-rules/accent-token-name.d.ts +20 -0
- package/dist/lib/source-rules/accent-token-name.js +4 -0
- package/dist/lib/source-rules/button-corners.d.ts +13 -0
- package/dist/lib/source-rules/button-corners.js +2 -0
- package/dist/lib/source-rules/editor-chrome-note.d.ts +16 -0
- package/dist/lib/source-rules/editor-chrome-note.js +13 -0
- package/dist/lib/source-rules/editor-context-menu.d.ts +5 -0
- package/dist/lib/source-rules/editor-context-menu.js +4 -0
- package/dist/lib/source-rules/editor-puck-drag-off.d.ts +8 -0
- package/dist/lib/source-rules/editor-puck-drag-off.js +4 -0
- package/dist/lib/source-rules/efficient-easel-version.d.ts +9 -0
- package/dist/lib/source-rules/efficient-easel-version.js +2 -0
- package/dist/lib/source-rules/every-button-follows-the-button-colour.d.ts +12 -0
- package/dist/lib/source-rules/every-button-follows-the-button-colour.js +7 -0
- package/dist/lib/source-rules/flat-theme-palette.d.ts +10 -0
- package/dist/lib/source-rules/flat-theme-palette.js +8 -0
- package/dist/lib/source-rules/full-width-means-full.d.ts +8 -0
- package/dist/lib/source-rules/full-width-means-full.js +2 -0
- package/dist/lib/source-rules/heading-ceiling-sweep.d.ts +11 -0
- package/dist/lib/source-rules/heading-ceiling-sweep.js +8 -0
- package/dist/lib/source-rules/label-hints.d.ts +7 -0
- package/dist/lib/source-rules/label-hints.js +5 -0
- package/dist/lib/source-rules/label-vocabulary.d.ts +14 -0
- package/dist/lib/source-rules/label-vocabulary.js +5 -0
- package/dist/lib/source-rules/mirrored-rows-agree.d.ts +19 -0
- package/dist/lib/source-rules/mirrored-rows-agree.js +10 -0
- package/dist/lib/source-rules/no-comment-in-jsx.d.ts +9 -0
- package/dist/lib/source-rules/no-comment-in-jsx.js +7 -0
- package/dist/lib/source-rules/no-glyph-rows.d.ts +15 -0
- package/dist/lib/source-rules/no-glyph-rows.js +4 -0
- package/dist/lib/source-rules/one-colour-control.d.ts +7 -0
- package/dist/lib/source-rules/one-colour-control.js +2 -0
- package/dist/lib/source-rules/one-dropdown.d.ts +10 -0
- package/dist/lib/source-rules/one-dropdown.js +4 -0
- package/dist/lib/source-rules/one-editable-list.d.ts +16 -0
- package/dist/lib/source-rules/one-editable-list.js +6 -0
- package/dist/lib/source-rules/one-editor-list.d.ts +7 -0
- package/dist/lib/source-rules/one-editor-list.js +3 -0
- package/dist/lib/source-rules/one-right-click.d.ts +10 -0
- package/dist/lib/source-rules/one-right-click.js +2 -0
- package/dist/lib/source-rules/one-switch.d.ts +9 -0
- package/dist/lib/source-rules/one-switch.js +7 -0
- package/dist/lib/source-rules/one-up-level-link.d.ts +16 -0
- package/dist/lib/source-rules/one-up-level-link.js +18 -0
- package/dist/lib/source-rules/panel-colour-tokens.d.ts +48 -0
- package/dist/lib/source-rules/panel-colour-tokens.js +20 -0
- package/dist/lib/source-rules/panel-no-divider-lines.d.ts +14 -0
- package/dist/lib/source-rules/panel-no-divider-lines.js +10 -0
- package/dist/lib/source-rules/panel-one-arrow.d.ts +21 -0
- package/dist/lib/source-rules/panel-one-arrow.js +1 -0
- package/dist/lib/source-rules/panel-one-hover.d.ts +8 -0
- package/dist/lib/source-rules/panel-one-hover.js +2 -0
- package/dist/lib/source-rules/panel-rows-use-the-shared-row.d.ts +23 -0
- package/dist/lib/source-rules/panel-rows-use-the-shared-row.js +22 -0
- package/dist/lib/source-rules/part-slider-fills-row.d.ts +11 -0
- package/dist/lib/source-rules/part-slider-fills-row.js +29 -0
- package/dist/lib/source-rules/part-style-naming.d.ts +10 -0
- package/dist/lib/source-rules/part-style-naming.js +2 -0
- package/dist/lib/source-rules/puck-document-surfaces.d.ts +16 -0
- package/dist/lib/source-rules/puck-document-surfaces.js +8 -0
- package/dist/lib/source-rules/reduced-motion.d.ts +26 -0
- package/dist/lib/source-rules/reduced-motion.js +9 -0
- package/dist/lib/source-rules/route-content-width.d.ts +22 -0
- package/dist/lib/source-rules/route-content-width.js +5 -0
- package/dist/lib/source-rules/rule.d.ts +21 -0
- package/dist/lib/source-rules/rule.js +1 -0
- package/dist/lib/source-rules/section-theme-preview.d.ts +9 -0
- package/dist/lib/source-rules/section-theme-preview.js +8 -0
- package/dist/lib/source-rules/site-gutter.d.ts +6 -0
- package/dist/lib/source-rules/site-gutter.js +4 -0
- package/dist/lib/source-rules/site-square-by-default.d.ts +17 -0
- package/dist/lib/source-rules/site-square-by-default.js +3 -0
- package/dist/lib/source-rules/site-width.d.ts +11 -0
- package/dist/lib/source-rules/site-width.js +7 -0
- package/dist/lib/source-rules/size-token-paints.d.ts +8 -0
- package/dist/lib/source-rules/size-token-paints.js +11 -0
- package/dist/lib/source-rules/social-icons-import.d.ts +6 -0
- package/dist/lib/source-rules/social-icons-import.js +6 -0
- package/dist/lib/source-rules/source-status-is-shared.d.ts +7 -0
- package/dist/lib/source-rules/source-status-is-shared.js +1 -0
- package/dist/lib/source-rules/style-face-matches-size.d.ts +10 -0
- package/dist/lib/source-rules/style-face-matches-size.js +4 -0
- package/dist/lib/source-rules/support/accent-rename-bytes.d.ts +5 -0
- package/dist/lib/source-rules/support/accent-rename-bytes.js +1 -0
- package/dist/lib/source-rules/support/css-box-model.d.ts +5 -0
- package/dist/lib/source-rules/support/css-box-model.js +1 -0
- package/dist/lib/source-rules/support/css-length.d.ts +2 -0
- package/dist/lib/source-rules/support/css-length.js +1 -0
- package/dist/lib/source-rules/support/css-rules.d.ts +12 -0
- package/dist/lib/source-rules/support/css-rules.js +1 -0
- package/dist/lib/source-rules/support/css-source.d.ts +2 -0
- package/dist/lib/source-rules/support/css-source.js +3 -0
- package/dist/lib/source-rules/support/label-extraction.d.ts +14 -0
- package/dist/lib/source-rules/support/label-extraction.js +5 -0
- package/dist/lib/source-rules/support/panel-select-cascade.d.ts +72 -0
- package/dist/lib/source-rules/support/panel-select-cascade.js +2 -0
- package/dist/lib/source-rules/support/part-slider-call-sites.d.ts +9 -0
- package/dist/lib/source-rules/support/part-slider-call-sites.js +17 -0
- package/dist/lib/source-rules/support/registry-source.d.ts +14 -0
- package/dist/lib/source-rules/support/registry-source.js +3 -0
- package/dist/lib/source-rules/support/ts-source.d.ts +2 -0
- package/dist/lib/source-rules/support/ts-source.js +3 -0
- package/dist/lib/source-rules/theme-mode-controls-gone.d.ts +10 -0
- package/dist/lib/source-rules/theme-mode-controls-gone.js +5 -0
- package/dist/lib/source-rules/upload-intake-guard.d.ts +11 -0
- package/dist/lib/source-rules/upload-intake-guard.js +6 -0
- package/dist/lib/source-rules/word-styles.d.ts +8 -0
- package/dist/lib/source-rules/word-styles.js +4 -0
- package/dist/lib/theme-dom.d.ts +14 -0
- package/dist/lib/theme-dom.js +1 -0
- package/dist/lib/theme-row-persist.d.ts +34 -0
- package/dist/lib/theme-row-persist.js +1 -0
- package/dist/lib/theme-save-message.d.ts +6 -0
- package/dist/lib/theme-save-message.js +1 -0
- package/dist/lib/theme.d.ts +177 -0
- package/dist/lib/theme.js +18 -0
- package/dist/lib/use-host-products.d.ts +2 -0
- package/dist/lib/use-host-products.js +1 -0
- package/dist/lib/web-backend.d.ts +138 -0
- package/dist/lib/web-backend.js +1 -0
- package/dist/lib/web-runtime.d.ts +7 -0
- package/dist/lib/web-runtime.js +1 -0
- package/dist/lib/website-document-addressing.d.ts +2 -0
- package/dist/lib/website-document-addressing.js +1 -0
- package/dist/lib/website-host-inbound.d.ts +1 -0
- package/dist/lib/website-host-inbound.js +1 -0
- package/dist/lib/website-session.d.ts +5 -0
- package/dist/lib/website-session.js +1 -0
- package/dist/lib/word-styles.d.ts +54 -0
- package/dist/lib/word-styles.js +1 -0
- package/package.json +50 -36
- package/dist/chunks/EditorPreviewCheckout-5KOAA2SK.js +0 -4
- package/dist/chunks/PreviewFooter-H6XJUR5S.js +0 -1
- package/dist/chunks/SectionEditorShell-EEZR7KFE.js +0 -1
- package/dist/chunks/SiteEditorProvider-ECGZVKLG.js +0 -1
- package/dist/chunks/StorefrontEditorChrome-4TFS62GY.js +0 -1
- package/dist/chunks/chunk-6CP4D6VJ.js +0 -1
- package/dist/chunks/chunk-7QXLVNFD.js +0 -1
- package/dist/chunks/chunk-BJOS4Y35.js +0 -15
- package/dist/chunks/chunk-BJOS4Y35.js.LEGAL.txt +0 -27
- package/dist/chunks/chunk-EIXUXJQ5.js +0 -153
- package/dist/chunks/chunk-EIXUXJQ5.js.LEGAL.txt +0 -4
- package/dist/chunks/chunk-H7O6ZYX6.js +0 -1
- package/dist/chunks/chunk-HVOO2GNE.js +0 -1
- package/dist/chunks/chunk-IFRGL3GL.js +0 -1
- package/dist/chunks/chunk-ML2AR222.js +0 -1
- package/dist/chunks/chunk-RRHBLOH4.js +0 -1
- package/dist/chunks/chunk-S6SXIMIG.js +0 -2
- package/dist/chunks/chunk-SNH7IFTZ.js +0 -1
- package/dist/chunks/chunk-Y4CZD2YY.js +0 -230
- package/dist/chunks/chunk-Y6SLVHK3.js +0 -1
- package/dist/chunks/chunk-YVQUISDX.js +0 -1
- package/dist/chunks/fitment-data-6NXSKODX.js +0 -1
- package/dist/chunks/gallery-builds-data-SWA6XKFF.js +0 -1
- package/dist/chunks/headers-3CAQXQEY.js +0 -1
- package/dist/chunks/render-client-YGYDU3K2.js +0 -1
- package/dist/contract.d.ts +0 -48
- package/dist/contract.js +0 -1
- package/dist/editor.css +0 -1
- package/dist/index.d.ts +0 -721
- package/dist/index.js +0 -11058
- package/dist/links.d.ts +0 -86
- package/dist/links.js +0 -1
|
@@ -0,0 +1,4870 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Storefront editor chrome — themed to the efficient-shell design system.
|
|
3
|
+
*
|
|
4
|
+
* The editor is efficient-easel's engine (`efficient-easel/easel`), hosted by
|
|
5
|
+
* StorefrontEditorChrome. Until blueprint 6.3 (2026-10-02) it was Puck
|
|
6
|
+
* (@measured/puck) driven through its composition API, and much of the
|
|
7
|
+
* reasoning below was measured against Puck's sheets; where a note names a
|
|
8
|
+
* Puck class or `puck.css`, read it as history unless it says otherwise.
|
|
9
|
+
* This file:
|
|
10
|
+
* 1. Tunes the canvas's own marks — the engine's lists, outlines and drop
|
|
11
|
+
* cells (`efficient-easel/easel.css`, `drag.css`) — to the storefront's
|
|
12
|
+
* rules about what a merchant should see.
|
|
13
|
+
* 2. Styles the bespoke chrome around the engine's pieces (top bar,
|
|
14
|
+
* left/right panels, device frame, inspector).
|
|
15
|
+
*
|
|
16
|
+
* Everything is scoped under `.sf-editor` so it can never leak into the public
|
|
17
|
+
* storefront. Colour is driven entirely by the `--sf-*` tokens below so the
|
|
18
|
+
* chrome themes in ONE place. The editor is deliberately light-only — it does
|
|
19
|
+
* NOT follow the admin portal's active theme. The admin still bridges its theme
|
|
20
|
+
* into the iframe, but lib/editor-theme.ts pins the editor to the light base
|
|
21
|
+
* regardless (see that file), so there is no dark block.
|
|
22
|
+
*
|
|
23
|
+
* WHERE THE VALUES LIVE (card 66034). They no longer live here. Every `--sf-*`
|
|
24
|
+
* colour, radius, shadow and font below is now an ALIAS onto the `--es-*` shell
|
|
25
|
+
* token layer that card 66024 promoted into the `efficient-easel` package
|
|
26
|
+
* (`efficient-easel/shell.css`, imported by each editor entry and scoped to the
|
|
27
|
+
* `es-editor` class this same root carries). The campaign designer aliases its
|
|
28
|
+
* own `--cd-*` names onto the identical set, so the two editors are guaranteed to
|
|
29
|
+
* agree by construction rather than by two lists being kept in step by hand.
|
|
30
|
+
*
|
|
31
|
+
* The alias layer is kept — rather than renaming every call site to `--es-*` —
|
|
32
|
+
* because `--sf-*` is the storefront chrome's own vocabulary, used ~700 times
|
|
33
|
+
* below and in the components' inline styles; the indirection is what lets the
|
|
34
|
+
* shared layer change underneath without touching any of them. Add a NEW value
|
|
35
|
+
* to editor-shell and alias it here; never re-introduce a literal.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/* Mounted inside another app's window (the efficient-web-builder package — the admin
|
|
39
|
+
portal's Storefront editor): the editor fills the WINDOW it is drawn in, not
|
|
40
|
+
the browser viewport, or its bottom edge (the canvas's last rows, "+ New
|
|
41
|
+
page") would sit under the window's own frame. The package wraps the editor
|
|
42
|
+
in `.sf-embedded`; the shop's own /edit routes never do. */
|
|
43
|
+
.sf-embedded {
|
|
44
|
+
height: 100%;
|
|
45
|
+
min-height: 0;
|
|
46
|
+
}
|
|
47
|
+
.sf-embedded .sf-editor {
|
|
48
|
+
height: 100%;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* Visually-hidden, screen-reader-only (e.g. the live search-result count). */
|
|
52
|
+
.sf-sr-only {
|
|
53
|
+
position: absolute;
|
|
54
|
+
width: 1px;
|
|
55
|
+
height: 1px;
|
|
56
|
+
margin: -1px;
|
|
57
|
+
padding: 0;
|
|
58
|
+
border: 0;
|
|
59
|
+
overflow: hidden;
|
|
60
|
+
clip: rect(0, 0, 0, 0);
|
|
61
|
+
white-space: nowrap;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* ── Top bar ─────────────────────────────────────────────────────────────
|
|
65
|
+
The bar, its clusters, the icon buttons, the divider, the device switch and
|
|
66
|
+
the ghost / primary buttons are editor-shell's (efficient-easel/chrome.css,
|
|
67
|
+
`.es-topbar` and friends), lifted from this sheet and shared with the
|
|
68
|
+
campaign editor (redesign PR 2a). Only the website's own additions follow. */
|
|
69
|
+
|
|
70
|
+
/* Reuse-component buttons in the top bar inherit the ghost look */
|
|
71
|
+
.sf-actions-slot > button {
|
|
72
|
+
display: flex;
|
|
73
|
+
align-items: center;
|
|
74
|
+
gap: 6px;
|
|
75
|
+
padding: 7px 12px;
|
|
76
|
+
border: 1px solid var(--sf-btn-border);
|
|
77
|
+
background: var(--sf-panel);
|
|
78
|
+
border-radius: 8px;
|
|
79
|
+
cursor: pointer;
|
|
80
|
+
font-size: 13px;
|
|
81
|
+
font-weight: 500;
|
|
82
|
+
color: var(--sf-btn-text);
|
|
83
|
+
}
|
|
84
|
+
.sf-actions-slot > button:hover {
|
|
85
|
+
background: var(--sf-hover);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* ── Body / floating panels ───────────────────────────────────────────── */
|
|
89
|
+
/* The panel's title and, beside it, WHICH SITE it is styling (card 66167).
|
|
90
|
+
`min-width: 0` on both so the name — which is a merchant's own words and can
|
|
91
|
+
be any length — is what gives way when the panel is dragged narrow, rather
|
|
92
|
+
than pushing the ✕ off the head. `baseline`, not `center`: the two are
|
|
93
|
+
different sizes and a shared baseline is what makes them read as one line. */
|
|
94
|
+
.sf-panel-heading {
|
|
95
|
+
display: flex;
|
|
96
|
+
align-items: baseline;
|
|
97
|
+
gap: 6px;
|
|
98
|
+
min-width: 0;
|
|
99
|
+
}
|
|
100
|
+
/* The site's name, read-only. Quiet and small — it is context, not a setting,
|
|
101
|
+
and the title beside it is the thing being named. It ellipsises rather than
|
|
102
|
+
wrapping, because a two-line head would move every row in the panel below it;
|
|
103
|
+
the whole name is on the `title`, along with where to change it. */
|
|
104
|
+
.sf-panel-site {
|
|
105
|
+
margin: 0;
|
|
106
|
+
min-width: 0;
|
|
107
|
+
overflow: hidden;
|
|
108
|
+
font-size: 11px;
|
|
109
|
+
font-weight: 500;
|
|
110
|
+
color: var(--sf-muted);
|
|
111
|
+
white-space: nowrap;
|
|
112
|
+
text-overflow: ellipsis;
|
|
113
|
+
}
|
|
114
|
+
.sf-panel-site::before {
|
|
115
|
+
content: "·";
|
|
116
|
+
margin-right: 6px;
|
|
117
|
+
}
|
|
118
|
+
.sf-x {
|
|
119
|
+
width: 24px;
|
|
120
|
+
height: 24px;
|
|
121
|
+
border: none;
|
|
122
|
+
background: transparent;
|
|
123
|
+
border-radius: 6px;
|
|
124
|
+
cursor: pointer;
|
|
125
|
+
color: var(--sf-muted);
|
|
126
|
+
display: flex;
|
|
127
|
+
align-items: center;
|
|
128
|
+
justify-content: center;
|
|
129
|
+
font-size: 14px;
|
|
130
|
+
}
|
|
131
|
+
.sf-x:hover {
|
|
132
|
+
background: var(--sf-hover);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/* ── Left panel: section tree (wraps Puck.Outline) ────────────────────── */
|
|
136
|
+
|
|
137
|
+
/* EVERY SEAM THE TREE STACKS, and no bare number among them.
|
|
138
|
+
The pairs are spelled out rather than written `> * + *` because the tree
|
|
139
|
+
interleaves group labels and subtrees between its rows: a rule that only
|
|
140
|
+
knows about `.sf-row` leaves those seams to whatever padding happens to be
|
|
141
|
+
nearby, which looks governed and is not.
|
|
142
|
+
`.sf-group-label` keeps its own `padding` and takes no margin here — it is a
|
|
143
|
+
heading, and a heading's air is part of the heading. */
|
|
144
|
+
.sf-tree > .sf-row + .sf-row,
|
|
145
|
+
.sf-tree > .sf-subtree + .sf-row {
|
|
146
|
+
margin-top: var(--es-rhythm-between);
|
|
147
|
+
}
|
|
148
|
+
.sf-row {
|
|
149
|
+
display: flex;
|
|
150
|
+
align-items: center;
|
|
151
|
+
gap: 8px;
|
|
152
|
+
/* ONE ROW, EVERY DEPTH (the owner's "One Ladder", 2026-09-04). The tree used
|
|
153
|
+
to draw three: a top-level bar (11px/600 in a 1px outline), a nested bar
|
|
154
|
+
(10.5px/600 on a mixed fill) and a leaf (11.5px/400). A merchant reading
|
|
155
|
+
down the panel had to learn three shapes that all meant "a level". Depth is
|
|
156
|
+
now said ONCE, by `.sf-subtree` — an indent and a hairline — and by nothing
|
|
157
|
+
else, so a row's look never has to be decided twice. */
|
|
158
|
+
padding: 7px 11px;
|
|
159
|
+
border-radius: var(--sf-row-radius);
|
|
160
|
+
cursor: pointer;
|
|
161
|
+
transition: background 0.12s;
|
|
162
|
+
/* Anchors the drop-indicator rules drawn during a drag-to-reorder, and the
|
|
163
|
+
drag grip, which sits in this row's own left padding. */
|
|
164
|
+
position: relative;
|
|
165
|
+
/* THE GROUND THIS ROW IS PAINTED ON, as a value the row's own children can
|
|
166
|
+
read. `.sf-row-actions` fades the name out beneath the hover eye/trash, and
|
|
167
|
+
a fade has to end in the colour that is actually behind the row — which
|
|
168
|
+
differs per state (plain, hovered, selected, bar, nested bar).
|
|
169
|
+
Every rule that changes the row's background changes this in the SAME
|
|
170
|
+
declaration block and then paints `background: var(--sf-row-scrim)`, so the
|
|
171
|
+
two can never name different colours. A resting row paints nothing, so its
|
|
172
|
+
ground is the panel it sits on. */
|
|
173
|
+
--sf-row-scrim: var(--sf-panel);
|
|
174
|
+
}
|
|
175
|
+
.sf-row:hover {
|
|
176
|
+
--sf-row-scrim: var(--sf-hover);
|
|
177
|
+
background: var(--sf-row-scrim);
|
|
178
|
+
}
|
|
179
|
+
/* The Layers rows' drag / drop marks (the dimmed grabbed row, the before /
|
|
180
|
+
after line, the drop-INTO box) and the group label are editor-shell's since
|
|
181
|
+
redesign 2b (`.es-tree-row.is-*`, `.es-tree-group`). The `.sf-row` rules here
|
|
182
|
+
serve the Pages list and the standalone section editor, which keep them. */
|
|
183
|
+
.sf-row.is-selected {
|
|
184
|
+
--sf-row-scrim: var(--sf-accent-tint);
|
|
185
|
+
background: var(--sf-row-scrim);
|
|
186
|
+
box-shadow: inset 2px 0 0 var(--sf-accent);
|
|
187
|
+
}
|
|
188
|
+
.sf-row.is-selected .sf-chip {
|
|
189
|
+
background: var(--sf-raised);
|
|
190
|
+
color: var(--sf-accent);
|
|
191
|
+
}
|
|
192
|
+
.sf-row.is-selected .sf-row-name {
|
|
193
|
+
color: var(--sf-accent-text);
|
|
194
|
+
font-weight: 600;
|
|
195
|
+
}
|
|
196
|
+
/* `.sf-add-section` WAS HERE, and it is gone on purpose (card 66228). Lewis
|
|
197
|
+
ruled on 2026-08-31 that ONE `+` in the top bar replaces every other add door
|
|
198
|
+
— the drawing is `editor-add-and-context-v1.html` in the SHARED `mockups/`
|
|
199
|
+
folder that sits beside the repo checkouts, NOT in this repo (card 66400.c:
|
|
200
|
+
the path here read `mockups/…`, which resolves to nothing from inside
|
|
201
|
+
efficient-storefront and has never existed in any commit of it, so a reader
|
|
202
|
+
checking the citation that justifies this removal found an empty hole):
|
|
203
|
+
「加东西只有一个入口。树底下原来那个 + Add block 也去掉了。」 Two doors to one
|
|
204
|
+
action is the fault this line keeps removing.
|
|
205
|
+
Removing THIS door is safe on its own — it was one of three ways into the
|
|
206
|
+
same picker, and the other two stay: the `.sf-gap` seam between two rows
|
|
207
|
+
(`openPickerAt(index)`) and the `.sf-preview-gap` overlay in the canvas
|
|
208
|
+
(`openPickerAt(g.index)`). The Footer panel's own Add block row also still
|
|
209
|
+
works. Do not remove those in the same breath as the top-bar `+`: the earlier
|
|
210
|
+
round said it plainly — 「右边那一行不能先删」 — get the order backwards and a
|
|
211
|
+
merchant loses a route.
|
|
212
|
+
`.sf-plus` is untouched; both of its rules are scoped to other buttons
|
|
213
|
+
(`.sf-add-card .sf-plus`) and `PagesPanel` / `AddChildRow` still render it. */
|
|
214
|
+
|
|
215
|
+
/* ── "Add section" seam between two tree rows ──────────────────────────────
|
|
216
|
+
A slim hover target sitting in the gap between rows; on hover (or keyboard
|
|
217
|
+
focus) it draws an accent insertion line with a centred "+" and clicking it
|
|
218
|
+
opens the Add-section picker targeted at that seam. Negative margin keeps it
|
|
219
|
+
from adding visible bulk to the resting tree. */
|
|
220
|
+
.sf-gap {
|
|
221
|
+
position: relative;
|
|
222
|
+
display: block;
|
|
223
|
+
width: 100%;
|
|
224
|
+
height: 9px;
|
|
225
|
+
/* Small negative margin so the seam mostly lives in the inter-row gap; kept
|
|
226
|
+
shallow so it barely overlaps the neighbouring rows' padding. */
|
|
227
|
+
margin: -2px 0;
|
|
228
|
+
padding: 0;
|
|
229
|
+
border: 0;
|
|
230
|
+
background: transparent;
|
|
231
|
+
cursor: pointer;
|
|
232
|
+
z-index: 1;
|
|
233
|
+
}
|
|
234
|
+
.sf-gap-line {
|
|
235
|
+
position: absolute;
|
|
236
|
+
left: 12px;
|
|
237
|
+
right: 12px;
|
|
238
|
+
top: 50%;
|
|
239
|
+
height: 2px;
|
|
240
|
+
transform: translateY(-50%);
|
|
241
|
+
border-radius: 2px;
|
|
242
|
+
background: var(--sf-accent);
|
|
243
|
+
opacity: 0;
|
|
244
|
+
transition: opacity 0.12s;
|
|
245
|
+
}
|
|
246
|
+
.sf-gap-plus {
|
|
247
|
+
position: absolute;
|
|
248
|
+
left: 50%;
|
|
249
|
+
top: 50%;
|
|
250
|
+
transform: translate(-50%, -50%) scale(0.7);
|
|
251
|
+
width: 18px;
|
|
252
|
+
height: 18px;
|
|
253
|
+
border-radius: 50%;
|
|
254
|
+
background: var(--sf-accent);
|
|
255
|
+
color: #fff;
|
|
256
|
+
display: flex;
|
|
257
|
+
align-items: center;
|
|
258
|
+
justify-content: center;
|
|
259
|
+
font-size: 14px;
|
|
260
|
+
line-height: 1;
|
|
261
|
+
box-shadow: 0 0 0 2px var(--sf-panel);
|
|
262
|
+
opacity: 0;
|
|
263
|
+
transition: opacity 0.12s, transform 0.12s;
|
|
264
|
+
}
|
|
265
|
+
.sf-gap:hover .sf-gap-line,
|
|
266
|
+
.sf-gap:focus-visible .sf-gap-line {
|
|
267
|
+
opacity: 1;
|
|
268
|
+
}
|
|
269
|
+
.sf-gap:hover .sf-gap-plus,
|
|
270
|
+
.sf-gap:focus-visible .sf-gap-plus {
|
|
271
|
+
opacity: 1;
|
|
272
|
+
transform: translate(-50%, -50%) scale(1);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/* ── Nested slot children (e.g. each Collections column) ────────────────────
|
|
276
|
+
ONE level of nesting costs 10px, and that is the whole indent — no 17px
|
|
277
|
+
margin, no rule down the left any more. Both were doing the job the row
|
|
278
|
+
ANATOMY was undoing: the parent above paid for a grip and a caret its
|
|
279
|
+
children did not have, so 26px of wrapper still left a child's name 18px to
|
|
280
|
+
the LEFT of its parent's (card 66199). With the grip out of the flow and the
|
|
281
|
+
caret at the row's right end, the wrapper is the only thing left that moves a
|
|
282
|
+
row sideways, so it can be small and still be the whole answer. The guide
|
|
283
|
+
rule goes with it: the bars now say what contains what, and a hairline down
|
|
284
|
+
the side of a grey bar reads as a border that failed to close. */
|
|
285
|
+
.sf-subtree {
|
|
286
|
+
/* THE ONLY THING IN THIS TREE THAT SAYS DEPTH (One Ladder, 2026-09-04).
|
|
287
|
+
Every row is now the same shape, so this wrapper carries the whole job:
|
|
288
|
+
16px of indent and a 1px rule down the left of the group it opens.
|
|
289
|
+
|
|
290
|
+
THE RULE IS NOT DECORATION. The fill it replaces was ~2% off white and
|
|
291
|
+
disappeared on a cheap panel; a hairline at `--sf-line` #e5e7eb is 10% and
|
|
292
|
+
does not. It also does something the fill never could — it runs the HEIGHT
|
|
293
|
+
of the group, so a child eight rows down still shows which parent it is
|
|
294
|
+
under without that parent being on screen.
|
|
295
|
+
|
|
296
|
+
The gap is the tree's own `--es-rhythm-between`, not a number of its own —
|
|
297
|
+
rows inside a group sit exactly as far apart as rows outside one, which is
|
|
298
|
+
what makes the ladder read as one list at three depths rather than three
|
|
299
|
+
lists. */
|
|
300
|
+
margin: var(--es-rhythm-between) 0 var(--es-rhythm-between) 16px;
|
|
301
|
+
padding-left: 9px;
|
|
302
|
+
border-left: 1px solid var(--sf-line);
|
|
303
|
+
display: flex;
|
|
304
|
+
flex-direction: column;
|
|
305
|
+
gap: var(--es-rhythm-between);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/* ── Footer "Add block" menu — heterogeneous block-type picker ──────────── */
|
|
309
|
+
|
|
310
|
+
/* ── Add — a mode over the left panel (components/AddSidePanel) ────────────
|
|
311
|
+
Blueprint step 3.7: the floating `.sf-picker` dialog is gone, and Add is the
|
|
312
|
+
left panel's content while it is open. The search, the headed groups and the
|
|
313
|
+
tiles are efficient-easel/drag's `AddPanel` (drag.css); a section is a CARD
|
|
314
|
+
with its cover there (`.es-add-grid.is-cards`). What is the website's alone
|
|
315
|
+
is the panel's inset and the Live chat row under the groups. */
|
|
316
|
+
/* The Live chat bubble: site-wide and not a section, so a switch on a row
|
|
317
|
+
rather than a tile. The name opens its settings; the switch turns it on. */
|
|
318
|
+
.sf-addside-sitewide {
|
|
319
|
+
display: flex;
|
|
320
|
+
align-items: center;
|
|
321
|
+
gap: 10px;
|
|
322
|
+
margin-top: 16px;
|
|
323
|
+
padding: 10px;
|
|
324
|
+
border: 1px solid var(--sf-divider);
|
|
325
|
+
border-radius: 10px;
|
|
326
|
+
}
|
|
327
|
+
.sf-addside-sitewide-glyph {
|
|
328
|
+
flex: none;
|
|
329
|
+
display: grid;
|
|
330
|
+
place-items: center;
|
|
331
|
+
width: 28px;
|
|
332
|
+
height: 28px;
|
|
333
|
+
border-radius: 7px;
|
|
334
|
+
background: var(--sf-hover);
|
|
335
|
+
color: var(--sf-muted);
|
|
336
|
+
}
|
|
337
|
+
.sf-addside-sitewide-name {
|
|
338
|
+
flex: 1;
|
|
339
|
+
min-width: 0;
|
|
340
|
+
display: flex;
|
|
341
|
+
flex-direction: column;
|
|
342
|
+
align-items: flex-start;
|
|
343
|
+
gap: 2px;
|
|
344
|
+
padding: 0;
|
|
345
|
+
border: 0;
|
|
346
|
+
background: none;
|
|
347
|
+
font: 600 12.5px/1.3 var(--sf-font);
|
|
348
|
+
color: var(--sf-text);
|
|
349
|
+
text-align: left;
|
|
350
|
+
cursor: pointer;
|
|
351
|
+
}
|
|
352
|
+
.sf-addside-sitewide-name:hover {
|
|
353
|
+
color: var(--sf-accent);
|
|
354
|
+
}
|
|
355
|
+
.sf-addside-sitewide-desc {
|
|
356
|
+
font-weight: 400;
|
|
357
|
+
font-size: 11.5px;
|
|
358
|
+
color: var(--sf-muted);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/* "Switch to Box footer" (blueprint step H.4) — a short note and its button
|
|
362
|
+
under the old footer's settings. A confirmation replaces the button in place
|
|
363
|
+
rather than opening a dialog: it is one decision, made where it is offered. */
|
|
364
|
+
.sf-box-footer-switch {
|
|
365
|
+
display: flex;
|
|
366
|
+
flex-direction: column;
|
|
367
|
+
align-items: flex-start;
|
|
368
|
+
gap: 10px;
|
|
369
|
+
margin: 18px 0 6px;
|
|
370
|
+
padding: 12px;
|
|
371
|
+
border: 1px solid var(--sf-divider);
|
|
372
|
+
border-radius: 10px;
|
|
373
|
+
}
|
|
374
|
+
.sf-box-footer-switch-text {
|
|
375
|
+
margin: 0;
|
|
376
|
+
font-size: 12px;
|
|
377
|
+
line-height: 1.45;
|
|
378
|
+
color: var(--sf-muted);
|
|
379
|
+
}
|
|
380
|
+
.sf-box-footer-switch-row {
|
|
381
|
+
display: flex;
|
|
382
|
+
gap: 8px;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/* Section-cover wireframe tokens — the bespoke palette the SectionThumbnail
|
|
386
|
+
* covers draw with (see components/SectionThumbnail.tsx). Defined once here so no
|
|
387
|
+
* colour literal lives in the .tsx (doc/no-hardcoding.md R3); the admin mirror
|
|
388
|
+
* defines the same block in src/index.css. Light-only: the picker + the console
|
|
389
|
+
* catalog both sit on a light surface. */
|
|
390
|
+
.sf-thumb {
|
|
391
|
+
--sf-thumb-card: #ffffff;
|
|
392
|
+
--sf-thumb-thumb-bg: #fcfdff;
|
|
393
|
+
--sf-thumb-thumb-border: #edeff4;
|
|
394
|
+
--sf-thumb-block: #e9ebf0;
|
|
395
|
+
--sf-thumb-bar-light: #dde1e8;
|
|
396
|
+
--sf-thumb-bar-dark: #c3c9d3;
|
|
397
|
+
--sf-thumb-hatch1: #e2e5ec;
|
|
398
|
+
--sf-thumb-hatch2: #edeff4;
|
|
399
|
+
--sf-thumb-accent: #2f6bed;
|
|
400
|
+
--sf-thumb-accent-tint: #e6edfd;
|
|
401
|
+
--sf-thumb-border: #e7eaf1;
|
|
402
|
+
|
|
403
|
+
/* ── THE SCENE PALETTE ─────────────────────────────────────────────────
|
|
404
|
+
Added when the covers stopped being grey wireframes. The eleven tokens
|
|
405
|
+
above are all pale grey-blue, because the old covers only ever drew bars:
|
|
406
|
+
they could say WHERE things sat and nothing else, which is why the owner
|
|
407
|
+
said he could not get any useful information out of them (2026-09-04).
|
|
408
|
+
|
|
409
|
+
A cover that reads at 196px needs the two things a wireframe throws away —
|
|
410
|
+
colour and content — so these are the grounds a scene is painted on, plus
|
|
411
|
+
the one warm highlight that stands in for a brand accent. Still tokens and
|
|
412
|
+
still no literals in the component (doc/no-hardcoding.md R3), and still
|
|
413
|
+
ONE definition per app.
|
|
414
|
+
|
|
415
|
+
⚠️ THE GROUNDS ARE NOT SITE COLOURS, and are not wired to a site's theme.
|
|
416
|
+
A cover pictures a KIND of section, and has to read the same in every
|
|
417
|
+
tenant and in the admin portal's catalog — a merchant comparing "Hero"
|
|
418
|
+
against "Split" is choosing a layout, not previewing their own palette.
|
|
419
|
+
Wiring the grounds to `--sf-accent` would repaint all 68 the moment a site
|
|
420
|
+
changed its accent, and make two shops disagree about what one section is.
|
|
421
|
+
|
|
422
|
+
⚠️ `--sf-thumb-accent` IS THE EXCEPTION, and it was here first. The ADMIN
|
|
423
|
+
portal overrides it per site (`--sf-cover-accent`, src/index.css) so a
|
|
424
|
+
Sites card's covers wear that site's real accent. That is a deliberate,
|
|
425
|
+
scoped override of ONE token — not a licence to theme the grounds, which
|
|
426
|
+
would take the same cover to a different picture rather than a different
|
|
427
|
+
highlight. */
|
|
428
|
+
--sf-thumb-ink: #1b2027; /* dark photographic ground, top */
|
|
429
|
+
--sf-thumb-ink-2: #39434f; /* …and its gradient end */
|
|
430
|
+
--sf-thumb-ink-soft: #2c3540; /* the lighter dark ground, for split scenes */
|
|
431
|
+
--sf-thumb-ink-soft-2: #4a5763;
|
|
432
|
+
--sf-thumb-paper: #f4f1ed; /* warm light ground */
|
|
433
|
+
--sf-thumb-paper-2: #cfc8bf; /* …and its gradient end */
|
|
434
|
+
--sf-thumb-warm: #e7c26a; /* the highlight — overline + CTA on a dark ground */
|
|
435
|
+
--sf-thumb-rust: #b4652a; /* the overline on a light ground */
|
|
436
|
+
--sf-thumb-on-ink: #ffffff;
|
|
437
|
+
--sf-thumb-scene-text: #171412; /* headline / price on a light ground */
|
|
438
|
+
--sf-thumb-scene-muted: #6b7280; /* section titles and secondary lines */
|
|
439
|
+
--sf-thumb-scene-rule: #eceef1; /* the hairline between table rows */
|
|
440
|
+
/* The product MARK — option 甲, picked by the owner on 2026-09-04: two soft
|
|
441
|
+
blocks, deliberately NOT a picture of a wheel. The catalogue also sells
|
|
442
|
+
tyres, lift kits, lights and pedals, so a round mark would be wrong on most
|
|
443
|
+
of it; this says "a product sits here" and claims nothing more. */
|
|
444
|
+
--sf-thumb-mark-1: #c8ccd1;
|
|
445
|
+
--sf-thumb-mark-2: #8e9aa6;
|
|
446
|
+
/* The scrim that keeps a headline legible over a dark photographic ground —
|
|
447
|
+
the one place a cover needs transparency, so it is a token like every other
|
|
448
|
+
colour here rather than an `rgba()` sitting in the component. */
|
|
449
|
+
--sf-thumb-scrim: rgba(0, 0, 0, 0.55);
|
|
450
|
+
}
|
|
451
|
+
/* Drives the Ticker cover's scrolling strip. */
|
|
452
|
+
@keyframes sf-thumb-marquee {
|
|
453
|
+
from {
|
|
454
|
+
transform: translateX(0);
|
|
455
|
+
}
|
|
456
|
+
to {
|
|
457
|
+
transform: translateX(-33.34%);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/* ── The one destructive confirm in the panel (Reset color) ─────────────────
|
|
462
|
+
[ADD] Reset On Every Site Style. Every other reset on Site styles clears a
|
|
463
|
+
number or a rung; this one deletes a merchant's authored palettes, so it asks
|
|
464
|
+
first (owner's ruling 2026-09-05, option B).
|
|
465
|
+
|
|
466
|
+
THE COLOURS LIVE HERE RATHER THAN ON THE COMPONENT, and that is the rule
|
|
467
|
+
rather than a preference. `test-panel-colour-tokens` sweeps `components/` for
|
|
468
|
+
literals — "a literal there is a private copy of one step of that scale: it
|
|
469
|
+
does not move when the scale moves". The older `LeaveConfirmDialog` spells its
|
|
470
|
+
palette in Tailwind literals and predates that sweep; a second dialog copying
|
|
471
|
+
it would have passed review and failed the gate.
|
|
472
|
+
|
|
473
|
+
The destructive button takes the `--sf-danger*` family that already exists,
|
|
474
|
+
not a red of its own. The radius is the 9px the theme cards and the add-card
|
|
475
|
+
button already wear, so the dialog reads as the same object as the rest of the
|
|
476
|
+
panel rather than a new shape. */
|
|
477
|
+
.sf-cleardlg-veil {
|
|
478
|
+
position: fixed;
|
|
479
|
+
inset: 0;
|
|
480
|
+
z-index: 200;
|
|
481
|
+
display: flex;
|
|
482
|
+
align-items: center;
|
|
483
|
+
justify-content: center;
|
|
484
|
+
padding: 16px;
|
|
485
|
+
background: var(--sf-addcard-veil);
|
|
486
|
+
}
|
|
487
|
+
.sf-cleardlg {
|
|
488
|
+
width: 100%;
|
|
489
|
+
max-width: 360px;
|
|
490
|
+
box-sizing: border-box;
|
|
491
|
+
padding: 20px;
|
|
492
|
+
border: 1px solid var(--sf-line);
|
|
493
|
+
border-radius: 9px;
|
|
494
|
+
background: var(--sf-panel);
|
|
495
|
+
color: var(--sf-text);
|
|
496
|
+
box-shadow: 0 20px 50px var(--sf-accent-shadow);
|
|
497
|
+
}
|
|
498
|
+
.sf-cleardlg-title {
|
|
499
|
+
margin: 0;
|
|
500
|
+
font-size: 15px;
|
|
501
|
+
font-weight: 600;
|
|
502
|
+
color: var(--sf-text);
|
|
503
|
+
}
|
|
504
|
+
.sf-cleardlg-body {
|
|
505
|
+
margin: 8px 0 0;
|
|
506
|
+
font-size: 13px;
|
|
507
|
+
line-height: 1.6;
|
|
508
|
+
color: var(--sf-muted);
|
|
509
|
+
}
|
|
510
|
+
/* The one line a merchant must not skim. NOT red — the button already carries
|
|
511
|
+
the danger colour, and a red sentence over a red button is the panel shouting
|
|
512
|
+
twice. Full-strength ink and a heavier weight instead. */
|
|
513
|
+
.sf-cleardlg-final {
|
|
514
|
+
margin: 8px 0 0;
|
|
515
|
+
font-size: 13px;
|
|
516
|
+
line-height: 1.6;
|
|
517
|
+
font-weight: 500;
|
|
518
|
+
color: var(--sf-text);
|
|
519
|
+
}
|
|
520
|
+
.sf-cleardlg-btns {
|
|
521
|
+
display: flex;
|
|
522
|
+
justify-content: flex-end;
|
|
523
|
+
gap: 8px;
|
|
524
|
+
margin-top: 18px;
|
|
525
|
+
}
|
|
526
|
+
.sf-cleardlg-btn {
|
|
527
|
+
font-family: var(--sf-font);
|
|
528
|
+
font-size: 13px;
|
|
529
|
+
padding: 7px 14px;
|
|
530
|
+
border-radius: var(--sf-field-radius);
|
|
531
|
+
border: 1px solid var(--sf-btn-border);
|
|
532
|
+
background: var(--sf-panel);
|
|
533
|
+
color: var(--sf-btn-text);
|
|
534
|
+
cursor: pointer;
|
|
535
|
+
}
|
|
536
|
+
.sf-cleardlg-btn:hover { background: var(--sf-hover); }
|
|
537
|
+
.sf-cleardlg-btn--danger {
|
|
538
|
+
font-weight: 600;
|
|
539
|
+
border-color: var(--sf-danger-strong);
|
|
540
|
+
background: var(--sf-danger-strong);
|
|
541
|
+
color: var(--sf-on-accent);
|
|
542
|
+
}
|
|
543
|
+
.sf-cleardlg-btn--danger:hover { filter: brightness(0.94); }
|
|
544
|
+
|
|
545
|
+
.sf-addcard-overlay {
|
|
546
|
+
position: absolute;
|
|
547
|
+
inset: 0;
|
|
548
|
+
display: flex;
|
|
549
|
+
align-items: center;
|
|
550
|
+
justify-content: center;
|
|
551
|
+
background: var(--sf-addcard-veil);
|
|
552
|
+
backdrop-filter: blur(2px);
|
|
553
|
+
-webkit-backdrop-filter: blur(2px);
|
|
554
|
+
opacity: 0;
|
|
555
|
+
transition: opacity 0.15s;
|
|
556
|
+
pointer-events: none;
|
|
557
|
+
}
|
|
558
|
+
.sf-addcard:hover .sf-addcard-overlay,
|
|
559
|
+
.sf-addcard:focus-visible .sf-addcard-overlay {
|
|
560
|
+
opacity: 1;
|
|
561
|
+
}
|
|
562
|
+
.sf-addcard-addbtn {
|
|
563
|
+
display: inline-flex;
|
|
564
|
+
align-items: center;
|
|
565
|
+
gap: 6px;
|
|
566
|
+
background: var(--sf-accent);
|
|
567
|
+
color: #fff;
|
|
568
|
+
border-radius: 9px;
|
|
569
|
+
padding: 8px 14px;
|
|
570
|
+
font-size: 12.5px;
|
|
571
|
+
font-weight: 600;
|
|
572
|
+
box-shadow: 0 4px 12px var(--sf-accent-shadow);
|
|
573
|
+
}
|
|
574
|
+
.sf-addcard-plus {
|
|
575
|
+
font-size: 15px;
|
|
576
|
+
line-height: 1;
|
|
577
|
+
margin-top: -1px;
|
|
578
|
+
}
|
|
579
|
+
.sf-addcard-meta {
|
|
580
|
+
display: flex;
|
|
581
|
+
flex-direction: column;
|
|
582
|
+
gap: 2px;
|
|
583
|
+
padding: 0 2px 2px;
|
|
584
|
+
}
|
|
585
|
+
.sf-addcard-name {
|
|
586
|
+
font-size: 12.5px;
|
|
587
|
+
font-weight: 600;
|
|
588
|
+
color: var(--sf-text);
|
|
589
|
+
}
|
|
590
|
+
.sf-addcard-desc {
|
|
591
|
+
font-size: 10.5px;
|
|
592
|
+
line-height: 1.35;
|
|
593
|
+
color: var(--sf-muted);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/* Empty-search state */
|
|
597
|
+
.sf-addempty {
|
|
598
|
+
display: flex;
|
|
599
|
+
flex-direction: column;
|
|
600
|
+
align-items: center;
|
|
601
|
+
justify-content: center;
|
|
602
|
+
gap: 9px;
|
|
603
|
+
padding: 64px 20px;
|
|
604
|
+
text-align: center;
|
|
605
|
+
color: var(--sf-muted);
|
|
606
|
+
}
|
|
607
|
+
.sf-addempty-icon {
|
|
608
|
+
display: flex;
|
|
609
|
+
color: var(--sf-field-placeholder);
|
|
610
|
+
}
|
|
611
|
+
.sf-addempty-icon svg {
|
|
612
|
+
width: 30px;
|
|
613
|
+
height: 30px;
|
|
614
|
+
}
|
|
615
|
+
.sf-addempty-title {
|
|
616
|
+
font-size: 14px;
|
|
617
|
+
font-weight: 600;
|
|
618
|
+
color: var(--sf-text);
|
|
619
|
+
}
|
|
620
|
+
.sf-addempty-sub {
|
|
621
|
+
font-size: 12.5px;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/* ── Center: device-framed preview (wraps Puck.Preview) ──────────────── */
|
|
625
|
+
.sf-frame--tablet,
|
|
626
|
+
.sf-frame--mobile {
|
|
627
|
+
/* device frames don't stretch to full width but still fill height */
|
|
628
|
+
align-self: stretch;
|
|
629
|
+
}
|
|
630
|
+
/* The device's edge is an OUTLINE drawn inside the frame, not a border: the
|
|
631
|
+
frame is border-box, so a 1px border sat inside the 390px width and the page
|
|
632
|
+
was laid out at 388 (800 → 798 on tablet) — card `[FIX] Editor Canvas Runs
|
|
633
|
+
The Live Page Head`. An outline takes no width, so the page gets the whole
|
|
634
|
+
device (DEVICE_W in StorefrontEditorChrome); painted last, it sits over the
|
|
635
|
+
page's outermost pixel. No radius of their own: `.sf-frame` above is square
|
|
636
|
+
and these follow it, so the website's corners are never clipped. */
|
|
637
|
+
.sf-frame--tablet {
|
|
638
|
+
width: 800px;
|
|
639
|
+
outline: 1px solid var(--sf-device-border);
|
|
640
|
+
outline-offset: -1px;
|
|
641
|
+
}
|
|
642
|
+
.sf-frame--mobile {
|
|
643
|
+
width: 390px;
|
|
644
|
+
outline: 1px solid var(--sf-device-border);
|
|
645
|
+
outline-offset: -1px;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
/* The Cart / Checkout surfaces are previewed in-canvas by rendering the real
|
|
649
|
+
components inside the Puck preview iframe (same-document, no nested `<iframe
|
|
650
|
+
src>`) — see components/EditorPreviewSurface. No editor-side frame CSS is
|
|
651
|
+
needed; the ribbon is styled inline in that component. */
|
|
652
|
+
|
|
653
|
+
/* ── One dashed outline on hover, not a field of them (card 66395) ─────────
|
|
654
|
+
The owner, 2026-09-01: hovering a section shows too many dashed lines. He
|
|
655
|
+
wants to find the hover target directly, and ONE is enough.
|
|
656
|
+
|
|
657
|
+
He was right, and the hover outline was never the cause. Puck draws FIVE
|
|
658
|
+
dashed outlines and four of them are STATES -- they paint only while a
|
|
659
|
+
merchant is hovering, selecting or dragging. The fifth has no state in its
|
|
660
|
+
selector at all:
|
|
661
|
+
|
|
662
|
+
._DropZone_<hash>:empty { background: <azure tint>; outline: 2px dashed }
|
|
663
|
+
|
|
664
|
+
`:empty` is true whenever a slot holds nothing, so that box is painted the
|
|
665
|
+
whole time. Measured in the real editor on the `sharpen` homepage: FOUR of
|
|
666
|
+
those boxes standing with nothing hovered, three of them stacked inside the
|
|
667
|
+
hero. Hovering added the fifth, and his eye had to find it among the four
|
|
668
|
+
that were already there.
|
|
669
|
+
|
|
670
|
+
So the standing one goes and the four states stay. Puck set
|
|
671
|
+
`[data-puck-dragging]` on `[data-puck-entry]` for the length of a drag, so
|
|
672
|
+
scoping to `:not([data-puck-dragging])` left every drag affordance exactly
|
|
673
|
+
as Puck shipped it -- a merchant still sees where a block can land, which is
|
|
674
|
+
the one thing that must not be traded away for this. (The engine sets no
|
|
675
|
+
such attribute and draws its drop targets over the frame, not in it, so the
|
|
676
|
+
scope is gone; the note on the rule below says why that is safe.)
|
|
677
|
+
|
|
678
|
+
ONLY the outline. Puck's rule paints a background tint as well, and that is
|
|
679
|
+
left alone: an empty slot stays a visible block, so nothing becomes
|
|
680
|
+
unfindable -- it just stops drawing a line round itself.
|
|
681
|
+
|
|
682
|
+
SPECIFICITY, NOT `!important`. Ours was (0,4,0) against Puck's (0,2,0), and
|
|
683
|
+
`storefront-editor.css` was imported after `puck.css` at every call site so
|
|
684
|
+
source order settled any tie (it is imported after the engine's
|
|
685
|
+
`efficient-easel/easel.css` now; guard §9). An `!important` here would also beat
|
|
686
|
+
`._DropZone--isDestination_`, which IS `!important`, and blind the merchant
|
|
687
|
+
mid-drag.
|
|
688
|
+
|
|
689
|
+
`[class*=]`, NOT the literal class. Puck's CSS-module names carry a build
|
|
690
|
+
hash (`_DropZone_1i2sv_1`); a literal one would stop matching on the next
|
|
691
|
+
Puck bump with no error at all, and the field of outlines would come back
|
|
692
|
+
silently. `scripts/test-one-hover-outline.tsx` asserts all of this, and
|
|
693
|
+
asserts Puck still draws the rule we are overriding -- if it ever stops,
|
|
694
|
+
this becomes dead code and the guard turns that into a red rather than
|
|
695
|
+
leaving something that looks load-bearing.
|
|
696
|
+
|
|
697
|
+
── An empty slot still ANSWERS when you point at it (card 66395.b) ────────
|
|
698
|
+
|
|
699
|
+
The paragraph above is right about the standing box and wrong about what
|
|
700
|
+
else it took. `:empty` does not stop being true while a slot is HOVERED or
|
|
701
|
+
SELECTED -- it only says the slot holds nothing -- and this selector is
|
|
702
|
+
LONGER than the Puck rules that paint those two states:
|
|
703
|
+
|
|
704
|
+
ours [data-puck-entry]:not([data-puck-dragging]) …:empty (0,4,0)
|
|
705
|
+
Puck --hoveringOverArea_:not(--isRootZone_) (0,2,0)
|
|
706
|
+
Puck --isAreaSelected_ (0,1,0)
|
|
707
|
+
|
|
708
|
+
So on an empty slot this rule won everywhere instead of only at rest.
|
|
709
|
+
Measured in the real editor on the `sharpen` homepage, merged main
|
|
710
|
+
8603ffd82: all four empty zones read `outline: none 0px` while hovered with
|
|
711
|
+
`--hoveringOverArea_` set, and two of them read the same while
|
|
712
|
+
`--isAreaSelected_` was set.
|
|
713
|
+
|
|
714
|
+
That matters more than a missing line. Hovering an empty slot IS the
|
|
715
|
+
deliberate act of pointing at it to put the first block in, so the merchant
|
|
716
|
+
got nothing at the one moment the affordance was being asked for. The
|
|
717
|
+
background tint the paragraph above relies on is true while nothing is
|
|
718
|
+
happening -- and something IS happening here.
|
|
719
|
+
|
|
720
|
+
THE TWO EXCLUSIONS ARE PUCK'S OWN CONDITIONS, NEGATED, NOT NEW ONES. Puck
|
|
721
|
+
paints a non-drag dashed outline on a zone in exactly two cases:
|
|
722
|
+
|
|
723
|
+
._DropZone--isAreaSelected_
|
|
724
|
+
._DropZone--hoveringOverArea_:not(._DropZone--isRootZone_)
|
|
725
|
+
|
|
726
|
+
and this rule now stands aside for each, character for character. §6 of
|
|
727
|
+
the guard BUILDS those two exclusions out of Puck's stylesheet and fails if
|
|
728
|
+
ours do not match, so a sixth state upstream becomes a red on the day Puck
|
|
729
|
+
ships it rather than a silent hole like this one.
|
|
730
|
+
|
|
731
|
+
⚠️ WHY THE HOVER EXCLUSION KEEPS ITS `:not(--isRootZone_)`, AND MUST. Puck
|
|
732
|
+
computes `hoveringOverArea = inNextDeepestArea || isRootZone`, so THE ROOT
|
|
733
|
+
ZONE CARRIES IT AT ALL TIMES -- that is why Puck's own rule qualifies it.
|
|
734
|
+
A bare `:not(--hoveringOverArea_)` here would therefore stop neutralising
|
|
735
|
+
the root zone, and an empty page would get its standing dashed box back:
|
|
736
|
+
half of the defect this rule exists to remove, restored quietly by a fix
|
|
737
|
+
for the other half. Nesting the qualifier keeps that box gone; measured on
|
|
738
|
+
the board, `empty · ROOT ZONE at rest` still reads `none 0px`.
|
|
739
|
+
|
|
740
|
+
ONE RULE, NOT TWO. `:not(A:not(B))` says "not (hovering AND not root)" in
|
|
741
|
+
one compound, so the root zone needs no second rule fighting this one over
|
|
742
|
+
the same outline. Specificity rises to (0,7,0), which still loses to
|
|
743
|
+
`--isDestination_` because that is `!important` and this is not -- the drag
|
|
744
|
+
affordance does not move in either direction, and the three DRAGGING rows
|
|
745
|
+
on the board read `dashed 2px` before and after.
|
|
746
|
+
|
|
747
|
+
Whether any of this is really PAINTED is not a question CSS text can
|
|
748
|
+
answer. `scripts/probe-empty-slot-outline.mjs` rendered these states in a
|
|
749
|
+
browser over Puck's classes; it went with Puck (blueprint 6.3), so measure
|
|
750
|
+
the engine's canvas in the live editor. */
|
|
751
|
+
/* Since blueprint 5.5 the lists are efficient-easel's `.es-zone`, and the
|
|
752
|
+
states this section answers are its classes: `.is-area-selected` (Puck's
|
|
753
|
+
`--isAreaSelected_`), `.is-hovering-area` (`--hoveringOverArea_`) and
|
|
754
|
+
`.is-root` (`--isRootZone_`). The reasoning above is unchanged; only the
|
|
755
|
+
names moved, from Puck's hashed modules to classes this repo can spell.
|
|
756
|
+
|
|
757
|
+
⚠️ NO DRAG SCOPE ANY MORE, AND A DRAG STILL SHOWS WHERE A BLOCK CAN LAND.
|
|
758
|
+
This rule and A/B below were scoped to `:not([data-puck-dragging])` so a
|
|
759
|
+
drag kept Puck's in-frame drop targets (`--isDestination_`). Nothing has
|
|
760
|
+
set that attribute since 5.5 — the engine has no such state — so the
|
|
761
|
+
`:not()` matched every time and only added specificity: dead code that
|
|
762
|
+
looked load-bearing. The engine draws a drag's targets in the HOST page,
|
|
763
|
+
over the frame: the drop line, and on an empty slot the dashed
|
|
764
|
+
`.es-canvas-empty` "+ Add block" cell (efficient-easel/drag.css), sized
|
|
765
|
+
to the zone, at rest and mid-drag alike. Measured 2026-10-03 in
|
|
766
|
+
/edit/preview-newpage with a drag from the Add panel: the cell stays over
|
|
767
|
+
the empty slot for the whole drag, so the zone's own outline under it is
|
|
768
|
+
not what the merchant sees during one. Every zone state (rest, selected,
|
|
769
|
+
hovered, root; empty and filled) computed the same outline before and
|
|
770
|
+
after the scope went. Without it this rule is (0,6,0) against the engine's
|
|
771
|
+
`.es-zone:empty` (0,2,0). */
|
|
772
|
+
[data-puck-entry]
|
|
773
|
+
.es-zone:empty:not(.is-area-selected):not(.is-hovering-area:not(.is-root)) {
|
|
774
|
+
outline: none;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
/* ── No dashed lines while pointing, and ONE line, not three (card 66517) ───
|
|
778
|
+
⚠️ THIS CARD'S MERGED COMMITS ON `main` SAY 66511, AND THAT IS NOT A TYPO.
|
|
779
|
+
Two cards were allocated 66511 on 2026-09-02: this one, and the `ground` glyph
|
|
780
|
+
card whose number is baked into a published `efficient-easel` icon entry and
|
|
781
|
+
named in this repo's released CHANGELOG. That one keeps the number, because
|
|
782
|
+
its copies cannot be recalled; this one moved, because comments can. The
|
|
783
|
+
squash subjects on `main` still read `66511 · …` and are deliberately NOT
|
|
784
|
+
rewritten — a merged subject is a record of what was done on the day, not a
|
|
785
|
+
pointer, and rewriting `main`'s history for a number costs more than the
|
|
786
|
+
confusion it saves. Follow 66517; `components/ThemeCard.tsx` is the other.
|
|
787
|
+
The owner, 2026-09-02, with a screenshot of the sharpen homepage: pointing
|
|
788
|
+
at the hero heading draws three nested dashed rectangles, and he does not
|
|
789
|
+
want dashed lines.
|
|
790
|
+
|
|
791
|
+
THIS IS THE SECOND TIME HE HAS RAISED IT, and card 66395 above did not miss.
|
|
792
|
+
It removed a box that was painted the whole time, on every empty slot,
|
|
793
|
+
whether or not anything was happening — a real defect, and it is gone. What
|
|
794
|
+
he is pointing at now is the set that is SUPPOSED to appear. Three rules
|
|
795
|
+
fire at once and each is correct on its own terms:
|
|
796
|
+
|
|
797
|
+
the zone whose owner you CLICKED --isAreaSelected_
|
|
798
|
+
the deepest zone you are INSIDE --hoveringOverArea_:not(--isRootZone_)
|
|
799
|
+
the block you are POINTING AT [data-puck-overlay-portal]:hover
|
|
800
|
+
|
|
801
|
+
MEASURED, not inferred, by scripts/probe-hover-outline-count.mjs (retired
|
|
802
|
+
with Puck in blueprint 6.3) against both stylesheets in the app's own import
|
|
803
|
+
order, with a real pointer:
|
|
804
|
+
|
|
805
|
+
pointing at a block 2 dashed boxes
|
|
806
|
+
pointing at a block you have clicked 3 dashed boxes <- his picture
|
|
807
|
+
|
|
808
|
+
⚠️ THE ROOT ZONE IS THE THIRD ONE, AND IT SURPRISES PEOPLE. Puck's
|
|
809
|
+
`isAreaSelected` rule carries no `:not(--isRootZone_)`, unlike its hover
|
|
810
|
+
rule, so selecting a top-level section outlines the whole page as well as
|
|
811
|
+
the section. That is why the count goes 2 -> 3 on a click rather than
|
|
812
|
+
staying at 2.
|
|
813
|
+
|
|
814
|
+
WHAT THIS DOES. One line, on the thing you are pointing at, and it is
|
|
815
|
+
SOLID. The zones keep their background tint and lose their line: the tint
|
|
816
|
+
already says which slot you are in, and it says it without drawing a
|
|
817
|
+
rectangle round a rectangle.
|
|
818
|
+
|
|
819
|
+
⚠️ AN EMPTY SLOT STILL HAS TO ANSWER. Card 66395.b exists because the first
|
|
820
|
+
version of the rule above took that away — hovering an empty slot IS the
|
|
821
|
+
deliberate act of pointing at it to put the first block in, and it got
|
|
822
|
+
nothing at the one moment the affordance was being asked for. An empty zone
|
|
823
|
+
has no block in it and therefore no overlay to carry the line, so rule B
|
|
824
|
+
below gives it one of its own. Solid, like everything else here.
|
|
825
|
+
|
|
826
|
+
⚠️ A DRAG IS NOT TOUCHED, AND MUST NOT BE. Under Puck every rule here sat
|
|
827
|
+
inside `:not([data-puck-dragging])`, so `--isDestination_` and
|
|
828
|
+
`--isEnabled_` shipped exactly as Puck wrote them. Dashed means something
|
|
829
|
+
during a drag — it is where a block can land — and that is the one
|
|
830
|
+
affordance card 66395 said must never be traded away for this. It still
|
|
831
|
+
holds, by other means: the engine draws a drag's targets over the frame
|
|
832
|
+
(the drop line, the `.es-canvas-empty` cell), where nothing here reaches,
|
|
833
|
+
so the scope went with Puck — see the note on the empty-slot rule above.
|
|
834
|
+
|
|
835
|
+
SPECIFICITY, NOT `!important`, the same as the rule above. A is (0,4,0)
|
|
836
|
+
against the engine's (0,3,0) state rules; its first selector carries
|
|
837
|
+
`:not(.is-root)` for that, in place of the old drag scope — without either
|
|
838
|
+
it would only TIE `.es-zone.is-area-selected:not(.is-root)` and win on
|
|
839
|
+
source order. Nothing is lost on the root: the engine never outlines a
|
|
840
|
+
selected root list, and an EMPTY selected root still gets B. B is (0,5,0)
|
|
841
|
+
so it wins over A on an empty zone. C has no upstream rule left to answer
|
|
842
|
+
(Puck's overlay-portal sheet went in 5.5). Ours is imported after the
|
|
843
|
+
engine's sheet at every call site all the same (guard §9).
|
|
844
|
+
|
|
845
|
+
`[class*=]`, NOT the literal class names — Puck's CSS-module names carry a
|
|
846
|
+
build hash, and a literal one would stop matching on the next Puck bump with
|
|
847
|
+
no error at all, silently putting all three boxes back. */
|
|
848
|
+
|
|
849
|
+
/* A · a zone draws no line while you point at it or after you click it. */
|
|
850
|
+
[data-puck-entry] .es-zone.is-area-selected:not(.is-root),
|
|
851
|
+
[data-puck-entry] .es-zone.is-hovering-area:not(.is-root) {
|
|
852
|
+
outline: none;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
/* ⚠️ EVERY COLOUR BELOW CARRIES ITS OWN FALLBACK, AND THAT IS NOT DECORATION.
|
|
856
|
+
These rules paint inside the canvas FRAME, whose document has no `.es-editor`
|
|
857
|
+
root, so no `--es-*` token is defined there (efficient-easel/easel.css
|
|
858
|
+
falls back the same way). Until blueprint 5.5 they leaned on Puck's
|
|
859
|
+
`puck.css`, which declared its `--puck-color-azure-*` ramp on the frame's
|
|
860
|
+
`:root` and drew the pointed-at block's colour and offset itself. 5.5 took
|
|
861
|
+
that sheet off the canvas: a bare `var(--puck-color-azure-08)` then resolved
|
|
862
|
+
to nothing, and an `outline` with an unresolvable colour is no outline at all
|
|
863
|
+
— the empty slot stopped answering when pointed at, silently. The colours are
|
|
864
|
+
Puck's ramp as the shell re-tints it (`--es-accent-line` = azure-08,
|
|
865
|
+
`--es-accent-tint-strong` = azure-09). */
|
|
866
|
+
|
|
867
|
+
/* B · …except an EMPTY one, which has no block to carry the line for it. */
|
|
868
|
+
[data-puck-entry]
|
|
869
|
+
.es-zone:empty:is(.is-area-selected, .is-hovering-area:not(.is-root)) {
|
|
870
|
+
outline: 1px solid var(--es-accent-line, #bfdbfe);
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
/* C · the block you are pointing at: one line, solid, 1px, 2px off the words.
|
|
874
|
+
Puck's own overlay-portal sheet drew it 2px dashed and this file narrowed it;
|
|
875
|
+
since that sheet left with 5.5 the whole line is declared here. */
|
|
876
|
+
[data-puck-overlay-portal]:hover {
|
|
877
|
+
outline: 1px solid var(--es-accent-tint-strong, #dbeafe);
|
|
878
|
+
outline-offset: 2px;
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
/* …and the rest of what Puck's overlay-portal sheet (lib/overlay-portal/
|
|
882
|
+
styles.css) gave a text-part anchor, carried here for the same reason: the
|
|
883
|
+
anchor takes the pointer, and draws a ring while the caret is in it. The
|
|
884
|
+
OPEN part's own hairline (PART_PICK_CSS, (0,3,0)) still outranks the ring
|
|
885
|
+
(0,2,0) — one line, card 11103. */
|
|
886
|
+
[data-puck-overlay-portal],
|
|
887
|
+
[data-puck-overlay-portal] * {
|
|
888
|
+
pointer-events: auto !important;
|
|
889
|
+
}
|
|
890
|
+
[data-puck-overlay-portal]:focus-within {
|
|
891
|
+
outline: 2px solid var(--es-accent-line, #bfdbfe);
|
|
892
|
+
outline-offset: 2px;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
/* D · …and ONLY the innermost one.
|
|
896
|
+
⚠️ FOUND IN THE REAL EDITOR, NOT ON THE BOARD, AND IT IS THE HALF THE BOARD
|
|
897
|
+
COULD NOT SEE. Puck nests an overlay per component, and `:hover` matches
|
|
898
|
+
every ancestor in that chain — so pointing at the heading of a section put
|
|
899
|
+
FOUR overlays in `:hover` at once. Measured at /edit/preview-footer with a
|
|
900
|
+
real pointer: 4 hovered overlays, 4 painted lines. Rules A-C removed every
|
|
901
|
+
dashed line and still left him four thin ones.
|
|
902
|
+
|
|
903
|
+
The board modelled ONE overlay because that is what a nesting sketch needs;
|
|
904
|
+
the editor stacks them because that is what a component tree does. Same
|
|
905
|
+
family as measuring a component outside the container it ships in — the
|
|
906
|
+
experiment was honest and the population was wrong.
|
|
907
|
+
|
|
908
|
+
`:has()` reads "an overlay that contains another hovered overlay stands
|
|
909
|
+
aside", which leaves exactly the deepest one — the thing under the cursor,
|
|
910
|
+
which is the one you are actually reaching for. Re-measured with this rule
|
|
911
|
+
live in the same editor: 4 hovered, 1 painted, 225x46, the heading itself.
|
|
912
|
+
|
|
913
|
+
⚠️ SETTLED BY THE OWNER, 2026-09-02: keep the innermost. He was shown the
|
|
914
|
+
alternative and the reason the choice is not obvious — on a heading the
|
|
915
|
+
innermost box hugs the text, which is right, but on the Subscribe button the
|
|
916
|
+
innermost is the button's LABEL (63x16) rather than the button (97x38). He
|
|
917
|
+
picked innermost anyway. DO NOT re-open this as "the button's box looks
|
|
918
|
+
small": that is the known cost of the rule he chose.
|
|
919
|
+
|
|
920
|
+
⚠️ AND THIS ONLY HIDES THE LINE. The duplicate overlays are still in the DOM.
|
|
921
|
+
Measured on /edit/preview-footer: TWELVE overlays carrying only FOUR distinct
|
|
922
|
+
`data-sf-part` ids, and all EIGHT nested pairs share their ancestor's id — so
|
|
923
|
+
the extra boxes were never separate things to select and never had settings
|
|
924
|
+
of their own. Marking one element per part is a separate card touching
|
|
925
|
+
several components; it is not this one. */
|
|
926
|
+
[data-puck-overlay-portal]:hover:has([data-puck-overlay-portal]:hover) {
|
|
927
|
+
outline: none;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
/* ── Canvas "Add section" seams (overlay between preview sections) ──────────
|
|
931
|
+
Absolutely positioned over .sf-preview-host (the iframe's box), one band per
|
|
932
|
+
seam between top-level sections, placed at the boundary Y measured from the
|
|
933
|
+
live iframe. The container ignores pointer events so the canvas stays
|
|
934
|
+
interactive; only the slim bands are clickable. On hover a band shows an accent
|
|
935
|
+
insertion line + a dark "Add section" pill; clicking opens the picker targeted
|
|
936
|
+
at that seam. It sits inside the scaled device frame, so it tracks the zoom. */
|
|
937
|
+
|
|
938
|
+
/* ── Right panel: inspector (wraps Puck.Fields) ──────────────────────── */
|
|
939
|
+
/* The head — chip, the panel's name as its h2 (card 66127), the kind line and
|
|
940
|
+
the Duplicate / Copy-to-page / Remove buttons — is editor-shell's
|
|
941
|
+
`.es-insp-head` (efficient-easel/chrome.css), lifted from this sheet (redesign 2a). */
|
|
942
|
+
/* The settings panel's scrolling body — and the settings TAB STRIP is inside it,
|
|
943
|
+
not above it (`PanelTabs` in lib/puck/controls.tsx renders the shell's
|
|
944
|
+
`SettingsTabs` among the fields). So the strip's width is this box's content
|
|
945
|
+
width, and `.sf-scroll`'s scrollbar is 11px of SPACE, not an overlay: a bucket
|
|
946
|
+
whose fields overflow used to take 11px off the strip.
|
|
947
|
+
|
|
948
|
+
`scrollbar-gutter: stable` is what stops that, and it is a fix rather than a
|
|
949
|
+
polish because the strip has three tiers (card 8810) that turn on its width —
|
|
950
|
+
glyphs replace the words under 270px, and the active tab's word goes too under
|
|
951
|
+
240px. A tier line is a cliff, so a saved panel width whose two strip widths
|
|
952
|
+
straddle one changes the TABS as a scrollbar comes and goes: the merchant
|
|
953
|
+
clicks Layout, its fields overflow, and the four bucket words they were just
|
|
954
|
+
reading become four glyphs. Two bands did this — saved 298-308 and 268-278 —
|
|
955
|
+
and `scripts/test-panel-strip-width-stable.ts` sweeps the whole resizable band
|
|
956
|
+
rather than trusting those two numbers.
|
|
957
|
+
|
|
958
|
+
AND THE 320 DEFAULT DID NOT ALREADY FIX IT, which is the part that reads like
|
|
959
|
+
it should. Card 8810 took `DEFAULT_PANEL_W.right` to 320, whose strip widths
|
|
960
|
+
(292 and 281) clear both bands — but `StorefrontEditorChrome.tsx` seeds the
|
|
961
|
+
width from `localStorage` under `PANEL_WIDTHS_KEY` and falls back to the
|
|
962
|
+
default ONLY when nothing is stored. A merchant who has ever dragged this
|
|
963
|
+
panel keeps their width permanently, and the old default was 308, sitting at
|
|
964
|
+
the top of the first band. So the merchants left inside it are the ones who
|
|
965
|
+
have used the editor most, and no change to a default can reach them.
|
|
966
|
+
|
|
967
|
+
The cost is 11px: a panel that is not scrolling is now as narrow as one that
|
|
968
|
+
is, never the reverse — at 320 the body is 281 in both states instead of 292
|
|
969
|
+
and 281. Nothing gets wider. Accepted (Lewis, from the mockup) as the price of
|
|
970
|
+
a strip that never jumps.
|
|
971
|
+
|
|
972
|
+
`stable` and not `stable both-edges`: reserve the gutter on the scrollbar's
|
|
973
|
+
own side, so the fields keep the padding they have on the other. */
|
|
974
|
+
.sf-insp-body {
|
|
975
|
+
flex: 1;
|
|
976
|
+
overflow-y: auto;
|
|
977
|
+
scrollbar-gutter: stable;
|
|
978
|
+
/* THE SIDE PADDING, ONCE. It was the literal `14px` below and a second
|
|
979
|
+
literal `8px` in the container query further down, and the module rule this
|
|
980
|
+
card adds needed a THIRD copy to cancel it — which is exactly how that rule
|
|
981
|
+
came to hang 6px OUTSIDE the panel at every width under 280 (measured: gap
|
|
982
|
+
-6.0px at 260 and at 220, against 0.0 at the default 320). One name, read
|
|
983
|
+
by the padding, by the narrow override, and by anything that undoes it. */
|
|
984
|
+
--sf-insp-pad-x: 14px;
|
|
985
|
+
padding: 4px var(--sf-insp-pad-x) 18px;
|
|
986
|
+
|
|
987
|
+
/* THE DROPDOWN ARROW, WRITTEN ONCE — card 66399.c.
|
|
988
|
+
Read by `.sf-insp-body select` at rest AND by the hover rule beside it. The
|
|
989
|
+
hover rule HAS to restate the image (overriding without `!important`
|
|
990
|
+
replaces only the properties you name, and Puck's hover repaints the arrow
|
|
991
|
+
darker), so without this token the glyph would be spelled out twice —
|
|
992
|
+
putting back the second copy card 66399 had just removed, and leaving the
|
|
993
|
+
two to drift apart on the next Puck bump.
|
|
994
|
+
|
|
995
|
+
⚠️ NOT AN `--es-*` ALIAS, and deliberately not one. Every other `--sf-*`
|
|
996
|
+
above is a design value we choose, so it belongs in the shell. This is
|
|
997
|
+
PUCK'S OWN GLYPH, matched to the package polygon for polygon so the six
|
|
998
|
+
rows Puck drew and the 55 the panel drew could not look different. Since
|
|
999
|
+
Puck left (blueprint 6.3) it is the panel's one arrow, declared here once;
|
|
1000
|
+
`scripts/test-panel-one-arrow.tsx` §4 fails if a second copy appears or a
|
|
1001
|
+
select resolves to anything else. */
|
|
1002
|
+
--sf-select-arrow: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23c3c3c3'><polygon points='0,0 100,0 50,50'/></svg>");
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
/* …AND THE 14 IS A DIFFERENT COST AT EACH END OF A PANEL THE MERCHANT DRAGS
|
|
1006
|
+
(card 66212). One number, held at every width from 220 to 560:
|
|
1007
|
+
|
|
1008
|
+
320px default 308 client (1px seam + 11px scrollbar) − 28 = 280 content
|
|
1009
|
+
220px minimum 208 client − 28 = 180 content
|
|
1010
|
+
|
|
1011
|
+
— 8.8% of the body at the default and 13.4% at the minimum, spent on the same
|
|
1012
|
+
gap. Lewis reported it on 2026-08-29 with a screenshot of the right panel at
|
|
1013
|
+
its minimum width.
|
|
1014
|
+
|
|
1015
|
+
WHY 280, WHICH IS NOT A ROUND NUMBER AND NOT AN OPINION. All 88 registered
|
|
1016
|
+
sections were rendered as real inspector panels — the live Puck config's own
|
|
1017
|
+
fields, each field's own `render()`, over this sheet and the shell's two — and
|
|
1018
|
+
swept across the resizable band in Chromium, counting elements whose
|
|
1019
|
+
`scrollWidth` exceeds their `clientWidth`:
|
|
1020
|
+
|
|
1021
|
+
panel 281px content 241 0 fields overflow
|
|
1022
|
+
panel 280px content 240 1 field overflows ← the first one to go
|
|
1023
|
+
panel 240px content 200 29 fields overflow
|
|
1024
|
+
panel 220px content 180 337 fields overflow
|
|
1025
|
+
|
|
1026
|
+
280 is the widest panel at which anything in the inspector stops fitting
|
|
1027
|
+
(ProductGrid's empty multi-value chip wants 204px and has 203px), so it is
|
|
1028
|
+
where the 12px is owed and not one pixel earlier. With 8px each side the first
|
|
1029
|
+
overflow moves down to a 268px panel, and at the 220px minimum the count falls
|
|
1030
|
+
337 → 97.
|
|
1031
|
+
|
|
1032
|
+
`< 280px` AND NOT `<= 280px`, because the query is answered by the CONTAINER's
|
|
1033
|
+
content box and `.sf-panel` draws a 1px seam border (card 66161): a panel
|
|
1034
|
+
saved at 281 asks with 280 and keeps its 14, a panel saved at 280 asks with
|
|
1035
|
+
279 and gets the 8. `scripts/test-panel-padding-narrows.ts` holds both ends.
|
|
1036
|
+
|
|
1037
|
+
ONLY THE SIDES MOVE. The 4px above and the 18px below are vertical room and
|
|
1038
|
+
this card is horizontal; `padding-inline` says so in the declaration rather
|
|
1039
|
+
than repeating the other two numbers where they could drift.
|
|
1040
|
+
|
|
1041
|
+
NOT A FONT SIZE, deliberately. The panel's sizes are already 12 / 11 / 10px
|
|
1042
|
+
and 10 has nothing to spare, and type is paid vertically as well — card 66206
|
|
1043
|
+
has just set the row rhythm to 16px, which shrinking type would hand straight
|
|
1044
|
+
back. The padding was the horizontal cost, so the padding is what moved. */
|
|
1045
|
+
@container (width < 280px) {
|
|
1046
|
+
.sf-insp-body {
|
|
1047
|
+
/* The TOKEN, not `padding-inline` — so everything that reads the padding
|
|
1048
|
+
narrows with it, instead of only the padding itself. */
|
|
1049
|
+
--sf-insp-pad-x: 8px;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
/* "Duplicate to another page" dropdown — portalled to <body> and pinned under
|
|
1054
|
+
the inspector button (see DuplicateToPageMenu), so it's position:fixed and
|
|
1055
|
+
right-aligned. Shares the floating-menu language of .sf-blockmenu. */
|
|
1056
|
+
.sf-dupmenu-backdrop {
|
|
1057
|
+
position: fixed;
|
|
1058
|
+
inset: 0;
|
|
1059
|
+
z-index: 1000;
|
|
1060
|
+
}
|
|
1061
|
+
.sf-dupmenu {
|
|
1062
|
+
position: fixed;
|
|
1063
|
+
z-index: 1001;
|
|
1064
|
+
display: flex;
|
|
1065
|
+
flex-direction: column;
|
|
1066
|
+
gap: 1px;
|
|
1067
|
+
min-width: 200px;
|
|
1068
|
+
max-width: 280px;
|
|
1069
|
+
max-height: 60vh;
|
|
1070
|
+
overflow: auto;
|
|
1071
|
+
padding: 4px;
|
|
1072
|
+
border: 1px solid var(--sf-line);
|
|
1073
|
+
border-radius: 8px;
|
|
1074
|
+
background: var(--sf-panel);
|
|
1075
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
|
|
1076
|
+
}
|
|
1077
|
+
.sf-dupmenu-head {
|
|
1078
|
+
padding: 6px 9px 4px;
|
|
1079
|
+
font-size: 11px;
|
|
1080
|
+
font-weight: 600;
|
|
1081
|
+
letter-spacing: 0.02em;
|
|
1082
|
+
color: var(--sf-muted);
|
|
1083
|
+
}
|
|
1084
|
+
.sf-dupmenu-empty {
|
|
1085
|
+
padding: 8px 9px;
|
|
1086
|
+
font-size: 13px;
|
|
1087
|
+
color: var(--sf-muted);
|
|
1088
|
+
}
|
|
1089
|
+
.sf-dupmenu-item {
|
|
1090
|
+
display: flex;
|
|
1091
|
+
align-items: center;
|
|
1092
|
+
gap: 8px;
|
|
1093
|
+
width: 100%;
|
|
1094
|
+
padding: 7px 9px;
|
|
1095
|
+
border: none;
|
|
1096
|
+
background: transparent;
|
|
1097
|
+
border-radius: 6px;
|
|
1098
|
+
cursor: pointer;
|
|
1099
|
+
font-size: 13px;
|
|
1100
|
+
text-align: left;
|
|
1101
|
+
color: var(--sf-text);
|
|
1102
|
+
}
|
|
1103
|
+
.sf-dupmenu-item:hover:not(:disabled) {
|
|
1104
|
+
background: var(--sf-accent-tint);
|
|
1105
|
+
color: var(--sf-accent);
|
|
1106
|
+
}
|
|
1107
|
+
.sf-dupmenu-item:disabled {
|
|
1108
|
+
cursor: default;
|
|
1109
|
+
opacity: 0.6;
|
|
1110
|
+
}
|
|
1111
|
+
.sf-dupmenu-name {
|
|
1112
|
+
flex: 1;
|
|
1113
|
+
min-width: 0;
|
|
1114
|
+
overflow: hidden;
|
|
1115
|
+
text-overflow: ellipsis;
|
|
1116
|
+
white-space: nowrap;
|
|
1117
|
+
}
|
|
1118
|
+
/* Here the note is a word trailing a menu row ("draft", "Copying…"), not a
|
|
1119
|
+
block: no inset of its own, and it takes the ROW's leading rather than the
|
|
1120
|
+
note's, or a draft row would stand 4px taller than a published one and the
|
|
1121
|
+
menu would lose its even rhythm. It stays quiet against the page name beside
|
|
1122
|
+
it by COLOUR, which is the note's own and the whole reason one class can
|
|
1123
|
+
serve both places. Placement only; the note style itself is .sf-note. */
|
|
1124
|
+
.sf-dupmenu-item > .sf-note {
|
|
1125
|
+
padding: 0;
|
|
1126
|
+
flex: none;
|
|
1127
|
+
line-height: inherit;
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
/* Floating-styled form controls for Puck's native fields */
|
|
1131
|
+
.sf-insp-body input[type="text"],
|
|
1132
|
+
.sf-insp-body input[type="number"],
|
|
1133
|
+
.sf-insp-body input:not([type]),
|
|
1134
|
+
.sf-insp-body textarea {
|
|
1135
|
+
width: 100%;
|
|
1136
|
+
border: 1px solid var(--sf-input-border);
|
|
1137
|
+
background: var(--sf-field-bg);
|
|
1138
|
+
border-radius: var(--sf-field-radius);
|
|
1139
|
+
padding: 8px 11px;
|
|
1140
|
+
font-size: 13px;
|
|
1141
|
+
color: var(--sf-field-text);
|
|
1142
|
+
font-family: var(--sf-font);
|
|
1143
|
+
}
|
|
1144
|
+
.sf-insp-body input::placeholder,
|
|
1145
|
+
.sf-insp-body textarea::placeholder {
|
|
1146
|
+
color: var(--sf-field-placeholder);
|
|
1147
|
+
opacity: 1; /* Firefox dims placeholders by default; keep our grey exact */
|
|
1148
|
+
}
|
|
1149
|
+
.sf-insp-body textarea {
|
|
1150
|
+
min-height: 74px;
|
|
1151
|
+
line-height: 1.45;
|
|
1152
|
+
resize: vertical;
|
|
1153
|
+
}
|
|
1154
|
+
.sf-insp-body input[type="text"]:focus,
|
|
1155
|
+
.sf-insp-body input:not([type]):focus,
|
|
1156
|
+
.sf-insp-body textarea:focus {
|
|
1157
|
+
outline: none;
|
|
1158
|
+
border-color: var(--sf-accent);
|
|
1159
|
+
box-shadow: 0 0 0 3px var(--sf-accent-ring);
|
|
1160
|
+
}
|
|
1161
|
+
/* A value the backend refused — the row says why in an `.sf-note--error` under
|
|
1162
|
+
it (Site settings ▸ Social links is the first user). Keyed on `aria-invalid`,
|
|
1163
|
+
not a class, so the red a sighted merchant sees and the "invalid" a screen
|
|
1164
|
+
reader announces are one attribute and cannot disagree. */
|
|
1165
|
+
.sf-insp-body input[aria-invalid="true"] {
|
|
1166
|
+
border-color: var(--sf-danger);
|
|
1167
|
+
}
|
|
1168
|
+
.sf-insp-body select {
|
|
1169
|
+
width: 100%;
|
|
1170
|
+
border: 1px solid var(--sf-input-border);
|
|
1171
|
+
/* ⚠️ LONGHAND, NEVER `background:` — card 66397. Puck draws this control's
|
|
1172
|
+
dropdown arrow as a 100x100 SVG polygon and then shrinks it with longhands
|
|
1173
|
+
(`background-size: 12px`, `background-repeat: no-repeat`). The shorthand
|
|
1174
|
+
that used to sit here reset every longhand it did not name, so on hover —
|
|
1175
|
+
where Puck re-declares only the IMAGE — the full-size tile repeated 2.48
|
|
1176
|
+
times across the 248px row and drew a dark bar with three triangles. That
|
|
1177
|
+
is what Lewis filed. It shipped in 486bf97fd and was never a regression.
|
|
1178
|
+
|
|
1179
|
+
Setting only the colour leaves Puck's own geometry alone, which is why this
|
|
1180
|
+
needs no override of the package's rules and no hashed Puck class name to
|
|
1181
|
+
rot on the next bump. `scripts/test-panel-one-arrow.tsx` §3 holds the
|
|
1182
|
+
invariant (moved there when Puck left): the arrow is drawn ONCE or not at
|
|
1183
|
+
all, never tiled, at rest or on hover.
|
|
1184
|
+
|
|
1185
|
+
🎨 THE ARROW COMING BACK IS THE OWNER'S OWN RULING, not a side effect. It
|
|
1186
|
+
puts a visible arrow into the panel's six Puck selects, which have not had
|
|
1187
|
+
one since the editor shipped. He was shown the row as it is today, this,
|
|
1188
|
+
and an arrow-less alternative — three shots of the real panel at its own
|
|
1189
|
+
320px — and on 2026-09-01 he chose this one: "the little arrow is fine."
|
|
1190
|
+
Do not quietly take it away again; it is a decision, with a date.
|
|
1191
|
+
|
|
1192
|
+
🎯 AND IT IS THE SAME ARROW ON EVERY ROW — card 66399. That ruling put an
|
|
1193
|
+
arrow on the SIX selects Puck draws. The panel draws 55 more from its own
|
|
1194
|
+
markup (the `select()` helper's custom field, and the `<select>`s panel
|
|
1195
|
+
components write themselves), and Puck never styles those: nothing set
|
|
1196
|
+
`appearance`, so each one drew whatever arrow the merchant's own browser
|
|
1197
|
+
draws. Measured on origin/main at 320px and again at the 220px minimum, the
|
|
1198
|
+
Divider block's "Style" row and its "Spacing" row — three rows apart in one
|
|
1199
|
+
panel — resolved `appearance: auto` / no image against `appearance: none` /
|
|
1200
|
+
the 12px triangle. A merchant could ask why two rows look different and the
|
|
1201
|
+
only true answer was "because of which library declared them".
|
|
1202
|
+
|
|
1203
|
+
So the five declarations below repeat Puck's OWN geometry, exactly, onto
|
|
1204
|
+
every select the panel draws. Two things follow from that, and both are the
|
|
1205
|
+
point rather than a side effect:
|
|
1206
|
+
|
|
1207
|
+
• THE SIX DO NOT MOVE. Puck's `select._Input-input_…` is (0,1,1) and this
|
|
1208
|
+
rule is (0,1,1) too, so the two collide at equal weight and source order
|
|
1209
|
+
decides — but they now declare the SAME values, so it does not matter
|
|
1210
|
+
which wins. Nothing here has to out-specify the package, and no hashed
|
|
1211
|
+
Puck class is named where it would rot on the next bump.
|
|
1212
|
+
• NEITHER TRAP IS SPRUNG. `appearance: none` alone leaves a row with NO
|
|
1213
|
+
arrow, which looks exactly like a stylesheet that failed to load; the
|
|
1214
|
+
image alone leaves the browser's arrow beside ours, TWO on one row.
|
|
1215
|
+
They only work as a pair.
|
|
1216
|
+
|
|
1217
|
+
⚠️ LONGHANDS, for card 66397's reason above — and this rule is now the one
|
|
1218
|
+
that would break if that were forgotten, because it is the rule that holds
|
|
1219
|
+
the image. `scripts/test-panel-one-arrow.tsx` resolves the whole cascade per
|
|
1220
|
+
markup shape and fails if any shape's arrow differs from any other's, and if
|
|
1221
|
+
this image ever stops matching the one Puck ships.
|
|
1222
|
+
|
|
1223
|
+
✅ NOW UNIFIED, one state along — card 66399.c. Puck darkens its own arrow on
|
|
1224
|
+
HOVER at (0,4,1), and that rule can reach only its six. This card's rule
|
|
1225
|
+
below holds it off at (0,5,1) so all 61 rows answer the pointer the same
|
|
1226
|
+
way; `scripts/test-panel-one-hover.tsx` is the guard for it.
|
|
1227
|
+
|
|
1228
|
+
⚠️ THAT NUMBER WAS WRONG HERE UNTIL 66399.c. It read (0,4,2), and so did the
|
|
1229
|
+
arrow guard's header and sh#1024's body. `:has(> select)` counts in the
|
|
1230
|
+
ELEMENT column, not the class one — and one column out is exactly the
|
|
1231
|
+
difference between three of our classes tying with Puck and losing to it. */
|
|
1232
|
+
background-color: var(--sf-field-bg);
|
|
1233
|
+
appearance: none;
|
|
1234
|
+
-webkit-appearance: none;
|
|
1235
|
+
background-image: var(--sf-select-arrow);
|
|
1236
|
+
background-size: 12px;
|
|
1237
|
+
background-repeat: no-repeat;
|
|
1238
|
+
background-position: calc(100% - 12px) calc(50% + 3px);
|
|
1239
|
+
border-radius: var(--sf-field-radius);
|
|
1240
|
+
padding: 8px 11px;
|
|
1241
|
+
font-size: 13px;
|
|
1242
|
+
color: var(--sf-field-text);
|
|
1243
|
+
cursor: pointer;
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
/* ── EVERY DROPDOWN ANSWERS THE POINTER THE SAME WAY — card 66399.c ─────────
|
|
1247
|
+
Card 66399 gave all 61 panel dropdowns the same arrow AT REST. Under the
|
|
1248
|
+
pointer they still split: Puck repaints its own six — ground, arrow AND
|
|
1249
|
+
border — from a rule the other 55 have no equivalent of, so one row lights up
|
|
1250
|
+
and the row three above it does nothing.
|
|
1251
|
+
|
|
1252
|
+
🎨 THIS IS THE OWNER'S PICK, WITH A DATE. Lewis was shown four treatments at
|
|
1253
|
+
the panel's own 320px and again at the 220px minimum on 2026-09-02 and chose
|
|
1254
|
+
this one: the ground goes to the panel's own `--sf-hover` and NOTHING ELSE
|
|
1255
|
+
MOVES. He was choosing against a darkened glyph and against a border that
|
|
1256
|
+
jumps 93 points — both of which exist nowhere else in this editor. Changing
|
|
1257
|
+
what this looks like is his call, not a later card's.
|
|
1258
|
+
|
|
1259
|
+
RULE ZERO, ONE GRAMMAR: `--sf-hover` is already what `.sf-row`, `.sf-chooser`,
|
|
1260
|
+
`.sf-rung`, `.sf-seg2 button` and the shell's own `.es-drill` do on hover. The
|
|
1261
|
+
dropdowns join that vocabulary instead of inventing a fifth one — which is
|
|
1262
|
+
also why nothing needs to change in `efficient-easel`: the shell already owns the
|
|
1263
|
+
VALUE (`--es-hover`), and this is the shop agreeing with it.
|
|
1264
|
+
|
|
1265
|
+
⚠️ WHY FOUR CLASSES, AND WHY THAT IS NOT COSMETIC. Puck's hover rule is
|
|
1266
|
+
(0,4,1) — `._Input_`(class) + `:has(> select)`(ELEMENT: `:has()` takes its
|
|
1267
|
+
argument's specificity) + `:hover`(class) + `._Input-input_`(class) +
|
|
1268
|
+
`:not([disabled])`(attribute). Measured, three of our classes TIES it and then
|
|
1269
|
+
wins only because `storefront-editor.css` is imported after `puck.css` at
|
|
1270
|
+
every editor entry; move an import anywhere and the six rows silently revert
|
|
1271
|
+
to Puck's azure with nothing going red. The fourth class buys independence
|
|
1272
|
+
from load order. No `!important`, and no hashed Puck class name that would rot
|
|
1273
|
+
on the next bump.
|
|
1274
|
+
|
|
1275
|
+
⚠️ ALL THREE DECLARATIONS ARE LOAD-BEARING. Overriding without `!important`
|
|
1276
|
+
replaces only the properties you NAME, so the arrow and the border are
|
|
1277
|
+
restated at their RESTING values purely to hold Puck's darker pair off. They
|
|
1278
|
+
are not a second opinion about how the row should look.
|
|
1279
|
+
|
|
1280
|
+
AND IT STANDS ASIDE EVERYWHERE ELSE. It needs `:hover`, so it cannot touch the
|
|
1281
|
+
row at rest; it is inside `.sf-insp-body`, so it cannot reach the storefront's
|
|
1282
|
+
own selects; and carrying no `!important` is what keeps Puck's drag paint
|
|
1283
|
+
(`[data-dnd-placeholder]`, which IS `!important`) out of its reach. Card 66395
|
|
1284
|
+
§6 is the precedent for getting that wrong — a shop rule that out-specified
|
|
1285
|
+
Puck the same way went on to win states it should have stood aside for, and
|
|
1286
|
+
every guard stayed green. `scripts/test-panel-one-hover.tsx` resolves the
|
|
1287
|
+
whole cascade per markup shape and asserts what must NOT move as well as what
|
|
1288
|
+
must. */
|
|
1289
|
+
.sf-editor .sf-body .sf-panel .sf-insp-body select:hover {
|
|
1290
|
+
background-color: var(--sf-hover);
|
|
1291
|
+
background-image: var(--sf-select-arrow);
|
|
1292
|
+
border-color: var(--sf-input-border);
|
|
1293
|
+
}
|
|
1294
|
+
.sf-insp-body input[type="range"] {
|
|
1295
|
+
accent-color: var(--sf-accent);
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
/* The panel's one-line dropdown TRIGGER and its in-flow MENU box, worn by the
|
|
1299
|
+
section Theme row (SectionThemePicker) and the part style chooser. They were
|
|
1300
|
+
MultiSelectField's; that control and SearchSelectField are efficient-easel's
|
|
1301
|
+
FieldSelect now (card [MERGE] One Pop-up List For Editor And One For
|
|
1302
|
+
Shoppers), so their option rows and readout went with them. */
|
|
1303
|
+
.sf-multi-btn {
|
|
1304
|
+
width: 100%;
|
|
1305
|
+
display: flex;
|
|
1306
|
+
align-items: center;
|
|
1307
|
+
justify-content: space-between;
|
|
1308
|
+
gap: 8px;
|
|
1309
|
+
border: 1px solid var(--sf-input-border);
|
|
1310
|
+
background: var(--sf-field-bg);
|
|
1311
|
+
border-radius: var(--sf-field-radius);
|
|
1312
|
+
padding: 8px 11px;
|
|
1313
|
+
font-size: 13px;
|
|
1314
|
+
font-family: var(--sf-font);
|
|
1315
|
+
color: var(--sf-field-text);
|
|
1316
|
+
text-align: left;
|
|
1317
|
+
cursor: pointer;
|
|
1318
|
+
}
|
|
1319
|
+
.sf-multi-btn:focus-visible {
|
|
1320
|
+
outline: none;
|
|
1321
|
+
border-color: var(--sf-accent);
|
|
1322
|
+
box-shadow: 0 0 0 3px var(--sf-accent-ring);
|
|
1323
|
+
}
|
|
1324
|
+
.sf-multi-caret {
|
|
1325
|
+
font-size: 10px;
|
|
1326
|
+
color: var(--sf-text-secondary);
|
|
1327
|
+
flex: none;
|
|
1328
|
+
}
|
|
1329
|
+
.sf-multi-menu {
|
|
1330
|
+
margin: 6px 0 0;
|
|
1331
|
+
padding: 4px;
|
|
1332
|
+
border: 1px solid var(--sf-input-border);
|
|
1333
|
+
border-radius: var(--sf-field-radius);
|
|
1334
|
+
background: var(--sf-field-bg);
|
|
1335
|
+
display: flex;
|
|
1336
|
+
flex-direction: column;
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
/* ── The section's Theme row (card 66313) ──────────────────────────────────
|
|
1340
|
+
A dropdown, not a swatch strip. The TRIGGER is `.sf-multi-btn` — the panel's
|
|
1341
|
+
existing dropdown trigger, worn rather than copied, because two triggers with
|
|
1342
|
+
different metrics in one panel is a difference nobody decided. What is new is
|
|
1343
|
+
the colour chip, the per-row Edit and the edit sheet, and only those take
|
|
1344
|
+
names here.
|
|
1345
|
+
|
|
1346
|
+
The menu is IN FLOW (`.sf-multi-menu`, inherited), never absolutely
|
|
1347
|
+
positioned: the inspector is its own scroll container, so a floating menu
|
|
1348
|
+
clips against it once the control sits near the bottom of a long section. */
|
|
1349
|
+
/* ── The closed trigger: the card, shut ────────────────────────────────────
|
|
1350
|
+
It no longer wears `.sf-multi-btn`. That class is the panel's ONE-LINE
|
|
1351
|
+
dropdown trigger — a 13px row with 8px of padding — and the reason it was
|
|
1352
|
+
worn here (two triggers with different metrics is a difference nobody
|
|
1353
|
+
decided) now points the other way: this control draws a theme card, so the
|
|
1354
|
+
thing it must match is the card, and it matches it by sharing the rule above.
|
|
1355
|
+
The caret is still `.sf-multi-caret`, the panel's own arrow, so the part that
|
|
1356
|
+
says "this opens" is unchanged.
|
|
1357
|
+
|
|
1358
|
+
THE HEIGHT IS THE DESIGN, not an overflow. ~110px against the old ~36px row,
|
|
1359
|
+
in a 320px panel, and Lewis was told the cost and chose it on 2026-09-03:
|
|
1360
|
+
seeing the theme happens every time the tab is opened, editing it happens
|
|
1361
|
+
occasionally. A shorter third drawing to win the space back would be a third
|
|
1362
|
+
way of drawing one thing, which is worse than the space. */
|
|
1363
|
+
/* ⚠️ A FRAME, NOT A BUTTON, SINCE 2026-09-03 — it holds one. `Edit` on the
|
|
1364
|
+
closed control has to be clickable, and a <button> inside a <button> is
|
|
1365
|
+
invalid markup that no two browsers un-nest the same way. So the press moved
|
|
1366
|
+
inside: `.sf-theme-pick` (the shared card's own press) wraps the preview and
|
|
1367
|
+
owns the disclosure, and the foot below it holds the name, the Edit and the
|
|
1368
|
+
caret. See `ThemeCardTrigger`. */
|
|
1369
|
+
.sf-secttheme-btn {
|
|
1370
|
+
display: block;
|
|
1371
|
+
width: 100%;
|
|
1372
|
+
}
|
|
1373
|
+
/* THE PANEL'S BUTTON RING, unchanged — `editor-focus-ring-vocabulary`: a button
|
|
1374
|
+
answers focus with the accent border and the ring, exactly as `.sf-multi-btn`
|
|
1375
|
+
did when it was worn here, so keyboard focus looks the same as it did before
|
|
1376
|
+
the drawing changed. */
|
|
1377
|
+
/* THE PANEL'S BUTTON RING, on whichever child actually took focus. It is drawn
|
|
1378
|
+
on the FRAME (`:focus-within`) rather than on the press, because the press has
|
|
1379
|
+
no border of its own — the frame is what a merchant sees, so the frame is what
|
|
1380
|
+
must light up. Same three tokens `.sf-multi-btn` used when this control was
|
|
1381
|
+
one button, so keyboard focus looks exactly as it did. */
|
|
1382
|
+
.sf-secttheme-btn:focus-within {
|
|
1383
|
+
outline: none;
|
|
1384
|
+
border-color: var(--sf-accent);
|
|
1385
|
+
box-shadow: 0 0 0 3px var(--sf-accent-ring);
|
|
1386
|
+
}
|
|
1387
|
+
.sf-secttheme-btn .sf-theme-pick:focus-visible,
|
|
1388
|
+
.sf-secttheme-btn .sf-theme-edit:focus-visible {
|
|
1389
|
+
outline: none;
|
|
1390
|
+
}
|
|
1391
|
+
/* THE CARET'S OWN BOX. A pointer target only (`aria-hidden`, out of the tab
|
|
1392
|
+
order — see `ThemeCardTrigger`), so it takes no ring and no hover treatment
|
|
1393
|
+
of its own: the frame's hover already answers the pointer. Sized to the row
|
|
1394
|
+
rather than to the glyph, so the click area is the whole right end. */
|
|
1395
|
+
.sf-secttheme-caret {
|
|
1396
|
+
flex: none;
|
|
1397
|
+
border: 0;
|
|
1398
|
+
background: none;
|
|
1399
|
+
padding: 3px 2px 3px 6px;
|
|
1400
|
+
font: inherit;
|
|
1401
|
+
line-height: 1;
|
|
1402
|
+
color: var(--sf-text-secondary);
|
|
1403
|
+
cursor: pointer;
|
|
1404
|
+
}
|
|
1405
|
+
/* WHERE THE SELECTED CARD WENT. Panel-quiet — the muted grey every other
|
|
1406
|
+
readout uses, never a colour that would read as a warning. It exists because
|
|
1407
|
+
a theme's name is positional, so hiding one leaves 1 · 2 · 4 · 5 · 6 and a
|
|
1408
|
+
missing number reads as missing data. Not a row: there is nothing here to
|
|
1409
|
+
choose. */
|
|
1410
|
+
.sf-secttheme-oncard {
|
|
1411
|
+
margin: 0;
|
|
1412
|
+
padding: 5px 4px 7px;
|
|
1413
|
+
font-size: 11px;
|
|
1414
|
+
line-height: 1.4;
|
|
1415
|
+
color: var(--sf-text-secondary);
|
|
1416
|
+
}
|
|
1417
|
+
/* A site that stores no palette at all has nothing to draw. Sized to the
|
|
1418
|
+
preview it stands in for, and dashed rather than empty for the reason
|
|
1419
|
+
`.sf-secttheme-chip--none` is: a bare outline reads as an image that failed.
|
|
1420
|
+
`Follow the page` does NOT come here — it borrows the page's own palette. */
|
|
1421
|
+
.sf-secttheme-nopreview {
|
|
1422
|
+
display: block;
|
|
1423
|
+
height: 74px;
|
|
1424
|
+
background: var(--sf-field-bg);
|
|
1425
|
+
border-bottom: 1px dashed var(--sf-input-border);
|
|
1426
|
+
}
|
|
1427
|
+
.sf-secttheme-chip {
|
|
1428
|
+
width: 30px;
|
|
1429
|
+
height: 20px;
|
|
1430
|
+
flex: none;
|
|
1431
|
+
display: flex;
|
|
1432
|
+
overflow: hidden;
|
|
1433
|
+
border-radius: 4px;
|
|
1434
|
+
/* A hairline of the merchant's own ink would vanish on a theme whose paper is
|
|
1435
|
+
that ink. A translucent black keeps the chip's edge on every palette. */
|
|
1436
|
+
border: 1px solid rgba(0, 0, 0, 0.14);
|
|
1437
|
+
}
|
|
1438
|
+
.sf-secttheme-chip i {
|
|
1439
|
+
display: block;
|
|
1440
|
+
height: 100%;
|
|
1441
|
+
flex: 1 1 auto;
|
|
1442
|
+
}
|
|
1443
|
+
/* The accent is the SMALLER half. The paper is what a merchant recognises a
|
|
1444
|
+
theme by — it is most of what the page is — and the accent is the thing
|
|
1445
|
+
picked out on it, so the chip is drawn in the proportion the page is. */
|
|
1446
|
+
/* `i.` MATTERS. `.sf-secttheme-chip i` above is (0,1,1) and a bare class is
|
|
1447
|
+
(0,1,0), so without the element it loses to the rule it is meant to override
|
|
1448
|
+
and both halves take `flex: 1 1 auto` — an even 14/14 split. Measured in
|
|
1449
|
+
Chromium: 14/14 before, 16.8/11.2 after, which is the 60/40 the design asks
|
|
1450
|
+
for. No guard we own looks at a proportion, so this could only be found by
|
|
1451
|
+
drawing it and reading the boxes back. */
|
|
1452
|
+
.sf-secttheme-chip i.sf-secttheme-chip-accent {
|
|
1453
|
+
flex: 0 0 40%;
|
|
1454
|
+
}
|
|
1455
|
+
/* "Follow the page" has no palette of its own to show. A neutral block, not an
|
|
1456
|
+
empty box: an outline with nothing in it reads as an image that failed. */
|
|
1457
|
+
.sf-secttheme-chip--none {
|
|
1458
|
+
background: var(--sf-field-bg);
|
|
1459
|
+
border-style: dashed;
|
|
1460
|
+
}
|
|
1461
|
+
.sf-secttheme-name {
|
|
1462
|
+
overflow: hidden;
|
|
1463
|
+
text-overflow: ellipsis;
|
|
1464
|
+
white-space: nowrap;
|
|
1465
|
+
text-align: left;
|
|
1466
|
+
flex: 1 1 auto;
|
|
1467
|
+
min-width: 0;
|
|
1468
|
+
}
|
|
1469
|
+
/* ⚠️ THE MENU HOLDS CARDS NOW, NOT ONE-LINE ROWS (card 66503), so it is spaced
|
|
1470
|
+
like the Site styles theme list it shares its drawing with — `.sf-theme-list`
|
|
1471
|
+
is `gap: 8px` and this matches it, because two lists of the same cards sitting
|
|
1472
|
+
at two different rhythms is the same drift one level up from the one this card
|
|
1473
|
+
closed. The 1px gap below was right for rows 30px tall and wrong for cards. */
|
|
1474
|
+
.sf-secttheme-menu {
|
|
1475
|
+
display: flex;
|
|
1476
|
+
flex-direction: column;
|
|
1477
|
+
padding: 4px;
|
|
1478
|
+
gap: 8px;
|
|
1479
|
+
/* ── THE TINT SAYS "THESE ARE OPTIONS" ────────────────────────────────────
|
|
1480
|
+
Lewis, 2026-09-04: 「代表这些是选项.」 It is a job, not decoration, and the
|
|
1481
|
+
job exists because of a deliberate earlier decision: the closed control and
|
|
1482
|
+
these rows draw the SAME card (66503), so the only thing separating *what
|
|
1483
|
+
this section is on* from *what you could pick* was position.
|
|
1484
|
+
|
|
1485
|
+
⚠️ THE FILL, NOT THE BORDER, and that is the whole of the choice. The cards
|
|
1486
|
+
are `--sf-panel` white and this container was `--sf-field-bg` white, so the
|
|
1487
|
+
container was invisible — which was the complaint. Filling it makes the 4px
|
|
1488
|
+
padding and the 8px gaps read as ONE REGION: the tint DRAWS the set instead
|
|
1489
|
+
of outlining it. A 1px line has to enclose a 707px stack to say the same
|
|
1490
|
+
thing, and at the 220px minimum it says it more quietly still. He was shown
|
|
1491
|
+
border-only, fill-only and both, at 320 and 220, and chose the fill.
|
|
1492
|
+
|
|
1493
|
+
⚠️ AND IT KEEPS BLUE OFF THE PALETTES. Every card is a page in the
|
|
1494
|
+
merchant's OWN colours on its own white fill, so a tinted CONTAINER never
|
|
1495
|
+
puts blue against a palette. Same care `.sf-secttheme-chip` takes when it
|
|
1496
|
+
draws its hairline in translucent black rather than in a colour.
|
|
1497
|
+
|
|
1498
|
+
⚠️ RULE ZERO — THIS IS AN EXCEPTION AND HERE IS ITS REASON. `.sf-multi-menu`
|
|
1499
|
+
is the shared dropdown container and exactly two controls wear it: this
|
|
1500
|
+
list, and `MultiSelectField` (components/MultiSelectField.tsx:144), a list
|
|
1501
|
+
of plain text options. That one is NOT tinted, and must not be "fixed" to
|
|
1502
|
+
match: a list of WORDS in a bordered box already looks like a menu, because
|
|
1503
|
+
that is what a menu is. A list of preview CARDS does not — each card is a
|
|
1504
|
+
miniature web page, so the region reads as CONTENT. The tint buys back the
|
|
1505
|
+
"these are choices" that the card drawing spent. He was offered the other
|
|
1506
|
+
answer (tint every dropdown) on the same board and did not take it.
|
|
1507
|
+
|
|
1508
|
+
No new hex: `--sf-accent-tint` is the shell's own (#eff6ff). A blue invented
|
|
1509
|
+
in a panel stylesheet is a second source for a decision the shell made. */
|
|
1510
|
+
background: var(--sf-accent-tint);
|
|
1511
|
+
}
|
|
1512
|
+
/* The follow row is still a ROW — it has no palette, so there is nothing for a
|
|
1513
|
+
card to draw. It keeps its own height rather than being stretched to a card's. */
|
|
1514
|
+
.sf-secttheme-menu > .sf-secttheme-item {
|
|
1515
|
+
flex: none;
|
|
1516
|
+
}
|
|
1517
|
+
.sf-secttheme-item {
|
|
1518
|
+
display: flex;
|
|
1519
|
+
align-items: center;
|
|
1520
|
+
gap: 9px;
|
|
1521
|
+
width: 100%;
|
|
1522
|
+
padding: 6px 7px;
|
|
1523
|
+
border: 0;
|
|
1524
|
+
background: transparent;
|
|
1525
|
+
border-radius: max(calc(var(--sf-field-radius) - 2px), 2px);
|
|
1526
|
+
font-size: 13px;
|
|
1527
|
+
font-family: var(--sf-font);
|
|
1528
|
+
color: var(--sf-field-text);
|
|
1529
|
+
text-align: left;
|
|
1530
|
+
cursor: pointer;
|
|
1531
|
+
}
|
|
1532
|
+
.sf-secttheme-item:hover {
|
|
1533
|
+
background: var(--sf-accent-ring);
|
|
1534
|
+
}
|
|
1535
|
+
/* ⚠️ ONLY THE FOLLOW ROW WEARS `.sf-secttheme-item` SINCE CARD 66503. Its
|
|
1536
|
+
theme siblings are `.sf-theme-card`, the Site styles card, so `is-active`
|
|
1537
|
+
here has one owner and one meaning again — the `:has(.sf-secttheme-pick…)`
|
|
1538
|
+
half went with the two-button row it described, along with `.sf-secttheme-pick`
|
|
1539
|
+
and `.sf-secttheme-edit`, which now have nothing to draw. */
|
|
1540
|
+
.sf-secttheme-item.is-active {
|
|
1541
|
+
background: var(--sf-accent-ring);
|
|
1542
|
+
font-weight: 600;
|
|
1543
|
+
}
|
|
1544
|
+
.sf-secttheme-item:focus-visible,
|
|
1545
|
+
.sf-secttheme-done:focus-visible {
|
|
1546
|
+
outline: 2px solid var(--sf-accent);
|
|
1547
|
+
outline-offset: -2px;
|
|
1548
|
+
border-radius: 4px;
|
|
1549
|
+
}
|
|
1550
|
+
.sf-secttheme-sep {
|
|
1551
|
+
height: 1px;
|
|
1552
|
+
margin: 3px 0;
|
|
1553
|
+
background: var(--sf-input-border);
|
|
1554
|
+
}
|
|
1555
|
+
/* ── The edit sheet ─────────────────────────────────────────────────────── */
|
|
1556
|
+
.sf-secttheme-sheet {
|
|
1557
|
+
margin-top: 6px;
|
|
1558
|
+
border: 1px solid var(--sf-input-border);
|
|
1559
|
+
border-radius: var(--sf-field-radius);
|
|
1560
|
+
overflow: hidden;
|
|
1561
|
+
}
|
|
1562
|
+
.sf-secttheme-sheet-head {
|
|
1563
|
+
display: flex;
|
|
1564
|
+
align-items: center;
|
|
1565
|
+
padding: 6px 9px;
|
|
1566
|
+
background: var(--sf-field-bg);
|
|
1567
|
+
border-bottom: 1px solid var(--sf-input-border);
|
|
1568
|
+
font-size: 12px;
|
|
1569
|
+
font-weight: 600;
|
|
1570
|
+
color: var(--sf-field-text);
|
|
1571
|
+
}
|
|
1572
|
+
.sf-secttheme-done {
|
|
1573
|
+
margin-left: auto;
|
|
1574
|
+
padding: 2px 4px;
|
|
1575
|
+
border: 0;
|
|
1576
|
+
background: transparent;
|
|
1577
|
+
color: var(--sf-text-secondary);
|
|
1578
|
+
font-size: 11px;
|
|
1579
|
+
font-family: var(--sf-font);
|
|
1580
|
+
cursor: pointer;
|
|
1581
|
+
}
|
|
1582
|
+
/* ⚠️ THE SHEET'S FIVE COLOUR ROWS ARE `ThemeColourRow` SINCE CARD 66503 — the
|
|
1583
|
+
shell's `SettingsField` wearing the shop's picker, the same row the Site
|
|
1584
|
+
styles card opens. So the row draws itself and the sheet only has to inset
|
|
1585
|
+
it, exactly as `.sf-theme-colours` does for the card. The local
|
|
1586
|
+
`.sf-secttheme-row` / `-hex` that used to draw a second, smaller colour row
|
|
1587
|
+
went with it, and with them the 11px hex that E6 would have had something to
|
|
1588
|
+
say about. */
|
|
1589
|
+
.sf-secttheme-rows {
|
|
1590
|
+
padding: 0 12px 12px;
|
|
1591
|
+
}
|
|
1592
|
+
.sf-secttheme-rows > .es-field:first-child {
|
|
1593
|
+
margin-top: var(--es-rhythm-group-first);
|
|
1594
|
+
}
|
|
1595
|
+
/* THE WARNING IS THE LAST THING IN THE SHEET AND IT IS NOT QUIET. A theme is a
|
|
1596
|
+
shared preset: editing it from one section repaints every section and page on
|
|
1597
|
+
it. Drawn in the panel's own warning ink rather than a new colour. */
|
|
1598
|
+
.sf-secttheme-warn {
|
|
1599
|
+
margin: 0;
|
|
1600
|
+
padding: 7px 9px;
|
|
1601
|
+
border-top: 1px solid var(--sf-input-border);
|
|
1602
|
+
background: var(--sf-accent-ring);
|
|
1603
|
+
font-size: 11px;
|
|
1604
|
+
line-height: 1.4;
|
|
1605
|
+
color: var(--sf-text-secondary);
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1608
|
+
/* Collapsed-panel state hook (when Puck's UI flags hide a side) */
|
|
1609
|
+
.sf-panel--hidden {
|
|
1610
|
+
display: none;
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
/* ── The icon rail: the shared editor-shell EaselRail (`.es-rail`) ───────────
|
|
1614
|
+
The rail markup + base styles live in the `efficient-easel` package (imported via
|
|
1615
|
+
`efficient-easel/rail.css`); the storefront no longer hand-rolls `.sf-rail`.
|
|
1616
|
+
editor-shell ships its own defaults, so we remap the themeable `--es-rail-*`
|
|
1617
|
+
custom properties onto the storefront's own `--sf-*` tokens, which is what
|
|
1618
|
+
keeps the shared rail reading as this editor's chrome rather than as the
|
|
1619
|
+
package's. (One mode only — the editor is deliberately light-only; see the
|
|
1620
|
+
note at the top of this file.)
|
|
1621
|
+
Scoped `.sf-editor .es-rail` (specificity 0,2,0) so it always beats rail.css's
|
|
1622
|
+
base `.es-rail` (0,1,0) whatever order the two stylesheets load in.
|
|
1623
|
+
|
|
1624
|
+
THREE TOKENS ARE DELIBERATELY NOT REMAPPED HERE, and each absence is load-
|
|
1625
|
+
bearing since card 66198 laid the rail into the top bar as a row:
|
|
1626
|
+
|
|
1627
|
+
--es-rail-w only the COLUMN reads it (`.es-rail { width:
|
|
1628
|
+
var(--es-rail-w) }`); the row is `width: auto` and sizes
|
|
1629
|
+
to its buttons, so a remap would be config nothing reads.
|
|
1630
|
+
--es-rail-bg the row variant re-points these to transparent / none / 0
|
|
1631
|
+
--es-rail-shadow ON PURPOSE: the bar already has its own surface, and a
|
|
1632
|
+
--es-rail-radius second white card floating inside it is the bug. This
|
|
1633
|
+
rule ties with `.es-rail.es-rail-row` on specificity
|
|
1634
|
+
(0,2,0 both), so setting them here would silently WIN
|
|
1635
|
+
and put that card back. The rail's surface is the bar's.
|
|
1636
|
+
|
|
1637
|
+
Everything left below is colour the row variant does not touch. */
|
|
1638
|
+
|
|
1639
|
+
/* ── Left panel: Pages view (Wix-style page list) ───────────────────────── */
|
|
1640
|
+
.sf-pages {
|
|
1641
|
+
display: flex;
|
|
1642
|
+
flex-direction: column;
|
|
1643
|
+
min-height: 0;
|
|
1644
|
+
height: 100%;
|
|
1645
|
+
}
|
|
1646
|
+
/* Site styles left panel — same column shell as .sf-pages; its body reuses the
|
|
1647
|
+
inspector's .sf-insp-body so the (right-inspector) field styling applies. */
|
|
1648
|
+
.sf-styles {
|
|
1649
|
+
display: flex;
|
|
1650
|
+
flex-direction: column;
|
|
1651
|
+
min-height: 0;
|
|
1652
|
+
height: 100%;
|
|
1653
|
+
}
|
|
1654
|
+
|
|
1655
|
+
/* The left panel's search field. It had a second wearer — the Add panel's own
|
|
1656
|
+
search (card 66400.c) — until that panel was deleted and the `+` was pointed
|
|
1657
|
+
at the one picker; the picker has its own `.sf-addsearch`, sized for a 772px
|
|
1658
|
+
dialog. So this is the Pages list's control alone again. */
|
|
1659
|
+
.sf-pages-search {
|
|
1660
|
+
flex: none;
|
|
1661
|
+
display: flex;
|
|
1662
|
+
align-items: center;
|
|
1663
|
+
gap: 7px;
|
|
1664
|
+
margin: 0 12px 8px;
|
|
1665
|
+
padding: 7px 10px;
|
|
1666
|
+
background: var(--sf-track-bg);
|
|
1667
|
+
border-radius: 8px;
|
|
1668
|
+
color: var(--sf-muted);
|
|
1669
|
+
}
|
|
1670
|
+
.sf-pages-search-input {
|
|
1671
|
+
flex: 1;
|
|
1672
|
+
min-width: 0;
|
|
1673
|
+
border: none;
|
|
1674
|
+
background: transparent;
|
|
1675
|
+
font-family: var(--sf-font);
|
|
1676
|
+
font-size: 13px;
|
|
1677
|
+
color: var(--sf-text);
|
|
1678
|
+
outline: none;
|
|
1679
|
+
}
|
|
1680
|
+
.sf-pages-search-input::placeholder {
|
|
1681
|
+
color: var(--sf-muted);
|
|
1682
|
+
}
|
|
1683
|
+
.sf-pages-list {
|
|
1684
|
+
flex: 1;
|
|
1685
|
+
min-height: 0;
|
|
1686
|
+
overflow-y: auto;
|
|
1687
|
+
padding: 0 8px 8px;
|
|
1688
|
+
}
|
|
1689
|
+
/* A note in this list is not the panel's body — it stands where a page row
|
|
1690
|
+
would, so it takes the ROW's inset and lines up with the group heads above
|
|
1691
|
+
it rather than with the panel edge. Placement only; the note style itself is
|
|
1692
|
+
.sf-note. */
|
|
1693
|
+
.sf-pages-list > .sf-note {
|
|
1694
|
+
padding: 10px 12px;
|
|
1695
|
+
}
|
|
1696
|
+
.sf-pages-list > .sf-note--error {
|
|
1697
|
+
margin: 4px 4px 0;
|
|
1698
|
+
}
|
|
1699
|
+
.sf-pgroup {
|
|
1700
|
+
margin-top: 2px;
|
|
1701
|
+
}
|
|
1702
|
+
.sf-pgroup-head {
|
|
1703
|
+
width: 100%;
|
|
1704
|
+
display: flex;
|
|
1705
|
+
align-items: center;
|
|
1706
|
+
gap: 7px;
|
|
1707
|
+
padding: 8px 8px 6px;
|
|
1708
|
+
border: none;
|
|
1709
|
+
background: transparent;
|
|
1710
|
+
cursor: pointer;
|
|
1711
|
+
color: var(--sf-muted);
|
|
1712
|
+
}
|
|
1713
|
+
.sf-pgroup-head:hover {
|
|
1714
|
+
color: var(--sf-text);
|
|
1715
|
+
}
|
|
1716
|
+
.sf-pgroup-label {
|
|
1717
|
+
flex: 1;
|
|
1718
|
+
text-align: left;
|
|
1719
|
+
font-size: 11px;
|
|
1720
|
+
font-weight: 700;
|
|
1721
|
+
letter-spacing: 0.4px;
|
|
1722
|
+
text-transform: uppercase;
|
|
1723
|
+
}
|
|
1724
|
+
.sf-pgroup-count {
|
|
1725
|
+
flex: none;
|
|
1726
|
+
font-size: 11px;
|
|
1727
|
+
font-weight: 600;
|
|
1728
|
+
color: var(--sf-muted);
|
|
1729
|
+
background: var(--sf-track-bg);
|
|
1730
|
+
border-radius: 999px;
|
|
1731
|
+
padding: 1px 7px;
|
|
1732
|
+
}
|
|
1733
|
+
.sf-pgroup-body {
|
|
1734
|
+
display: flex;
|
|
1735
|
+
flex-direction: column;
|
|
1736
|
+
}
|
|
1737
|
+
/* Page rows reuse .sf-row; anchors (Cart/Checkout) reset link chrome. */
|
|
1738
|
+
.sf-prow {
|
|
1739
|
+
text-decoration: none;
|
|
1740
|
+
color: inherit;
|
|
1741
|
+
}
|
|
1742
|
+
.sf-page-draft {
|
|
1743
|
+
flex: none;
|
|
1744
|
+
font-size: 10px;
|
|
1745
|
+
font-weight: 600;
|
|
1746
|
+
color: var(--sf-muted);
|
|
1747
|
+
text-transform: uppercase;
|
|
1748
|
+
letter-spacing: 0.3px;
|
|
1749
|
+
}
|
|
1750
|
+
/* Page-TYPE pills — mirror the admin Console's Pages list so a per-product PDP
|
|
1751
|
+
template (dynamic, blue) or an editable popup (lightbox, green) is as obvious
|
|
1752
|
+
in the editor's page list as it is in the Console. */
|
|
1753
|
+
.sf-badge-dynamic,
|
|
1754
|
+
.sf-badge-lightbox {
|
|
1755
|
+
flex: none;
|
|
1756
|
+
font-size: 9px;
|
|
1757
|
+
font-weight: 700;
|
|
1758
|
+
letter-spacing: 0.3px;
|
|
1759
|
+
text-transform: uppercase;
|
|
1760
|
+
padding: 2px 7px;
|
|
1761
|
+
border-radius: 999px;
|
|
1762
|
+
}
|
|
1763
|
+
.sf-badge-dynamic {
|
|
1764
|
+
color: var(--sf-accent-text);
|
|
1765
|
+
background: var(--sf-accent-tint);
|
|
1766
|
+
}
|
|
1767
|
+
.sf-badge-lightbox {
|
|
1768
|
+
color: #047857; /* emerald-700 — matches the Console's Lightbox pill */
|
|
1769
|
+
background: #ecfdf5; /* emerald-50 */
|
|
1770
|
+
}
|
|
1771
|
+
.sf-page-edit {
|
|
1772
|
+
flex: none;
|
|
1773
|
+
width: 24px;
|
|
1774
|
+
height: 24px;
|
|
1775
|
+
border: none;
|
|
1776
|
+
background: transparent;
|
|
1777
|
+
border-radius: 6px;
|
|
1778
|
+
color: var(--sf-muted);
|
|
1779
|
+
display: none;
|
|
1780
|
+
align-items: center;
|
|
1781
|
+
justify-content: center;
|
|
1782
|
+
cursor: pointer;
|
|
1783
|
+
}
|
|
1784
|
+
.sf-row:hover .sf-page-edit,
|
|
1785
|
+
.sf-row:focus-within .sf-page-edit {
|
|
1786
|
+
display: flex;
|
|
1787
|
+
}
|
|
1788
|
+
.sf-page-edit:hover {
|
|
1789
|
+
background: var(--sf-hover);
|
|
1790
|
+
color: var(--sf-text);
|
|
1791
|
+
}
|
|
1792
|
+
/* Row hover-delete (template pages — inline page management). */
|
|
1793
|
+
.sf-page-edit--danger:hover {
|
|
1794
|
+
background: var(--sf-danger-tint);
|
|
1795
|
+
color: var(--sf-danger);
|
|
1796
|
+
}
|
|
1797
|
+
.sf-page-edit--danger:disabled {
|
|
1798
|
+
opacity: 0.5;
|
|
1799
|
+
cursor: default;
|
|
1800
|
+
}
|
|
1801
|
+
/* "Preview" pill on Cart / Checkout — signals "opens the live page, view-only". */
|
|
1802
|
+
.sf-badge-preview {
|
|
1803
|
+
flex: none;
|
|
1804
|
+
font-size: 9px;
|
|
1805
|
+
font-weight: 700;
|
|
1806
|
+
letter-spacing: 0.3px;
|
|
1807
|
+
text-transform: uppercase;
|
|
1808
|
+
padding: 2px 7px;
|
|
1809
|
+
border-radius: 999px;
|
|
1810
|
+
color: var(--sf-warning);
|
|
1811
|
+
background: var(--sf-preview-tint);
|
|
1812
|
+
}
|
|
1813
|
+
.sf-pages-new {
|
|
1814
|
+
flex: none;
|
|
1815
|
+
margin: 6px 10px 10px;
|
|
1816
|
+
display: flex;
|
|
1817
|
+
align-items: center;
|
|
1818
|
+
justify-content: center;
|
|
1819
|
+
gap: 6px;
|
|
1820
|
+
padding: 9px;
|
|
1821
|
+
border: 1px dashed var(--sf-line);
|
|
1822
|
+
border-radius: var(--sf-row-radius);
|
|
1823
|
+
background: transparent;
|
|
1824
|
+
color: var(--sf-accent-text);
|
|
1825
|
+
font-family: var(--sf-font);
|
|
1826
|
+
font-size: 13px;
|
|
1827
|
+
font-weight: 600;
|
|
1828
|
+
cursor: pointer;
|
|
1829
|
+
}
|
|
1830
|
+
.sf-pages-new:hover {
|
|
1831
|
+
background: var(--sf-hover);
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
/* ── Layers rows (redesign 2b) ──────────────────────────────────────────
|
|
1835
|
+
The Layers tree's rows are editor-shell's `TreeRow` (efficient-easel/tree.css):
|
|
1836
|
+
the name box with the eye and trash laid over its END (card 66199), the
|
|
1837
|
+
hover / focus-within reveal, a hidden row's permanent eye, the grip in the
|
|
1838
|
+
row's own left padding, the caret-or-spacer column (One Ladder), the drag and
|
|
1839
|
+
drop marks and the rename box — all lifted from this sheet. What stays below
|
|
1840
|
+
is `.sf-row-del`, which the standalone section editor's own rows still wear. */
|
|
1841
|
+
/* Per-row delete — a hover-revealed trash on section, slot-child and
|
|
1842
|
+
footer-block rows. Laid out inside `.sf-row-actions` above, invisible +
|
|
1843
|
+
non-interactive until the row is hovered or a control inside it is focused,
|
|
1844
|
+
so it stays out of the way of the visibility eye.
|
|
1845
|
+
Deleting is a normal dispatch, so Undo restores the row. */
|
|
1846
|
+
.sf-row-del {
|
|
1847
|
+
width: 22px;
|
|
1848
|
+
height: 22px;
|
|
1849
|
+
border: none;
|
|
1850
|
+
background: transparent;
|
|
1851
|
+
border-radius: 5px;
|
|
1852
|
+
cursor: pointer;
|
|
1853
|
+
color: var(--sf-danger);
|
|
1854
|
+
display: flex;
|
|
1855
|
+
align-items: center;
|
|
1856
|
+
justify-content: center;
|
|
1857
|
+
opacity: 0;
|
|
1858
|
+
pointer-events: none;
|
|
1859
|
+
flex: none;
|
|
1860
|
+
transition: opacity 0.12s, background 0.12s, color 0.12s;
|
|
1861
|
+
}
|
|
1862
|
+
.sf-row:hover .sf-row-del,
|
|
1863
|
+
.sf-row:focus-within .sf-row-del {
|
|
1864
|
+
opacity: 0.7;
|
|
1865
|
+
pointer-events: auto;
|
|
1866
|
+
}
|
|
1867
|
+
.sf-row-del:hover {
|
|
1868
|
+
opacity: 1;
|
|
1869
|
+
background: var(--sf-danger-tint);
|
|
1870
|
+
color: var(--sf-danger-strong);
|
|
1871
|
+
}
|
|
1872
|
+
.sf-panel-head-actions {
|
|
1873
|
+
display: flex;
|
|
1874
|
+
align-items: center;
|
|
1875
|
+
gap: 2px;
|
|
1876
|
+
}
|
|
1877
|
+
|
|
1878
|
+
/* The relocated heading-outline tool sits muted at the bottom of the tree. */
|
|
1879
|
+
.sf-tree-tool {
|
|
1880
|
+
margin-top: 14px;
|
|
1881
|
+
/* The left inset is the tree's 11px column, not `.sf-tree`'s padding — that
|
|
1882
|
+
is 0 on this side now so the bars can bleed. */
|
|
1883
|
+
padding: 10px 0 0 11px;
|
|
1884
|
+
}
|
|
1885
|
+
|
|
1886
|
+
/* `.sf-field-section` AND `.sf-field-group` WERE HERE, and they are gone on
|
|
1887
|
+
purpose (card 66300). They were the panel's two heading tiers — a 12px label
|
|
1888
|
+
over a 1.5px rule, and a 10.5px label over a 1px one — and the rules are what
|
|
1889
|
+
the owner objected to on 2026-08-31: "these lines, I still find them annoying
|
|
1890
|
+
to look at".
|
|
1891
|
+
Both tiers are drawn by `efficient-easel/panel` now: `SettingsGroupHead` (the
|
|
1892
|
+
filled pill) and `SettingsGroupSub` (the quiet tier, added in 0.25.0 for this).
|
|
1893
|
+
Nothing in this repo renders either class any more — the four panels that
|
|
1894
|
+
inlined `.sf-field-group` as a bare div (HeroText, Ticker, HeroMedia, Chat)
|
|
1895
|
+
call `GroupLabel` in the same card, because leaving them behind would have put
|
|
1896
|
+
the hairline back in four panels and given the editor two answers to "what does
|
|
1897
|
+
a group heading look like" — which is the fault the conversion is fixing.
|
|
1898
|
+
Deleted rather than left dead: a rule nobody renders is a rule the next person
|
|
1899
|
+
edits and watches do nothing.
|
|
1900
|
+
CARD 66300.a FINISHED THE JOB. The last selector that named `.sf-field-section`
|
|
1901
|
+
went with them: a `[class*="_PuckFields-field_"]:first-child` descendant that
|
|
1902
|
+
pulled the first header flush to the panel top. It had matched nothing since the
|
|
1903
|
+
rule above was deleted in this same pull request. The two comments that described
|
|
1904
|
+
the pair went with it, and so did the section header that had nothing left under
|
|
1905
|
+
it — the real "floating custom controls" rules live further up, at
|
|
1906
|
+
`Floating-styled form controls for Puck's native fields`.
|
|
1907
|
+
MEASURED BEFORE CUTTING, with controls in the same sweep, so the zero is a
|
|
1908
|
+
measurement and not a query that finds nothing: `.sf-field-section` and
|
|
1909
|
+
`.sf-field-group` return ZERO renders across app/, components/, lib/ AND the
|
|
1910
|
+
installed `efficient-easel` / `efficient-shell` bundles, while the same query returns
|
|
1911
|
+
`.sf-field-label` 45, `.sf-panel-title` 5, `.sf-insp-name` 1, `.es-group-head` 2
|
|
1912
|
+
and `.es-group-sub` 1. The shell controls are the ones that matter: they prove the
|
|
1913
|
+
sweep reaches into the package that draws the replacement markup, so a class
|
|
1914
|
+
rendered THERE could not have hidden from it. */
|
|
1915
|
+
|
|
1916
|
+
/* ── The settings TABS (card 8802; the Inspector's since blueprint 4.4) ───────
|
|
1917
|
+
The strip is `.es-tabs` from `efficient-easel/panel.css`, drawn by
|
|
1918
|
+
efficient-easel's `Inspector` (components/SiteFields) above its rows. Puck's
|
|
1919
|
+
flat list of hashed wrappers, which made `lib/puck/controls.tsx` mark each
|
|
1920
|
+
bucket and hide the others' rows with a DOM pass, is gone: a row on another
|
|
1921
|
+
tab is `hidden` by the Inspector itself, and a bucket header is a marker
|
|
1922
|
+
field that draws no row at all. What is left here is only the storefront's
|
|
1923
|
+
own look of the strip.
|
|
1924
|
+
|
|
1925
|
+
Editor-only, like every rule around it — never on the published page. */
|
|
1926
|
+
|
|
1927
|
+
/* AND IT IS PINNED TO THE TOP OF THE PANEL (card [FIX] Pin The Settings Tabs).
|
|
1928
|
+
Lewis, 2026-09-03, scrolling a Product Grid's settings: the four bucket tabs
|
|
1929
|
+
scrolled away with the rows, so a merchant three screens down had no way to
|
|
1930
|
+
change bucket without scrolling back up. The strip is a BOUNDARY, not a row —
|
|
1931
|
+
it should behave like the panel head it sits under.
|
|
1932
|
+
|
|
1933
|
+
`position: sticky` on the STRIP'S WRAPPER, and the two conditions it needs
|
|
1934
|
+
are both already true here, which is why this is three declarations and not a
|
|
1935
|
+
restructure:
|
|
1936
|
+
|
|
1937
|
+
the nearest scrolling ancestor is `.sf-insp-body` (`overflow-y: auto`
|
|
1938
|
+
above); the Inspector's own `.es-insp` / `.es-insp-rows` carry NO
|
|
1939
|
+
overflow, and `SectionTextSuppressProvider` / `FoldHeadingScope` are
|
|
1940
|
+
context only and draw no element — so nothing between the wrapper and the
|
|
1941
|
+
scroll box clips it. Checked, not assumed: a sticky that does not stick
|
|
1942
|
+
reports nothing at all.
|
|
1943
|
+
|
|
1944
|
+
THE BACKGROUND IS NOT DECORATION. A pinned element with no background lets
|
|
1945
|
+
the rows scroll through it, and `.es-tabs` paints none of its own — it draws
|
|
1946
|
+
only the rule along its bottom edge. `var(--sf-panel)` is the same token the
|
|
1947
|
+
panel behind it uses, so the strip stays the surface it is already sitting
|
|
1948
|
+
on rather than becoming a second one.
|
|
1949
|
+
|
|
1950
|
+
NOTHING HERE TOUCHES `.es-tabs` — the shell owns the strip's own looks, and
|
|
1951
|
+
`scripts/test-panel-tabs-single-home.ts` fails if this repo reaches into it.
|
|
1952
|
+
What is styled is the strip's place in this panel (`.es-insp-tabs`, the
|
|
1953
|
+
Inspector's own wrapper around it); that place is this repo's to set. */
|
|
1954
|
+
.sf-insp-body .es-insp-tabs {
|
|
1955
|
+
padding: 0;
|
|
1956
|
+
position: sticky;
|
|
1957
|
+
/* Flush with the top of the scroll box, so the rows pass UNDER the strip
|
|
1958
|
+
rather than beside it. The body's own 4px of top padding is above this
|
|
1959
|
+
line and scrolls away with the first row, which is what makes the strip
|
|
1960
|
+
land against the panel head. */
|
|
1961
|
+
top: 0;
|
|
1962
|
+
/* Over the rows and over the fold headings, under the panel head — which is
|
|
1963
|
+
outside this scroll box entirely and cannot be overlapped. */
|
|
1964
|
+
z-index: 2;
|
|
1965
|
+
background: var(--sf-panel);
|
|
1966
|
+
/* …AND THE PAINT REACHES ABOVE IT. Lewis, 2026-09-03, with a screenshot: the
|
|
1967
|
+
strip pins, but a row's words show through a thin band above it.
|
|
1968
|
+
|
|
1969
|
+
MEASURED, not guessed. In a real `.sf-panel` scrolled 260px, the band
|
|
1970
|
+
between the scrollport's top edge and the pinned strip is exactly 4px —
|
|
1971
|
+
`.sf-insp-body`'s own `padding-top` — and `elementFromPoint` in the middle
|
|
1972
|
+
of it returns a row's `.sf-field-label`. The strip is doing its job; the
|
|
1973
|
+
4px above it simply belongs to nobody, so the rows keep it.
|
|
1974
|
+
|
|
1975
|
+
A SHADOW AND NOT LAYOUT, because the gap is not the complaint: the spacing
|
|
1976
|
+
is right and only the transparency is wrong. `box-shadow` paints and
|
|
1977
|
+
occupies nothing, so the strip stays exactly where it is and every row
|
|
1978
|
+
below keeps its position — a `padding-top` here, or a negative `top`,
|
|
1979
|
+
would move the strip and change the spacing he asked to keep.
|
|
1980
|
+
|
|
1981
|
+
16px AND NOT 4, deliberately. The scroll box clips its own overflow, so
|
|
1982
|
+
paint above the scrollport's top edge cannot escape into the panel head no
|
|
1983
|
+
matter how far it reaches — the value only has to be AT LEAST the body's
|
|
1984
|
+
padding. Pinning it to 4 would mean a future change to
|
|
1985
|
+
`.sf-insp-body`'s padding silently reopens this leak, and a leak that
|
|
1986
|
+
comes back looks like the fix was never made. */
|
|
1987
|
+
box-shadow: 0 -16px 0 0 var(--sf-panel);
|
|
1988
|
+
}
|
|
1989
|
+
/* The NARROW panel is the shell's problem, and the shell solves it. Nothing
|
|
1990
|
+
here styles `.es-tabs` — see scripts/test-panel-tabs-single-home.ts, which
|
|
1991
|
+
fails if anything does.
|
|
1992
|
+
|
|
1993
|
+
Why the upstream rule exists, since this is where the defect was found: the
|
|
1994
|
+
settings panel is draggable down to MIN_PANEL_W = 220px
|
|
1995
|
+
(components/panel-widths.ts) and four tabs need 267px, so at anything under
|
|
1996
|
+
~270 the last tab — Layout — was clipped off the right edge and could not be
|
|
1997
|
+
reached at all. Measured: at 220px and at 260px the fourth tab sat past the
|
|
1998
|
+
strip's right edge; wrapping runs the strip to two rows (37px → 75px) and
|
|
1999
|
+
every tab stays reachable, while the default 308px panel is untouched at one
|
|
2000
|
+
row.
|
|
2001
|
+
|
|
2002
|
+
`efficient-easel/src/panel/panel.css` now carries that as `flex-wrap: wrap` on
|
|
2003
|
+
`.es-tabs` itself, with `flex: none; white-space: nowrap` on `.es-tab` so a
|
|
2004
|
+
wrapped tab keeps the width its label needs. Both editors get it, which is
|
|
2005
|
+
the point — the storefront had been fixing this for itself while the campaign
|
|
2006
|
+
designer went without. Card 8802 held a local copy here under a comment
|
|
2007
|
+
claiming card 8802.d had already deleted it; 8802.d had done the upstream
|
|
2008
|
+
half only, so the copy outlived its own obituary until card 66130. */
|
|
2009
|
+
/* ── THE PANEL'S VERTICAL RHYTHM COMES FROM THE SHELL ──────────────────────
|
|
2010
|
+
Card [PLAN] Panel Spacing Rules. Lewis, 2026-09-03: the panel is too loose.
|
|
2011
|
+
Measured before anything was changed, in Chromium against these stylesheets
|
|
2012
|
+
and editor-shell 0.29.0, on a Product Grid's Media tab at the real 320px:
|
|
2013
|
+
|
|
2014
|
+
a group heading to its first setting 74px
|
|
2015
|
+
one setting to the next 50px
|
|
2016
|
+
the last setting to the next heading 74px
|
|
2017
|
+
|
|
2018
|
+
36px OF EVERY ONE OF THOSE WAS NEVER A DECISION. Puck wraps each field in
|
|
2019
|
+
`._PuckFields-field_` and gives it `padding: 16px 16px 12px` plus an 8px
|
|
2020
|
+
`margin-top` between wrappers. That padding was the air around a RULED cell
|
|
2021
|
+
— Puck draws a `border-top` between fields. Card 66334 deleted every one of
|
|
2022
|
+
those lines, on the owner's word, and left the padding behind. It has been
|
|
2023
|
+
dead air stacked on top of the shell's rhythm ever since, and it is why a
|
|
2024
|
+
panel that reads as "too loose" measures as one nobody has loosened.
|
|
2025
|
+
|
|
2026
|
+
⚠️ ZEROED, NOT TUNED — and since blueprint 4.4 there is nothing left to zero.
|
|
2027
|
+
The rows are efficient-easel's `.es-insp-row`, which carry no padding, no
|
|
2028
|
+
gap and no rule of their own, so every gap below comes from ONE place.
|
|
2029
|
+
|
|
2030
|
+
`--es-rhythm-*` ARE THE SHELL'S AND ARE NOT COPIED. They are declared on
|
|
2031
|
+
`.es-editor` in `efficient-easel/src/panel/panel.css`, floored on
|
|
2032
|
+
`--es-row-gap`, and the six values are the owner's own from 2026-08-31
|
|
2033
|
+
(card 66301, "too tight, open it up"). Reading them here is what stops this
|
|
2034
|
+
sheet from being a second source for numbers that sheet already owns — the
|
|
2035
|
+
fault card 66228 removed from the Layers tree and this leaves in the
|
|
2036
|
+
settings panel. Never re-state one as a literal beside the token.
|
|
2037
|
+
|
|
2038
|
+
⛔ NO RAW VERTICAL PX BETWEEN TWO THINGS IN THIS PANEL. A control's own
|
|
2039
|
+
INNER padding is not a gap and is not covered. Enforced by
|
|
2040
|
+
`scripts/test-panel-spacing-tokens.ts`, which reads this file and fails on a
|
|
2041
|
+
raw length in a between-element margin — the allow-list there carries a
|
|
2042
|
+
written reason for each of the few that remain. */
|
|
2043
|
+
/* BETWEEN two settings. */
|
|
2044
|
+
.sf-field {
|
|
2045
|
+
margin-top: var(--es-rhythm-between);
|
|
2046
|
+
}
|
|
2047
|
+
|
|
2048
|
+
/* ── ONE SETTINGS MODULE ENDS AND THE NEXT BEGINS ──────────────────────────
|
|
2049
|
+
Owner ruling, Lewis, 2026-09-03. He asked for "a line after each settings
|
|
2050
|
+
module" because two modules in one panel read as one long list, then
|
|
2051
|
+
rejected the first drawing of it in his own words: it read like a header's
|
|
2052
|
+
rule with its options under it, not like a boundary between two things.
|
|
2053
|
+
|
|
2054
|
+
THAT IS NOT A DRAWING MISTAKE, and it is why this rule looks the way it
|
|
2055
|
+
does. A hairline INSET to the rows belongs to the content column, and so to
|
|
2056
|
+
the heading directly beneath it; an interface's commonest use of that shape
|
|
2057
|
+
is a header rule, so that is what the eye picks. Five versions were drawn at
|
|
2058
|
+
the panel's real 320px and he chose this one:
|
|
2059
|
+
|
|
2060
|
+
FULL BLEED — the rule runs to the panel's own edges, past the rows, so it
|
|
2061
|
+
reads as the panel's structure rather than as something belonging to the
|
|
2062
|
+
text under it. This is the ONLY difference from the version he rejected,
|
|
2063
|
+
and `scripts/test-panel-no-divider-lines.tsx` asserts it: without that
|
|
2064
|
+
check, insetting the line is a one-word edit that turns the allowed rule
|
|
2065
|
+
back into the rejected one with every test still green.
|
|
2066
|
+
|
|
2067
|
+
30px OF AIR ON EACH SIDE — his number, picked on the real editor after
|
|
2068
|
+
looking at 28. Symmetric on purpose: the full bleed is what says which
|
|
2069
|
+
side the rule belongs to, so the air does not have to.
|
|
2070
|
+
|
|
2071
|
+
⚠️ WRITTEN AS `field + field`, FOUR CLASSES, AND THAT IS NOT COSMETIC. Two
|
|
2072
|
+
rules further down are (0,3,0) — card 66334's `border-top: 0` and this
|
|
2073
|
+
card's own `margin-top: 0` — and a two-class rule loses to both SILENTLY:
|
|
2074
|
+
the line never paints and the panel looks untouched. Measured in a fixture
|
|
2075
|
+
against this stylesheet before it reached the preview door. Same specificity
|
|
2076
|
+
trap as the 8px below, on the same card, found the same way.
|
|
2077
|
+
|
|
2078
|
+
THE FIRST MODULE TAKES NO RULE. A module heading is not `:first-child`
|
|
2079
|
+
here — the hidden bucket header and the tab strip come before it — so
|
|
2080
|
+
excluding it means naming the wrappers that can precede it. The strip
|
|
2081
|
+
already draws its own bottom rule; a second one under it is two lines.
|
|
2082
|
+
|
|
2083
|
+
⚠️ THIS IS A LINE, so it is on card 66334's allow-list as a KEEP with his
|
|
2084
|
+
words. It is NOT one of the twenty-eight that card removed: those were drawn
|
|
2085
|
+
between every ROW, which is what he called annoying. This is one per
|
|
2086
|
+
module — three or four in a panel. */
|
|
2087
|
+
/* ⚠️ THE THEME SHEET REACHES THE SAME RULE BY JOINING THIS SELECTOR LIST, never
|
|
2088
|
+
by declaring the values again. Lewis, 2026-09-04, looking at the open theme
|
|
2089
|
+
card: `SURFACES` sat against the row above it and there was no line between
|
|
2090
|
+
the two modules. Both symptoms had one cause — the sheet hand-rolled its own
|
|
2091
|
+
`.sf-subgroup` heading while the shell shipped `SettingsGroupSub`, so this
|
|
2092
|
+
rule, which keys on `.es-group-sub`, could never see it.
|
|
2093
|
+
|
|
2094
|
+
The heading is the shell's now, and these two selectors are what carry the
|
|
2095
|
+
rule into a sheet that does not draw Puck field wrappers: it renders its rows
|
|
2096
|
+
as bare `SettingsField`s inside its own container. Same 30px, same full
|
|
2097
|
+
bleed, same token-read cancel — one block, because a second copy of his
|
|
2098
|
+
number is the thing that goes stale.
|
|
2099
|
+
|
|
2100
|
+
⚠️ AND THE COMMENT LIVES ABOVE THE RULE, NOT INSIDE THE SELECTOR LIST. Put
|
|
2101
|
+
between two selectors it split the list in the divider guard's parser, which
|
|
2102
|
+
then reported half of one rule as an unlisted line — a comment changing what
|
|
2103
|
+
a guard sees. */
|
|
2104
|
+
.sf-insp-body .es-insp-row:has(.es-group-sub),
|
|
2105
|
+
.sf-theme-colours .es-group-sub,
|
|
2106
|
+
.sf-secttheme-rows .es-group-sub {
|
|
2107
|
+
border-top: 1px solid var(--sf-line);
|
|
2108
|
+
margin-top: 30px;
|
|
2109
|
+
padding-top: 30px;
|
|
2110
|
+
/* Cancel the panel body's side padding, then put it back inside, so the rule
|
|
2111
|
+
reaches the panel edge while the words stay on the rows' left edge.
|
|
2112
|
+
⚠️ READ FROM THE TOKEN, never typed. A literal `14px` here hung the line
|
|
2113
|
+
6px OUTSIDE the panel at every width under 280, where card 66212 narrows
|
|
2114
|
+
the padding to 8 — measured at 260 and at 220 before this was a `var()`. */
|
|
2115
|
+
margin-left: calc(var(--sf-insp-pad-x) * -1);
|
|
2116
|
+
margin-right: calc(var(--sf-insp-pad-x) * -1);
|
|
2117
|
+
padding-left: var(--sf-insp-pad-x);
|
|
2118
|
+
padding-right: var(--sf-insp-pad-x);
|
|
2119
|
+
}
|
|
2120
|
+
/* The heading's own top margin is the wrapper's job now. */
|
|
2121
|
+
.sf-insp-body .es-insp-row:has(.es-group-sub) .es-group-sub {
|
|
2122
|
+
margin-top: 0;
|
|
2123
|
+
}
|
|
2124
|
+
/* No rule directly under the tab strip, or under a hidden bucket header. */
|
|
2125
|
+
.sf-insp-body .es-insp-row:nth-child(1 of :not([hidden], :empty, :has(> [data-sf-device-hidden], > [data-sf-no-control]))):has(.es-group-sub) {
|
|
2126
|
+
border-top: 0;
|
|
2127
|
+
margin-top: 0;
|
|
2128
|
+
padding-top: var(--es-rhythm-group-first);
|
|
2129
|
+
}
|
|
2130
|
+
/* A HEADING OWNS ITS FIRST SETTING, so that setting sits closer to it than to
|
|
2131
|
+
the settings below it. The shell says this as
|
|
2132
|
+
`.es-group-body > .es-field:first-child`, which cannot fire here: Puck's
|
|
2133
|
+
inspector is a FLAT sibling list, so a heading never wraps the rows it heads
|
|
2134
|
+
and there is no `:first-child` to select. Same rule, said the only way this
|
|
2135
|
+
DOM can say it — the row after the heading's wrapper. Without it the
|
|
2136
|
+
heading's own 24px bottom margin simply loses the collapse to the 38px above
|
|
2137
|
+
the row, and every heading sits as far from its own settings as from
|
|
2138
|
+
somebody else's. */
|
|
2139
|
+
.sf-insp-body .es-insp-row:has(.es-group-sub) + .es-insp-row .sf-field,
|
|
2140
|
+
.sf-insp-body .es-insp-row:has(.es-group-head) + .es-insp-row .sf-field {
|
|
2141
|
+
margin-top: var(--es-rhythm-group-first);
|
|
2142
|
+
}
|
|
2143
|
+
.sf-field-label {
|
|
2144
|
+
display: block;
|
|
2145
|
+
font-size: 12px;
|
|
2146
|
+
font-weight: 500;
|
|
2147
|
+
color: var(--sf-text-secondary);
|
|
2148
|
+
/* WITHIN one setting: its label to its own control. This gap is the only
|
|
2149
|
+
thing saying which label owns which control, so it stays plainly smaller
|
|
2150
|
+
than the gap BETWEEN settings — the pair the shell asks a consumer to keep
|
|
2151
|
+
when it re-scales (panel.css, `--es-rhythm-within`). */
|
|
2152
|
+
margin-bottom: var(--es-rhythm-within);
|
|
2153
|
+
}
|
|
2154
|
+
.sf-field-label--inline {
|
|
2155
|
+
margin-bottom: 0;
|
|
2156
|
+
}
|
|
2157
|
+
/* A hint that answers a question you only have WHILE TYPING waits until the box
|
|
2158
|
+
is in use (card 8802.g). Which sentence is which — and why one waits and the
|
|
2159
|
+
other never does — is decided once, in `hintIsWhileTyping` in
|
|
2160
|
+
lib/puck/controls.tsx; this is only the showing and the hiding.
|
|
2161
|
+
|
|
2162
|
+
CSS rather than React state, the same call card 8802.h made in editor-shell:
|
|
2163
|
+
a repaint on focus drops the browser's text selection, and the formatting bar
|
|
2164
|
+
above the box exists to act on that selection.
|
|
2165
|
+
|
|
2166
|
+
SCOPED TO THE MODIFIER, NEVER TO .es-field-hint ITSELF. The shared caption
|
|
2167
|
+
class also carries the anchor sentence, which is on every section and is the
|
|
2168
|
+
only thing that says what the term of art "Anchor name" means. A rule written
|
|
2169
|
+
one class wider would take that explanation off all of them at once. */
|
|
2170
|
+
/* ── The section panel's own hints switch ───────────────────────────────────
|
|
2171
|
+
[ADD] Section Panel Folds Its Hints, 2026-09-06. Owner asked for the same
|
|
2172
|
+
control the Basics tab has had since card 66177 — a section's Style tab was
|
|
2173
|
+
carrying two- and three-line explanations on rows a merchant has read once.
|
|
2174
|
+
|
|
2175
|
+
⚠️ IT FOLDS A ROW'S EXPLANATION, NEVER A STATE. Every quiet line is
|
|
2176
|
+
`.es-field-hint` now, and two kinds must stay on screen: the "Anchor name"
|
|
2177
|
+
sentence, the only place that term of art is explained, and the source note,
|
|
2178
|
+
which tells a merchant why clicking a hydrated word gave them no caret. Both
|
|
2179
|
+
are marked `.sf-hint-keep`, and the rule below leaves them alone. */
|
|
2180
|
+
/* ⚠️ AND NEVER A HINT THAT HOLDS `.sf-hint-keep` ([MERGE] One Settings Row And
|
|
2181
|
+
Hint In The Website Editor, 2026-10-06). The shop's own hint classes are
|
|
2182
|
+
gone; every quiet line under a control is `SettingsField`'s `hint`. The few
|
|
2183
|
+
that are a STATE rather than an explanation — loading, empty, why a control
|
|
2184
|
+
is disabled — wrap their words in `components/KeepHint.tsx`, and a line under
|
|
2185
|
+
no row wears `sf-hint-keep` itself; this rule leaves both on screen. `scripts/test-section-hints-fold.ts` holds both. */
|
|
2186
|
+
.sf-panel--right.sf-hints-folded .es-field-hint:not(.sf-hint-keep):not(:has(.sf-hint-keep)) {
|
|
2187
|
+
display: none;
|
|
2188
|
+
}
|
|
2189
|
+
|
|
2190
|
+
.es-field-hint:has(.sf-hint-while-typing) {
|
|
2191
|
+
display: none;
|
|
2192
|
+
}
|
|
2193
|
+
.es-field:focus-within > .es-field-hint:has(.sf-hint-while-typing) {
|
|
2194
|
+
display: block;
|
|
2195
|
+
}
|
|
2196
|
+
|
|
2197
|
+
/* ── Device-aware fields (lib/puck/device-fields.tsx) ─────────────────────────
|
|
2198
|
+
The rule that collapses a row holding the device gate's marker
|
|
2199
|
+
(`[data-sf-device-hidden]`) is efficient-easel/screen.css's since 0.103.0:
|
|
2200
|
+
the screen's own gate paints the marker, so every host that mounts the screen
|
|
2201
|
+
needs the rule, and this sheet goes to one of them. It loads before this
|
|
2202
|
+
sheet, where the rule stood; no rule here meets it on `display !important`. */
|
|
2203
|
+
/* ── A field that draws NO CONTROL here (card 66178) ──────────────────────────
|
|
2204
|
+
Puck owned the wrapper around every top-level field and ruled the gap between
|
|
2205
|
+
two of them, so a field whose render returned nothing still took its
|
|
2206
|
+
`16px 16px 12px` and still drew the line: a hairline with only blank space on
|
|
2207
|
+
one side. (Since blueprint 4.4 the row is efficient-easel's `.es-insp-row`.) It was three of
|
|
2208
|
+
them stacked on the Collections Content tab, and 338 such rows across 74
|
|
2209
|
+
panels.
|
|
2210
|
+
|
|
2211
|
+
The field says so instead, and the wrapper goes — `display: none`, so the row
|
|
2212
|
+
leaves the accessibility tree with it rather than lingering as an unlabelled
|
|
2213
|
+
blank a screen reader still walks through. Declarative, like the device
|
|
2214
|
+
gate's rule (efficient-easel/screen.css) and the one below, so it cannot race
|
|
2215
|
+
the tab pass; and the attribute name is stated once in
|
|
2216
|
+
`lib/puck/panel-no-control-mark`, which `scripts/test-panel-no-empty-rows.tsx`
|
|
2217
|
+
§4 reads back to prove this rule is really here.
|
|
2218
|
+
The marker is the screen's (efficient-easel paints it), so the rule belongs
|
|
2219
|
+
in efficient-easel/screen.css too, and moves there once that storefront guard
|
|
2220
|
+
reads both sheets (`editorSheet()`); easel's tests/screen-css-closure lists it
|
|
2221
|
+
as open until then. */
|
|
2222
|
+
.es-insp-row:has(> [data-sf-no-control]) {
|
|
2223
|
+
display: none !important;
|
|
2224
|
+
}
|
|
2225
|
+
|
|
2226
|
+
/* ── NO DIVIDER HAIRLINES IN THIS PANEL (card 66334) ──────────────────────────
|
|
2227
|
+
The owner asked for these lines to go twice. Deleting our own was only part of
|
|
2228
|
+
it: the rule below is drawn by a PACKAGE, it is the majority of what is
|
|
2229
|
+
actually on screen, and it cannot be deleted from here.
|
|
2230
|
+
|
|
2231
|
+
Puck rules the gap between every pair of top-level fields, so it draws once
|
|
2232
|
+
per field for the whole panel — 28 lines in a single section panel, measured.
|
|
2233
|
+
That is most of the panel's lines on its own, which is why removing the shop's
|
|
2234
|
+
own two heading rules (card 66300) did not change what he saw.
|
|
2235
|
+
|
|
2236
|
+
⚠️ THERE WERE TWO OF THESE, AND THE OTHER ONE IS GONE. The shell drew
|
|
2237
|
+
`.es-drill + .es-drill`, 16 more lines between the rows that list a section's
|
|
2238
|
+
text parts. It was held here under a written expiry, because a rule that lives
|
|
2239
|
+
in another repo could not be reached from this one. editor-shell 0.29.0 (card
|
|
2240
|
+
66350) deleted it AT SOURCE and card 66351 deleted this repo's copy with it —
|
|
2241
|
+
the ending the Puck rule below cannot have, since `@measured/puck` is not ours
|
|
2242
|
+
to change. That seam is now held from both ends by
|
|
2243
|
+
`scripts/test-drill-rows-separated-by-air.ts`: it fails if the shell starts
|
|
2244
|
+
drawing on it again, and it fails if a local override for it reappears here.
|
|
2245
|
+
|
|
2246
|
+
⚠️ SPECIFICITY, NOT `!important`. Puck's rule is (0,3,0) —
|
|
2247
|
+
`wrapFields field + field` — so this restates all three parts to match it, and
|
|
2248
|
+
wins on order: `storefront-editor.css` is imported after `puck.css` and after
|
|
2249
|
+
`panel.css` at every call site. The `[class*=]` form is this file's existing
|
|
2250
|
+
idiom for Puck's hashed module names (see the three rules above); a bare class
|
|
2251
|
+
would break on the next Puck bump, silently, by putting the lines back.
|
|
2252
|
+
|
|
2253
|
+
This is an override of a live upstream rule, not dead code:
|
|
2254
|
+
`scripts/test-panel-no-divider-lines.tsx` §2 asserts the upstream rule still
|
|
2255
|
+
exists before checking it, so if Puck ever drops its own line, the guard says
|
|
2256
|
+
to delete the override rather than leave it lying here — which is exactly what
|
|
2257
|
+
happened to the drill one above. */
|
|
2258
|
+
|
|
2259
|
+
/* The header panel's px readouts (Size, Space from the logo, Height) follow
|
|
2260
|
+
option E (Lewis, 2026-10-07): grey while the setting is unchanged — the grey
|
|
2261
|
+
is what says "default" — and the text colour once it is set, beside the ↺. */
|
|
2262
|
+
.sf-header-value[data-changed] { color: var(--sf-text); }
|
|
2263
|
+
|
|
2264
|
+
/* ── Inherit / overridden badge: GONE (owner 2026-10-06) ─────────────────────
|
|
2265
|
+
The `.sf-inherit` chip ("Inherits · Site" / "Overridden ↺") was replaced by
|
|
2266
|
+
easel's `SettingsDefaultReset` — the word "Default", and a "Reset" button —
|
|
2267
|
+
which draws itself from `efficient-easel/panel.css`. One part, both editors;
|
|
2268
|
+
no shop rule styles it. `scripts/test-one-default-reset.ts` fails on a new
|
|
2269
|
+
`.sf-inherit` rule. */
|
|
2270
|
+
|
|
2271
|
+
/* Read-only value display — same metrics as an inspector input, but styled as a
|
|
2272
|
+
system-set value the panel SHOWS rather than edits (e.g. the Website name,
|
|
2273
|
+
which is renamed in the Console). Muted fill + secondary text + a default
|
|
2274
|
+
cursor so it never reads as an editable field; a long name ellipsises. */
|
|
2275
|
+
.sf-field-readonly {
|
|
2276
|
+
border: 1px solid var(--sf-input-border);
|
|
2277
|
+
background: var(--sf-chip-bg);
|
|
2278
|
+
border-radius: var(--sf-field-radius);
|
|
2279
|
+
padding: 8px 11px;
|
|
2280
|
+
font-size: 13px;
|
|
2281
|
+
color: var(--sf-text-secondary);
|
|
2282
|
+
font-family: var(--sf-font);
|
|
2283
|
+
cursor: default;
|
|
2284
|
+
overflow: hidden;
|
|
2285
|
+
text-overflow: ellipsis;
|
|
2286
|
+
white-space: nowrap;
|
|
2287
|
+
}
|
|
2288
|
+
|
|
2289
|
+
/* Text field with a visibility eye: leading type glyph · label · trailing eye.
|
|
2290
|
+
The eye flips a stored `hidden` flag that drops the element from the slide
|
|
2291
|
+
render — see controls.tsx. The input stays editable (dimmed) while hidden. */
|
|
2292
|
+
.sf-field-head {
|
|
2293
|
+
display: flex;
|
|
2294
|
+
align-items: center;
|
|
2295
|
+
gap: 8px;
|
|
2296
|
+
/* The same label-to-control gap as `.sf-field-label` above — this is that
|
|
2297
|
+
label, with a glyph and an eye beside it. */
|
|
2298
|
+
margin-bottom: var(--es-rhythm-within);
|
|
2299
|
+
}
|
|
2300
|
+
.sf-field-head .sf-field-label {
|
|
2301
|
+
flex: 1;
|
|
2302
|
+
min-width: 0;
|
|
2303
|
+
margin-bottom: 0;
|
|
2304
|
+
}
|
|
2305
|
+
.sf-field-eye {
|
|
2306
|
+
flex: none;
|
|
2307
|
+
width: 22px;
|
|
2308
|
+
height: 22px;
|
|
2309
|
+
border: none;
|
|
2310
|
+
background: transparent;
|
|
2311
|
+
border-radius: 5px;
|
|
2312
|
+
cursor: pointer;
|
|
2313
|
+
color: var(--sf-muted);
|
|
2314
|
+
display: flex;
|
|
2315
|
+
align-items: center;
|
|
2316
|
+
justify-content: center;
|
|
2317
|
+
opacity: 0.6;
|
|
2318
|
+
transition: background 0.12s, color 0.12s, opacity 0.12s;
|
|
2319
|
+
}
|
|
2320
|
+
.sf-field-eye:hover {
|
|
2321
|
+
background: var(--sf-hover);
|
|
2322
|
+
opacity: 1;
|
|
2323
|
+
color: var(--sf-text-secondary);
|
|
2324
|
+
}
|
|
2325
|
+
/* Hidden: the element is dropped from the slide, but the input stays so the copy
|
|
2326
|
+
is preserved and editable. Strike the label + dim the input + light the eye —
|
|
2327
|
+
mirroring the section tree's hidden-row cue. */
|
|
2328
|
+
.es-field.is-hidden .es-field-label {
|
|
2329
|
+
color: var(--sf-muted);
|
|
2330
|
+
text-decoration: line-through;
|
|
2331
|
+
}
|
|
2332
|
+
.es-field.is-hidden .sf-field-eye {
|
|
2333
|
+
opacity: 1;
|
|
2334
|
+
color: var(--sf-text-secondary);
|
|
2335
|
+
}
|
|
2336
|
+
.es-field.is-hidden input,
|
|
2337
|
+
.es-field.is-hidden textarea {
|
|
2338
|
+
opacity: 0.5;
|
|
2339
|
+
}
|
|
2340
|
+
|
|
2341
|
+
/* Formatting bar above a copy field — bold · italic · strike · highlight.
|
|
2342
|
+
Select words in the field, press a button; the button writes the markup the
|
|
2343
|
+
renderer understands, so a merchant never types a delimiter. Sits between the
|
|
2344
|
+
label row and the input, at the icon-button metrics the eye already uses, so a
|
|
2345
|
+
copy field gains a row of chrome rather than a new visual language.
|
|
2346
|
+
The buttons take their ink from the same tokens as every other inspector icon,
|
|
2347
|
+
so light and dark both follow the panel — no colour is named here. */
|
|
2348
|
+
/* ⚠️ THE ROW ITSELF IS `efficient-easel/copy`'s `MarkBar` NOW (`.es-copy-bar`), and
|
|
2349
|
+
these rules are what keep it looking like the shop's. The shell dresses its
|
|
2350
|
+
bar from `--es-*` with its own metrics; the inspector's bar has to belong to
|
|
2351
|
+
the inspector. Same rule, two skins — the split the two editors already make.
|
|
2352
|
+
|
|
2353
|
+
`.sf-markup` — the container class this repo's own bar carried — is GONE from
|
|
2354
|
+
these selectors, because nothing renders it any more (swept: no `"sf-markup"`
|
|
2355
|
+
class in app / components / lib). `.sf-markup-btn` stays: the Clear button is
|
|
2356
|
+
still the host's own and still takes its metrics from it. */
|
|
2357
|
+
.sf-copybox > .es-copy-bar,
|
|
2358
|
+
.es-list-above > .es-copy-bar {
|
|
2359
|
+
display: flex;
|
|
2360
|
+
align-items: center;
|
|
2361
|
+
gap: 2px;
|
|
2362
|
+
/* ZERO, and it is the shell's 4px being neutralised rather than a gap being
|
|
2363
|
+
chosen. `copy.css` gives its bar a gap to the box below it, because in the
|
|
2364
|
+
campaign designer the bar floats above a separately framed box. Here the
|
|
2365
|
+
bar sits INSIDE the frame (card 8802.g) and the list column already spaces
|
|
2366
|
+
its children — both places set 0, which is what the two rules further down
|
|
2367
|
+
used to do one at a time. */
|
|
2368
|
+
margin-bottom: 0;
|
|
2369
|
+
}
|
|
2370
|
+
/* ⚠️ THE BAR WRAPS, and it has to now that three of its buttons are WORDS.
|
|
2371
|
+
|
|
2372
|
+
It was `nowrap` to reproduce the old `.sf-markup` exactly, which was right
|
|
2373
|
+
while every button was a 24px glyph. Highlight / Bold / Quiet are names
|
|
2374
|
+
(card: the three blank buttons), and three names do not share a line with
|
|
2375
|
+
four glyphs and a Clear button in a narrow panel. Measured, `text` row:
|
|
2376
|
+
|
|
2377
|
+
panel nowrap wrap
|
|
2378
|
+
320px Clear 6px inside 6px inside, one line
|
|
2379
|
+
220px Clear 12px OUTSIDE 6px inside, two lines
|
|
2380
|
+
181px Clear 51px OUTSIDE 6px inside, two lines
|
|
2381
|
+
|
|
2382
|
+
So the wrap is not a preference: without it the fix for the blank buttons
|
|
2383
|
+
would trade three unreadable buttons for an unreachable one. `copy.css`
|
|
2384
|
+
already wraps; this rule now only exists to say why that is wanted here. */
|
|
2385
|
+
.sf-copybox > .es-copy-bar,
|
|
2386
|
+
.es-list-above > .es-copy-bar {
|
|
2387
|
+
flex-wrap: wrap;
|
|
2388
|
+
row-gap: 2px;
|
|
2389
|
+
}
|
|
2390
|
+
/* A button that draws a GLYPH is a square; a button that draws a WORD is as
|
|
2391
|
+
wide as its word. `has-glyph` is the shell's own marker for the difference
|
|
2392
|
+
(editor-shell 0.62.0), so the two cases are told apart by what they hold
|
|
2393
|
+
rather than by a list of style names kept in step by hand. */
|
|
2394
|
+
.sf-markup-btn,
|
|
2395
|
+
.sf-copybox .es-copy-mark.has-glyph,
|
|
2396
|
+
.es-list-above .es-copy-mark.has-glyph {
|
|
2397
|
+
width: 24px;
|
|
2398
|
+
}
|
|
2399
|
+
.sf-copybox .es-copy-mark:not(.has-glyph),
|
|
2400
|
+
.es-list-above .es-copy-mark:not(.has-glyph) {
|
|
2401
|
+
/* The style's NAME — Highlight / Bold / Quiet. Padded so two of them do not
|
|
2402
|
+
read as one word, and never wrapped mid-name. */
|
|
2403
|
+
padding: 0 6px;
|
|
2404
|
+
font-size: 11px;
|
|
2405
|
+
line-height: 1;
|
|
2406
|
+
white-space: nowrap;
|
|
2407
|
+
}
|
|
2408
|
+
.sf-markup-btn,
|
|
2409
|
+
.sf-copybox .es-copy-mark,
|
|
2410
|
+
.es-list-above .es-copy-mark {
|
|
2411
|
+
height: 22px;
|
|
2412
|
+
border: none;
|
|
2413
|
+
background: transparent;
|
|
2414
|
+
border-radius: 5px;
|
|
2415
|
+
cursor: pointer;
|
|
2416
|
+
color: var(--sf-icon);
|
|
2417
|
+
display: flex;
|
|
2418
|
+
align-items: center;
|
|
2419
|
+
justify-content: center;
|
|
2420
|
+
opacity: 0.75;
|
|
2421
|
+
transition: background 0.12s, color 0.12s, opacity 0.12s;
|
|
2422
|
+
}
|
|
2423
|
+
.sf-markup-btn:hover:not(:disabled),
|
|
2424
|
+
.sf-copybox .es-copy-mark:hover:not(:disabled),
|
|
2425
|
+
.es-list-above .es-copy-mark:hover:not(:disabled) {
|
|
2426
|
+
background: var(--sf-hover);
|
|
2427
|
+
color: var(--sf-text-secondary);
|
|
2428
|
+
opacity: 1;
|
|
2429
|
+
}
|
|
2430
|
+
.sf-markup-btn:active:not(:disabled),
|
|
2431
|
+
.sf-copybox .es-copy-mark:active:not(:disabled),
|
|
2432
|
+
.es-list-above .es-copy-mark:active:not(:disabled) {
|
|
2433
|
+
background: var(--sf-accent-tint);
|
|
2434
|
+
color: var(--sf-accent-text);
|
|
2435
|
+
}
|
|
2436
|
+
.sf-markup-btn:disabled,
|
|
2437
|
+
.sf-copybox .es-copy-mark:disabled,
|
|
2438
|
+
.es-list-above .es-copy-mark:disabled {
|
|
2439
|
+
color: var(--sf-disabled);
|
|
2440
|
+
cursor: default;
|
|
2441
|
+
}
|
|
2442
|
+
/* The fifth button — clear formatting (card 8809) — pushed away from the four.
|
|
2443
|
+
The four ADD a mark to a selection; this one TAKES every mark off the whole
|
|
2444
|
+
field, so it does not stand shoulder to shoulder with them. This one rule is
|
|
2445
|
+
the whole separation: `margin-left: auto` makes the bar's own `.es-divider-v`
|
|
2446
|
+
eat the free space, which IS the flexible spacer, and carries the button after
|
|
2447
|
+
it to the far end. No new class, no new line and no new colour — the divider
|
|
2448
|
+
already draws itself in --sf-divider, and the button takes `.sf-markup-btn`
|
|
2449
|
+
for its metrics, its hover and its :disabled look.
|
|
2450
|
+
|
|
2451
|
+
The height is the one adjustment: `.es-divider-v` is 22px for the 30px icon
|
|
2452
|
+
buttons of the top toolbar, which in a 22px row would run edge to edge and
|
|
2453
|
+
read as a wall rather than a seam. 14px matches the glyphs it separates. */
|
|
2454
|
+
.sf-copybox > .es-copy-bar > .es-copy-bar-split,
|
|
2455
|
+
.es-list-above > .es-copy-bar > .es-copy-bar-split {
|
|
2456
|
+
margin-left: auto;
|
|
2457
|
+
height: 14px;
|
|
2458
|
+
}
|
|
2459
|
+
/* ⚠️ AND THE AUTO MARGIN IS ON THE BUTTON TOO, not only on the divider.
|
|
2460
|
+
`margin-left: auto` eats the free space of the line the item is ON. While
|
|
2461
|
+
the bar was one line that was the same thing. Now that it wraps, the divider
|
|
2462
|
+
can end line 1 while Clear starts line 2 — and Clear, with no auto margin of
|
|
2463
|
+
its own, sat at the LEFT of that line. Measured at 181px: three rows, glyphs
|
|
2464
|
+
/ names / Clear, with Clear 135px from the right edge it is supposed to be
|
|
2465
|
+
at. One declaration, and it is at the far end of whichever line it lands on. */
|
|
2466
|
+
.sf-copybox > .es-copy-bar > .sf-markup-clear,
|
|
2467
|
+
.es-list-above > .es-copy-bar > .sf-markup-clear {
|
|
2468
|
+
margin-left: auto;
|
|
2469
|
+
}
|
|
2470
|
+
/* The shell's divider dressed as the shop's `.es-divider-v`: the same seam, so
|
|
2471
|
+
the bar has ONE divider rather than the shell's plus a hand-rolled one.
|
|
2472
|
+
NO COLOUR IS NAMED — copy.css already draws it in `--es-copy-rule`, which the
|
|
2473
|
+
editor aliases onto its own border token, exactly as `.es-divider-v` drew
|
|
2474
|
+
itself in `--es-divider`. A colour here would be a second answer. */
|
|
2475
|
+
.sf-copybox > .es-copy-bar > .es-copy-bar-split,
|
|
2476
|
+
.es-list-above > .es-copy-bar > .es-copy-bar-split {
|
|
2477
|
+
align-self: center;
|
|
2478
|
+
margin-right: 2px;
|
|
2479
|
+
}
|
|
2480
|
+
/* A hidden element's copy is still editable, so the bar dims with the input
|
|
2481
|
+
rather than disappearing — same cue, same reason as the input's 0.5. */
|
|
2482
|
+
.es-field.is-hidden .es-copy-bar {
|
|
2483
|
+
opacity: 0.5;
|
|
2484
|
+
}
|
|
2485
|
+
|
|
2486
|
+
/* ── The copy box: ONE frame around the bar and the words ─────────────────────
|
|
2487
|
+
Card 8802.g. The bar and the input used to be siblings — the bar with no
|
|
2488
|
+
frame of its own, the input with one — so a copy field read as a row of loose
|
|
2489
|
+
glyphs floating above a box rather than as a single control, and the eye had
|
|
2490
|
+
to decide which box the bar belonged to. The border, the radius and the field
|
|
2491
|
+
background move onto this wrapper; the input inside gives up all three; and
|
|
2492
|
+
the WHOLE box takes the focus ring, so a click anywhere in it lights up the
|
|
2493
|
+
thing you are about to type into.
|
|
2494
|
+
|
|
2495
|
+
The shared-bar list keeps its own shape on purpose: `.es-list-above` holds ONE
|
|
2496
|
+
bar above N rows, which cannot be framed together with the words the way one
|
|
2497
|
+
bar above one box can. Every rule here is scoped to a DIRECT child of
|
|
2498
|
+
.sf-copybox, so none of them reaches it. */
|
|
2499
|
+
.sf-copybox {
|
|
2500
|
+
border: 1px solid var(--sf-input-border);
|
|
2501
|
+
border-radius: var(--sf-field-radius);
|
|
2502
|
+
background: var(--sf-field-bg);
|
|
2503
|
+
/* The bar's strip is square; this is what bends it to the frame's radius. */
|
|
2504
|
+
overflow: hidden;
|
|
2505
|
+
}
|
|
2506
|
+
.sf-copybox:focus-within {
|
|
2507
|
+
border-color: var(--sf-accent);
|
|
2508
|
+
box-shadow: 0 0 0 3px var(--sf-accent-ring);
|
|
2509
|
+
}
|
|
2510
|
+
/* The bar, inside the frame: a strip at the top, divided from the words by a
|
|
2511
|
+
hairline. --sf-hover is the panel's own faintest fill, the tint every other
|
|
2512
|
+
inspector control uses to say "chrome, not content", so no new colour and no
|
|
2513
|
+
literal is introduced here. */
|
|
2514
|
+
.sf-copybox > .es-copy-bar {
|
|
2515
|
+
margin-bottom: 0;
|
|
2516
|
+
padding: 3px 6px;
|
|
2517
|
+
/* ⚠️ NOT a panel divider, and card 66334 deliberately left it. This hairline
|
|
2518
|
+
is INSIDE one control: it divides the formatting bar from the words, and it
|
|
2519
|
+
exists instead of giving the bar a second full frame -- which is the thing
|
|
2520
|
+
card 8802.g removed. `scripts/test-copy-field-box.tsx` asserts both halves
|
|
2521
|
+
("divided by a hairline" AND "takes no second frame"), so deleting it here
|
|
2522
|
+
puts that card's defect back. */
|
|
2523
|
+
border-bottom: 1px solid var(--sf-input-border);
|
|
2524
|
+
background: var(--sf-hover);
|
|
2525
|
+
}
|
|
2526
|
+
/* THE BAR WHILE TYPING (blueprint 4.9's text box design, 4.10 here): at rest a
|
|
2527
|
+
copy box is its words, and the strip arrives with the caret — a column of
|
|
2528
|
+
text settings is a column of words, not a column of toolbars. Hidden, not
|
|
2529
|
+
unmounted: the bar keeps its place in the markup, and a keyboard user who
|
|
2530
|
+
Shift+Tabs out of the words lands on its last button, which keeps the box
|
|
2531
|
+
focused and the bar shown. */
|
|
2532
|
+
.sf-copybox:not(:focus-within) > .es-copy-bar {
|
|
2533
|
+
display: none;
|
|
2534
|
+
}
|
|
2535
|
+
/* PRESSED: the selection already wears this mark, so a press takes it off. The
|
|
2536
|
+
same tint as the :active press above, held — under the pointer too, which is
|
|
2537
|
+
where it is right after the press (the hover rule would otherwise win). */
|
|
2538
|
+
.sf-copybox .es-copy-mark.is-active,
|
|
2539
|
+
.sf-copybox .es-copy-mark.is-active:hover:not(:disabled),
|
|
2540
|
+
.es-list-above .es-copy-mark.is-active,
|
|
2541
|
+
.es-list-above .es-copy-mark.is-active:hover:not(:disabled) {
|
|
2542
|
+
background: var(--sf-accent-tint);
|
|
2543
|
+
color: var(--sf-accent-text);
|
|
2544
|
+
}
|
|
2545
|
+
/* The input gives up its own frame to the wrapper. The `.sf-insp-body` +
|
|
2546
|
+
attribute selectors are not decoration: the base control rule near the top of
|
|
2547
|
+
this file is `.sf-insp-body input[type="text"]`, which ties on specificity
|
|
2548
|
+
with a plain `.sf-copybox > input`, and a reader would have to know both line
|
|
2549
|
+
numbers to see why this one wins. `display: block` kills the inline
|
|
2550
|
+
descender gap that would otherwise show a sliver of background under a
|
|
2551
|
+
textarea, inside the frame. */
|
|
2552
|
+
.sf-copybox > input,
|
|
2553
|
+
.sf-copybox > textarea,
|
|
2554
|
+
.sf-insp-body .sf-copybox > input[type="text"],
|
|
2555
|
+
.sf-insp-body .sf-copybox > input:not([type]),
|
|
2556
|
+
.sf-insp-body .sf-copybox > textarea {
|
|
2557
|
+
border: none;
|
|
2558
|
+
border-radius: 0;
|
|
2559
|
+
background: transparent;
|
|
2560
|
+
display: block;
|
|
2561
|
+
width: 100%;
|
|
2562
|
+
}
|
|
2563
|
+
.sf-copybox > input:focus,
|
|
2564
|
+
.sf-copybox > textarea:focus,
|
|
2565
|
+
.sf-insp-body .sf-copybox > input[type="text"]:focus,
|
|
2566
|
+
.sf-insp-body .sf-copybox > input:not([type]):focus,
|
|
2567
|
+
.sf-insp-body .sf-copybox > textarea:focus {
|
|
2568
|
+
box-shadow: none;
|
|
2569
|
+
}
|
|
2570
|
+
|
|
2571
|
+
/* Color swatches */
|
|
2572
|
+
.sf-swatches {
|
|
2573
|
+
display: flex;
|
|
2574
|
+
align-items: center;
|
|
2575
|
+
gap: 10px;
|
|
2576
|
+
}
|
|
2577
|
+
.sf-swatch {
|
|
2578
|
+
width: 26px;
|
|
2579
|
+
height: 26px;
|
|
2580
|
+
border-radius: 7px;
|
|
2581
|
+
border: none;
|
|
2582
|
+
cursor: pointer;
|
|
2583
|
+
padding: 0;
|
|
2584
|
+
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.18);
|
|
2585
|
+
}
|
|
2586
|
+
.sf-swatch.is-active {
|
|
2587
|
+
box-shadow: 0 0 0 2px var(--sf-panel), 0 0 0 4px var(--sf-accent);
|
|
2588
|
+
}
|
|
2589
|
+
.sf-swatch-hex {
|
|
2590
|
+
font-size: 11px;
|
|
2591
|
+
color: var(--sf-muted);
|
|
2592
|
+
font-variant-numeric: tabular-nums;
|
|
2593
|
+
margin-left: 2px;
|
|
2594
|
+
}
|
|
2595
|
+
|
|
2596
|
+
/* ── THE colour control — efficient-easel's `ColourPicker` (blueprint 4.8) ──
|
|
2597
|
+
One swatch, one typeable hex, and — pressing the swatch — the package's own
|
|
2598
|
+
window under the row: the site's theme colours, a saturation square, a hue
|
|
2599
|
+
strip and the hex. Its look is `efficient-easel/pick.css`; what is here is
|
|
2600
|
+
only how the shop's rows hold it. There used to be two colour controls in
|
|
2601
|
+
this file's rows, then one on `<input type="color">`, whose window was the
|
|
2602
|
+
operating system's. See lib/puck/ColourControl.tsx.
|
|
2603
|
+
|
|
2604
|
+
THE ROW HOLDS THE PICKER IN ITS LABEL LINE — `SettingsField`'s `action`
|
|
2605
|
+
slot (`colorInput()` too, since [MERGE] One Settings Row And Hint) — so the picker's own box steps aside
|
|
2606
|
+
(`display: contents`) and its two halves become items of that line: the
|
|
2607
|
+
swatch and hex stay at the end of the label line (`margin-left: auto`, which
|
|
2608
|
+
the shell gives `.es-field-value` and nothing else), and the window wraps
|
|
2609
|
+
onto a line of its own at the row's FULL width. Left inside the picker's box
|
|
2610
|
+
it would open in the few pixels the action slot has. */
|
|
2611
|
+
.es-field-head:has(> .es-pick-colour) {
|
|
2612
|
+
flex-wrap: wrap;
|
|
2613
|
+
}
|
|
2614
|
+
.es-field-head > .es-pick-colour {
|
|
2615
|
+
display: contents;
|
|
2616
|
+
}
|
|
2617
|
+
.es-field-head > .es-pick-colour > .es-pick-colour-row {
|
|
2618
|
+
margin-left: auto;
|
|
2619
|
+
}
|
|
2620
|
+
.es-field-head > .es-pick-colour > .es-pick-window {
|
|
2621
|
+
flex: 1 0 100%;
|
|
2622
|
+
min-width: 0;
|
|
2623
|
+
/* LAST on the line, whatever follows it in the markup: the row's Default /
|
|
2624
|
+
Reset part (easel's `SettingsDefaultReset`, owner 2026-10-06) comes after
|
|
2625
|
+
the picker, and without this an open window pushed Reset onto a line of
|
|
2626
|
+
its own UNDER the window, away from the swatch it belongs beside. */
|
|
2627
|
+
order: 1;
|
|
2628
|
+
}
|
|
2629
|
+
|
|
2630
|
+
/* ⚠️ THE HEX BOX MUST OUT-SPECIFY THE SHARED INSPECTOR INPUT. `.sf-insp-body
|
|
2631
|
+
input[type="text"]` (0,2,1) is `width: 100%`, `padding: 8px 11px`,
|
|
2632
|
+
`font-size: 13px` — a full-width form field — and it beats the package's
|
|
2633
|
+
one-class rule. Inherited here it would eat the row and shove the swatch out
|
|
2634
|
+
of it, and at 13px `#DDDDDD` rendered `#DDDDD`, one digit short, on a control
|
|
2635
|
+
whose whole job is to show a hex exactly (the 2026-09-04 drawing). So EVERY
|
|
2636
|
+
property the shared rule sets is restated, at the package's own values, on
|
|
2637
|
+
a selector that wins on specificity (0,3,1) and not on source order. */
|
|
2638
|
+
.sf-insp-body input[type="text"].es-pick-hex {
|
|
2639
|
+
width: var(--es-pick-readout-w);
|
|
2640
|
+
border: 1px solid transparent;
|
|
2641
|
+
background: transparent;
|
|
2642
|
+
border-radius: 6px;
|
|
2643
|
+
padding: 4px 6px;
|
|
2644
|
+
font-size: 12px;
|
|
2645
|
+
color: var(--es-text);
|
|
2646
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
2647
|
+
flex: none;
|
|
2648
|
+
}
|
|
2649
|
+
.sf-insp-body input[type="text"].es-pick-hex:hover {
|
|
2650
|
+
border-color: var(--es-input-border);
|
|
2651
|
+
}
|
|
2652
|
+
.sf-insp-body input[type="text"].es-pick-hex:focus {
|
|
2653
|
+
outline: none;
|
|
2654
|
+
border-color: var(--es-accent);
|
|
2655
|
+
box-shadow: none;
|
|
2656
|
+
background: var(--es-panel);
|
|
2657
|
+
}
|
|
2658
|
+
|
|
2659
|
+
|
|
2660
|
+
/* ── Site styles' own controls (card 66148) ───────────────────────────────────
|
|
2661
|
+
These three shapes -- a dropdown, a strip of choice rungs, and the small text
|
|
2662
|
+
around them -- were spelled out in raw Tailwind `zinc-*` inside ThemeField,
|
|
2663
|
+
TypeGroupsField and CornersField, and never read a token.
|
|
2664
|
+
|
|
2665
|
+
⚠️ `zinc` and `gray` ARE NOT THE SAME RAMP, which is what made this invisible
|
|
2666
|
+
for so long: every pair is close enough to look deliberate and none of them
|
|
2667
|
+
match. Measured in this project (Tailwind v4, no config override), resolved
|
|
2668
|
+
through a canvas because v4 emits lab():
|
|
2669
|
+
|
|
2670
|
+
border zinc-300 #d4d4d8 --sf-input-border #d1d5db
|
|
2671
|
+
menu zinc-200 #e4e4e7 --sf-divider #e5e7eb
|
|
2672
|
+
quiet zinc-400 #9f9fa9 --sf-disabled #9ca3af
|
|
2673
|
+
hint zinc-500 #71717b --sf-muted #6b7280
|
|
2674
|
+
text zinc-800 #27272a --sf-field-text #1f2937
|
|
2675
|
+
loud zinc-900 #18181b --sf-text #111827
|
|
2676
|
+
ground zinc-100 #f4f4f5 --sf-chip-bg #f3f4f6
|
|
2677
|
+
|
|
2678
|
+
So the panel ran two neutral ramps as well as two spacings, and along the same
|
|
2679
|
+
boundary. These classes put every one of them on the panel's own tokens, which
|
|
2680
|
+
alias the shell's -- the alias block at the top of this file is untouched.
|
|
2681
|
+
|
|
2682
|
+
They are CLASSES, not a copy per component, because the dropdown was written
|
|
2683
|
+
twice (ThemeField's preset picker, TypeGroupsField's font picker) and the rung
|
|
2684
|
+
strip three times (Corners, Capitals, Spacing). Same markup, same colours,
|
|
2685
|
+
three chances to drift. */
|
|
2686
|
+
|
|
2687
|
+
/* The dropdown: a full-width button that opens a menu under itself. */
|
|
2688
|
+
.sf-chooser {
|
|
2689
|
+
display: flex;
|
|
2690
|
+
width: 100%;
|
|
2691
|
+
align-items: center;
|
|
2692
|
+
gap: 8px;
|
|
2693
|
+
padding: 6px 10px;
|
|
2694
|
+
border: 1px solid var(--sf-input-border);
|
|
2695
|
+
border-radius: var(--sf-field-radius);
|
|
2696
|
+
background: var(--sf-field-bg);
|
|
2697
|
+
color: var(--sf-field-text);
|
|
2698
|
+
font-size: 13px;
|
|
2699
|
+
text-align: left;
|
|
2700
|
+
cursor: pointer;
|
|
2701
|
+
}
|
|
2702
|
+
.sf-chooser:hover {
|
|
2703
|
+
background: var(--sf-hover);
|
|
2704
|
+
}
|
|
2705
|
+
/* The chosen thing's name. Clips rather than wraps: a long font name must not
|
|
2706
|
+
push the category and the caret off the end of a 288px row. */
|
|
2707
|
+
.sf-chooser-name {
|
|
2708
|
+
flex: 1;
|
|
2709
|
+
min-width: 0;
|
|
2710
|
+
overflow: hidden;
|
|
2711
|
+
text-overflow: ellipsis;
|
|
2712
|
+
white-space: nowrap;
|
|
2713
|
+
}
|
|
2714
|
+
/* SANS / SERIF / MONO beside a font's name -- a classification, not the value,
|
|
2715
|
+
so it reads quieter than everything else on the row. */
|
|
2716
|
+
.sf-chooser-meta {
|
|
2717
|
+
flex: none;
|
|
2718
|
+
font-size: 10px;
|
|
2719
|
+
text-transform: uppercase;
|
|
2720
|
+
letter-spacing: 0.05em;
|
|
2721
|
+
color: var(--sf-disabled);
|
|
2722
|
+
}
|
|
2723
|
+
.sf-chooser-caret {
|
|
2724
|
+
flex: none;
|
|
2725
|
+
color: var(--sf-disabled);
|
|
2726
|
+
}
|
|
2727
|
+
.sf-chooser-menu {
|
|
2728
|
+
position: absolute;
|
|
2729
|
+
left: 0;
|
|
2730
|
+
z-index: 50;
|
|
2731
|
+
margin-top: 4px;
|
|
2732
|
+
width: 100%;
|
|
2733
|
+
overflow: hidden;
|
|
2734
|
+
padding: 4px 0;
|
|
2735
|
+
border: 1px solid var(--sf-divider);
|
|
2736
|
+
border-radius: var(--sf-field-radius);
|
|
2737
|
+
background: var(--sf-panel);
|
|
2738
|
+
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
|
|
2739
|
+
}
|
|
2740
|
+
/* The font menu is long enough to need its own ceiling; the theme menu is not. */
|
|
2741
|
+
.sf-chooser-menu--tall {
|
|
2742
|
+
max-height: 256px;
|
|
2743
|
+
overflow: hidden auto;
|
|
2744
|
+
}
|
|
2745
|
+
.sf-chooser-item {
|
|
2746
|
+
display: flex;
|
|
2747
|
+
width: 100%;
|
|
2748
|
+
align-items: center;
|
|
2749
|
+
gap: 8px;
|
|
2750
|
+
padding: 6px 10px;
|
|
2751
|
+
border: 0;
|
|
2752
|
+
background: none;
|
|
2753
|
+
text-align: left;
|
|
2754
|
+
font-size: 13px;
|
|
2755
|
+
color: var(--sf-text-secondary);
|
|
2756
|
+
cursor: pointer;
|
|
2757
|
+
}
|
|
2758
|
+
.sf-chooser-item:hover {
|
|
2759
|
+
background: var(--sf-hover);
|
|
2760
|
+
}
|
|
2761
|
+
.sf-chooser-item.is-active {
|
|
2762
|
+
font-weight: 600;
|
|
2763
|
+
color: var(--sf-text);
|
|
2764
|
+
}
|
|
2765
|
+
/* "Add new theme" -- an action rather than a choice, so it takes the accent.
|
|
2766
|
+
That colour is the whole signal now (card 66334 removed the rule that used to
|
|
2767
|
+
sit above it). `--sf-accent-text` and not `--sf-accent`: the shell keeps a
|
|
2768
|
+
darker variant for accent-coloured TEXT, which is what this is. */
|
|
2769
|
+
.sf-chooser-add {
|
|
2770
|
+
color: var(--sf-accent-text);
|
|
2771
|
+
font-weight: 500;
|
|
2772
|
+
}
|
|
2773
|
+
.sf-chooser-add:hover {
|
|
2774
|
+
background: var(--sf-hover);
|
|
2775
|
+
}
|
|
2776
|
+
|
|
2777
|
+
/* The choice rungs: two or three buttons in a row, one of them held down.
|
|
2778
|
+
|
|
2779
|
+
⏳ LEAVING. Every pick-one row draws efficient-easel's SettingsSegmented since
|
|
2780
|
+
[MERGE] One Pick-One Control (2026-10-06); only TextStylesField still draws
|
|
2781
|
+
this strip, because the S2 card owns that file, and `.sf-rung` alone is the
|
|
2782
|
+
hints switch's base. `test-segmented-controls` §8 stops a new strip. Delete
|
|
2783
|
+
these rules when the last of those two moves.
|
|
2784
|
+
|
|
2785
|
+
`--sf-disabled` on the pressed border is not a disabled state -- it is the one
|
|
2786
|
+
token on the gray ramp that lands where `zinc-400` did, a mid-grey a step
|
|
2787
|
+
darker than a field border. */
|
|
2788
|
+
.sf-rungs {
|
|
2789
|
+
display: flex;
|
|
2790
|
+
width: 100%;
|
|
2791
|
+
gap: 4px;
|
|
2792
|
+
}
|
|
2793
|
+
.sf-rung {
|
|
2794
|
+
flex: 1;
|
|
2795
|
+
padding: 4px 8px;
|
|
2796
|
+
border: 1px solid var(--sf-input-border);
|
|
2797
|
+
border-radius: var(--sf-field-radius);
|
|
2798
|
+
background: var(--sf-field-bg);
|
|
2799
|
+
color: var(--sf-text-secondary);
|
|
2800
|
+
font-size: 12px;
|
|
2801
|
+
cursor: pointer;
|
|
2802
|
+
}
|
|
2803
|
+
.sf-rung:hover:not(.is-active) {
|
|
2804
|
+
background: var(--sf-hover);
|
|
2805
|
+
}
|
|
2806
|
+
.sf-rung.is-active {
|
|
2807
|
+
border-color: var(--sf-disabled);
|
|
2808
|
+
background: var(--sf-chip-bg);
|
|
2809
|
+
color: var(--sf-text);
|
|
2810
|
+
font-weight: 600;
|
|
2811
|
+
}
|
|
2812
|
+
/* The Card shadow miniature: a tiny card showing the shadow each option casts,
|
|
2813
|
+
drawn in the package's segmented-control glyph slot beside the word (it was
|
|
2814
|
+
`.sf-rung-chip` in the hand-built `.sf-rung--inline` strip until [MERGE] One
|
|
2815
|
+
Pick-One Control, 2026-10-06). Its shadow is set inline, per option, because
|
|
2816
|
+
that IS what the option is showing.
|
|
2817
|
+
|
|
2818
|
+
16px wide to sit inside the slot (`--es-chip-icon`). Small, but it only has
|
|
2819
|
+
to answer "none, a little, or a lot", and the 1px border keeps all three
|
|
2820
|
+
legible at this size. */
|
|
2821
|
+
.sf-shadow-chip {
|
|
2822
|
+
display: block;
|
|
2823
|
+
flex: none;
|
|
2824
|
+
box-sizing: border-box;
|
|
2825
|
+
width: 16px;
|
|
2826
|
+
height: 11px;
|
|
2827
|
+
border: 1px solid var(--sf-disabled);
|
|
2828
|
+
background: var(--sf-field-bg);
|
|
2829
|
+
}
|
|
2830
|
+
|
|
2831
|
+
/* The one control that folds the Basics tab's five explanations (card 66177).
|
|
2832
|
+
It sits at the FOOT of the tab, under the last row's own separation, and it
|
|
2833
|
+
is deliberately quiet: it is chrome about the panel, not one of the
|
|
2834
|
+
merchant's settings, so it must not read as loudly as the rows above it. */
|
|
2835
|
+
.sf-hints {
|
|
2836
|
+
display: flex;
|
|
2837
|
+
margin-top: 28px;
|
|
2838
|
+
}
|
|
2839
|
+
/* A rung that is not part of a strip: it sizes to its own word rather than
|
|
2840
|
+
sharing a row, so the `flex: 1` every rung takes has to come back off. */
|
|
2841
|
+
.sf-hints-toggle {
|
|
2842
|
+
display: inline-flex;
|
|
2843
|
+
flex: none;
|
|
2844
|
+
align-items: center;
|
|
2845
|
+
gap: 5px;
|
|
2846
|
+
color: var(--sf-muted);
|
|
2847
|
+
}
|
|
2848
|
+
.sf-hints-toggle svg {
|
|
2849
|
+
flex: none;
|
|
2850
|
+
}
|
|
2851
|
+
|
|
2852
|
+
/* A heading INSIDE one control, below the row's own label: "Dark surfaces",
|
|
2853
|
+
"Light surfaces". Deliberately not `.sf-field-group`, which heads a group of
|
|
2854
|
+
settings -- these head a group of colours inside ONE setting. */
|
|
2855
|
+
/* ⛔ `.sf-subgroup` LIVED HERE AND IS GONE (2026-09-04). It was this panel's
|
|
2856
|
+
hand-rolled group heading, and the shell has shipped `SettingsGroupSub` all
|
|
2857
|
+
along — the theme sheet draws that now, so nothing renders this class. It is
|
|
2858
|
+
deleted rather than left: a rule nobody paints is the shape `ss.focal-dead-css`
|
|
2859
|
+
was a whole card to clean up, and the next person reading it would take it for
|
|
2860
|
+
the panel's heading and match the wrong thing.
|
|
2861
|
+
|
|
2862
|
+
⚠️ ITS ABSENCE IS THE FIX, not tidiness. It declared a font and NO MARGIN, so
|
|
2863
|
+
the heading took whatever air happened to be there — which is why `SURFACES`
|
|
2864
|
+
sat against the row above it — and card 1103's module rule keys on
|
|
2865
|
+
`.es-group-sub`, so a heading wearing this name could never draw the line
|
|
2866
|
+
between two modules. */
|
|
2867
|
+
/* The small and large A flanking a size slider. */
|
|
2868
|
+
.sf-scale-a {
|
|
2869
|
+
flex: none;
|
|
2870
|
+
font-size: 11px;
|
|
2871
|
+
line-height: 1;
|
|
2872
|
+
color: var(--sf-disabled);
|
|
2873
|
+
}
|
|
2874
|
+
.sf-scale-a--lg {
|
|
2875
|
+
font-size: 15px;
|
|
2876
|
+
color: var(--sf-muted);
|
|
2877
|
+
}
|
|
2878
|
+
/* The "Auto" button that clears an optional number back to the built-in. */
|
|
2879
|
+
.sf-auto-reset {
|
|
2880
|
+
padding: 2px 6px;
|
|
2881
|
+
border: 1px solid var(--sf-input-border);
|
|
2882
|
+
border-radius: var(--sf-field-radius);
|
|
2883
|
+
background: var(--sf-field-bg);
|
|
2884
|
+
font-size: 11px;
|
|
2885
|
+
color: var(--sf-text-secondary);
|
|
2886
|
+
cursor: pointer;
|
|
2887
|
+
}
|
|
2888
|
+
.sf-auto-reset:hover {
|
|
2889
|
+
background: var(--sf-hover);
|
|
2890
|
+
}
|
|
2891
|
+
/* ─── The Text list (card 66162) ──────────────────────────────────────────
|
|
2892
|
+
ONE list of text styles, one row per font role. Rows are separated by a rule
|
|
2893
|
+
rather than boxed: the old three groups were cards, and four cards in a 288px
|
|
2894
|
+
panel spend more of it on borders than on settings. */
|
|
2895
|
+
/* ── SITE STYLES: THE SAME AIR UNDER THE TAB STRIP, IN EVERY TAB ───────────
|
|
2896
|
+
Lewis, 2026-09-04, on SHARPEN, unprompted: Basics and Theme have a band of
|
|
2897
|
+
space above their first row and Text has none — why is it not uniform?
|
|
2898
|
+
|
|
2899
|
+
MEASURED at the left panel's real 288px, before anything changed:
|
|
2900
|
+
|
|
2901
|
+
Basics 38px first element is `CornersField` → the shell's `.es-field`
|
|
2902
|
+
Theme 38px first element is a `.es-field` too
|
|
2903
|
+
Text 0px first element is `.sf-style-list`, which states no margin
|
|
2904
|
+
|
|
2905
|
+
NOBODY DECIDED EITHER NUMBER, and that is the whole finding. `.es-field`'s
|
|
2906
|
+
38 is `--es-rhythm-between` — the gap BETWEEN two settings. The first row has
|
|
2907
|
+
nothing above it, so that rule is spending a between-rows gap on a boundary
|
|
2908
|
+
it was never measured against; and the Text tab simply has no rule at all.
|
|
2909
|
+
Two tabs are wrong in one direction, the third in the other, and no line
|
|
2910
|
+
anywhere said what the air under the strip should be.
|
|
2911
|
+
|
|
2912
|
+
⚠️ NOT CAUSED BY THE PANEL-SPACING CARD. Checked rather than assumed: the
|
|
2913
|
+
same three tabs measure 38 / 38 / 0 on `ad353cf60`, the commit before that
|
|
2914
|
+
card's three PRs. Those changed `.sf-field` and Puck's field wrappers; this
|
|
2915
|
+
panel draws the shell's `.es-field`, whose 38 has stood since card 66301 —
|
|
2916
|
+
the owner's own re-scale on 2026-08-31.
|
|
2917
|
+
|
|
2918
|
+
`--es-rhythm-group-first` IS THE NAME THIS ALREADY HAD. It means "a boundary
|
|
2919
|
+
to the first thing under it", which is exactly what the tab strip is. Not a
|
|
2920
|
+
new number, and not the nearest number picked for its arithmetic: 24 is
|
|
2921
|
+
tighter than 38, which is the direction the owner asked for, and it is not 0,
|
|
2922
|
+
which reads as the first row having fallen through the strip.
|
|
2923
|
+
|
|
2924
|
+
ON THE TAB PANEL'S FIRST CHILD, whatever that child is. A rule per tab would
|
|
2925
|
+
be three statements of one fact, and would go stale the first time a tab's
|
|
2926
|
+
opening control changes — which is precisely how these three drifted apart. */
|
|
2927
|
+
#sf-site-styles-tabpanel > :first-child {
|
|
2928
|
+
margin-top: var(--es-rhythm-group-first);
|
|
2929
|
+
}
|
|
2930
|
+
|
|
2931
|
+
.sf-style-list {
|
|
2932
|
+
display: flex;
|
|
2933
|
+
flex-direction: column;
|
|
2934
|
+
}
|
|
2935
|
+
/* The whole row is the control -- there is no Edit button, because the row's
|
|
2936
|
+
own name is what a merchant points at.
|
|
2937
|
+
|
|
2938
|
+
⚠️ `center`, NOT `baseline` (card 66177). The row used to hold one word; it
|
|
2939
|
+
now holds a chevron, a name and a readout drawn at that style's own size, and
|
|
2940
|
+
sitting a 15px readout on the same baseline as an 11px name tips the whole
|
|
2941
|
+
line. */
|
|
2942
|
+
.sf-style-head {
|
|
2943
|
+
display: flex;
|
|
2944
|
+
width: 100%;
|
|
2945
|
+
align-items: center;
|
|
2946
|
+
gap: 8px;
|
|
2947
|
+
padding: 10px 0;
|
|
2948
|
+
background: none;
|
|
2949
|
+
border: 0;
|
|
2950
|
+
text-align: left;
|
|
2951
|
+
cursor: pointer;
|
|
2952
|
+
}
|
|
2953
|
+
.sf-style-head:hover .sf-style-sample {
|
|
2954
|
+
color: var(--sf-text);
|
|
2955
|
+
}
|
|
2956
|
+
/* The visible sign that a row opens (card 66177): `aria-expanded` had said so
|
|
2957
|
+
to a screen reader since 66162, and nothing had said it to an eye. One glyph,
|
|
2958
|
+
turned a quarter when the row is open. */
|
|
2959
|
+
.sf-style-caret {
|
|
2960
|
+
display: inline-flex;
|
|
2961
|
+
flex: none;
|
|
2962
|
+
align-items: center;
|
|
2963
|
+
color: var(--sf-disabled);
|
|
2964
|
+
transition: transform 120ms ease;
|
|
2965
|
+
}
|
|
2966
|
+
.sf-style-row.is-open .sf-style-caret {
|
|
2967
|
+
transform: rotate(90deg);
|
|
2968
|
+
}
|
|
2969
|
+
/* The style's NAME, in the panel's own label type -- the same 11px/600 quiet
|
|
2970
|
+
word every `SettingsField` on the other two tabs wears, so a merchant moving
|
|
2971
|
+
between tabs does not have to learn how to read a second kind of row. */
|
|
2972
|
+
.sf-style-name {
|
|
2973
|
+
flex: none;
|
|
2974
|
+
font-size: 11px;
|
|
2975
|
+
font-weight: 600;
|
|
2976
|
+
color: var(--sf-muted);
|
|
2977
|
+
}
|
|
2978
|
+
/* The row's READOUT -- the face it is set in, named, and drawn in itself.
|
|
2979
|
+
Everything about how it looks is inline, per row, because that IS what the
|
|
2980
|
+
row is showing; the only things the stylesheet may decide here are where it
|
|
2981
|
+
sits, its colour and its overflow.
|
|
2982
|
+
|
|
2983
|
+
`margin-left: auto` puts it at the end of the line, which is where every
|
|
2984
|
+
other row in this panel carries its value (`.es-field-value` does the same).
|
|
2985
|
+
A long face name ellipses rather than pushing the tick off the row. */
|
|
2986
|
+
.sf-style-sample {
|
|
2987
|
+
min-width: 0;
|
|
2988
|
+
margin-left: auto;
|
|
2989
|
+
overflow: hidden;
|
|
2990
|
+
color: var(--sf-text);
|
|
2991
|
+
text-overflow: ellipsis;
|
|
2992
|
+
white-space: nowrap;
|
|
2993
|
+
}
|
|
2994
|
+
/* Where Done used to sit. The editor autosaves, so the thing to say here is
|
|
2995
|
+
"stored", and it says it once and goes quiet again. */
|
|
2996
|
+
.sf-style-slot {
|
|
2997
|
+
display: inline-flex;
|
|
2998
|
+
flex: none;
|
|
2999
|
+
width: 14px;
|
|
3000
|
+
height: 14px;
|
|
3001
|
+
align-items: center;
|
|
3002
|
+
justify-content: center;
|
|
3003
|
+
/* Quiet ink, not green — and the REASON is the panel, not the palette.
|
|
3004
|
+
|
|
3005
|
+
⚠️ THIS NOTE USED TO SAY THE SHARED LAYER HAS NO GREEN. That was WRONG:
|
|
3006
|
+
`--es-success` has shipped in editor-shell since card 8802.g, and the top
|
|
3007
|
+
bar's saved dot (editor-shell's `.es-savestate.is-saved`) wears it. The rule that
|
|
3008
|
+
is real and still binding is the other half — a shop-LOCAL green would be a
|
|
3009
|
+
second source for a design-system colour (doc/editor-ui.md E2, enforced by
|
|
3010
|
+
scripts/test-inspector-inherit.tsx). Take the token; never invent the value.
|
|
3011
|
+
|
|
3012
|
+
So this tick stays muted because of WHERE it is. It sits at the end of a
|
|
3013
|
+
settings row, inches from the Reset button, which is already an accent-blue
|
|
3014
|
+
mark on the same line; a second coloured mark beside it would read as a
|
|
3015
|
+
second thing to act on. The top bar has no such neighbour — its dot is the
|
|
3016
|
+
only mark in the corner — which is why the same idea is allowed a colour
|
|
3017
|
+
there and not here. Card 66103 is not the reason: it settled the WORD. */
|
|
3018
|
+
color: var(--sf-muted);
|
|
3019
|
+
opacity: 0;
|
|
3020
|
+
transform: scale(0.6);
|
|
3021
|
+
transition: opacity 160ms ease, transform 160ms ease;
|
|
3022
|
+
}
|
|
3023
|
+
.sf-style-slot.is-saved {
|
|
3024
|
+
opacity: 1;
|
|
3025
|
+
transform: scale(1);
|
|
3026
|
+
}
|
|
3027
|
+
@media (prefers-reduced-motion: reduce) {
|
|
3028
|
+
.sf-style-slot {
|
|
3029
|
+
transition: none;
|
|
3030
|
+
}
|
|
3031
|
+
}
|
|
3032
|
+
/* The settings under an open row. */
|
|
3033
|
+
.sf-style-body {
|
|
3034
|
+
padding: 2px 0 12px;
|
|
3035
|
+
}
|
|
3036
|
+
/* The face picker -- a native select, so the platform draws the list, the
|
|
3037
|
+
keyboard works and a phone gets its own wheel. */
|
|
3038
|
+
.sf-select {
|
|
3039
|
+
padding: 5px 8px;
|
|
3040
|
+
border: 1px solid var(--sf-input-border);
|
|
3041
|
+
border-radius: var(--sf-field-radius);
|
|
3042
|
+
background: var(--sf-field-bg);
|
|
3043
|
+
color: var(--sf-text);
|
|
3044
|
+
font-size: 12px;
|
|
3045
|
+
cursor: pointer;
|
|
3046
|
+
}
|
|
3047
|
+
/* A rung showing a LETTERFORM rather than a word -- the B and the I. It is the
|
|
3048
|
+
letter's own shape that carries the meaning, so it is sized to be read as a
|
|
3049
|
+
glyph and it keeps its accessible name in `aria-label`. */
|
|
3050
|
+
.sf-rung--glyph {
|
|
3051
|
+
flex: 0 0 34px;
|
|
3052
|
+
font-size: 13px;
|
|
3053
|
+
line-height: 18px;
|
|
3054
|
+
text-align: center;
|
|
3055
|
+
}
|
|
3056
|
+
.sf-rung--glyph:disabled {
|
|
3057
|
+
color: var(--sf-disabled);
|
|
3058
|
+
cursor: not-allowed;
|
|
3059
|
+
}
|
|
3060
|
+
.sf-rung--glyph:disabled:hover {
|
|
3061
|
+
background: var(--sf-field-bg);
|
|
3062
|
+
}
|
|
3063
|
+
/* One theme's swatch in the preset dropdown, and one colour row's chip. */
|
|
3064
|
+
/* ── The theme list: one card per theme, each a small page in its own palette ──
|
|
3065
|
+
Card 66304. Sized against the RIGHT panel's real widths — 320px default and
|
|
3066
|
+
220px the narrowest a merchant can drag to (components/panel-widths.ts). The
|
|
3067
|
+
approved drawing says 288px six times; 288 is the LEFT panel's default and
|
|
3068
|
+
this control never opens at it, so every measurement below was re-derived
|
|
3069
|
+
rather than inherited.
|
|
3070
|
+
|
|
3071
|
+
The OUTER spacing is the shell's — `--es-rhythm-*`, shipped in editor-shell
|
|
3072
|
+
0.22.0 — so this list sits in the panel's rhythm rather than a hand-tuned one.
|
|
3073
|
+
The spacing INSIDE a card is the preview's own: it is a picture of a web page,
|
|
3074
|
+
not a run of settings, and the panel's row rhythm would be the wrong ruler. */
|
|
3075
|
+
.sf-theme-list {
|
|
3076
|
+
display: flex;
|
|
3077
|
+
flex-direction: column;
|
|
3078
|
+
gap: 8px;
|
|
3079
|
+
margin-top: max(var(--es-row-gap), var(--es-rhythm-group-first));
|
|
3080
|
+
}
|
|
3081
|
+
|
|
3082
|
+
/* ⚠️ THE CLOSED TRIGGER WEARS THIS FRAME TOO (`.sf-secttheme-btn`), rather than
|
|
3083
|
+
a second frame with the same numbers in it. It is the same card — one open in
|
|
3084
|
+
a list, one shut in a row — so the border, the radius and the clip are
|
|
3085
|
+
declared once and both wear them. Only what is genuinely different about a
|
|
3086
|
+
BUTTON (its resets, its focus ring) is written under its own name below. */
|
|
3087
|
+
.sf-theme-card,
|
|
3088
|
+
.sf-secttheme-btn {
|
|
3089
|
+
border: 1px solid var(--sf-input-border);
|
|
3090
|
+
border-radius: 9px;
|
|
3091
|
+
overflow: hidden;
|
|
3092
|
+
background: var(--sf-panel);
|
|
3093
|
+
}
|
|
3094
|
+
.sf-theme-card:hover,
|
|
3095
|
+
.sf-secttheme-btn:hover { border-color: var(--sf-muted); }
|
|
3096
|
+
/* The ring says WHICH theme is live. Colour alone would not: `aria-checked` on
|
|
3097
|
+
the radio carries the same fact for a screen reader. */
|
|
3098
|
+
.sf-theme-card.is-selected {
|
|
3099
|
+
border-color: var(--sf-accent);
|
|
3100
|
+
box-shadow: 0 0 0 2px var(--sf-accent-ring);
|
|
3101
|
+
}
|
|
3102
|
+
|
|
3103
|
+
.sf-theme-pick {
|
|
3104
|
+
display: block;
|
|
3105
|
+
width: 100%;
|
|
3106
|
+
padding: 0;
|
|
3107
|
+
border: 0;
|
|
3108
|
+
background: none;
|
|
3109
|
+
font: inherit;
|
|
3110
|
+
text-align: left;
|
|
3111
|
+
cursor: pointer;
|
|
3112
|
+
}
|
|
3113
|
+
|
|
3114
|
+
/* ── The preview itself: a page, drawn in the theme's own colours ───────────
|
|
3115
|
+
Every length here is fixed rather than relative, and deliberately: this is a
|
|
3116
|
+
picture of a page at a small size, so the type scale is the drawing's own and
|
|
3117
|
+
must not follow the panel's. It stays legible at 220px because nothing in it
|
|
3118
|
+
wraps — the one line that could is clipped. */
|
|
3119
|
+
.sf-theme-page {
|
|
3120
|
+
display: flex;
|
|
3121
|
+
flex-direction: column;
|
|
3122
|
+
gap: 4px;
|
|
3123
|
+
padding: 10px 12px;
|
|
3124
|
+
}
|
|
3125
|
+
.sf-theme-eyebrow {
|
|
3126
|
+
font-size: 7.5px;
|
|
3127
|
+
font-weight: 700;
|
|
3128
|
+
letter-spacing: 0.14em;
|
|
3129
|
+
text-transform: uppercase;
|
|
3130
|
+
line-height: 1;
|
|
3131
|
+
}
|
|
3132
|
+
.sf-theme-headline {
|
|
3133
|
+
font-size: 14px;
|
|
3134
|
+
font-weight: 750;
|
|
3135
|
+
letter-spacing: -0.01em;
|
|
3136
|
+
line-height: 1.1;
|
|
3137
|
+
}
|
|
3138
|
+
.sf-theme-body {
|
|
3139
|
+
font-size: 9.5px;
|
|
3140
|
+
line-height: 1.4;
|
|
3141
|
+
opacity: 0.9;
|
|
3142
|
+
/* One line, clipped. A preview that wraps changes height with its own words
|
|
3143
|
+
and the list stops being a set of comparable cards. */
|
|
3144
|
+
white-space: nowrap;
|
|
3145
|
+
overflow: hidden;
|
|
3146
|
+
text-overflow: ellipsis;
|
|
3147
|
+
}
|
|
3148
|
+
.sf-theme-row {
|
|
3149
|
+
display: flex;
|
|
3150
|
+
align-items: center;
|
|
3151
|
+
gap: 7px;
|
|
3152
|
+
margin-top: 1px;
|
|
3153
|
+
}
|
|
3154
|
+
.sf-theme-btn {
|
|
3155
|
+
font-size: 8.5px;
|
|
3156
|
+
font-weight: 700;
|
|
3157
|
+
letter-spacing: 0.02em;
|
|
3158
|
+
padding: 5px 11px;
|
|
3159
|
+
border-radius: 4px;
|
|
3160
|
+
white-space: nowrap;
|
|
3161
|
+
flex: none;
|
|
3162
|
+
}
|
|
3163
|
+
.sf-theme-mini {
|
|
3164
|
+
flex: 1;
|
|
3165
|
+
min-width: 0;
|
|
3166
|
+
height: 22px;
|
|
3167
|
+
border-radius: 3px;
|
|
3168
|
+
border: 1px solid;
|
|
3169
|
+
display: flex;
|
|
3170
|
+
align-items: center;
|
|
3171
|
+
justify-content: center;
|
|
3172
|
+
font-size: 7.5px;
|
|
3173
|
+
font-weight: 600;
|
|
3174
|
+
opacity: 0.75;
|
|
3175
|
+
}
|
|
3176
|
+
|
|
3177
|
+
/* ── The name strip: which theme this is, and the way into its colours ────── */
|
|
3178
|
+
.sf-theme-foot {
|
|
3179
|
+
display: flex;
|
|
3180
|
+
align-items: center;
|
|
3181
|
+
justify-content: space-between;
|
|
3182
|
+
gap: 8px;
|
|
3183
|
+
padding: 5px 8px 6px 12px;
|
|
3184
|
+
background: var(--sf-hover);
|
|
3185
|
+
}
|
|
3186
|
+
.sf-theme-card.is-selected .sf-theme-foot { color: var(--sf-accent-text); }
|
|
3187
|
+
.sf-theme-name {
|
|
3188
|
+
font-size: 11px;
|
|
3189
|
+
font-weight: 700;
|
|
3190
|
+
min-width: 0;
|
|
3191
|
+
overflow: hidden;
|
|
3192
|
+
text-overflow: ellipsis;
|
|
3193
|
+
white-space: nowrap;
|
|
3194
|
+
}
|
|
3195
|
+
/* The one sentence a card says when its content colour cannot be read on its own
|
|
3196
|
+
page. Amber rather than red: the theme still works, it is a warning about the
|
|
3197
|
+
colour a merchant chose, not a failure of the editor. It never carries a
|
|
3198
|
+
number — the ratio it was measured from stays out of the panel. */
|
|
3199
|
+
.sf-theme-warn {
|
|
3200
|
+
flex: none;
|
|
3201
|
+
margin-left: auto;
|
|
3202
|
+
font-size: 10px;
|
|
3203
|
+
font-weight: 700;
|
|
3204
|
+
color: #b45309;
|
|
3205
|
+
white-space: nowrap;
|
|
3206
|
+
}
|
|
3207
|
+
.sf-theme-warn + .sf-theme-edit { margin-left: 8px; }
|
|
3208
|
+
/* With no warning beside it the Edit still sits hard right. */
|
|
3209
|
+
.sf-theme-name { margin-right: auto; }
|
|
3210
|
+
|
|
3211
|
+
.sf-theme-edit {
|
|
3212
|
+
flex: none;
|
|
3213
|
+
border: 1px solid var(--sf-input-border);
|
|
3214
|
+
background: var(--sf-panel);
|
|
3215
|
+
border-radius: 4px;
|
|
3216
|
+
font: inherit;
|
|
3217
|
+
font-size: 10px;
|
|
3218
|
+
font-weight: 700;
|
|
3219
|
+
letter-spacing: 0.03em;
|
|
3220
|
+
color: var(--sf-text-secondary);
|
|
3221
|
+
padding: 3px 8px;
|
|
3222
|
+
line-height: 1.3;
|
|
3223
|
+
cursor: pointer;
|
|
3224
|
+
}
|
|
3225
|
+
.sf-theme-edit:hover { border-color: var(--sf-muted); color: var(--sf-text); }
|
|
3226
|
+
.sf-theme-edit.is-open {
|
|
3227
|
+
background: var(--sf-accent);
|
|
3228
|
+
border-color: var(--sf-accent);
|
|
3229
|
+
color: #fff;
|
|
3230
|
+
}
|
|
3231
|
+
|
|
3232
|
+
/* This theme's own colours, inside this theme's own card. The first row carries
|
|
3233
|
+
the shell's group-first rhythm so it clears the strip above it by the same
|
|
3234
|
+
distance a first setting clears any heading. */
|
|
3235
|
+
.sf-theme-colours { padding: 0 12px 12px; }
|
|
3236
|
+
.sf-theme-colours[hidden] { display: none; }
|
|
3237
|
+
.sf-theme-colours > .es-field:first-child { margin-top: var(--es-rhythm-group-first); }
|
|
3238
|
+
|
|
3239
|
+
.sf-theme-reset {
|
|
3240
|
+
width: 100%;
|
|
3241
|
+
margin-top: var(--es-rhythm-between-tight);
|
|
3242
|
+
border: 0;
|
|
3243
|
+
background: none;
|
|
3244
|
+
font: inherit;
|
|
3245
|
+
font-size: 10.5px;
|
|
3246
|
+
font-weight: 600;
|
|
3247
|
+
color: var(--sf-accent-text);
|
|
3248
|
+
padding: 0;
|
|
3249
|
+
cursor: pointer;
|
|
3250
|
+
text-align: left;
|
|
3251
|
+
}
|
|
3252
|
+
.sf-theme-reset:disabled { color: var(--sf-muted); cursor: default; }
|
|
3253
|
+
|
|
3254
|
+
.sf-theme-add {
|
|
3255
|
+
display: flex;
|
|
3256
|
+
align-items: center;
|
|
3257
|
+
gap: 6px;
|
|
3258
|
+
margin-top: 8px;
|
|
3259
|
+
border: 0;
|
|
3260
|
+
background: none;
|
|
3261
|
+
font: inherit;
|
|
3262
|
+
font-size: 12px;
|
|
3263
|
+
font-weight: 600;
|
|
3264
|
+
color: var(--sf-accent-text);
|
|
3265
|
+
padding: 4px 0;
|
|
3266
|
+
cursor: pointer;
|
|
3267
|
+
}
|
|
3268
|
+
.sf-theme-add:hover { text-decoration: underline; }
|
|
3269
|
+
|
|
3270
|
+
/* `.sf-ink-row` / `.sf-ink-hex` RETIRED — the second colour control.
|
|
3271
|
+
It drew Page settings' Background, the five rows a theme carries and Theme
|
|
3272
|
+
button colour, at 32x24 with a border and a monospaced hex, while
|
|
3273
|
+
`.sf-colorinput` drew the other seven rows at 26x26. Owner 2026-09-04 chose
|
|
3274
|
+
the 26x26 one and the two became one; every row those rules used to paint now
|
|
3275
|
+
draws the one colour control (efficient-easel's `ColourPicker` since
|
|
3276
|
+
blueprint 4.8, held by the rules above). */
|
|
3277
|
+
|
|
3278
|
+
/* ── Theme colour, one per mode (components/ThemeColourField.tsx) ─────────────
|
|
3279
|
+
Two colour rows joined by the link switch, then the readability line. The card
|
|
3280
|
+
around them is what says the three belong together: they are one decision. */
|
|
3281
|
+
.sf-colour-lede {
|
|
3282
|
+
margin-top: -3px;
|
|
3283
|
+
margin-bottom: 10px;
|
|
3284
|
+
}
|
|
3285
|
+
.sf-colour-pair {
|
|
3286
|
+
border: 1px solid var(--sf-divider);
|
|
3287
|
+
border-radius: var(--sf-row-radius);
|
|
3288
|
+
padding: 2px 11px 11px;
|
|
3289
|
+
background: var(--sf-app-bg);
|
|
3290
|
+
}
|
|
3291
|
+
/* The rows sit inside a card that already spaces them, so they set their own
|
|
3292
|
+
top margin rather than taking a second one from the panel's row class.
|
|
3293
|
+
Card 66148 moved the FLEX half here too: these three declarations came from
|
|
3294
|
+
`.sf-field--row`, the panel row class Site styles no longer draws, and a
|
|
3295
|
+
sub-row inside one setting's card has no business borrowing the class that
|
|
3296
|
+
sets the distance between two settings. Copied exactly — nothing moves. */
|
|
3297
|
+
.sf-colour-row {
|
|
3298
|
+
margin-top: 9px;
|
|
3299
|
+
display: flex;
|
|
3300
|
+
align-items: center;
|
|
3301
|
+
justify-content: space-between;
|
|
3302
|
+
gap: 12px;
|
|
3303
|
+
}
|
|
3304
|
+
/* The two mode names inside the colour card. They used to borrow their type
|
|
3305
|
+
from `.sf-field-label`, which is the class the whole panel stopped drawing in
|
|
3306
|
+
card 66148 — so the three declarations they actually used are written here,
|
|
3307
|
+
against the same token, and nothing moves. They stay 12px/500 rather than
|
|
3308
|
+
joining the shell's 11px/600 row label on purpose: these name a colour input
|
|
3309
|
+
INSIDE one setting, and reading as a quieter copy of the row above them is
|
|
3310
|
+
what said they were the same thing. */
|
|
3311
|
+
.sf-colour-mode {
|
|
3312
|
+
font-size: 12px;
|
|
3313
|
+
font-weight: 500;
|
|
3314
|
+
color: var(--sf-text-secondary);
|
|
3315
|
+
}
|
|
3316
|
+
.sf-colour-mode small {
|
|
3317
|
+
display: block;
|
|
3318
|
+
margin-top: 1px;
|
|
3319
|
+
font-size: 11px;
|
|
3320
|
+
font-weight: 400;
|
|
3321
|
+
color: var(--sf-muted);
|
|
3322
|
+
}
|
|
3323
|
+
|
|
3324
|
+
.sf-readability {
|
|
3325
|
+
margin-top: 10px;
|
|
3326
|
+
padding: 11px 12px 12px;
|
|
3327
|
+
border: 1px solid var(--sf-divider);
|
|
3328
|
+
border-radius: var(--sf-row-radius);
|
|
3329
|
+
}
|
|
3330
|
+
.sf-readability-head {
|
|
3331
|
+
margin-bottom: 7px;
|
|
3332
|
+
font-size: 10px;
|
|
3333
|
+
font-weight: 700;
|
|
3334
|
+
letter-spacing: 0.06em;
|
|
3335
|
+
text-transform: uppercase;
|
|
3336
|
+
color: var(--sf-muted);
|
|
3337
|
+
}
|
|
3338
|
+
.sf-readability-row {
|
|
3339
|
+
display: flex;
|
|
3340
|
+
align-items: center;
|
|
3341
|
+
gap: 9px;
|
|
3342
|
+
padding: 4px 0;
|
|
3343
|
+
font-size: 12px;
|
|
3344
|
+
}
|
|
3345
|
+
.sf-readability-who {
|
|
3346
|
+
flex: 1;
|
|
3347
|
+
color: var(--sf-text-secondary);
|
|
3348
|
+
}
|
|
3349
|
+
.sf-readability-dot {
|
|
3350
|
+
width: 8px;
|
|
3351
|
+
height: 8px;
|
|
3352
|
+
flex: none;
|
|
3353
|
+
border-radius: 50%;
|
|
3354
|
+
background: var(--sf-disabled);
|
|
3355
|
+
}
|
|
3356
|
+
/* No `tabular-nums` here, unlike the candidate buttons below: card 66204 took
|
|
3357
|
+
the ratio off this row and it prints a grade in words, so there are no digits
|
|
3358
|
+
left to line up. */
|
|
3359
|
+
.sf-readability-val {
|
|
3360
|
+
color: var(--sf-muted);
|
|
3361
|
+
}
|
|
3362
|
+
/* Grade, in colour AND in the words beside it — the dot summarises the label,
|
|
3363
|
+
it never carries the meaning on its own.
|
|
3364
|
+
TWO colours for three grades, deliberately. The shared --es-* layer carries
|
|
3365
|
+
danger and warning and no counterpart for "this reads fine", and a shop-local
|
|
3366
|
+
green would be a second source for a design-system colour (doc/editor-ui.md
|
|
3367
|
+
E2, enforced by scripts/test-inspector-inherit.tsx). It is also the better
|
|
3368
|
+
panel: a settings row that lights up green on every healthy value is noise,
|
|
3369
|
+
and the words already say which grade it is. So GOOD is drawn as an ordinary
|
|
3370
|
+
measurement in the panel's own ink, and only the two states that want the
|
|
3371
|
+
merchant's attention take a colour. */
|
|
3372
|
+
.sf-readability-dot.is-good { background: var(--sf-muted); }
|
|
3373
|
+
.sf-readability-dot.is-large-only { background: var(--sf-warning); }
|
|
3374
|
+
.sf-readability-dot.is-hard { background: var(--sf-danger); }
|
|
3375
|
+
.sf-readability-val.is-good { color: var(--sf-text-secondary); }
|
|
3376
|
+
.sf-readability-val.is-large-only { color: var(--sf-warning); }
|
|
3377
|
+
.sf-readability-val.is-hard { color: var(--sf-danger); }
|
|
3378
|
+
|
|
3379
|
+
.sf-readability-advice {
|
|
3380
|
+
margin-top: 7px;
|
|
3381
|
+
font-size: 11px;
|
|
3382
|
+
line-height: 1.6;
|
|
3383
|
+
color: var(--sf-muted);
|
|
3384
|
+
}
|
|
3385
|
+
.sf-readability-suggestions {
|
|
3386
|
+
display: flex;
|
|
3387
|
+
flex-wrap: wrap;
|
|
3388
|
+
gap: 6px;
|
|
3389
|
+
margin-top: 8px;
|
|
3390
|
+
}
|
|
3391
|
+
.sf-readability-suggestion {
|
|
3392
|
+
display: inline-flex;
|
|
3393
|
+
align-items: center;
|
|
3394
|
+
gap: 5px;
|
|
3395
|
+
height: 26px;
|
|
3396
|
+
padding: 0 9px;
|
|
3397
|
+
border: 1px solid var(--sf-input-border);
|
|
3398
|
+
border-radius: var(--sf-field-radius);
|
|
3399
|
+
background: var(--sf-field-bg);
|
|
3400
|
+
color: var(--sf-btn-text);
|
|
3401
|
+
font-size: 11px;
|
|
3402
|
+
font-variant-numeric: tabular-nums;
|
|
3403
|
+
cursor: pointer;
|
|
3404
|
+
}
|
|
3405
|
+
.sf-readability-suggestion:hover {
|
|
3406
|
+
background: var(--sf-hover);
|
|
3407
|
+
}
|
|
3408
|
+
.sf-readability-chip {
|
|
3409
|
+
width: 9px;
|
|
3410
|
+
height: 9px;
|
|
3411
|
+
flex: none;
|
|
3412
|
+
border-radius: 2px;
|
|
3413
|
+
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.18);
|
|
3414
|
+
}
|
|
3415
|
+
|
|
3416
|
+
/* The nine-square grid moved into `efficient-easel/panel` as `SettingsPlacement`
|
|
3417
|
+
(0.35.0), so the `.sf-focal*` rules that lived here are gone rather than left
|
|
3418
|
+
as a second copy nobody would remember to update. The chosen cell also stopped
|
|
3419
|
+
being card 8811's tint on the way: the shell tells the chosen thing apart by
|
|
3420
|
+
being the darkest in the row on a grey track (66138 / 66302), and its suite
|
|
3421
|
+
bans the tint token package-wide, so the retired look could not travel. */
|
|
3422
|
+
|
|
3423
|
+
/* Slider */
|
|
3424
|
+
.sf-slider {
|
|
3425
|
+
display: flex;
|
|
3426
|
+
align-items: center;
|
|
3427
|
+
gap: 12px;
|
|
3428
|
+
}
|
|
3429
|
+
/* …AND IT TAKES THE WHOLE ROW WHEREVER THE SHELL STACKS IT (card 66247, owner
|
|
3430
|
+
2026-08-31: the slider fills the row).
|
|
3431
|
+
|
|
3432
|
+
`efficient-easel`'s `SettingsField` puts a control on its own line for one stated
|
|
3433
|
+
reason — its own comment, `src/panel/SettingsField.tsx`: "The row is stacked
|
|
3434
|
+
rather than side-by-side so the control gets the panel's full width — a 308px
|
|
3435
|
+
panel cannot afford a label column AND a usable slider." The slot it stacks
|
|
3436
|
+
into is `.es-field-ctl`, and that slot is `display: flex`.
|
|
3437
|
+
|
|
3438
|
+
A block-level `.sf-slider` fills its parent, which is why the sliders in this
|
|
3439
|
+
panel's OWN `.sf-field` rows always looked right. As a flex ITEM it does not:
|
|
3440
|
+
with no `flex` and no `width` it is `flex: 0 1 auto` and sizes to its content,
|
|
3441
|
+
a bare `input[type=range]` — 129px in Chromium, and 129px whatever the panel
|
|
3442
|
+
is dragged to. Measured before this rule existed (scripts/harness/part-slider-width.tsx):
|
|
3443
|
+
|
|
3444
|
+
panel 220 (MIN_PANEL_W) field content 192 track 129 67% of the row
|
|
3445
|
+
panel 320 (the default) field content 280 track 129 46% of the row
|
|
3446
|
+
panel 560 (MAX_PANEL_W) field content 520 track 129 25% of the row
|
|
3447
|
+
|
|
3448
|
+
So the slot fills the row and the track inside it did not, and the wider a
|
|
3449
|
+
merchant dragged the panel the smaller a fraction of it the control took.
|
|
3450
|
+
|
|
3451
|
+
`flex: 1`, not `width: 100%`, and that is the same call the rule ten lines
|
|
3452
|
+
below already made for the range input inside this box: a percentage width is
|
|
3453
|
+
right only while the slider is alone in the slot, and would overflow the row
|
|
3454
|
+
the day a second thing joined it. Written against `.es-field-ctl` rather than
|
|
3455
|
+
against this panel or that one, because the promise being kept is the SHELL's
|
|
3456
|
+
and every row it stacks is owed it — `PartSettingsPanel`'s Size / Line
|
|
3457
|
+
spacing / Letter spacing and `SiteWidthField`'s Site width are the four this
|
|
3458
|
+
reaches today. Guarded by `scripts/test-part-slider-fills-row.ts`. */
|
|
3459
|
+
.es-field-ctl > .sf-slider {
|
|
3460
|
+
flex: 1;
|
|
3461
|
+
min-width: 0;
|
|
3462
|
+
}
|
|
3463
|
+
/* The range was the one control still drawn entirely by the browser — a native
|
|
3464
|
+
track and thumb tinted with `accent-color`, sitting beside a panel of bespoke
|
|
3465
|
+
toggles, segmenteds and swatches. It read as an unstyled leftover at every OS,
|
|
3466
|
+
and each OS drew it differently. Drawn explicitly here instead, off the same
|
|
3467
|
+
tokens as its neighbours: a 4px rail on the field track colour, and a white
|
|
3468
|
+
thumb ringed in the accent (the shell's control shape — cf. `.es-switch`).
|
|
3469
|
+
|
|
3470
|
+
`accent-color` is deliberately dropped: with an explicit thumb + track it only
|
|
3471
|
+
fights the rules below. The two vendor thumb selectors CANNOT be combined into
|
|
3472
|
+
one rule — a selector list is discarded wholesale by any browser that doesn't
|
|
3473
|
+
recognise one member, which would leave the thumb unstyled. */
|
|
3474
|
+
.sf-slider input[type="range"] {
|
|
3475
|
+
flex: 1;
|
|
3476
|
+
min-width: 0;
|
|
3477
|
+
height: 18px;
|
|
3478
|
+
margin: 0;
|
|
3479
|
+
padding: 0;
|
|
3480
|
+
background: transparent;
|
|
3481
|
+
cursor: pointer;
|
|
3482
|
+
-webkit-appearance: none;
|
|
3483
|
+
appearance: none;
|
|
3484
|
+
}
|
|
3485
|
+
.sf-slider input[type="range"]::-webkit-slider-runnable-track {
|
|
3486
|
+
height: 4px;
|
|
3487
|
+
border-radius: 999px;
|
|
3488
|
+
background: var(--sf-track-bg);
|
|
3489
|
+
box-shadow: inset 0 0 0 1px var(--sf-input-border);
|
|
3490
|
+
}
|
|
3491
|
+
.sf-slider input[type="range"]::-moz-range-track {
|
|
3492
|
+
height: 4px;
|
|
3493
|
+
border-radius: 999px;
|
|
3494
|
+
background: var(--sf-track-bg);
|
|
3495
|
+
box-shadow: inset 0 0 0 1px var(--sf-input-border);
|
|
3496
|
+
}
|
|
3497
|
+
.sf-slider input[type="range"]::-webkit-slider-thumb {
|
|
3498
|
+
-webkit-appearance: none;
|
|
3499
|
+
appearance: none;
|
|
3500
|
+
width: 14px;
|
|
3501
|
+
height: 14px;
|
|
3502
|
+
/* Centre the thumb on a 4px track: (4 - 14) / 2. Webkit lays the thumb out
|
|
3503
|
+
from the track's top edge, so without this it hangs below the rail. */
|
|
3504
|
+
margin-top: -5px;
|
|
3505
|
+
border-radius: 50%;
|
|
3506
|
+
background: var(--sf-knob);
|
|
3507
|
+
border: 2px solid var(--sf-accent);
|
|
3508
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
|
|
3509
|
+
transition: transform 0.12s;
|
|
3510
|
+
}
|
|
3511
|
+
.sf-slider input[type="range"]::-moz-range-thumb {
|
|
3512
|
+
width: 14px;
|
|
3513
|
+
height: 14px;
|
|
3514
|
+
border-radius: 50%;
|
|
3515
|
+
background: var(--sf-knob);
|
|
3516
|
+
border: 2px solid var(--sf-accent);
|
|
3517
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
|
|
3518
|
+
transition: transform 0.12s;
|
|
3519
|
+
}
|
|
3520
|
+
.sf-slider input[type="range"]:hover::-webkit-slider-thumb {
|
|
3521
|
+
transform: scale(1.12);
|
|
3522
|
+
}
|
|
3523
|
+
.sf-slider input[type="range"]:hover::-moz-range-thumb {
|
|
3524
|
+
transform: scale(1.12);
|
|
3525
|
+
}
|
|
3526
|
+
/* THE NOTCH — where the style is, on a track that overrides it (card 66116).
|
|
3527
|
+
Drag away from it to override; land on it and the override is cleared, so the
|
|
3528
|
+
way back is on the control the merchant is already holding.
|
|
3529
|
+
|
|
3530
|
+
Placed against the thumb's REAL travel, not the track's width: a range input
|
|
3531
|
+
moves the thumb's centre from half a thumb in to half a thumb short of the
|
|
3532
|
+
end, so a plain percentage would sit beside the thumb rather than under it at
|
|
3533
|
+
both ends. `--sf-notch` is the 0-1 position the control computes. */
|
|
3534
|
+
.sf-slider.has-notch {
|
|
3535
|
+
position: relative;
|
|
3536
|
+
}
|
|
3537
|
+
.sf-slider.has-notch::before {
|
|
3538
|
+
content: "";
|
|
3539
|
+
position: absolute;
|
|
3540
|
+
top: 50%;
|
|
3541
|
+
left: calc(7px + (100% - 14px) * var(--sf-notch));
|
|
3542
|
+
width: 2px;
|
|
3543
|
+
height: 10px;
|
|
3544
|
+
margin-top: -5px;
|
|
3545
|
+
border-radius: 1px;
|
|
3546
|
+
background: var(--sf-input-border);
|
|
3547
|
+
pointer-events: none;
|
|
3548
|
+
}
|
|
3549
|
+
|
|
3550
|
+
/* THE NUMBER, AND IT IS A BUTTON (card 66275). A track that runs 200–900 in
|
|
3551
|
+
tens has seventy stops on it, and 380 is one of them — reachable by dragging
|
|
3552
|
+
only if the merchant lands the thumb on exactly the right pixel. So the
|
|
3553
|
+
readout is pressed to type into, which means it is a real <button> and needs
|
|
3554
|
+
the browser's own button drawing taken off it: everything below the first
|
|
3555
|
+
five declarations is undoing an appearance, not adding one. It must measure
|
|
3556
|
+
exactly what the <span> measured, because `.es-field-value` and this box sit
|
|
3557
|
+
in the same 42px column and a merchant reads down it. */
|
|
3558
|
+
.sf-slider-val {
|
|
3559
|
+
font-size: 12px;
|
|
3560
|
+
color: var(--sf-icon);
|
|
3561
|
+
font-variant-numeric: tabular-nums;
|
|
3562
|
+
min-width: 42px;
|
|
3563
|
+
text-align: right;
|
|
3564
|
+
padding: 0;
|
|
3565
|
+
border: none;
|
|
3566
|
+
background: none;
|
|
3567
|
+
font-family: inherit;
|
|
3568
|
+
line-height: inherit;
|
|
3569
|
+
}
|
|
3570
|
+
button.sf-slider-val {
|
|
3571
|
+
cursor: text;
|
|
3572
|
+
border-radius: 4px;
|
|
3573
|
+
}
|
|
3574
|
+
button.sf-slider-val:hover {
|
|
3575
|
+
color: var(--sf-text);
|
|
3576
|
+
box-shadow: inset 0 0 0 1px var(--sf-input-border);
|
|
3577
|
+
}
|
|
3578
|
+
/* The same box, being typed into. It keeps the readout's own width and
|
|
3579
|
+
alignment so the row does not shift under the merchant's caret the moment
|
|
3580
|
+
they click it — a number that jumps sideways as it becomes editable reads as
|
|
3581
|
+
two different controls. */
|
|
3582
|
+
input.sf-slider-typed {
|
|
3583
|
+
width: 42px;
|
|
3584
|
+
color: var(--sf-text);
|
|
3585
|
+
box-shadow: inset 0 0 0 1px var(--sf-accent);
|
|
3586
|
+
border-radius: 4px;
|
|
3587
|
+
padding: 1px 3px;
|
|
3588
|
+
/* iOS zooms a focused input under 16px unless the page says otherwise; the
|
|
3589
|
+
editor is desktop-first but the panel is reachable on a tablet. */
|
|
3590
|
+
touch-action: manipulation;
|
|
3591
|
+
}
|
|
3592
|
+
input.sf-slider-typed:focus {
|
|
3593
|
+
outline: none;
|
|
3594
|
+
}
|
|
3595
|
+
|
|
3596
|
+
/* Pinned editor-only toggle bar — sits BETWEEN the inspector head and the
|
|
3597
|
+
scrolling body (SectionEditor), so an aid like "Preview hover state" stays
|
|
3598
|
+
put at the top while the fields below it scroll. `flex: none` keeps it from
|
|
3599
|
+
shrinking; the body (`flex: 1`) takes the remaining height and scrolls. */
|
|
3600
|
+
.sf-preview-pin {
|
|
3601
|
+
display: flex;
|
|
3602
|
+
align-items: center;
|
|
3603
|
+
justify-content: space-between;
|
|
3604
|
+
gap: 12px;
|
|
3605
|
+
flex: none;
|
|
3606
|
+
padding: 9px 14px;
|
|
3607
|
+
background: var(--sf-panel);
|
|
3608
|
+
}
|
|
3609
|
+
.sf-preview-pin-text {
|
|
3610
|
+
display: flex;
|
|
3611
|
+
flex-direction: column;
|
|
3612
|
+
gap: 1px;
|
|
3613
|
+
min-width: 0;
|
|
3614
|
+
}
|
|
3615
|
+
.sf-preview-pin-label {
|
|
3616
|
+
font-size: 13px;
|
|
3617
|
+
font-weight: 500;
|
|
3618
|
+
color: var(--sf-text);
|
|
3619
|
+
}
|
|
3620
|
+
.sf-preview-pin-hint {
|
|
3621
|
+
font-size: 11px;
|
|
3622
|
+
color: var(--sf-muted);
|
|
3623
|
+
}
|
|
3624
|
+
|
|
3625
|
+
/* Columns-per-line stepper — a compact − N + shown for the view the footer's
|
|
3626
|
+
"Columns per line" control is currently editing (the top-bar device). */
|
|
3627
|
+
.sf-colstep {
|
|
3628
|
+
display: flex;
|
|
3629
|
+
align-items: center;
|
|
3630
|
+
gap: 6px;
|
|
3631
|
+
}
|
|
3632
|
+
.sf-colstep-btn {
|
|
3633
|
+
width: 22px;
|
|
3634
|
+
height: 22px;
|
|
3635
|
+
padding: 0;
|
|
3636
|
+
border: 1px solid var(--sf-line);
|
|
3637
|
+
border-radius: 6px;
|
|
3638
|
+
background: transparent;
|
|
3639
|
+
color: var(--sf-text);
|
|
3640
|
+
font-size: 15px;
|
|
3641
|
+
line-height: 1;
|
|
3642
|
+
cursor: pointer;
|
|
3643
|
+
display: flex;
|
|
3644
|
+
align-items: center;
|
|
3645
|
+
justify-content: center;
|
|
3646
|
+
}
|
|
3647
|
+
.sf-colstep-btn:hover:not(:disabled) {
|
|
3648
|
+
border-color: var(--sf-accent);
|
|
3649
|
+
}
|
|
3650
|
+
.sf-colstep-btn:disabled {
|
|
3651
|
+
opacity: 0.4;
|
|
3652
|
+
cursor: default;
|
|
3653
|
+
}
|
|
3654
|
+
.sf-colstep-value {
|
|
3655
|
+
min-width: 14px;
|
|
3656
|
+
text-align: center;
|
|
3657
|
+
font-size: 13px;
|
|
3658
|
+
font-weight: 500;
|
|
3659
|
+
color: var(--sf-text);
|
|
3660
|
+
}
|
|
3661
|
+
|
|
3662
|
+
/* Checkbox — a literal tick box tinted to the editor accent. The row is the
|
|
3663
|
+
shell's SettingsField with the box in its `action` slot (label left, box
|
|
3664
|
+
right); the label points at the box, so the text is clickable. */
|
|
3665
|
+
.sf-checkbox {
|
|
3666
|
+
cursor: pointer;
|
|
3667
|
+
}
|
|
3668
|
+
.sf-checkbox input[type="checkbox"] {
|
|
3669
|
+
width: 17px;
|
|
3670
|
+
height: 17px;
|
|
3671
|
+
margin: 0;
|
|
3672
|
+
accent-color: var(--sf-accent);
|
|
3673
|
+
cursor: pointer;
|
|
3674
|
+
}
|
|
3675
|
+
|
|
3676
|
+
/* A field group greyed out because a higher-level setting overrides it — e.g. the
|
|
3677
|
+
manual ProductPicker (Category + Product) when the Product Grid's Products
|
|
3678
|
+
source is set to All wheels / a collection. */
|
|
3679
|
+
.sf-locked {
|
|
3680
|
+
opacity: 0.5;
|
|
3681
|
+
pointer-events: none;
|
|
3682
|
+
}
|
|
3683
|
+
|
|
3684
|
+
/* ── Keyboard focus rings on the inspector controls (card 66034) ──────────────
|
|
3685
|
+
The inspector's bespoke controls are all <button>/<input>, so they were always
|
|
3686
|
+
reachable by Tab — but every one of them had its browser outline suppressed by
|
|
3687
|
+
the reset at the top of this file and nothing put back, leaving a keyboard user
|
|
3688
|
+
with no visible caret anywhere in the panel (flagged by the 2026-08-06 audit).
|
|
3689
|
+
|
|
3690
|
+
`:focus-visible`, not `:focus`, so a mouse click never paints a ring — the
|
|
3691
|
+
reason the outline was dropped in the first place. Same 2px accent ring as
|
|
3692
|
+
the top bar's `.es-btn-ghost` (editor-shell) / `.sf-addcard`, so focus reads identically across the whole
|
|
3693
|
+
editor rather than per-control. */
|
|
3694
|
+
.sf-seg2 button:focus-visible,
|
|
3695
|
+
.sf-readability-suggestion:focus-visible,
|
|
3696
|
+
.sf-swatch:focus-visible,
|
|
3697
|
+
.sf-field-eye:focus-visible,
|
|
3698
|
+
.sf-slider input[type="range"]:focus-visible,
|
|
3699
|
+
.sf-insp-body select:focus-visible,
|
|
3700
|
+
.sf-checkbox input[type="checkbox"]:focus-visible {
|
|
3701
|
+
outline: 2px solid var(--sf-accent);
|
|
3702
|
+
outline-offset: 2px;
|
|
3703
|
+
}
|
|
3704
|
+
/* The segmented sits in a 3px-padded track, so a 2px offset ring would be clipped
|
|
3705
|
+
by the track's own rounding — tuck it inside instead. */
|
|
3706
|
+
.sf-seg2 button:focus-visible {
|
|
3707
|
+
outline-offset: -1px;
|
|
3708
|
+
}
|
|
3709
|
+
/* The text list's × and "+ Add item" (card 22118) are efficient-easel's since
|
|
3710
|
+
2026-10-06 and ring themselves (fields.css). Its row input keeps the shared
|
|
3711
|
+
`.sf-insp-body input[type="text"]:focus` cue every text input draws. */
|
|
3712
|
+
|
|
3713
|
+
/* Segmented */
|
|
3714
|
+
.sf-seg2 {
|
|
3715
|
+
display: flex;
|
|
3716
|
+
gap: 3px;
|
|
3717
|
+
background: var(--sf-track-bg);
|
|
3718
|
+
border: 1px solid var(--sf-input-border);
|
|
3719
|
+
border-radius: 9px;
|
|
3720
|
+
padding: 3px;
|
|
3721
|
+
}
|
|
3722
|
+
.sf-seg2 button {
|
|
3723
|
+
flex: 1;
|
|
3724
|
+
border: none;
|
|
3725
|
+
background: transparent;
|
|
3726
|
+
border-radius: 6px;
|
|
3727
|
+
padding: 6px 8px;
|
|
3728
|
+
font-size: 12px;
|
|
3729
|
+
font-weight: 500;
|
|
3730
|
+
color: var(--sf-icon);
|
|
3731
|
+
cursor: pointer;
|
|
3732
|
+
transition: background 0.12s, color 0.12s, box-shadow 0.12s;
|
|
3733
|
+
}
|
|
3734
|
+
/* …AND AT THE NARROW END, THE LAST 3.48px (card 66221). Wrapping the header
|
|
3735
|
+
panel's rows put every strip onto a line of its own, which took the widest of
|
|
3736
|
+
them — Background, four options — from 88px over the body to 3.48px over it.
|
|
3737
|
+
The strip's own width is where those last pixels are, and it is spent like
|
|
3738
|
+
this at a 220px panel:
|
|
3739
|
+
|
|
3740
|
+
border 1 × 2 2.00
|
|
3741
|
+
padding 3 × 2 6.00
|
|
3742
|
+
gaps 3 × 3 9.00
|
|
3743
|
+
buttons Page 44.75 + Dark 43.09 + Light 45.30
|
|
3744
|
+
+ Accent 56.34 189.48
|
|
3745
|
+
total 206.48 body: 203
|
|
3746
|
+
|
|
3747
|
+
Every button is ALREADY at its min-content width — `flex: 1` cannot shrink one
|
|
3748
|
+
below its own word, because `min-width` is `auto`. So the strip does not get
|
|
3749
|
+
narrower by being asked; something has to cost less. The word is not available
|
|
3750
|
+
(the four options are derived from `SECTION_SURFACES` so they match a section's
|
|
3751
|
+
own Background row exactly) and neither is the type (12 / 11 / 10px already,
|
|
3752
|
+
and type is paid vertically too). That leaves the padding either side of each
|
|
3753
|
+
word, and taking it 8 → 6 gives back 4 × 4 = 16px:
|
|
3754
|
+
|
|
3755
|
+
220px panel strip 190.48 of 203 12.52px spare, on the widest strip we draw
|
|
3756
|
+
|
|
3757
|
+
HEADROOM AND NOT A HAIRLINE, deliberately: this file's own probe records that
|
|
3758
|
+
these widths depend on the platform UI font, so a fix that cleared the defect
|
|
3759
|
+
by half a pixel would be a fix that held on the machine that measured it. The
|
|
3760
|
+
other rows gain the same 16px, which is what moves Alignment off its 3.05px
|
|
3761
|
+
margin and "Text colour at the top" off its 0.00.
|
|
3762
|
+
|
|
3763
|
+
SCOPED TO THE NARROW PANEL, on the container card 66212 already put on
|
|
3764
|
+
`.sf-panel` — the same rule, one level down: that card paid the horizontal
|
|
3765
|
+
cost out of the body's padding, and this pays the rest out of the strip's.
|
|
3766
|
+
Above 280px nothing changes, so all 23 `segmented()` call sites and the four
|
|
3767
|
+
panels that draw their own label rows are byte-identical at every width where
|
|
3768
|
+
they already fit. A `.sf-seg2` that is not inside a `.sf-panel` matches no
|
|
3769
|
+
container and is untouched by construction. */
|
|
3770
|
+
@container (width < 280px) {
|
|
3771
|
+
.sf-seg2 button {
|
|
3772
|
+
padding-inline: 6px;
|
|
3773
|
+
}
|
|
3774
|
+
}
|
|
3775
|
+
|
|
3776
|
+
/* ─── The strip needs a parent with a WIDTH (card 66248) ──────────────────────
|
|
3777
|
+
The shared strip is `efficient-easel`'s `SettingsSegmented` now, and its outer
|
|
3778
|
+
box `.es-segs-fit` is `container-type: inline-size` — so it takes its inline
|
|
3779
|
+
size FROM its parent and contributes NOTHING to it. `HeaderSettingsPanel`'s
|
|
3780
|
+
`Field` puts the control in a `flex-shrink-0` div, which sizes TO its content.
|
|
3781
|
+
|
|
3782
|
+
A parent sizing to a child that sizes to its parent resolves to ZERO. Measured
|
|
3783
|
+
in a real browser at both panel widths: control 0px, strip 0px, every word
|
|
3784
|
+
clamped to `max-width: 0`, and each button reduced to its own 16px of padding.
|
|
3785
|
+
Seven rows drew a label and no control, and every automated gate we own was
|
|
3786
|
+
green over it — a zero-width box is present in every tree walk and absent to
|
|
3787
|
+
every merchant. Forcing `container-type: normal` restores the strip to
|
|
3788
|
+
104.37px, which is what says the containment is the cause and not a symptom.
|
|
3789
|
+
|
|
3790
|
+
THE RULE HAS TO SIT ABOVE THE CONTAINMENT, so this is not something the strip
|
|
3791
|
+
or a wrapper inside it can fix — a child cannot bootstrap width from a parent
|
|
3792
|
+
that has none. Measured: a full-width wrapper INSIDE the control div leaves
|
|
3793
|
+
all three at 0.
|
|
3794
|
+
|
|
3795
|
+
`:has()` KEEPS IT OFF THE ROWS THIS CARD DID NOT MOVE. `Field`'s control div
|
|
3796
|
+
also carries switches and selects, which ride the LABEL line by card 8801's
|
|
3797
|
+
deliberate design — that is what lets a 308px panel show four settings instead
|
|
3798
|
+
of three. Matching only a control div that actually contains a strip leaves
|
|
3799
|
+
them exactly as they were. Not a new dependency: `efficient-easel`'s own
|
|
3800
|
+
`panel.css` uses `:has()` three times, so the package this panel renders
|
|
3801
|
+
already requires it.
|
|
3802
|
+
|
|
3803
|
+
FULL WIDTH IS THE HOUSE SHAPE, not a compromise — `efficient-easel`'s
|
|
3804
|
+
`SettingsField` stacks its own rows for the same reason ("a 308px panel cannot
|
|
3805
|
+
afford a label column AND a usable slider"). The label moves above the strip
|
|
3806
|
+
and the strip takes the body's width. Scoped to `.sf-panel` because
|
|
3807
|
+
`.flex-shrink-0` is a Tailwind utility used in seven other files, and none of
|
|
3808
|
+
them is this panel. */
|
|
3809
|
+
/* An inactive segment gave no feedback at all before the click, so the strip read
|
|
3810
|
+
as static text until you hit it. */
|
|
3811
|
+
.sf-seg2 button:hover:not(.is-active) {
|
|
3812
|
+
color: var(--sf-text-secondary);
|
|
3813
|
+
background: var(--sf-hover);
|
|
3814
|
+
}
|
|
3815
|
+
.sf-seg2 button.is-active {
|
|
3816
|
+
background: var(--sf-raised);
|
|
3817
|
+
color: var(--sf-text-strong);
|
|
3818
|
+
/* Softer and shorter than the old flat 0.14 drop: the active segment should
|
|
3819
|
+
look lifted off the track, not outlined against it. */
|
|
3820
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 0 1px rgba(0, 0, 0, 0.04);
|
|
3821
|
+
}
|
|
3822
|
+
/* ─── A control the panel has taken out of force (card 66216) ─────────────
|
|
3823
|
+
The setting still exists and still shows the merchant's saved answer; another
|
|
3824
|
+
setting in the same panel has simply taken the decision away — the Header's
|
|
3825
|
+
"Transparent at the top" and "Text colour at the top" under a pinned
|
|
3826
|
+
Background. DIMMED, NEVER HIDDEN: a control that disappears reads as a feature
|
|
3827
|
+
that was removed, and leaves the merchant no way to see what to change.
|
|
3828
|
+
|
|
3829
|
+
`--sf-disabled` is the panel's existing token for exactly this — the same dim
|
|
3830
|
+
the top bar's icon and ghost buttons wear (editor-shell's `.es-iconbtn` /
|
|
3831
|
+
`.es-btn-ghost`, lifted from this sheet); this is the same state on
|
|
3832
|
+
the control that had no rule for it (the switch is efficient-easel's
|
|
3833
|
+
`.es-switch`, which dims itself). The track keeps its border and the
|
|
3834
|
+
pressed segment keeps its lift, so the strip still READS as a strip with an
|
|
3835
|
+
answer in it — it is quieter, not broken. */
|
|
3836
|
+
.sf-seg2[data-disabled] {
|
|
3837
|
+
opacity: 0.5;
|
|
3838
|
+
cursor: not-allowed;
|
|
3839
|
+
}
|
|
3840
|
+
.sf-seg2[data-disabled] button {
|
|
3841
|
+
cursor: not-allowed;
|
|
3842
|
+
color: var(--sf-disabled);
|
|
3843
|
+
}
|
|
3844
|
+
.sf-seg2[data-disabled] button.is-active {
|
|
3845
|
+
color: var(--sf-text-secondary);
|
|
3846
|
+
}
|
|
3847
|
+
/* Neither may answer the pointer any more — `:hover:not(.is-active)` above would
|
|
3848
|
+
otherwise still light a segment the merchant cannot choose. */
|
|
3849
|
+
.sf-seg2[data-disabled] button:hover:not(.is-active) {
|
|
3850
|
+
background: transparent;
|
|
3851
|
+
color: var(--sf-disabled);
|
|
3852
|
+
}
|
|
3853
|
+
|
|
3854
|
+
/* A segment whose label is a DRAWING rather than a word — the part panel's three
|
|
3855
|
+
alignment rules, which have no honest three-letter word between them. Laid out
|
|
3856
|
+
as a block so it centres on the button instead of sitting on a text baseline
|
|
3857
|
+
with a descender's worth of space beneath it. */
|
|
3858
|
+
.sf-seg2 button > svg {
|
|
3859
|
+
display: block;
|
|
3860
|
+
margin: 0 auto;
|
|
3861
|
+
}
|
|
3862
|
+
|
|
3863
|
+
/* Lines of copy (textList, the ticker): efficient-easel's ONE list since the
|
|
3864
|
+
owner's ruling of 2026-10-06 — its rows, its ×, its "+ Add item" and its
|
|
3865
|
+
drag are fields.css's (`.es-list-*`). What is the storefront's own is the ONE
|
|
3866
|
+
formatting bar it carries (`.es-list-above`, rules further up, with the copy
|
|
3867
|
+
box's) and the row that bar is aimed at.
|
|
3868
|
+
|
|
3869
|
+
The row the bar is aimed at has to stay visible AFTER the caret leaves — the
|
|
3870
|
+
merchant clicks the bar, which takes the focus ring off the row — so the cue
|
|
3871
|
+
is painted rather than borrowed from :focus. Accent tokens only. */
|
|
3872
|
+
.es-list-above > .es-copy-bar {
|
|
3873
|
+
margin-bottom: 0;
|
|
3874
|
+
}
|
|
3875
|
+
input.sf-list-marking {
|
|
3876
|
+
border-color: var(--sf-accent);
|
|
3877
|
+
box-shadow: 0 0 0 1px var(--sf-accent-tint);
|
|
3878
|
+
}
|
|
3879
|
+
|
|
3880
|
+
/* Blog source — the Events block's "link to Storefront → Blog" control:
|
|
3881
|
+
a status line + a refresh button + a hint. Snapshots posts onto the block. */
|
|
3882
|
+
.sf-blogsource {
|
|
3883
|
+
display: flex;
|
|
3884
|
+
flex-direction: column;
|
|
3885
|
+
gap: 9px;
|
|
3886
|
+
}
|
|
3887
|
+
.sf-blogsource-status {
|
|
3888
|
+
margin: 0;
|
|
3889
|
+
font-size: 12px;
|
|
3890
|
+
color: var(--sf-text-secondary);
|
|
3891
|
+
}
|
|
3892
|
+
.sf-blogsource-status[data-state="error"] {
|
|
3893
|
+
color: var(--sf-danger);
|
|
3894
|
+
}
|
|
3895
|
+
/* The "Open" control inside a source note — the route the sentence names.
|
|
3896
|
+
[ADD] Source Note Opens The Record, 2026-09-06.
|
|
3897
|
+
|
|
3898
|
+
AN INLINE BUTTON, NOT A BLOCK ONE (`.sf-blogsource-btn` is the block form on
|
|
3899
|
+
the product inspector). This one sits INSIDE the sentence, at the end, so it
|
|
3900
|
+
inherits the caption's 11px and only its colour and underline say it is
|
|
3901
|
+
pressable — a 12px pill on the end of an 11px line would be a second control
|
|
3902
|
+
grammar for the same act.
|
|
3903
|
+
|
|
3904
|
+
It is a real <button> and not an <a>: the editor is embedded and reaches the
|
|
3905
|
+
admin over postMessage, so there is no href to give. Styled as a link because
|
|
3906
|
+
that is what it does, named as a button because that is what it is. */
|
|
3907
|
+
.sf-source-open {
|
|
3908
|
+
display: inline;
|
|
3909
|
+
padding: 0;
|
|
3910
|
+
border: 0;
|
|
3911
|
+
background: none;
|
|
3912
|
+
font: inherit;
|
|
3913
|
+
color: var(--sf-accent-text);
|
|
3914
|
+
text-decoration: underline;
|
|
3915
|
+
text-underline-offset: 2px;
|
|
3916
|
+
cursor: pointer;
|
|
3917
|
+
}
|
|
3918
|
+
.sf-source-open:hover { color: var(--sf-accent); }
|
|
3919
|
+
.sf-source-open:focus-visible {
|
|
3920
|
+
outline: 2px solid var(--sf-accent);
|
|
3921
|
+
outline-offset: 2px;
|
|
3922
|
+
border-radius: 2px;
|
|
3923
|
+
}
|
|
3924
|
+
|
|
3925
|
+
.sf-blogsource-btn {
|
|
3926
|
+
align-self: flex-start;
|
|
3927
|
+
padding: 7px 14px;
|
|
3928
|
+
border: 1px solid var(--sf-input-border);
|
|
3929
|
+
border-radius: 8px;
|
|
3930
|
+
background: transparent;
|
|
3931
|
+
color: var(--sf-text-secondary);
|
|
3932
|
+
font-size: 12px;
|
|
3933
|
+
font-weight: 500;
|
|
3934
|
+
cursor: pointer;
|
|
3935
|
+
transition: border-color 0.12s, color 0.12s, background 0.12s;
|
|
3936
|
+
}
|
|
3937
|
+
.sf-blogsource-btn:hover:not(:disabled) {
|
|
3938
|
+
border-color: var(--sf-accent);
|
|
3939
|
+
color: var(--sf-accent);
|
|
3940
|
+
}
|
|
3941
|
+
.sf-blogsource-btn:disabled {
|
|
3942
|
+
opacity: 0.55;
|
|
3943
|
+
cursor: default;
|
|
3944
|
+
}
|
|
3945
|
+
|
|
3946
|
+
/* Form picker — the "which form does this section show" control. Reuses the
|
|
3947
|
+
blog-source card for its frame, buttons and hint, and adds the read-only
|
|
3948
|
+
summary of the picked form (its fields, and where the answers go). */
|
|
3949
|
+
.sf-formpicker {
|
|
3950
|
+
display: flex;
|
|
3951
|
+
flex-direction: column;
|
|
3952
|
+
gap: 9px;
|
|
3953
|
+
}
|
|
3954
|
+
.sf-formsummary-caption {
|
|
3955
|
+
margin-bottom: 4px;
|
|
3956
|
+
font-size: 11px;
|
|
3957
|
+
font-weight: 600;
|
|
3958
|
+
letter-spacing: 0.02em;
|
|
3959
|
+
color: var(--sf-text-secondary);
|
|
3960
|
+
}
|
|
3961
|
+
.sf-formsummary-fields {
|
|
3962
|
+
margin: 0;
|
|
3963
|
+
padding-left: 18px;
|
|
3964
|
+
font-size: 12px;
|
|
3965
|
+
line-height: 1.55;
|
|
3966
|
+
color: var(--sf-text-secondary);
|
|
3967
|
+
}
|
|
3968
|
+
.sf-formsummary-warn {
|
|
3969
|
+
margin: 0;
|
|
3970
|
+
font-size: 11.5px;
|
|
3971
|
+
line-height: 1.45;
|
|
3972
|
+
color: var(--sf-danger);
|
|
3973
|
+
}
|
|
3974
|
+
.sf-formsummary-actions {
|
|
3975
|
+
display: flex;
|
|
3976
|
+
flex-wrap: wrap;
|
|
3977
|
+
gap: 8px;
|
|
3978
|
+
}
|
|
3979
|
+
|
|
3980
|
+
/* THE MEDIA ROW IS efficient-easel's `ImageBox` since blueprint step 4.8
|
|
3981
|
+
(`es-pick-image-*`, efficient-easel/pick.css): the picture, its name under
|
|
3982
|
+
it, Replace and Remove. What stays here is the shop's own around it — the
|
|
3983
|
+
button the focus row borrows, the drop's live regions, and the template's
|
|
3984
|
+
inert slot. */
|
|
3985
|
+
.sf-image-btn {
|
|
3986
|
+
border: 1px solid var(--sf-btn-border);
|
|
3987
|
+
background: var(--sf-panel);
|
|
3988
|
+
color: var(--sf-btn-text);
|
|
3989
|
+
border-radius: 6px;
|
|
3990
|
+
padding: 4px 10px;
|
|
3991
|
+
font-size: 12px;
|
|
3992
|
+
font-weight: 500;
|
|
3993
|
+
cursor: pointer;
|
|
3994
|
+
transition: background 0.12s;
|
|
3995
|
+
}
|
|
3996
|
+
.sf-image-btn:hover:not(:disabled) {
|
|
3997
|
+
background: var(--sf-hover);
|
|
3998
|
+
}
|
|
3999
|
+
.sf-image-btn:disabled {
|
|
4000
|
+
cursor: default;
|
|
4001
|
+
opacity: 0.55;
|
|
4002
|
+
}
|
|
4003
|
+
/* Loading / error line under the slot, so a slow or failed picker round-trip is
|
|
4004
|
+
visible instead of nothing happening. */
|
|
4005
|
+
.sf-image-status {
|
|
4006
|
+
margin-top: 6px;
|
|
4007
|
+
font-size: 11px;
|
|
4008
|
+
color: var(--sf-muted);
|
|
4009
|
+
}
|
|
4010
|
+
.sf-image-status--error {
|
|
4011
|
+
color: var(--sf-danger);
|
|
4012
|
+
}
|
|
4013
|
+
/* The shell's FileIntakeAlert renders a dropped file's rejection as a list whose
|
|
4014
|
+
items carry the kit's own light-theme utilities (text-xs text-red-600). Inside
|
|
4015
|
+
the editor they read the slot's status line instead, so a rejection flips with
|
|
4016
|
+
the editor theme like the error line above it. */
|
|
4017
|
+
ul.sf-image-status {
|
|
4018
|
+
list-style: none;
|
|
4019
|
+
padding: 0;
|
|
4020
|
+
}
|
|
4021
|
+
.sf-image-status--error li {
|
|
4022
|
+
color: inherit;
|
|
4023
|
+
font-size: inherit;
|
|
4024
|
+
}
|
|
4025
|
+
/* Shown in place of the media slot above when the open document can't hold
|
|
4026
|
+
media (a template): the same dashed frame, plainly not a button. It is the
|
|
4027
|
+
SLOT in its inert state, not a note — it was only ever counted as one
|
|
4028
|
+
because of its old name, `.sf-media-note` (card 66121). */
|
|
4029
|
+
.sf-image-slot-inert {
|
|
4030
|
+
border: 1.5px dashed var(--sf-input-border);
|
|
4031
|
+
border-radius: 9px;
|
|
4032
|
+
padding: 12px 14px;
|
|
4033
|
+
font-size: 12px;
|
|
4034
|
+
line-height: 1.5;
|
|
4035
|
+
color: var(--sf-muted);
|
|
4036
|
+
background-image: repeating-linear-gradient(45deg, var(--sf-hatch) 0 1px, transparent 1px 12px);
|
|
4037
|
+
}
|
|
4038
|
+
|
|
4039
|
+
/* ── The image FOCUS point (card 66226) ──────────────────────────────────────
|
|
4040
|
+
WHICH PART OF A BACKGROUND IMAGE SURVIVES ITS CROP, as any point on the
|
|
4041
|
+
picture rather than as one of nine. The `Image focus` row opens (the shared
|
|
4042
|
+
.sf-style-head grammar, see components/ImageFocusRow.tsx), shows the whole
|
|
4043
|
+
photograph, and a press or an arrow key puts the point where the merchant
|
|
4044
|
+
wants it. The stored value is the same CSS `object-position` string it has
|
|
4045
|
+
always been.
|
|
4046
|
+
|
|
4047
|
+
⚠️ THE MEDIA ROW'S OWN FRAME IS NOT RESTYLED, EVER. `.es-pick-image-frame`
|
|
4048
|
+
stays `cover` because that is what the PAGE will look like, and that
|
|
4049
|
+
is its job. This block is a second frame, on screen only while a merchant is
|
|
4050
|
+
actually setting the point, because a `cover` view cannot express a point it
|
|
4051
|
+
has already cropped away. */
|
|
4052
|
+
.sf-focus {
|
|
4053
|
+
display: flex;
|
|
4054
|
+
flex-direction: column;
|
|
4055
|
+
gap: 6px;
|
|
4056
|
+
}
|
|
4057
|
+
/* THE PHOTOGRAPH IS A REAL <button>, not a div wearing a tabIndex. What this
|
|
4058
|
+
card replaced is a `role="radiogroup"` a keyboard could already drive, so the
|
|
4059
|
+
successor has to earn its place in the tab order the same way. `touch-action`
|
|
4060
|
+
is off so a drag on a phone moves the point instead of scrolling the panel. */
|
|
4061
|
+
.sf-focus-canvas {
|
|
4062
|
+
display: flex;
|
|
4063
|
+
align-items: center;
|
|
4064
|
+
justify-content: center;
|
|
4065
|
+
min-height: 150px;
|
|
4066
|
+
padding: 0;
|
|
4067
|
+
border: 1px solid var(--sf-line);
|
|
4068
|
+
border-radius: 6px;
|
|
4069
|
+
background: var(--sf-preview-bg);
|
|
4070
|
+
cursor: crosshair;
|
|
4071
|
+
touch-action: none;
|
|
4072
|
+
}
|
|
4073
|
+
.sf-focus-canvas:focus-visible {
|
|
4074
|
+
outline: 2px solid var(--sf-accent);
|
|
4075
|
+
outline-offset: 1px;
|
|
4076
|
+
}
|
|
4077
|
+
/* Shrink-wraps the picture. The marker and crosshairs are positioned against
|
|
4078
|
+
THIS and not against the canvas, because a whole photograph in a fixed-height
|
|
4079
|
+
box is letterboxed — measuring against the box would land the marker on a
|
|
4080
|
+
different pixel for every aspect ratio, and the merchant would watch the dot
|
|
4081
|
+
drift away from where they pressed. */
|
|
4082
|
+
.sf-focus-pane {
|
|
4083
|
+
position: relative;
|
|
4084
|
+
display: inline-block;
|
|
4085
|
+
max-width: 100%;
|
|
4086
|
+
line-height: 0;
|
|
4087
|
+
}
|
|
4088
|
+
.sf-focus-img {
|
|
4089
|
+
display: block;
|
|
4090
|
+
width: auto;
|
|
4091
|
+
height: auto;
|
|
4092
|
+
max-width: 100%;
|
|
4093
|
+
max-height: 150px;
|
|
4094
|
+
object-fit: contain;
|
|
4095
|
+
}
|
|
4096
|
+
.sf-focus-cross {
|
|
4097
|
+
position: absolute;
|
|
4098
|
+
background: rgb(255 255 255 / 45%);
|
|
4099
|
+
pointer-events: none;
|
|
4100
|
+
}
|
|
4101
|
+
.sf-focus-cross--h {
|
|
4102
|
+
right: 0;
|
|
4103
|
+
left: 0;
|
|
4104
|
+
height: 1px;
|
|
4105
|
+
}
|
|
4106
|
+
.sf-focus-cross--v {
|
|
4107
|
+
top: 0;
|
|
4108
|
+
bottom: 0;
|
|
4109
|
+
width: 1px;
|
|
4110
|
+
}
|
|
4111
|
+
/* Drawn in white with a dark ring rather than in a panel token: it sits on a
|
|
4112
|
+
merchant's own photograph, which can be any colour, and a token that read
|
|
4113
|
+
correctly against the panel would vanish against half of them. */
|
|
4114
|
+
.sf-focus-marker {
|
|
4115
|
+
position: absolute;
|
|
4116
|
+
width: 18px;
|
|
4117
|
+
height: 18px;
|
|
4118
|
+
border: 2px solid #fff;
|
|
4119
|
+
border-radius: 50%;
|
|
4120
|
+
box-shadow: 0 0 0 1.5px rgb(0 0 0 / 55%), 0 1px 5px rgb(0 0 0 / 50%);
|
|
4121
|
+
transform: translate(-50%, -50%);
|
|
4122
|
+
pointer-events: none;
|
|
4123
|
+
}
|
|
4124
|
+
.sf-focus-bar {
|
|
4125
|
+
display: flex;
|
|
4126
|
+
align-items: center;
|
|
4127
|
+
gap: 8px;
|
|
4128
|
+
}
|
|
4129
|
+
.sf-focus-hint {
|
|
4130
|
+
min-width: 0;
|
|
4131
|
+
flex: 1;
|
|
4132
|
+
font-size: 11px;
|
|
4133
|
+
color: var(--sf-muted);
|
|
4134
|
+
}
|
|
4135
|
+
/* THE PHOTOGRAPH IS NEVER ON SCREEN TWICE. The 96px crop belongs to the
|
|
4136
|
+
Background image field and this row belongs to `imageFocal` — two sibling
|
|
4137
|
+
Puck fields, which cannot reach each other from React — so the crop stands
|
|
4138
|
+
down for as long as a focus session is open, and comes back the moment it
|
|
4139
|
+
closes. The `:has()` on Puck's own field wrapper is this stylesheet's
|
|
4140
|
+
established idiom for exactly that problem (see the `[data-sf-bucket]` and
|
|
4141
|
+
`[data-sf-no-control]` rules above). */
|
|
4142
|
+
.es-insp-rows:has([data-sf-focusing]) .es-pick-image-frame {
|
|
4143
|
+
display: none;
|
|
4144
|
+
}
|
|
4145
|
+
|
|
4146
|
+
/* ── The note (card 66121) ───────────────────────────────────────────────────
|
|
4147
|
+
THE chrome's quiet sentence: what a panel says when it has something to tell
|
|
4148
|
+
the merchant and nothing to let them edit. A whole-panel stand-in for
|
|
4149
|
+
settings that belong to a website the open document does not have; "No pages
|
|
4150
|
+
yet"; "Loading…"; the word "draft" trailing a row in the duplicate-to-page
|
|
4151
|
+
menu. One voice, so it is one class.
|
|
4152
|
+
|
|
4153
|
+
It was six classes at five sizes — .sf-pages-note, .sf-sm-note,
|
|
4154
|
+
.sf-panel-note, .sf-dupmenu-note, and two more that were only counted as
|
|
4155
|
+
notes because of their names (see .sf-image-slot-inert and .sf-device-scope).
|
|
4156
|
+
A third of those arrived with the part panel and was renamed the same way,
|
|
4157
|
+
for the same reason — see .sf-part-style-state, which is a card's subtitle.
|
|
4158
|
+
None of them was wrong on its own; each was written beside the block that
|
|
4159
|
+
needed it, which is exactly how you get six. 13px is where four of the six
|
|
4160
|
+
already were and is the size the panels are set in — a note is a SENTENCE, so
|
|
4161
|
+
it is read at the panel's reading size, and the muted colour is what makes it
|
|
4162
|
+
quiet.
|
|
4163
|
+
|
|
4164
|
+
THE CLASS CARRIES THE TYPE. The padding here is the note's home placement: a
|
|
4165
|
+
panel's own body inset. Where a note sits somewhere else, the block it sits
|
|
4166
|
+
in says so (`.sf-pages-list > .sf-note`, below its own list) — never a
|
|
4167
|
+
`--wide` / `--tight` pair here, because a family of padding variants is the
|
|
4168
|
+
same six classes wearing one name. */
|
|
4169
|
+
.sf-note {
|
|
4170
|
+
padding: 14px 16px;
|
|
4171
|
+
font-size: 13px;
|
|
4172
|
+
line-height: 1.5;
|
|
4173
|
+
color: var(--sf-muted);
|
|
4174
|
+
}
|
|
4175
|
+
.sf-note p + p {
|
|
4176
|
+
margin-top: 8px;
|
|
4177
|
+
}
|
|
4178
|
+
/* The one word the note lifts out of its own quiet: the thing being explained. */
|
|
4179
|
+
.sf-note strong {
|
|
4180
|
+
color: var(--sf-text);
|
|
4181
|
+
font-weight: 600;
|
|
4182
|
+
}
|
|
4183
|
+
/* The one line in a note that is NOT addressed to the merchant: the part id and
|
|
4184
|
+
the check that failed, on the screen a part could not be resolved on (card
|
|
4185
|
+
[FIX] Part Says It Is Gone). It is in the panel rather than the console
|
|
4186
|
+
because the person who meets this defect first is the one taking the
|
|
4187
|
+
screenshot, and a screenshot carries no console. Quieter and smaller than the
|
|
4188
|
+
sentence above it, so it reads as a footnote and not as an instruction. */
|
|
4189
|
+
.sf-note-detail {
|
|
4190
|
+
margin-top: 10px;
|
|
4191
|
+
font-size: 11px;
|
|
4192
|
+
color: var(--sf-muted);
|
|
4193
|
+
opacity: 0.75;
|
|
4194
|
+
word-break: break-all;
|
|
4195
|
+
}
|
|
4196
|
+
/* Inline create/delete failure (a native alert is a no-op in the iframe). The
|
|
4197
|
+
note's only loud state, and the only one that is not merely informative. */
|
|
4198
|
+
.sf-note--error {
|
|
4199
|
+
color: var(--sf-danger);
|
|
4200
|
+
background: var(--sf-danger-tint);
|
|
4201
|
+
border-radius: 6px;
|
|
4202
|
+
}
|
|
4203
|
+
/* Where this section's words come from, when they are not the merchant's to
|
|
4204
|
+
type (card 66089, owner ruling 7). A MODIFIER rather than a second note
|
|
4205
|
+
style: it sits BESIDE live controls instead of replacing one — under them
|
|
4206
|
+
since 2026-09-03, when the note moved to the foot of the panel so it stops
|
|
4207
|
+
standing between the panel head and the tab strip (`components/SectionEditor.tsx`
|
|
4208
|
+
carries the owner's word and the reason it was kept rather than deleted).
|
|
4209
|
+
It used to draw
|
|
4210
|
+
a rule under itself to say where it stopped; card 66334 removed that with
|
|
4211
|
+
every other divider, and the note's own colour and air carry it instead. It
|
|
4212
|
+
is the panel's quietest thing on purpose; it explains, it does not warn. */
|
|
4213
|
+
|
|
4214
|
+
/* ── Part panel: the inspector scoped to ONE clicked control ──────────── */
|
|
4215
|
+
/* The style CARD: which site style this part follows, what that style actually
|
|
4216
|
+
looks like, and how far this part has been pulled away from it. Sits above
|
|
4217
|
+
every control because it is the thing the controls are relative TO — a
|
|
4218
|
+
merchant who does not know a part follows a style reads every override below
|
|
4219
|
+
as an ordinary setting.
|
|
4220
|
+
|
|
4221
|
+
It SHOWS the style rather than only naming it (card 66116, v3): deciding
|
|
4222
|
+
whether to override "Headings" is deciding about a face, a size and a weight,
|
|
4223
|
+
and the page has already measured all three. */
|
|
4224
|
+
.sf-part-style {
|
|
4225
|
+
position: relative;
|
|
4226
|
+
/* ⚠️ NO `overflow: hidden` HERE, AND IT CANNOT COME BACK. The style chooser's
|
|
4227
|
+
menu is absolutely positioned inside this card, so clipping the card clipped
|
|
4228
|
+
the MENU: a merchant opening it saw one truncated row and no way to reach
|
|
4229
|
+
the other six. The clip existed only to round the 3px accent edge below,
|
|
4230
|
+
which now rounds itself. */
|
|
4231
|
+
margin: 0 0 4px;
|
|
4232
|
+
padding: 11px 13px;
|
|
4233
|
+
border: 1px solid var(--sf-divider);
|
|
4234
|
+
border-radius: 12px;
|
|
4235
|
+
background: var(--sf-track-bg);
|
|
4236
|
+
}
|
|
4237
|
+
/* Marked only once something has actually been overridden, so the card is quiet
|
|
4238
|
+
on the ~all sections nobody has styled. The edge is the third carrier of that
|
|
4239
|
+
one fact (with the chip and the accent labels below) and the only one visible
|
|
4240
|
+
while the card is scrolled to the top of a long panel. */
|
|
4241
|
+
.sf-part-style.has-overrides {
|
|
4242
|
+
border-color: var(--sf-accent-ring);
|
|
4243
|
+
}
|
|
4244
|
+
.sf-part-style.has-overrides::before {
|
|
4245
|
+
content: "";
|
|
4246
|
+
position: absolute;
|
|
4247
|
+
inset: 0 auto 0 0;
|
|
4248
|
+
width: 3px;
|
|
4249
|
+
background: var(--sf-accent);
|
|
4250
|
+
/* Rounds ITSELF against the card's left corners, so the card no longer needs
|
|
4251
|
+
`overflow: hidden` to hide the square ends. Left radii only — the right side
|
|
4252
|
+
is a straight edge into the card. */
|
|
4253
|
+
border-radius: 12px 0 0 12px;
|
|
4254
|
+
}
|
|
4255
|
+
/* The card's own caption — the panel's small-label voice, so it reads as a
|
|
4256
|
+
heading for the name below rather than as another name. */
|
|
4257
|
+
.sf-part-style-caption {
|
|
4258
|
+
margin-bottom: 2px;
|
|
4259
|
+
font-size: 11px;
|
|
4260
|
+
font-weight: 600;
|
|
4261
|
+
letter-spacing: 0.06em;
|
|
4262
|
+
text-transform: uppercase;
|
|
4263
|
+
color: var(--sf-muted);
|
|
4264
|
+
}
|
|
4265
|
+
.sf-part-style-count {
|
|
4266
|
+
margin-bottom: 3px;
|
|
4267
|
+
font-size: 11px;
|
|
4268
|
+
font-weight: 600;
|
|
4269
|
+
color: var(--sf-muted);
|
|
4270
|
+
}
|
|
4271
|
+
.sf-part-style-name {
|
|
4272
|
+
min-width: 0;
|
|
4273
|
+
font-size: 20px;
|
|
4274
|
+
line-height: 1.15;
|
|
4275
|
+
letter-spacing: -0.01em;
|
|
4276
|
+
color: var(--sf-text-strong);
|
|
4277
|
+
overflow: hidden;
|
|
4278
|
+
white-space: nowrap;
|
|
4279
|
+
text-overflow: ellipsis;
|
|
4280
|
+
}
|
|
4281
|
+
/* ── The style box's name, as a chooser ([ADD] Text Follows Style) ──────────
|
|
4282
|
+
The name was a readout; it is a button now. Everything it looked like it
|
|
4283
|
+
kept: `.sf-part-style-name` still carries the face and weight, still drawn in
|
|
4284
|
+
the style's own type, so the one place in the panel that shows a value BY
|
|
4285
|
+
being it did not become a place that merely names it.
|
|
4286
|
+
|
|
4287
|
+
The popup is `.sf-multi-menu`'s, reused rather than redrawn — the trigger's
|
|
4288
|
+
own chrome is all that is added here. */
|
|
4289
|
+
.sf-part-style-pick {
|
|
4290
|
+
position: relative;
|
|
4291
|
+
}
|
|
4292
|
+
.sf-part-style-trigger {
|
|
4293
|
+
display: flex;
|
|
4294
|
+
align-items: center;
|
|
4295
|
+
gap: 8px;
|
|
4296
|
+
width: 100%;
|
|
4297
|
+
padding: 0;
|
|
4298
|
+
border: 0;
|
|
4299
|
+
background: none;
|
|
4300
|
+
text-align: left;
|
|
4301
|
+
cursor: pointer;
|
|
4302
|
+
/* The name can be long and the panel narrows to 220; the caret must not be
|
|
4303
|
+
pushed off the end, so the NAME is what gives way. */
|
|
4304
|
+
min-width: 0;
|
|
4305
|
+
}
|
|
4306
|
+
.sf-part-style-trigger .sf-part-style-name {
|
|
4307
|
+
min-width: 0;
|
|
4308
|
+
overflow: hidden;
|
|
4309
|
+
text-overflow: ellipsis;
|
|
4310
|
+
white-space: nowrap;
|
|
4311
|
+
}
|
|
4312
|
+
/* Matches `.es-group-sign` in editor-shell exactly — same 16px box, same right
|
|
4313
|
+
edge, same `−` / `+`. Deliberately NOT a caret: this panel already teaches one
|
|
4314
|
+
"this opens" mark on Typeface and Size & spacing, and a second vocabulary for
|
|
4315
|
+
the same act is what made the old dot unreadable. */
|
|
4316
|
+
.sf-part-style-sign {
|
|
4317
|
+
margin-left: auto;
|
|
4318
|
+
width: 16px;
|
|
4319
|
+
flex: none;
|
|
4320
|
+
text-align: center;
|
|
4321
|
+
color: var(--sf-muted);
|
|
4322
|
+
font-size: 14px;
|
|
4323
|
+
line-height: 1;
|
|
4324
|
+
}
|
|
4325
|
+
.sf-part-style-trigger[aria-expanded="false"] .sf-part-style-sign::before {
|
|
4326
|
+
content: "+";
|
|
4327
|
+
}
|
|
4328
|
+
.sf-part-style-trigger[aria-expanded="true"] .sf-part-style-sign::before {
|
|
4329
|
+
content: "−";
|
|
4330
|
+
}
|
|
4331
|
+
.sf-part-style-trigger:focus-visible {
|
|
4332
|
+
outline: 2px solid var(--sf-accent);
|
|
4333
|
+
outline-offset: 2px;
|
|
4334
|
+
border-radius: 3px;
|
|
4335
|
+
}
|
|
4336
|
+
/* Sits over the card's own content rather than pushing it down: the card is a
|
|
4337
|
+
summary and a menu that grew it would move the controls under it while a
|
|
4338
|
+
merchant was reading them. */
|
|
4339
|
+
.sf-part-style-menu {
|
|
4340
|
+
position: absolute;
|
|
4341
|
+
z-index: 30;
|
|
4342
|
+
left: 0;
|
|
4343
|
+
right: 0;
|
|
4344
|
+
box-shadow: 0 8px 24px rgb(0 0 0 / 0.18);
|
|
4345
|
+
}
|
|
4346
|
+
.sf-part-style-option {
|
|
4347
|
+
display: flex;
|
|
4348
|
+
align-items: baseline;
|
|
4349
|
+
gap: 8px;
|
|
4350
|
+
width: 100%;
|
|
4351
|
+
padding: 7px 9px;
|
|
4352
|
+
border: 0;
|
|
4353
|
+
background: none;
|
|
4354
|
+
text-align: left;
|
|
4355
|
+
/* E6 — a field label is never smaller than 12px, and an option is a label. */
|
|
4356
|
+
font-size: 13px;
|
|
4357
|
+
color: var(--sf-field-text);
|
|
4358
|
+
border-radius: max(calc(var(--sf-field-radius) - 2px), 2px);
|
|
4359
|
+
cursor: pointer;
|
|
4360
|
+
}
|
|
4361
|
+
.sf-part-style-option:hover {
|
|
4362
|
+
background: var(--sf-accent-ring);
|
|
4363
|
+
}
|
|
4364
|
+
.sf-part-style-option:focus-visible {
|
|
4365
|
+
outline: 2px solid var(--sf-accent);
|
|
4366
|
+
outline-offset: -2px;
|
|
4367
|
+
}
|
|
4368
|
+
.sf-part-style-option.is-on {
|
|
4369
|
+
background: var(--sf-accent-ring);
|
|
4370
|
+
font-weight: 600;
|
|
4371
|
+
}
|
|
4372
|
+
.sf-part-style-option-name {
|
|
4373
|
+
/* ⚠️ THE NAME NEVER GIVES WAY — it is the whole content of the row. It was
|
|
4374
|
+
`flex: 1 1 auto` with an ellipsis, so a note beside it squeezed "No style"
|
|
4375
|
+
down to "No…": the one row a merchant needs to find became unreadable while
|
|
4376
|
+
its explanation stayed whole. The NOTE gives way now, and only it. */
|
|
4377
|
+
flex: 0 0 auto;
|
|
4378
|
+
white-space: nowrap;
|
|
4379
|
+
}
|
|
4380
|
+
.sf-part-style-option .sf-note {
|
|
4381
|
+
min-width: 0;
|
|
4382
|
+
margin-left: auto;
|
|
4383
|
+
overflow: hidden;
|
|
4384
|
+
text-overflow: ellipsis;
|
|
4385
|
+
white-space: nowrap;
|
|
4386
|
+
}
|
|
4387
|
+
/* The text region's Style row is easel's FieldSelect (card [MERGE] One Pop-up
|
|
4388
|
+
List For Editor And One For Shoppers). Its "No style" row draws its own note
|
|
4389
|
+
so the NAME keeps its width and the NOTE gives way (owner 2026-09-06) — the
|
|
4390
|
+
reverse of FieldSelect's meta, which is right for a price. */
|
|
4391
|
+
.es-fsel-label.sf-part-style-keep {
|
|
4392
|
+
flex: none;
|
|
4393
|
+
}
|
|
4394
|
+
.sf-part-style-aside {
|
|
4395
|
+
min-width: 0;
|
|
4396
|
+
margin-left: auto;
|
|
4397
|
+
overflow: hidden;
|
|
4398
|
+
text-overflow: ellipsis;
|
|
4399
|
+
white-space: nowrap;
|
|
4400
|
+
font-size: 11px;
|
|
4401
|
+
font-weight: 400;
|
|
4402
|
+
color: var(--es-muted);
|
|
4403
|
+
}
|
|
4404
|
+
.sf-part-style-meta {
|
|
4405
|
+
margin-top: 1px;
|
|
4406
|
+
font-size: 11px;
|
|
4407
|
+
color: var(--sf-muted);
|
|
4408
|
+
font-variant-numeric: tabular-nums;
|
|
4409
|
+
}
|
|
4410
|
+
.sf-part-style-top {
|
|
4411
|
+
display: flex;
|
|
4412
|
+
align-items: center;
|
|
4413
|
+
gap: 9px;
|
|
4414
|
+
margin-top: 8px;
|
|
4415
|
+
}
|
|
4416
|
+
/* Pushes "Edit style" to the end whatever sits before it — a note, or the chip
|
|
4417
|
+
and Clear all together. */
|
|
4418
|
+
.sf-part-style-gap {
|
|
4419
|
+
flex: 1;
|
|
4420
|
+
}
|
|
4421
|
+
/* THE STYLE CARD'S OWN SUBTITLE — not a note, and never was one (card 66123).
|
|
4422
|
+
It was called `.sf-part-style-note`, which is the only reason the note gate
|
|
4423
|
+
counted it: the third time a name alone put something in that family, after
|
|
4424
|
+
`.sf-image-slot-inert` and `.sf-device-scope` (card 66121). Two things say it
|
|
4425
|
+
is not a note. It is painted `--sf-text-secondary` where every real note is
|
|
4426
|
+
`--sf-muted` — a note is quiet BY COLOUR, and this line is not. And it does
|
|
4427
|
+
not sit under a block explaining it; it sits INSIDE the bordered style card,
|
|
4428
|
+
in a row with the override chip and "Edit style", finishing the card's own
|
|
4429
|
+
head where `.sf-part-style-name` and `-meta` leave off. Folded onto `.sf-note`
|
|
4430
|
+
it read at 13px and wrapped, taking "Edit style" over two lines with it. So
|
|
4431
|
+
it keeps its look exactly and takes an honest name. */
|
|
4432
|
+
.sf-part-style-state {
|
|
4433
|
+
font-size: 11.5px;
|
|
4434
|
+
color: var(--sf-text-secondary);
|
|
4435
|
+
}
|
|
4436
|
+
/* The override count. A chip rather than plain text because it is a NUMBER a
|
|
4437
|
+
merchant looks for, and because it has to read at a glance beside a link. */
|
|
4438
|
+
.sf-part-chip {
|
|
4439
|
+
display: inline-flex;
|
|
4440
|
+
align-items: center;
|
|
4441
|
+
border-radius: 999px;
|
|
4442
|
+
padding: 2px 9px;
|
|
4443
|
+
background: var(--sf-accent-tint);
|
|
4444
|
+
color: var(--sf-accent-text);
|
|
4445
|
+
font-size: 10.5px;
|
|
4446
|
+
font-weight: 700;
|
|
4447
|
+
font-variant-numeric: tabular-nums;
|
|
4448
|
+
}
|
|
4449
|
+
|
|
4450
|
+
/* The panel's one text-button link — "Edit style", "Clear all". Underlined
|
|
4451
|
+
rather than coloured-only, so it is still a link without colour vision. */
|
|
4452
|
+
.sf-part-link {
|
|
4453
|
+
border: 0;
|
|
4454
|
+
background: none;
|
|
4455
|
+
padding: 0;
|
|
4456
|
+
font: inherit;
|
|
4457
|
+
font-size: 12px;
|
|
4458
|
+
font-weight: 500;
|
|
4459
|
+
color: var(--sf-accent-text);
|
|
4460
|
+
cursor: pointer;
|
|
4461
|
+
text-decoration: underline;
|
|
4462
|
+
text-underline-offset: 3px;
|
|
4463
|
+
text-decoration-thickness: 1px;
|
|
4464
|
+
text-decoration-color: var(--sf-accent-ring);
|
|
4465
|
+
}
|
|
4466
|
+
.sf-part-link:hover {
|
|
4467
|
+
text-decoration-color: currentColor;
|
|
4468
|
+
}
|
|
4469
|
+
|
|
4470
|
+
/* THE GROUPS AND THE ROWS ARE NOT DRAWN HERE ANY MORE. `.es-group` /
|
|
4471
|
+
`.es-field` come from `efficient-easel/panel.css`, imported by each editor entry
|
|
4472
|
+
— the folding pill with its count chip and the icon + quiet label + loud value
|
|
4473
|
+
row are the shared grammar both editors' panels are built from. What is left
|
|
4474
|
+
below is only what this panel adds to them.
|
|
4475
|
+
|
|
4476
|
+
The override mark, half one, is theirs too: `.es-field.is-changed
|
|
4477
|
+
.es-field-label` takes the accent. Blue AND the dot is deliberately two
|
|
4478
|
+
signals — colour alone would not survive a colour-blind merchant or a
|
|
4479
|
+
greyscale screenshot, which is exactly when "why does this page not match the
|
|
4480
|
+
site" gets asked. */
|
|
4481
|
+
|
|
4482
|
+
/* One note for a whole group, where the rule it states belongs to every row in
|
|
4483
|
+
it rather than to any one of them (E6: a label is a name, never a sentence).
|
|
4484
|
+
It stands above the first row, so it takes the ROW's left inset instead of
|
|
4485
|
+
the panel's and pulls the group's own top gap back out from under itself.
|
|
4486
|
+
`.es-group-body` is editor-shell's, which is the block it genuinely sits in.
|
|
4487
|
+
Placement only; the note style itself is .sf-note. */
|
|
4488
|
+
.es-group-body > .sf-note {
|
|
4489
|
+
margin: 12px 0 -4px;
|
|
4490
|
+
padding: 0 0 0 2px;
|
|
4491
|
+
}
|
|
4492
|
+
|
|
4493
|
+
/* …and inside a SLOT LIST the note sits between the group heading and the rows
|
|
4494
|
+
it describes, so it takes the ROW's inset rather than the note's own default
|
|
4495
|
+
16px: `.es-drill` is `10px 11px` and `.sf-slot-rows .sf-add-card` is
|
|
4496
|
+
`8px 11px`, and a sentence stepped five pixels past the rows it is about
|
|
4497
|
+
reads as belonging to something above them. The BOX only — the colour, the
|
|
4498
|
+
size and the line-height stay the one note style's (card 66211). */
|
|
4499
|
+
.sf-slot-rows > .sf-note {
|
|
4500
|
+
padding: 10px 11px 12px;
|
|
4501
|
+
}
|
|
4502
|
+
|
|
4503
|
+
/* A value that reads "style" is not a measurement, so it is drawn as quietly as
|
|
4504
|
+
the label rather than as loudly as a number. */
|
|
4505
|
+
/* The `style` word is quieter than a number, because it is the absence of one.
|
|
4506
|
+
Since card 66275 that word lives inside the typeable readout rather than
|
|
4507
|
+
being the value slot's own text, so the rule has to reach the control the
|
|
4508
|
+
slot now holds — without it the row keeps drawing `style` at full strength
|
|
4509
|
+
and the one visual difference between "set" and "following the style"
|
|
4510
|
+
disappears. */
|
|
4511
|
+
.sf-part-field.is-style-value > .es-field-head > .es-field-value,
|
|
4512
|
+
.sf-part-field.is-style-value > .es-field-head > .es-field-value > .sf-slider-val {
|
|
4513
|
+
color: var(--sf-muted);
|
|
4514
|
+
}
|
|
4515
|
+
|
|
4516
|
+
/* The font dropdown fills the row like every other control in the panel; the
|
|
4517
|
+
inspector's own `select` rules give it its box. */
|
|
4518
|
+
.sf-part-select {
|
|
4519
|
+
width: 100%;
|
|
4520
|
+
min-width: 0;
|
|
4521
|
+
}
|
|
4522
|
+
|
|
4523
|
+
/* The `Color` row's control row: the dropdown, and — only once `Custom…` is
|
|
4524
|
+
chosen — the swatch and hex under it.
|
|
4525
|
+
|
|
4526
|
+
⚠️ A COLUMN, NOT A ROW, AND 220px IS WHY. `MIN_PANEL_W` is 220, which leaves
|
|
4527
|
+
a 181px content box; the dropdown alone wants that, and the swatch (26) plus
|
|
4528
|
+
the hex box (57) plus two 8px gaps is another 99. Side by side they do not
|
|
4529
|
+
fit, and the first thing to collapse would be the dropdown showing which
|
|
4530
|
+
colour is selected. Stacked, each keeps its full width at every panel size —
|
|
4531
|
+
and the shell's `SettingsField` already gives a row a control area under its
|
|
4532
|
+
label, so this costs no new shape.
|
|
4533
|
+
|
|
4534
|
+
The swatch pair is right-aligned to sit under the dropdown's own right edge,
|
|
4535
|
+
where `SettingsField`'s `action` slot puts every other trailing control. */
|
|
4536
|
+
.sf-part-ink {
|
|
4537
|
+
display: flex;
|
|
4538
|
+
flex-direction: column;
|
|
4539
|
+
gap: 8px;
|
|
4540
|
+
min-width: 0;
|
|
4541
|
+
}
|
|
4542
|
+
/* In this column the picker keeps its own box: the window opens under the
|
|
4543
|
+
dropdown at the column's width, and the swatch and hex sit at its end. */
|
|
4544
|
+
.sf-part-ink > .es-pick-colour > .es-pick-colour-row {
|
|
4545
|
+
align-self: flex-end;
|
|
4546
|
+
}
|
|
4547
|
+
|
|
4548
|
+
/* The override mark, half two — and it IS the reset button, which is why it is
|
|
4549
|
+
a real <button> with a name and not a painted dot. The dot shrinks away under
|
|
4550
|
+
the pointer and the reset arrow takes its place, so the affordance is
|
|
4551
|
+
discovered by hovering the only new thing on the row. */
|
|
4552
|
+
.sf-part-mark {
|
|
4553
|
+
width: 18px;
|
|
4554
|
+
height: 18px;
|
|
4555
|
+
flex: none;
|
|
4556
|
+
display: grid;
|
|
4557
|
+
place-items: center;
|
|
4558
|
+
padding: 0;
|
|
4559
|
+
border: 0;
|
|
4560
|
+
border-radius: 50%;
|
|
4561
|
+
background: none;
|
|
4562
|
+
color: var(--sf-accent);
|
|
4563
|
+
cursor: pointer;
|
|
4564
|
+
}
|
|
4565
|
+
.sf-part-mark-dot {
|
|
4566
|
+
transform-origin: center;
|
|
4567
|
+
transition: transform 0.15s ease, opacity 0.15s ease;
|
|
4568
|
+
}
|
|
4569
|
+
.sf-part-mark-arrow {
|
|
4570
|
+
opacity: 0;
|
|
4571
|
+
transition: opacity 0.15s ease;
|
|
4572
|
+
}
|
|
4573
|
+
.sf-part-mark:hover .sf-part-mark-dot,
|
|
4574
|
+
.sf-part-mark:focus-visible .sf-part-mark-dot {
|
|
4575
|
+
transform: scale(0);
|
|
4576
|
+
opacity: 0;
|
|
4577
|
+
}
|
|
4578
|
+
.sf-part-mark:hover .sf-part-mark-arrow,
|
|
4579
|
+
.sf-part-mark:focus-visible .sf-part-mark-arrow {
|
|
4580
|
+
opacity: 1;
|
|
4581
|
+
}
|
|
4582
|
+
@media (prefers-reduced-motion: reduce) {
|
|
4583
|
+
.sf-part-mark-dot,
|
|
4584
|
+
.sf-part-mark-arrow {
|
|
4585
|
+
transition: none;
|
|
4586
|
+
}
|
|
4587
|
+
}
|
|
4588
|
+
|
|
4589
|
+
/* The copy box at the TOP of the drill (card 8819). Clicking a word drills
|
|
4590
|
+
straight to its editor, so the box is the first thing on the part screen —
|
|
4591
|
+
right under the way back, above the style it follows. It is the plain copy box
|
|
4592
|
+
(.sf-copybox) the section screen used to draw; only its placement is here. */
|
|
4593
|
+
.sf-part-text {
|
|
4594
|
+
margin-top: 4px;
|
|
4595
|
+
margin-bottom: 4px;
|
|
4596
|
+
}
|
|
4597
|
+
/* Roomy in the drill: this is the part's PRIMARY editor now, not a folded-away
|
|
4598
|
+
afterthought, so a multi-line field opens with room to write rather than the
|
|
4599
|
+
browser's two-row default. Scoped to the drill so the identifier rows (a slide
|
|
4600
|
+
name) and every other panel's copy box keep their own height. */
|
|
4601
|
+
.sf-part-text .sf-copybox textarea {
|
|
4602
|
+
min-height: 84px;
|
|
4603
|
+
line-height: 1.5;
|
|
4604
|
+
resize: vertical;
|
|
4605
|
+
}
|
|
4606
|
+
|
|
4607
|
+
/* ── The text ENTRY group at the bottom of the section screen (card 8819) ──── */
|
|
4608
|
+
|
|
4609
|
+
/* The section screen lists its scalar text parts here, under the real settings,
|
|
4610
|
+
as the way into each part's drill. The rows themselves are the shell's
|
|
4611
|
+
`.es-drill` (single source); this is only the group frame around them. */
|
|
4612
|
+
.sf-entries {
|
|
4613
|
+
margin-top: 32px;
|
|
4614
|
+
}
|
|
4615
|
+
|
|
4616
|
+
|
|
4617
|
+
/* The group's caption — the section panel's small-caps heading, so this group
|
|
4618
|
+
reads like the buckets above it. A real <h3>, so it joins the panel outline. */
|
|
4619
|
+
.sf-entries-head {
|
|
4620
|
+
margin: 14px 0 4px;
|
|
4621
|
+
font-size: 11px;
|
|
4622
|
+
font-weight: 600;
|
|
4623
|
+
letter-spacing: 0.06em;
|
|
4624
|
+
text-transform: uppercase;
|
|
4625
|
+
color: var(--sf-muted);
|
|
4626
|
+
}
|
|
4627
|
+
|
|
4628
|
+
/* The "hidden on the page" eye a row carries when a part is toggled off — the
|
|
4629
|
+
same cue the copy box's own eye draws, so the two read as one idea. */
|
|
4630
|
+
.sf-entry-eye {
|
|
4631
|
+
display: inline-flex;
|
|
4632
|
+
align-items: center;
|
|
4633
|
+
color: var(--sf-muted);
|
|
4634
|
+
}
|
|
4635
|
+
|
|
4636
|
+
/* ── A slot section's children, listed in its OWN panel (card 66186) ──────────
|
|
4637
|
+
The Hero Slideshow's Content tab was empty: `slides` is a slot, and Puck draws
|
|
4638
|
+
a slot as nothing in the inspector, so the slides were reachable only from the
|
|
4639
|
+
Sections tree. The rows are the shell's `.es-drill` (single source, as in
|
|
4640
|
+
`.sf-entries` above) and the heading is the panel's own `.sf-field-group`, so
|
|
4641
|
+
the only thing this frame owns is where the add row meets them.
|
|
4642
|
+
|
|
4643
|
+
It owns that because the two come from different places and did not line up:
|
|
4644
|
+
`.sf-add-card` is the TREE's affordance and pads `6px 9px`, a drill row pads
|
|
4645
|
+
`10px 11px`, so the "+" sat 2px inside the names above it (measured).
|
|
4646
|
+
|
|
4647
|
+
⚠️ It used to draw a `border-top` as well, to match the `.es-drill + .es-drill`
|
|
4648
|
+
separator that could not reach a row which is not a drill. That separator is
|
|
4649
|
+
gone entirely now — editor-shell 0.29.0 deleted it and card 66351 deleted this
|
|
4650
|
+
repo's override of it — so matching it means drawing NOTHING, and the padding
|
|
4651
|
+
above is the whole of what this rule still owns. */
|
|
4652
|
+
.sf-slot-rows .sf-add-card {
|
|
4653
|
+
padding: 8px 11px;
|
|
4654
|
+
border-radius: 0;
|
|
4655
|
+
}
|
|
4656
|
+
|
|
4657
|
+
/* The drop zone round the media row's box. `SettingsField` puts its control in
|
|
4658
|
+
`.es-field-ctl`, a flex ROW, where a plain block shrinks to its content: the
|
|
4659
|
+
empty slot drew 190px wide in a 280px row. It takes the row instead. */
|
|
4660
|
+
.sf-image-drop {
|
|
4661
|
+
flex: 1;
|
|
4662
|
+
min-width: 0;
|
|
4663
|
+
}
|
|
4664
|
+
/* Drag-over highlight for the media row (MediaUploadField's drop shortcut):
|
|
4665
|
+
the empty slot takes the accent, a filled picture an accent ring. */
|
|
4666
|
+
.sf-image-drop.is-dragover .es-pick-image-slot {
|
|
4667
|
+
border-color: var(--sf-accent);
|
|
4668
|
+
background-color: var(--sf-accent-tint);
|
|
4669
|
+
}
|
|
4670
|
+
.sf-image-drop.is-dragover .es-pick-image-frame {
|
|
4671
|
+
outline: 2px solid var(--sf-accent);
|
|
4672
|
+
outline-offset: -2px;
|
|
4673
|
+
}
|
|
4674
|
+
|
|
4675
|
+
|
|
4676
|
+
/* ── THE PHOTO WALL'S LAYOUT PICKER ─────────────────────────────────────────
|
|
4677
|
+
The Customer Photo Grid's one layout control: a strip of pictures, filtered by
|
|
4678
|
+
how many photos sit in a row. The owner, 2026-09-07, on the numbers it
|
|
4679
|
+
replaced: he could not read them, and he was right — 6·3·3, 2·1·1 and "two
|
|
4680
|
+
thirds" were three notations for one idea. There are no numbers on this
|
|
4681
|
+
control at all. The picture is the explanation and the name is only so the
|
|
4682
|
+
layout can be named.
|
|
4683
|
+
|
|
4684
|
+
⚠️ THE FILTER CHIPS CARRY NO ICON, and that is his ruling of 2026-08-29 about
|
|
4685
|
+
filter rows, applying here for the reason he gave: the buckets are grown from
|
|
4686
|
+
the layouts, so a glyph per bucket is a queue that never empties.
|
|
4687
|
+
|
|
4688
|
+
THE STRIP FILLS BY TILE WIDTH, NOT BY A COLUMN COUNT. `auto-fill` with a 58px
|
|
4689
|
+
minimum gives four across the 320px panel and three at the 220px minimum, so
|
|
4690
|
+
nothing is cut off and nothing scrolls sideways at either width. */
|
|
4691
|
+
.sf-gallery-filter {
|
|
4692
|
+
display: flex;
|
|
4693
|
+
gap: 5px;
|
|
4694
|
+
flex-wrap: wrap;
|
|
4695
|
+
}
|
|
4696
|
+
.sf-gallery-filter button {
|
|
4697
|
+
border: 1px solid var(--sf-input-border);
|
|
4698
|
+
background: var(--sf-field-bg);
|
|
4699
|
+
border-radius: 999px;
|
|
4700
|
+
padding: 4px 11px;
|
|
4701
|
+
font-size: 11.5px;
|
|
4702
|
+
font-weight: 600;
|
|
4703
|
+
color: var(--sf-icon);
|
|
4704
|
+
cursor: pointer;
|
|
4705
|
+
transition: background 0.12s, color 0.12s, border-color 0.12s;
|
|
4706
|
+
}
|
|
4707
|
+
.sf-gallery-filter button:hover {
|
|
4708
|
+
background: var(--sf-hover);
|
|
4709
|
+
}
|
|
4710
|
+
.sf-gallery-filter button[aria-pressed="true"] {
|
|
4711
|
+
background: var(--sf-accent);
|
|
4712
|
+
border-color: var(--sf-accent);
|
|
4713
|
+
color: var(--sf-on-accent);
|
|
4714
|
+
}
|
|
4715
|
+
|
|
4716
|
+
.sf-gallery-layouts {
|
|
4717
|
+
display: grid;
|
|
4718
|
+
grid-template-columns: repeat(auto-fill, minmax(58px, 1fr));
|
|
4719
|
+
gap: 6px;
|
|
4720
|
+
margin-top: 7px;
|
|
4721
|
+
}
|
|
4722
|
+
/* ⚠️ THE STRIP MUST BE TOLD TO FILL THE SHELL'S CONTROL SLOT, OR IT COLLAPSES.
|
|
4723
|
+
editor-shell card 66516, and the shop is now the second consumer to meet it.
|
|
4724
|
+
|
|
4725
|
+
`SettingsField` stacks its control into `.es-field-ctl`, and that slot is
|
|
4726
|
+
`display: flex`. A grid written for a BLOCK row — which this was, for its whole
|
|
4727
|
+
life — therefore stops stretching and sizes to its own content. Measured on
|
|
4728
|
+
this card's board: 291px wide before the move, 58px after. One tile per line,
|
|
4729
|
+
nineteen lines deep, and every layout still clickable, so nothing looked
|
|
4730
|
+
broken enough to fail.
|
|
4731
|
+
|
|
4732
|
+
The shell already ships this exact two-line cure for its own `.es-tabs-fit`
|
|
4733
|
+
and `.es-segs-fit`, and its note on that rule is the reason this comment is
|
|
4734
|
+
long: card 66508 shipped 1198 green checks over a control 0px wide, because
|
|
4735
|
+
every check asked whether markup EXISTED and none asked whether it OCCUPIED
|
|
4736
|
+
SPACE. `scripts/probe-settings-rows-shared.mjs` now asks that question, which
|
|
4737
|
+
is what caught this one.
|
|
4738
|
+
|
|
4739
|
+
`flex: 1 1 auto` and not a width, because the slot may hold a value readout
|
|
4740
|
+
or a second control beside the strip. `min-width: 0` because a flex item's
|
|
4741
|
+
automatic minimum is its content size, which is what stops it shrinking.
|
|
4742
|
+
|
|
4743
|
+
⚠️ BOTH GALLERY CONTROLS ARE NAMED, and the second one is why this is a rule
|
|
4744
|
+
and not a patch. `.sf-gallery-filter` — the `Photos in a row` chips — is the
|
|
4745
|
+
same shape, and it did NOT look broken: measured 291px before and 185px after
|
|
4746
|
+
at a 320px panel, with the row a pixel and a half SHORTER, because the chips
|
|
4747
|
+
simply stopped stretching. Nothing wrapped at the two widths that were
|
|
4748
|
+
measured, so every height check passed. What it had was a smaller box to wrap
|
|
4749
|
+
inside at any width nobody happened to measure.
|
|
4750
|
+
|
|
4751
|
+
⚠️ SO THIS IS A DEFECT A HEIGHT RULE CANNOT CATCH, AND THAT IS THE POINT.
|
|
4752
|
+
The card that made this change stops at a row moving more than about 6px
|
|
4753
|
+
(GG, 2026-09-22). This row moved 1.5px, in the RIGHT direction, and was
|
|
4754
|
+
wrong. Measuring how tall a row stands cannot see a control that quietly
|
|
4755
|
+
stopped filling it — only asking the width can, which is why
|
|
4756
|
+
`scripts/probe-settings-rows-shared.mjs` now asks it of every row on both
|
|
4757
|
+
sides, and why that question found both of these on its first run.
|
|
4758
|
+
|
|
4759
|
+
A rule that fixed the strip and left the chips would be a trap wearing a fix
|
|
4760
|
+
— which is exactly what the shell says about naming both of its own `-fit`
|
|
4761
|
+
wrappers. This is the FOURTH instance of this collapse in this repo:
|
|
4762
|
+
`.sf-slider` carries the same two lines from card 66247, and the shell
|
|
4763
|
+
carries them for `.es-tabs-fit` and `.es-segs-fit`.
|
|
4764
|
+
|
|
4765
|
+
`.sf-linkstack` was on this list until the link field became the shared
|
|
4766
|
+
picker ([MERGE] One Link Picker For Both Editors): its stack is now the
|
|
4767
|
+
shell's own `.es-flink`, and the shell carries the same two lines for it.
|
|
4768
|
+
Every consumer control that is a flex or grid box written for a block row
|
|
4769
|
+
belongs on this selector; the day one is fixed somewhere else instead, the
|
|
4770
|
+
list stops being the place to look. */
|
|
4771
|
+
.es-field-ctl > .sf-gallery-layouts,
|
|
4772
|
+
.es-field-ctl > .sf-gallery-filter {
|
|
4773
|
+
flex: 1 1 auto;
|
|
4774
|
+
min-width: 0;
|
|
4775
|
+
}
|
|
4776
|
+
.sf-gallery-layouts button {
|
|
4777
|
+
border: 1px solid var(--sf-input-border);
|
|
4778
|
+
background: var(--sf-field-bg);
|
|
4779
|
+
border-radius: 7px;
|
|
4780
|
+
padding: 5px;
|
|
4781
|
+
cursor: pointer;
|
|
4782
|
+
transition: border-color 0.12s, box-shadow 0.12s, background 0.12s;
|
|
4783
|
+
}
|
|
4784
|
+
.sf-gallery-layouts button:hover {
|
|
4785
|
+
background: var(--sf-hover);
|
|
4786
|
+
}
|
|
4787
|
+
.sf-gallery-layouts button[aria-pressed="true"] {
|
|
4788
|
+
border-color: var(--sf-accent);
|
|
4789
|
+
box-shadow: 0 0 0 2px var(--sf-accent-ring);
|
|
4790
|
+
background: var(--sf-panel);
|
|
4791
|
+
}
|
|
4792
|
+
|
|
4793
|
+
/* The little drawing of a wall. Same twelve positions the real wall uses, so the
|
|
4794
|
+
picture cannot disagree with what pressing it draws. */
|
|
4795
|
+
.sf-gallery-pic {
|
|
4796
|
+
display: grid;
|
|
4797
|
+
grid-template-columns: repeat(12, minmax(0, 1fr));
|
|
4798
|
+
grid-auto-rows: 6px;
|
|
4799
|
+
grid-auto-flow: row dense;
|
|
4800
|
+
gap: 2px;
|
|
4801
|
+
}
|
|
4802
|
+
.sf-gallery-pic i {
|
|
4803
|
+
display: block;
|
|
4804
|
+
background: var(--sf-track-bg);
|
|
4805
|
+
border-radius: 1.5px;
|
|
4806
|
+
}
|
|
4807
|
+
.sf-gallery-layouts button[aria-pressed="true"] .sf-gallery-pic i {
|
|
4808
|
+
background: var(--sf-accent);
|
|
4809
|
+
}
|
|
4810
|
+
|
|
4811
|
+
/* How many the filter left. Without it an empty-looking strip is a mystery. */
|
|
4812
|
+
.sf-gallery-count {
|
|
4813
|
+
font-size: 10.5px;
|
|
4814
|
+
color: var(--sf-disabled);
|
|
4815
|
+
margin-top: 7px;
|
|
4816
|
+
}
|
|
4817
|
+
|
|
4818
|
+
/* ── Side panel heads (components/SidePanelHead) ─────────────────────────
|
|
4819
|
+
Every side panel's head is efficient-easel's `InspectorHead`; these two
|
|
4820
|
+
are the pieces the website editor adds to it. The hairline parts a panel's
|
|
4821
|
+
own tools from the hide button that ends every head, and a mode's way out
|
|
4822
|
+
is a word ("Done", "Cancel") on the engine's ghost button, drawn to the
|
|
4823
|
+
28px of the head's icon buttons so the row keeps one height. */
|
|
4824
|
+
|
|
4825
|
+
/* ── The Contact / Locations inspector's level views ────────────────────────
|
|
4826
|
+
LocationsGroupedField shows ONE level at a time (section, group, city, its
|
|
4827
|
+
image or map). Each level used to be wrapped in a bare `.sf-field`, which
|
|
4828
|
+
made the whole view one "row" with rows inside it. The rows are
|
|
4829
|
+
efficient-easel's `SettingsField` now ([MERGE] One Settings Row And Hint In
|
|
4830
|
+
The Website Editor, 2026-10-06); this keeps the view's own top air, from the
|
|
4831
|
+
shell's rhythm token like every row beside it. */
|
|
4832
|
+
.sf-locations-view {
|
|
4833
|
+
margin-top: var(--es-rhythm-between);
|
|
4834
|
+
}
|
|
4835
|
+
|
|
4836
|
+
/* ── A quiet line that belongs to no row ────────────────────────────────────
|
|
4837
|
+
[MERGE] One Settings Row And Hint In The Website Editor, 2026-10-06. A line
|
|
4838
|
+
UNDER A CONTROL is `SettingsField`'s own `hint`. A few lines sit under no
|
|
4839
|
+
row — the caption inside a linked-source card, a panel's opening sentence,
|
|
4840
|
+
the empty state of an open focus picker — and they wear the SAME class,
|
|
4841
|
+
`<p class="es-field-hint sf-hint-keep">`: one hint line in the whole editor,
|
|
4842
|
+
not a shop copy of its look. That replaces the shop's `.sf-field-hint` and
|
|
4843
|
+
`.sf-blogsource-hint`, which drew this idea twice, slightly differently.
|
|
4844
|
+
|
|
4845
|
+
Not a NEW class, and not `.sf-note`: `test-editor-chrome-note` holds the
|
|
4846
|
+
chrome to ONE note style, and these are hints, at the hint's size.
|
|
4847
|
+
`sf-hint-keep` on the element keeps the hints switch off them — none is a
|
|
4848
|
+
row's explanation.
|
|
4849
|
+
|
|
4850
|
+
Inside a source card the card's own gap spaces it. */
|
|
4851
|
+
.sf-blogsource > .es-field-hint,
|
|
4852
|
+
.sf-formsummary .es-field-hint {
|
|
4853
|
+
margin: 0;
|
|
4854
|
+
}
|
|
4855
|
+
|
|
4856
|
+
/* The copy box sits in `SettingsField`'s control slot, which is
|
|
4857
|
+
`display: flex` — the trap the Gallery layouts note above describes. Told to
|
|
4858
|
+
fill the slot, or it shrinks to its own words. (The select fields need no
|
|
4859
|
+
rule: easel's `.es-fsel` is `width: 100%` itself.) */
|
|
4860
|
+
.es-field-ctl > .sf-copybox {
|
|
4861
|
+
flex: 1 1 auto;
|
|
4862
|
+
min-width: 0;
|
|
4863
|
+
}
|
|
4864
|
+
|
|
4865
|
+
/* The focal-point picker's row is TextStyleRow's disclosure row, not a
|
|
4866
|
+
SettingsField; this keeps the gap above it that its old bare `.sf-field`
|
|
4867
|
+
wrapper gave, from the same rhythm token. */
|
|
4868
|
+
.sf-focal-row {
|
|
4869
|
+
margin-top: var(--es-rhythm-between);
|
|
4870
|
+
}
|