/* savoy-custom.css — Savoy runtime theme, ported VERBATIM from the licensed theme's inline
   nm-custom-styles block (Redux customizer output, home.html). Colors + spacing kept EXACTLY
   for a 1-1 clone. Loaded 12th (after elements.css) so it governs the runtime theme.
   Brand layer at the bottom overrides ONLY fonts (per DESIGN-LANGUAGE) + fixes the icon-font path. */

:root{ --nm--font-size-xsmall:12px;--nm--font-size-small:14px;--nm--font-size-medium:16px;--nm--font-size-large:18px;--nm--color-font:#777777;--nm--color-font-strong:;--nm--color-font-highlight:#dc9814;--nm--color-border:#eeeeee;--nm--color-divider:#cccccc;--nm--color-button:#ffffff;--nm--color-button-background:#282828;--nm--color-body-background:#ffffff;--nm--border-radius-container:0px;--nm--border-radius-image:0px;--nm--border-radius-image-fullwidth:0px;--nm--border-radius-inputs:0px;--nm--border-radius-button:0px;--nm--mobile-menu-color-font:#555555;--nm--mobile-menu-color-font-hover:#282828;--nm--mobile-menu-color-border:#eeeeee;--nm--mobile-menu-color-background:#ffffff;--nm--shop-preloader-color:#ffffff;--nm--shop-preloader-gradient:linear-gradient(90deg, rgba(238,238,238,0) 20%, rgba(238,238,238,0.3) 50%, rgba(238,238,238,0) 70%);--nm--shop-rating-color:#dc9814;--nm--single-product-background-color:#eeeeee;--nm--single-product-background-color-mobile:#eeeeee;--nm--single-product-mobile-gallery-width:500px;}body{font-family:"Roboto",sans-serif;}.nm-menu li a{font-size:16px;font-weight:normal;}#nm-mobile-menu .menu > li > a{font-weight:normal;}#nm-mobile-menu-main-ul.menu > li > a{font-size:18px;}#nm-mobile-menu-secondary-ul.menu li a,#nm-mobile-menu .sub-menu a{font-size:15px;}.vc_tta.vc_tta-accordion .vc_tta-panel-title > a,.vc_tta.vc_general .vc_tta-tab > a,.nm-team-member-content h2,.nm-post-slider-content h3,.vc_pie_chart .wpb_pie_chart_heading,.wpb_content_element .wpb_tour_tabs_wrapper .wpb_tabs_nav a,.wpb_content_element .wpb_accordion_header a,#order_review .shop_table tfoot .order-total,#order_review .shop_table tfoot .order-total,.cart-collaterals .shop_table tr.order-total,.shop_table.cart .nm-product-details a,#nm-shop-sidebar-popup #nm-shop-search input,.nm-shop-categories li a,.nm-shop-filter-menu li a,.woocommerce-message,.woocommerce-info,.woocommerce-error,blockquote,.commentlist .comment .comment-text .meta strong,.nm-related-posts-content h3,.nm-blog-no-results h1,.nm-term-description,.nm-blog-categories-list li a,.nm-blog-categories-toggle li a,.nm-blog-heading h1,#nm-mobile-menu-top-ul .nm-mobile-menu-item-search input{font-size:18px;}@media all and (max-width:768px){.vc_toggle_title h3{font-size:18px;}}@media all and (max-width:400px){#nm-shop-search input{font-size:18px;}}.add_to_cart_inline .add_to_cart_button,.add_to_cart_inline .amount,.nm-product-category-text > a,.nm-testimonial-description,.nm-feature h3,.nm_btn,.vc_toggle_content,.nm-message-box,.wpb_text_column,#nm-wishlist-table ul li.title .woocommerce-loop-product__title,.nm-order-track-top p,.customer_details h3,.woocommerce-order-details .order_details tbody,.woocommerce-MyAccount-content .shop_table tr th,.woocommerce-MyAccount-navigation ul li a,.nm-MyAccount-user-info .nm-username,.nm-MyAccount-dashboard,.nm-myaccount-lost-reset-password h2,.nm-login-form-divider span,.woocommerce-thankyou-order-details li strong,.woocommerce-order-received h3,#order_review .shop_table tbody .product-name,.woocommerce-checkout .nm-coupon-popup-wrap .nm-shop-notice,.nm-checkout-login-coupon .nm-shop-notice,.shop_table.cart .nm-product-quantity-pricing .product-subtotal,.shop_table.cart .product-quantity,.shop_attributes tr th,.shop_attributes tr td,#tab-description,.woocommerce-tabs .tabs li a,.woocommerce-product-details__short-description,.nm-shop-no-products h3,.nm-infload-controls a,#nm-shop-browse-wrap .term-description,.list_nosep .nm-shop-categories .nm-shop-sub-categories li a,.nm-shop-taxonomy-text .term-description,.nm-shop-loop-details h3,.woocommerce-loop-category__title,div.wpcf7-response-output,.wpcf7 .wpcf7-form-control,.widget_search button,.widget_product_search #searchsubmit,#wp-calendar caption,.widget .nm-widget-title,.post .entry-content,.comment-form p label,.no-comments,.commentlist .pingback p,.commentlist .trackback p,.commentlist .comment .comment-text .description,.nm-search-results .nm-post-content,.post-password-form > p:first-child,.nm-post-pagination a .long-title,.nm-blog-list .nm-post-content,.nm-blog-grid .nm-post-content,.nm-blog-classic .nm-post-content,.nm-blog-pagination a,.nm-blog-categories-list.columns li a,.page-numbers li a,.page-numbers li span,#nm-widget-panel .total,#nm-widget-panel .nm-cart-panel-item-price .amount,#nm-widget-panel .quantity .qty,#nm-widget-panel .nm-cart-panel-quantity-pricing > span.quantity,#nm-widget-panel .product-quantity,.nm-cart-panel-product-title,#nm-widget-panel .product_list_widget .empty,#nm-cart-panel-loader h5,.nm-widget-panel-header,.button,input[type=submit]{font-size:16px;}@media all and (max-width:991px){#nm-shop-sidebar .widget .nm-widget-title,.nm-shop-categories li a{font-size:16px;}}@media all and (max-width:768px){.vc_tta.vc_tta-accordion .vc_tta-panel-title > a,.vc_tta.vc_tta-tabs.vc_tta-tabs-position-left .vc_tta-tab > a,.vc_tta.vc_tta-tabs.vc_tta-tabs-position-top .vc_tta-tab > a,.wpb_content_element .wpb_tour_tabs_wrapper .wpb_tabs_nav a,.wpb_content_element .wpb_accordion_header a,.nm-term-description{font-size:16px;}}@media all and (max-width:550px){.shop_table.cart .nm-product-details a,.nm-shop-notice,.nm-related-posts-content h3{font-size:16px;}}@media all and (max-width:400px){.nm-product-category-text .nm-product-category-heading,.nm-team-member-content h2,#nm-wishlist-empty h1,.cart-empty,.nm-shop-filter-menu li a,.nm-blog-categories-list li a{font-size:16px;}}.vc_progress_bar .vc_single_bar .vc_label,.woocommerce-tabs .tabs li a span,#nm-shop-sidebar-popup-reset-button,#nm-shop-sidebar-popup .nm-shop-sidebar .widget:last-child .nm-widget-title,#nm-shop-sidebar-popup .nm-shop-sidebar .widget .nm-widget-title,.woocommerce-loop-category__title .count,span.wpcf7-not-valid-tip,.widget_rss ul li .rss-date,.wp-caption-text,.comment-respond h3 #cancel-comment-reply-link,.nm-blog-categories-toggle li .count,.nm-menu-wishlist-count,.nm-menu li.nm-menu-offscreen .nm-menu-cart-count,.nm-menu-cart .count,.nm-menu .sub-menu li a,body{font-size:14px;}@media all and (max-width:768px){.wpcf7 .wpcf7-form-control{font-size:14px;}}@media all and (max-width:400px){.nm-blog-grid .nm-post-content,.header-mobile-default .nm-menu-cart.no-icon .count{font-size:14px;}}#nm-wishlist-table .nm-variations-list,.nm-MyAccount-user-info .nm-logout-button.border,#order_review .place-order noscript,#payment .payment_methods li .payment_box,#order_review .shop_table tfoot .woocommerce-remove-coupon,.cart-collaterals .shop_table tr.cart-discount td a,#nm-shop-sidebar-popup #nm-shop-search-notice,.wc-item-meta,.variation,.woocommerce-password-hint,.woocommerce-password-strength,.nm-validation-inline-notices .form-row.woocommerce-invalid-required-field:after{font-size:12px;}body{font-weight:normal;}h1, .h1-size{font-weight:normal;}h2, .h2-size{font-weight:normal;}h3, .h3-size{font-weight:normal;}h4, .h4-size,h5, .h5-size,h6, .h6-size{font-weight:normal;}body{color:#777777;}.nm-portfolio-single-back a span {background:#777777;}.mfp-close,.wpb_content_element .wpb_tour_tabs_wrapper .wpb_tabs_nav li.ui-tabs-active a,.vc_pie_chart .vc_pie_chart_value,.vc_progress_bar .vc_single_bar .vc_label .vc_label_units,.nm-testimonial-description,.form-row label,.woocommerce-form__label,#nm-shop-search-close:hover,.products .price .amount,.nm-shop-loop-actions > a,.nm-shop-loop-actions > a:active,.nm-shop-loop-actions > a:focus,.nm-infload-controls a,.woocommerce-breadcrumb a, .woocommerce-breadcrumb span,.variations,.woocommerce-grouped-product-list-item__label a,.woocommerce-grouped-product-list-item__price ins .amount,.woocommerce-grouped-product-list-item__price > .amount,.nm-quantity-wrap .quantity .nm-qty-minus,.nm-quantity-wrap .quantity .nm-qty-plus,.product .summary .single_variation_wrap .nm-quantity-wrap label:not(.nm-qty-label-abbrev),.woocommerce-tabs .tabs li.active a,.shop_attributes th,.product_meta,.shop_table.cart .nm-product-details a,.shop_table.cart .product-quantity,.shop_table.cart .nm-product-quantity-pricing .product-subtotal,.shop_table.cart .product-remove a,.cart-collaterals,.nm-cart-empty,#order_review .shop_table,#payment .payment_methods li label,.woocommerce-thankyou-order-details li strong,.wc-bacs-bank-details li strong,.nm-MyAccount-user-info .nm-username strong,.woocommerce-MyAccount-navigation ul li a:hover,.woocommerce-MyAccount-navigation ul li.is-active a,.woocommerce-table--order-details,#nm-wishlist-empty .note i,a.dark,a:hover,.nm-blog-heading h1 strong,.nm-post-header .nm-post-meta a,.nm-post-pagination a,.commentlist > li .comment-text .meta strong,.commentlist > li .comment-text .meta strong a,.comment-form p label,.entry-content strong,blockquote,blockquote p,.widget_search button,.widget_product_search #searchsubmit,.widget_recent_comments ul li .comment-author-link,.widget_recent_comments ul li:before{color:;}@media all and (max-width: 991px){.nm-shop-menu .nm-shop-filter-menu li a:hover,.nm-shop-menu .nm-shop-filter-menu li.active a,#nm-shop-sidebar .widget.show .nm-widget-title,#nm-shop-sidebar .widget .nm-widget-title:hover{color:;}}.nm-portfolio-single-back a:hover span{background:;}.wpb_content_element .wpb_tour_tabs_wrapper .wpb_tabs_nav a,.wpb_content_element .wpb_accordion_header a,#nm-shop-search-close,.woocommerce-breadcrumb,.nm-single-product-menu a,.star-rating:before,.woocommerce-tabs .tabs li a,.product_meta span.sku,.product_meta a,.nm-post-meta,.nm-post-pagination a .short-title,.commentlist > li .comment-text .meta time{color:#a3a3a3;}.vc_toggle_title i,#nm-wishlist-empty p.icon i,h1{color:#282828;}h2{color:#282828;}h3{color:#282828;}h4, h5, h6{color:#282828;}a,a.dark:hover,a.gray:hover,a.invert-color:hover,.nm-highlight-text,.nm-highlight-text h1,.nm-highlight-text h2,.nm-highlight-text h3,.nm-highlight-text h4,.nm-highlight-text h5,.nm-highlight-text h6,.nm-highlight-text p,.nm-menu-wishlist-count,.nm-menu-cart a .count,.nm-menu li.nm-menu-offscreen .nm-menu-cart-count,.page-numbers li span.current,.page-numbers li a:hover,.nm-blog .sticky .nm-post-thumbnail:before,.nm-blog .category-sticky .nm-post-thumbnail:before,.nm-blog-categories-list li a:hover,.nm-blog-categories ul li.current-cat a,.widget ul li.active,.widget ul li a:hover,.widget ul li a:focus,.widget ul li a.active,#wp-calendar tbody td a,.nm-banner-link.type-txt:hover,.nm-banner.text-color-light .nm-banner-link.type-txt:hover,.nm-portfolio-categories li.current a,.add_to_cart_inline ins,.nm-product-categories.layout-separated .product-category:hover .nm-product-category-text > a,.woocommerce-breadcrumb a:hover,.products .price ins .amount,.products .price ins,.no-touch .nm-shop-loop-actions > a:hover,.nm-shop-menu ul li a:hover,.nm-shop-menu ul li.current-cat > a,.nm-shop-menu ul li.active a,.nm-shop-heading span,.nm-single-product-menu a:hover,.woocommerce-product-gallery__trigger:hover,.woocommerce-product-gallery .flex-direction-nav a:hover,.product-summary .price .amount,.product-summary .price ins,.product .summary .price .amount,.nm-product-wishlist-button-wrap a.added:active,.nm-product-wishlist-button-wrap a.added:focus,.nm-product-wishlist-button-wrap a.added:hover,.nm-product-wishlist-button-wrap a.added,.woocommerce-tabs .tabs li a span,.product_meta a:hover,.nm-order-view .commentlist li .comment-text .meta,.nm_widget_price_filter ul li.current,.post-type-archive-product .widget_product_categories .product-categories > li:first-child > a,.widget_product_categories ul li.current-cat > a,.widget_layered_nav ul li.chosen a,.widget_layered_nav_filters ul li.chosen a,.product_list_widget li ins .amount,.woocommerce.widget_rating_filter .wc-layered-nav-rating.chosen > a,.nm-wishlist-button.added:active,.nm-wishlist-button.added:focus,.nm-wishlist-button.added:hover,.nm-wishlist-button.added,.slick-prev:not(.slick-disabled):hover,.slick-next:not(.slick-disabled):hover,.flickity-button:hover,.nm-portfolio-categories li a:hover{color:#dc9814;}.nm-blog-categories ul li.current-cat a,.nm-portfolio-categories li.current a,.woocommerce-product-gallery.pagination-enabled .flex-control-thumbs li img.flex-active,.widget_layered_nav ul li.chosen a,.widget_layered_nav_filters ul li.chosen a,.slick-dots li.slick-active button,.flickity-page-dots .dot.is-selected{border-color:#dc9814;}.nm-image-overlay:before,.nm-image-overlay:after,.gallery-icon:before,.gallery-icon:after,.widget_tag_cloud a:hover,.widget_product_tag_cloud a:hover{background:#dc9814;}@media all and (max-width:400px){.woocommerce-product-gallery.pagination-enabled .flex-control-thumbs li img.flex-active,.slick-dots li.slick-active button,.flickity-page-dots .dot.is-selected{background:#dc9814;}}.header-border-1 .nm-header,.nm-blog-list .nm-post-divider,#nm-blog-pagination.infinite-load,.nm-post-pagination,.no-post-comments .nm-related-posts,.nm-footer-widgets.has-border,#nm-shop-browse-wrap.nm-shop-description-borders .term-description,.nm-shop-sidebar-default #nm-shop-sidebar .widget,.products.grid-list li:not(:last-child) .nm-shop-loop-product-wrap,.nm-infload-controls a,.woocommerce-tabs,.upsells,.related,.shop_table.cart tr td,#order_review .shop_table tbody tr th,#order_review .shop_table tbody tr td,#payment .payment_methods,#payment .payment_methods li,.woocommerce-MyAccount-orders tr td,.woocommerce-MyAccount-orders tr:last-child td,.woocommerce-table--order-details tbody tr td,.woocommerce-table--order-details tbody tr:first-child td,.woocommerce-table--order-details tfoot tr:last-child td,.woocommerce-table--order-details tfoot tr:last-child th,#nm-wishlist-table > ul > li,#nm-wishlist-table > ul:first-child > li,.wpb_accordion .wpb_accordion_section,.nm-portfolio-single-footer{border-color:#eeeeee;}.nm-search-results .nm-post-divider{background:#eeeeee;}.nm-blog-categories-list li span,.nm-portfolio-categories li span{color: #cccccc;}.nm-post-meta:before,.nm-testimonial-author span:before{background:#cccccc;}.nm-border-radius{border-radius:0px;}@media (max-width:1440px){.nm-page-wrap .elementor-column-gap-no .nm-banner-slider,.nm-page-wrap .elementor-column-gap-no .nm-banner,.nm-page-wrap .elementor-column-gap-no img,.nm-page-wrap .nm-row-full-nopad .nm-banner-slider,.nm-page-wrap .nm-row-full-nopad .nm-banner,.nm-page-wrap .nm-row-full-nopad .nm-banner-image,.nm-page-wrap .nm-row-full-nopad img{border-radius:var(--nm--border-radius-image-fullwidth);}}.button,input[type=submit],.widget_tag_cloud a, .widget_product_tag_cloud a,.add_to_cart_inline .add_to_cart_button,#nm-shop-sidebar-popup-button,.products.grid-list .nm-shop-loop-actions > a:first-of-type,.products.grid-list .nm-shop-loop-actions > a:first-child,#order_review .shop_table tbody .product-name .product-quantity{color:#ffffff;background-color:#282828;}.button:hover,input[type=submit]:hover.products.grid-list .nm-shop-loop-actions > a:first-of-type,.products.grid-list .nm-shop-loop-actions > a:first-child{color:#ffffff;}#nm-blog-pagination a,.button.border{border-color:#aaaaaa;}#nm-blog-pagination a,#nm-blog-pagination a:hover,.button.border,.button.border:hover{color:#282828;}#nm-blog-pagination a:not([disabled]):hover,.button.border:not([disabled]):hover{color:#282828;border-color:#282828;}.product-summary .quantity .nm-qty-minus,.product-summary .quantity .nm-qty-plus{color:#282828;}.nm-page-wrap{background-color:#ffffff;}.nm-divider .nm-divider-title,.nm-header-search{background:#ffffff;}.woocommerce-cart .blockOverlay,.woocommerce-checkout .blockOverlay {background-color:#ffffff !important;}.nm-top-bar{border-color:transparent;background:#282828;}.nm-top-bar .nm-top-bar-text,.nm-top-bar .nm-top-bar-text a,.nm-top-bar .nm-menu > li > a,.nm-top-bar .nm-menu > li > a:hover,.nm-top-bar-social li i{color:#eeeeee;}.nm-header-placeholder{height:84px;}.nm-header{line-height:50px;padding-top:17px;padding-bottom:17px;background:#ffffff;}.home .nm-header{background:#ffffff;}.mobile-menu-open .nm-header{background:#ffffff !important;}.header-on-scroll .nm-header,.home.header-transparency.header-on-scroll .nm-header{background:#ffffff;}.header-on-scroll .nm-header:not(.static-on-scroll){padding-top:10px;padding-bottom:10px;}.nm-header.stacked .nm-header-logo,.nm-header.stacked-logo-centered .nm-header-logo,.nm-header.stacked-centered .nm-header-logo{padding-bottom:0px;}.nm-header-logo svg,.nm-header-logo img{height:16px;}@media all and (max-width:991px){.nm-header-placeholder{height:70px;}.nm-header{line-height:50px;padding-top:10px;padding-bottom:10px;}.nm-header.stacked .nm-header-logo,.nm-header.stacked-logo-centered .nm-header-logo,.nm-header.stacked-centered .nm-header-logo{padding-bottom:0px;}.nm-header-logo svg,.nm-header-logo img{height:16px;}}@media all and (max-width:400px){.nm-header-placeholder{height:70px;}.nm-header{line-height:50px;}.nm-header-logo svg,.nm-header-logo img{height:16px;}}.nm-menu li a{color:#707070;}.nm-menu li a:hover{color:#282828;}.header-transparency-light:not(.header-on-scroll):not(.mobile-menu-open) #nm-main-menu-ul > li > a,.header-transparency-light:not(.header-on-scroll):not(.mobile-menu-open) #nm-right-menu-ul > li > a{color:#ffffff;}.header-transparency-dark:not(.header-on-scroll):not(.mobile-menu-open) #nm-main-menu-ul > li > a,.header-transparency-dark:not(.header-on-scroll):not(.mobile-menu-open) #nm-right-menu-ul > li > a{color:#282828;}.header-transparency-light:not(.header-on-scroll):not(.mobile-menu-open) #nm-main-menu-ul > li > a:hover,.header-transparency-light:not(.header-on-scroll):not(.mobile-menu-open) #nm-right-menu-ul > li > a:hover{color:#dcdcdc;}.header-transparency-dark:not(.header-on-scroll):not(.mobile-menu-open) #nm-main-menu-ul > li > a:hover,.header-transparency-dark:not(.header-on-scroll):not(.mobile-menu-open) #nm-right-menu-ul > li > a:hover{color:#707070;}.no-touch .header-transparency-light:not(.header-on-scroll):not(.mobile-menu-open) .nm-header:hover{background-color:transparent;}.no-touch .header-transparency-dark:not(.header-on-scroll):not(.mobile-menu-open) .nm-header:hover{background-color:transparent;}.nm-menu .sub-menu{background:#282828;}.nm-menu .sub-menu li a{color:#a0a0a0;}.nm-menu .megamenu > .sub-menu > ul > li:not(.nm-menu-item-has-image) > a,.nm-menu .sub-menu li a .label,.nm-menu .sub-menu li a:hover{color:#eeeeee;}.nm-menu .megamenu.full > .sub-menu{padding-top:28px;padding-bottom:15px;background:#ffffff;}.nm-menu .megamenu.full > .sub-menu > ul{max-width:1080px;}.nm-menu .megamenu.full .sub-menu li a{color:#777777;}.nm-menu .megamenu.full > .sub-menu > ul > li:not(.nm-menu-item-has-image) > a,.nm-menu .megamenu.full .sub-menu li a:hover{color:#282828;}.nm-menu .megamenu > .sub-menu > ul > li.nm-menu-item-has-image{border-right-color:#eeeeee;}.nm-menu-icon span{background:#707070;}.header-transparency-light:not(.header-on-scroll):not(.mobile-menu-open) .nm-menu-icon span{background:#ffffff;}.header-transparency-dark:not(.header-on-scroll):not(.mobile-menu-open) .nm-menu-icon span{background:#282828;}#nm-mobile-menu-top-ul .nm-mobile-menu-item-search input,#nm-mobile-menu-top-ul .nm-mobile-menu-item-search span,.nm-mobile-menu-social-ul li a{color:#555555;}.no-touch #nm-mobile-menu .menu a:hover,#nm-mobile-menu .menu li.active > a,#nm-mobile-menu .menu > li.active > .nm-menu-toggle:before,#nm-mobile-menu .menu a .label,.nm-mobile-menu-social-ul li a:hover{color:#282828;}.nm-footer-widgets{padding-top:55px;padding-bottom:15px;background-color:#ffffff;}.nm-footer-widgets,.nm-footer-widgets .widget ul li a,.nm-footer-widgets a{color:#777777;}.nm-footer-widgets .widget .nm-widget-title{color:#282828;}.nm-footer-widgets .widget ul li a:hover,.nm-footer-widgets a:hover{color:#dc9814;}.nm-footer-widgets .widget_tag_cloud a:hover,.nm-footer-widgets .widget_product_tag_cloud a:hover{background:#dc9814;}@media all and (max-width:991px){.nm-footer-widgets{padding-top:55px;padding-bottom:15px;}}.nm-footer-bar{color:#aaaaaa;}.nm-footer-bar-inner{padding-top:30px;padding-bottom:30px;background-color:#282828;}.nm-footer-bar a{color:#aaaaaa;}.nm-footer-bar a:hover{color:#eeeeee;}.nm-footer-bar .menu > li{border-bottom-color:#3a3a3a;}.nm-footer-bar-social a{color:#eeeeee;}.nm-footer-bar-social a:hover{color:#c6c6c6;}@media all and (max-width:991px){.nm-footer-bar-inner{padding-top:30px;padding-bottom:30px;}}.nm-comments{background:#f7f7f7;}.nm-comments .commentlist > li,.nm-comments .commentlist .pingback,.nm-comments .commentlist .trackback{border-color:#e7e7e7;}#nm-shop-products-overlay,#nm-shop{background-color:#ffffff;}#nm-shop-taxonomy-header.has-image{height:370px;}.nm-shop-taxonomy-text-col{max-width:none;}.nm-shop-taxonomy-text h1{color:#282828;}.nm-shop-taxonomy-text .term-description{color:#777777;}@media all and (max-width:991px){#nm-shop-taxonomy-header.has-image{height:370px;}}@media all and (max-width:768px){#nm-shop-taxonomy-header.has-image{height:210px;}} .nm-shop-widget-scroll{max-height:145px;}.onsale{color:#282828;background:#ffffff;}.nm-label-itsnew{color:#ffffff;background:#282828;}.products li.outofstock .nm-shop-loop-thumbnail > .woocommerce-LoopProduct-link:after{color:#282828;background:#ffffff;}.nm-shop-loop-thumbnail{background:#eeeeee;}.nm-featured-video-icon{color:#282828;background:#ffffff;}@media all and (max-width:1080px){.woocommerce-product-gallery.pagination-enabled .flex-control-thumbs{background-color:#ffffff;}}.nm-variation-control.nm-variation-control-color li i{width:19px;height:19px;}.nm-variation-control.nm-variation-control-image li .nm-pa-image-thumbnail-wrap{width:19px;height:19px;}


/* ============================================================================
   BRAND / FIX LAYER (Sophia) — appended after the verbatim Savoy block so it wins.
   ============================================================================ */

/* Icon font path fix: theme-icons.min.css requests fonts/nm-font.woff%3F2g9dqm relative to
   /savoy/css/, but the woff lives at /savoy/fonts/. Re-declare @font-face with the real path. */
@font-face{font-family:"nm-font";src:url("/savoy/fonts/nm-font.woff") format("woff");font-weight:400;font-style:normal;font-display:block;}

/* Brand type: override Savoy's Roboto with the Sophia brand fonts (Cormorant display + Raleway body).
   Colors, spacing, structure remain pure Savoy. */
body{font-family:var(--font-body);}
h1,h2,h3,h4,h5,h6,.h1-size,.h2-size,.h3-size,.h4-size,.h5-size,.h6-size{font-family:var(--font-heading);}

/* Sophia wordmark lockup (stand-in until Shirley's SVG logo lands). The centered header positions
   .nm-header-logo absolutely; this text lockup sits in place of Savoy's <img class="nm-logo">. */
.nm-header-logo .nm-logo-lockup{display:inline-flex;flex-direction:column;align-items:center;justify-content:center;line-height:1;text-align:center;white-space:nowrap;}
.nm-header-logo .nm-logo-name{font-family:var(--font-heading);font-size:24px;line-height:.95;letter-spacing:.16em;text-transform:uppercase;color:#282828;}
.nm-header-logo .nm-logo-tag{font-family:var(--font-body);font-size:9px;line-height:1;letter-spacing:.34em;text-transform:uppercase;color:#282828;margin-top:4px;}
@media all and (max-width:991px){.nm-header-logo .nm-logo-name{font-size:20px;}.nm-header-logo .nm-logo-tag{font-size:8px;}}

/* Home section rhythm (the ONE net-new home class; demo got this from Elementor padding). */
.nm-home-section{padding:66px 0;}
@media all and (max-width:768px){.nm-home-section{padding:42px 0;}}
/* Journal teaser (native link types; a little spacing only). */
.nm-home-journal{margin-top:4px;}
.nm-home-journal > li{padding-bottom:8px;}
.nm-home-journal h3{margin:0 0 8px;}
.nm-home-journal p{margin:0 0 10px;color:#777;}
/* Category-showcase tiles: keep a uniform frame so mixed-ratio product photos read as a grid. */
.nm-product-categories .product-category .nm-home-cat-frame{position:relative;display:block;overflow:hidden;aspect-ratio:4/5;background:#eee;}
.nm-product-categories .product-category .nm-home-cat-frame img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;}

/* ── Clone polish for real (mixed-ratio) product photography ──────────────────
   Savoy's demo images are all identical size, so its grid rows are even. Our real
   product shots vary (tall bags, wide clutches) which staggers the float grid.
   Lock every loop thumbnail to ONE SQUARE ratio + contain on white so the grid is
   even AND the whole piece shows: the catalogue photos are square white-background
   shots, so `cover` in a 3:4 portrait frame cropped the ends off wide clutches.
   Square + contain matches the "Shop by category" tiles. */
.nm-shop-loop-thumbnail{aspect-ratio:1/1;background:#fff;}
.nm-shop-loop-thumbnail .nm-shop-loop-thumbnail-link{display:block;width:100%;height:100%;}
.nm-shop-loop-thumbnail img.wp-post-image,
.nm-shop-loop-thumbnail img.nm-shop-hover-image{width:100%;height:100%;object-fit:contain;object-position:center;}

/* Legibility scrim behind banner copy over photographic backgrounds (fades from the
   text side). text-color-dark → light scrim; text-color-light → dark scrim. */
.nm-banner.text-color-dark::before,
.nm-banner.text-color-light::before{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;}
.nm-banner.text-color-dark::before{background:linear-gradient(90deg,rgba(255,255,255,.72),rgba(255,255,255,.28) 42%,rgba(255,255,255,0) 68%);}
.nm-banner.text-color-light::before{background:linear-gradient(90deg,rgba(20,18,16,.62),rgba(20,18,16,.22) 42%,rgba(20,18,16,0) 68%);}

/* Home hero CTA scrolls to the shop section; offset for the fixed header + smooth (motion-safe). */
#nm-shop{scroll-margin-top:96px;}
@media (prefers-reduced-motion: no-preference){html{scroll-behavior:smooth;}}

/* PDP gallery thumbnail buttons (unstyled; the img inside keeps Savoy's .flex-control-thumbs style). */
.flex-control-thumbs .nm-gallery-thumb-btn{display:block;width:100%;padding:0;border:0;background:none;cursor:pointer;line-height:0;}

/* ── Home hero SLIDER (crossfade, gold dots bottom-left, arrows on hover) ────── */
.sbs-hero-slider{position:relative;overflow:hidden;}
.sbs-hero-track{position:relative;height:600px;}
.sbs-hero-slide{position:absolute;inset:0;opacity:0;pointer-events:none;transition:opacity .45s ease;} /* L5: 800ms→450ms */
.sbs-hero-slide.is-active{opacity:1;pointer-events:auto;}
.sbs-hero-slider .sbs-hero-slide .nm-banner-image{height:100%!important;}
@media all and (max-width:768px){.sbs-hero-track{height:440px;}}
/* dots — bottom-left, gold active ring (Savoy slick-theme look) */
.sbs-hero-slider .slick-dots{position:absolute;left:0;right:0;bottom:26px;z-index:20;margin:0;padding:0 30px;list-style:none;text-align:left;line-height:1;}
.sbs-hero-slider .slick-dots li{display:inline-block;vertical-align:middle;margin:0 9px 0 0;}
/* M23/M31: the visible dot stays small (6px/11px active) but the <button> itself is a 44x44
   invisible hit area (flex-centered ::before dot) so the tap target meets the minimum without
   growing the visual mark. */
.sbs-hero-slider .slick-dots li button{display:flex;align-items:center;justify-content:center;width:44px;height:44px;margin:-19px 0;padding:0;border:0;background:none;font-size:0;line-height:0;cursor:pointer;}
.sbs-hero-slider .slick-dots li button::before{content:"";display:block;width:6px;height:6px;border-radius:30px;background:#9a9a9a;transition:width .2s,height .2s,background .2s,border .2s;}
.sbs-hero-slider .slick-dots li.slick-active button::before{width:11px;height:11px;background:transparent;border:2px solid #dc9814;}
/* arrows — hidden until hover */
.sbs-hero-arrow{position:absolute;top:50%;transform:translateY(-50%);z-index:20;width:52px;height:96px;padding:0;border:0;background:none;color:#282828;cursor:pointer;opacity:0;transition:opacity .2s ease,color .2s ease;}
/* M22: the arrows were revealed on :hover only, so Tab-focusing one (they're real, always-
   focusable <button>s under opacity:0, never removed from the tab order) landed keyboard focus on
   an invisible control. :focus-within on the slider reveals both arrows the same way :hover does. */
.sbs-hero-slider:hover .sbs-hero-arrow,.sbs-hero-slider:focus-within .sbs-hero-arrow{opacity:1;}
.sbs-hero-arrow:hover{color:#dc9814;}
.sbs-hero-arrow i{font-size:42px;line-height:96px;}
.slick-prev.sbs-hero-arrow{left:12px;}
.slick-next.sbs-hero-arrow{right:12px;}
@media (hover:none){.sbs-hero-arrow{opacity:1;}}

/* ── Home TESTIMONIALS slider (TestimonialSlider.tsx) — ALL approved reviews, product-tagged
   AND general, centered/boxed to a readable column. Deliberately on-brand quiet: Cormorant
   quote + Raleway small-caps cite + a single gold accent (the CTA link + active dot) — NOT the
   card-grid/photo-avatar "Instagram testimonial" look some themes default to. Track uses CSS
   grid stacking (`grid-area:1/1` on every slide) so the container height follows the tallest
   testimonial in play without a hard-coded pixel guess (review bodies vary a lot in length,
   unlike the hero's fixed-aspect photos). */
.sbs-testimonial-slider{position:relative;max-width:760px;margin:0 auto;padding:56px 64px;text-align:center;}
/* All slides share one grid cell, so the track is as tall as the LONGEST testimonial (stable
   height = no reflow jump on autoplay). align-items:center then vertically centers each slide in
   that cell, so a SHORT quote sits balanced in the middle instead of top-aligned with dead space
   below it. */
.sbs-testimonial-track{display:grid;align-items:center;}
.sbs-testimonial-slide{grid-area:1/1;margin:0;padding:0;border:0;opacity:0;pointer-events:none;transition:opacity .5s ease;}
.sbs-testimonial-slide.is-active{opacity:1;pointer-events:auto;}
.sbs-testimonial-body{margin:0 0 16px;font-family:var(--font-heading);font-style:italic;font-size:26px;line-height:1.4;color:var(--sbs-ink,#1C1917);}
.sbs-testimonial-slide .star-rating{margin-bottom:14px;}
.sbs-testimonial-cite{display:block;font-family:var(--font-body);font-style:normal;font-size:13px;letter-spacing:.05em;text-transform:uppercase;color:var(--sbs-muted,#78716C);}
.sbs-testimonial-link{display:inline-block;margin-top:10px;font-family:var(--font-body);font-size:13px;letter-spacing:.04em;text-transform:uppercase;color:var(--sbs-gold-ink,#9A6B12);text-decoration:none;border-bottom:1px solid transparent;transition:border-color .2s ease;}
.sbs-testimonial-link:hover,.sbs-testimonial-link:focus-visible{border-color:var(--sbs-gold-ink,#9A6B12);}
/* arrows — quiet, always visible (unlike the hero's hover-reveal; this section has no imagery
   to protect from clutter and a testimonials slider is usually read, not glanced past). */
.sbs-testimonial-arrow{position:absolute;top:50%;transform:translateY(-50%);z-index:5;width:40px;height:40px;padding:0;border:0;background:none;color:var(--sbs-muted,#78716C);cursor:pointer;display:flex;align-items:center;justify-content:center;}
.sbs-testimonial-arrow:hover{color:var(--sbs-gold-ink,#9A6B12);}
.sbs-testimonial-arrow i{font-size:20px;}
.sbs-testimonial-prev{left:0;}
.sbs-testimonial-next{right:0;}
/* dots — same fill convention as the hero's slick-dots (small dot, gold ring when active). */
.sbs-testimonial-dots{display:flex;justify-content:center;gap:6px;margin:26px 0 0;padding:0;list-style:none;}
.sbs-testimonial-dots li button{display:flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;border:0;background:none;font-size:0;line-height:0;cursor:pointer;}
.sbs-testimonial-dots li button::before{content:"";display:block;width:6px;height:6px;border-radius:30px;background:#9a9a9a;transition:width .2s,height .2s,background .2s,border .2s;}
.sbs-testimonial-dots li.is-active button::before{width:11px;height:11px;background:transparent;border:2px solid var(--sbs-gold-ink,#9A6B12);}
@media all and (max-width:768px){
  .sbs-testimonial-slider{padding:40px 46px;}
  .sbs-testimonial-body{font-size:21px;}
  .sbs-testimonial-arrow{width:36px;height:36px;}
}

/* Journal (blog grid) — uniform thumbnail frame (posts have no native image ratio). */
/* Savoy renders blog thumbnails at NATURAL height (that's what staggers the masonry). */
.nm-post-thumbnail .nm-journal-thumb-frame{position:relative;display:block;overflow:hidden;background:#eee;}
.nm-post-thumbnail .nm-journal-thumb-frame img{display:block;width:100%;height:auto;}

/* PDP gallery main image sizing (Savoy sizes it via `__image a img`; we dropped the lightbox <a>). */
.woocommerce-product-gallery__image .wp-post-image{display:block;width:100%;height:auto;}

/* PDP gallery: main image opens the lightbox (zoom cursor); the lightbox reuses magnific .mfp-* CSS. */
.woocommerce-product-gallery__image .nm-gallery-open{display:block;width:100%;padding:0;border:0;background:none;cursor:zoom-in;}
.mfp-bg.mfp-ready{opacity:.9;}
.mfp-wrap .mfp-img{max-width:100%;max-height:calc(100vh - 80px);width:auto;height:auto;margin:0 auto;display:block;}
.mfp-wrap .mfp-figure{line-height:0;}
/* --nm--page-overlay-background is undefined in the ported vars → force the lightbox scrim dark. */
.mfp-bg{background:#141210;}
.mfp-close{color:#fff;opacity:.85;font-size:34px;}
.mfp-close:hover{opacity:1;}
/* Lightbox polish: darker scrim, compact top-right close, clearer arrows. */
.mfp-bg.mfp-ready{opacity:.95;}
.mfp-close{width:44px;height:44px;line-height:40px;right:6px;top:6px;left:auto;padding:0;color:#fff;font-size:32px;opacity:.9;text-align:center;}
.mfp-close:hover{opacity:1;}
.mfp-arrow{opacity:.75;}
.mfp-arrow:hover{opacity:1;}

/* Full-screen product lightbox: main image + side arrows + thumbnail strip (over the .mfp-bg scrim). */
.sbs-lightbox{position:fixed;inset:0;z-index:1045;display:flex;flex-direction:column;padding:16px 12px;}
.sbs-lightbox-close{position:absolute;top:8px;right:16px;z-index:3;width:44px;height:44px;padding:0;border:0;background:none;color:#fff;font-size:36px;line-height:1;opacity:.85;cursor:pointer;}
.sbs-lightbox-close:hover{opacity:1;}
.sbs-lightbox-stage{position:relative;flex:1 1 auto;display:flex;align-items:center;justify-content:center;min-height:0;touch-action:pan-y;}
.sbs-lightbox-img{max-width:100%;max-height:100%;width:auto;height:auto;object-fit:contain;display:block;}
.sbs-lightbox-arrow{position:absolute;top:50%;transform:translateY(-50%);z-index:2;width:56px;height:90px;padding:0;border:0;background:none;color:#fff;opacity:.65;cursor:pointer;transition:opacity .2s;}
.sbs-lightbox-arrow:hover{opacity:1;}
.sbs-lightbox-arrow i{font-size:44px;line-height:90px;}
.sbs-lightbox-prev{left:4px;}
.sbs-lightbox-next{right:4px;}
.sbs-lightbox-thumbs{flex:0 0 auto;display:flex;gap:10px;justify-content:center;flex-wrap:wrap;padding:16px 0 4px;}
.sbs-lightbox-thumb{width:58px;height:74px;padding:0;border:0;background:none;cursor:pointer;opacity:.45;overflow:hidden;transition:opacity .2s;}
.sbs-lightbox-thumb.is-active{opacity:1;outline:2px solid #dc9814;outline-offset:-2px;}
.sbs-lightbox-thumb img{width:100%;height:100%;object-fit:cover;display:block;}
@media (max-width:768px){.sbs-lightbox-thumb{width:46px;height:58px;}.sbs-lightbox-arrow{width:38px;}.sbs-lightbox-arrow i{font-size:30px;}}

/* One-of-a-kind note in the PDP summary (replaces the qty stepper — every piece is quantity-1). */
.product .summary .nm-single-availability{margin:2px 0 18px;font-family:var(--font-body);font-size:12px;line-height:1.5;letter-spacing:.16em;text-transform:uppercase;color:#9A6B12;}

/* Qty stepper ± are <button> for functionality/a11y — strip default button chrome. */
.nm-quantity-wrap .quantity button.nm-qty-minus,.nm-quantity-wrap .quantity button.nm-qty-plus{padding:0;border:0;background:none;}

/* Savoy makes the loop wishlist heart pointer-events:none (a hover-reveal decoration). Ours is a
   REAL toggle — make it always clickable (card + PDP). This is why real clicks did nothing. */
.products .nm-wishlist-button,.nm-product-wishlist-button-wrap .nm-wishlist-button{pointer-events:auto;cursor:pointer;}

/* Contact form (Savoy's contact page is a wpcf7 form). Inputs/textarea inherit Savoy's baseline
   (padding 12/16, 1px #e1e1e1) — we add full width, uppercase Raleway labels, field rhythm. */
.sbs-contact-form .sbs-field{display:block;margin:0 0 20px;}
.sbs-contact-form .sbs-field label{display:block;margin:0 0 8px;font-family:var(--font-body);font-size:11px;font-weight:600;letter-spacing:.18em;text-transform:uppercase;color:#78716C;}
.sbs-contact-form .sbs-field input,.sbs-contact-form .sbs-field select,.sbs-contact-form .sbs-field textarea{width:100%;display:block;font-size:15px;color:#282828;background:#fff;}
.sbs-contact-form .sbs-field input:focus,.sbs-contact-form .sbs-field select:focus,.sbs-contact-form .sbs-field textarea:focus{border-color:#282828;}
.sbs-contact-form .sbs-field textarea{resize:vertical;min-height:120px;}
.sbs-contact-form .button.alt{margin-top:4px;}
/* L3 — post-submit status: aria-live announcement + a real fallback link if the wa.me popup is
   blocked (or never noticed). Gold-ink, not the bright decorative gold, per the accessible-colour
   pass. */
.sbs-contact-status{margin:14px 0 0;font-size:14px;color:#44403C;}
.sbs-contact-status a{color:var(--sbs-gold-ink);text-decoration:underline;}

/* FAQ accordion (Savoy footer links a FAQs page). Clean bordered rows, +/- toggle, gold on open. */
.sbs-faq-group{margin:0 0 44px;}
.sbs-faq-group-title{margin:0 0 6px;font-family:var(--font-display);font-size:24px;font-weight:500;color:#282828;}
.sbs-faq-item{border-bottom:1px solid #E7E5E4;}
.sbs-faq-item:first-of-type{border-top:1px solid #E7E5E4;}
.sbs-faq-q{display:flex;align-items:center;justify-content:space-between;gap:20px;width:100%;padding:20px 2px;border:0;background:none;text-align:left;cursor:pointer;font-family:var(--font-body);font-size:16px;line-height:1.4;color:#282828;transition:color .2s ease;}
.sbs-faq-q:hover,.sbs-faq-item.is-open .sbs-faq-q{color:#9A6B12;}
.sbs-faq-toggle{flex:0 0 auto;font-size:22px;line-height:1;color:#dc9814;font-weight:400;}
.sbs-faq-a{padding:0 2px 22px;}
.sbs-faq-a p{margin:0;font-family:var(--font-body);font-size:15px;line-height:1.7;color:#44403C;}

/* Accessible visually-hidden (SEO/a11y h1 on pages Savoy renders titleless, e.g. blog). */
.nm-visually-hidden{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;}

/* About — 1-1 with Savoy about-2: left title, full-width banner, label-left/content-right rows. */
.sbs-about-head{padding-bottom:0;}
.sbs-about-title{margin:0;font-family:var(--font-display);font-size:38px;line-height:1.15;font-weight:500;color:#282828;text-align:left;}
.sbs-about-banner{position:relative;width:100%;aspect-ratio:16/7;overflow:hidden;background:#eee;}
.sbs-about-banner img{object-fit:cover;object-position:center 22%;}
.sbs-about-row .sbs-about-label{margin:0;padding-top:2px;font-family:var(--font-display);font-size:24px;line-height:1.2;font-weight:500;color:#282828;}
.sbs-about-row .entry-content p{margin:0 0 20px;}
.sbs-about-row .entry-content p:last-child{margin-bottom:0;}
.sbs-about-contact-block p{margin:0 0 18px;line-height:1.7;}
.sbs-about-contact-block p:last-child{margin-bottom:0;}

/* Document body (terms/privacy/shipping/press/journal posts) — readable legal/policy typography.
   Left-aligned prose with paragraph rhythm, sectioned headings, and real lists. */
/* L27: 1.8 is looser than the --leading-body token (1.65).
   L2: ContentBody.tsx sets `style={{maxWidth:820}}` inline on this same element (terms/privacy/
   shipping/press) — an inline style attribute always wins over any CSS selector unless the CSS
   uses !important, so this is a deliberate, narrowly-scoped !important (a handful of others like
   it are used further down this file, each commented at the point of use — never a broad reset).
   680px lands the long-form body in the ~60-75ch reading-measure range. */
.sbs-doc-body{text-align:left;font-size:16px;line-height:var(--leading-body);color:#44403C;max-width:680px!important;}
.sbs-doc-body p{margin:0 0 18px;}
.sbs-doc-body h2{font-family:var(--font-display);font-size:26px;line-height:1.25;color:#282828;margin:38px 0 14px;}
.sbs-doc-body h3{font-family:var(--font-display);font-size:20px;line-height:1.3;color:#282828;margin:32px 0 10px;}
.sbs-doc-body h2:first-child,.sbs-doc-body h3:first-child{margin-top:0;}
.sbs-doc-body ul,.sbs-doc-body ol{margin:0 0 18px;padding-left:24px;}
.sbs-doc-body ul{list-style:disc;}
.sbs-doc-body ol{list-style:decimal;}
.sbs-doc-body li{margin:0 0 8px;padding-left:4px;}
.sbs-doc-body strong{color:#282828;}
.sbs-doc-body a{color:#9A6B12;text-decoration:underline;}
@media (max-width:768px){
  .sbs-about-title{font-size:30px;}
  .sbs-about-banner{aspect-ratio:4/3;}
  .sbs-about-row .sbs-about-label{margin-bottom:14px;}
}

/* Journal — Savoy blog grid: a top-aligned 3-up row of post cards (natural-height thumbnails, so
   rows stagger as posts accumulate). Flex (not CSS columns) so distribution is reliable at any count. */
.sbs-journal-masonry{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;align-items:flex-start;gap:60px 3.2%;}
.sbs-journal-masonry > li{flex:0 0 auto;width:calc((100% - 2 * 3.2%) / 3);margin:0;}
@media (max-width:1020px){.sbs-journal-masonry{gap:50px 4%;} .sbs-journal-masonry > li{width:calc((100% - 4%) / 2);}}
@media (max-width:750px){.sbs-journal-masonry{gap:44px 0;} .sbs-journal-masonry > li{width:100%;}}

/* Order confirmation — centered thank-you card: divider heading, a one-line next-step lede,
   the order line-items table, and the WhatsApp CTA. Constrained + centered on the paper. */
.sbs-order-confirmation{max-width:620px;margin:0 auto;padding:10px 0 40px;text-align:center;}
.sbs-order-confirmation-lede{margin:0 auto 30px;max-width:480px;font-size:16px;line-height:1.7;color:#78716C;}
.sbs-order-confirmation .shop_table{width:100%;margin:0 0 30px;text-align:left;}
.sbs-order-confirmation .shop_table td.product-total,.sbs-order-confirmation .shop_table .order-total td{text-align:right;}
.sbs-order-confirmation .buttons{margin:0;}

/* Cart-panel line item — our title/qty are <span>s (Savoy's originals were <a>/block via the
   `li a` rule), so force block-level to stack them: title above the qty×price line, not overlapping. */
#nm-cart-panel .nm-cart-panel-product-title,
#nm-cart-panel .nm-cart-panel-quantity-pricing{display:block;}
#nm-cart-panel .nm-cart-panel-quantity-pricing .amount{color:#78716C;}

/* Checkout error message — server-rejected order (409/419/generic). */
.sbs-checkout-error{color:#b3261e;font-size:13px;margin:0 0 16px;}

/* Cart-panel reservation countdown — align with the panel's 37px-padded list/summary (it was an
   unstyled <p> sitting flush-left), rendered as a quiet Savoy label above the subtotal.
   H3: #a3a3a3 (~2.5:1) fails AA for meaningful text (the TTL) — use --sbs-muted. */
.sbs-cart-countdown{margin:0;padding:8px 37px 0;font-size:12px;letter-spacing:.1em;text-transform:uppercase;color:var(--sbs-muted);}

/* ============================================================================
   Shopping Cart page (/cart) — Savoy look: left page title, item list + an
   estimated-total box. One-of-a-kind pieces → qty is always 1 (no stepper).
   ============================================================================ */
.sbs-cart-page{padding-bottom:60px;}
.sbs-cart-page-title{font-family:var(--font-display);font-size:34px;line-height:1.1;color:#282828;margin:0 0 34px;}
.sbs-cart-layout{align-items:flex-start;}

.sbs-cart-items{list-style:none;margin:0;padding:0;border-top:1px solid #eee;}
.sbs-cart-item{display:flex;align-items:center;gap:22px;padding:22px 0;border-bottom:1px solid #eee;}
.sbs-cart-item-thumb{flex:0 0 auto;display:block;width:96px;height:120px;background:#f4f2f0;overflow:hidden;}
.sbs-cart-item-thumb img{width:100%;height:100%;object-fit:cover;display:block;}
.sbs-cart-item-noimg{display:block;width:100%;height:100%;background:#f4f2f0;}
.sbs-cart-item-info{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:6px;}
.sbs-cart-item-name{font-family:var(--font-body);font-size:15px;letter-spacing:.02em;color:#282828;}
.no-touch .sbs-cart-item-name:hover{color:#9A6B12;}
/* H3: unit price at #a3a3a3 (~2.5:1) fails AA; L1: tabular-nums on money. */
.sbs-cart-item-unit{font-size:13px;color:var(--sbs-muted);font-variant-numeric:tabular-nums;}
.sbs-cart-item-total{flex:0 0 auto;font-size:15px;color:#282828;white-space:nowrap;font-variant-numeric:tabular-nums;}
/* M23/M31: 34x34 → 44x44 via padding + matching negative margin (hit area grows, the icon and
   surrounding row stay visually put). */
.sbs-cart-item-remove{flex:0 0 auto;width:44px;height:44px;margin:-5px;padding:0;border:0;background:none;color:#c0bdba;font-size:14px;cursor:pointer;transition:color .2s ease;}
.no-touch .sbs-cart-item-remove:hover{color:#282828;}

.sbs-cart-summary{border:1px solid #eee;padding:28px 26px;}
@media (min-width:992px){.sbs-cart-summary{margin-left:20px;}}
/* L1: tabular-nums so the cart subtotal/total columns align digit-to-digit. */
.sbs-cart-summary-row{display:flex;justify-content:space-between;align-items:baseline;font-size:15px;color:#44403C;padding:10px 0;font-variant-numeric:tabular-nums;}
.sbs-cart-summary-total{margin-top:6px;padding-top:20px;border-top:1px solid #eee;font-size:17px;color:#282828;font-variant-numeric:tabular-nums;}
.sbs-cart-summary-total strong{font-weight:600;}
.sbs-cart-checkout-btn{display:block;width:100%;text-align:center;margin-top:22px;}

.sbs-cart-empty{padding:20px 0 40px;}
.sbs-cart-empty p{font-size:16px;color:#78716C;margin:0 0 22px;}

/* ============================================================================
   Checkout (/checkout) — Savoy two-column: contact/delivery/payment on the left,
   a live order-summary sidebar on the right. Reuses .sbs-contact-form field styles.
   ============================================================================ */
.sbs-checkout .nm-row{align-items:flex-start;}
.sbs-checkout-section{margin:0 0 34px;}
.sbs-checkout-heading{font-family:var(--font-display);font-size:22px;line-height:1.2;color:#282828;margin:0 0 20px;padding-bottom:12px;border-bottom:1px solid #eee;}
.sbs-checkout #payment .payment_methods{margin:0;padding:0;list-style:none;border:1px solid #eee;}
.sbs-checkout #payment .payment_methods li{display:flex;align-items:center;gap:10px;margin:0;padding:15px 18px;border-bottom:1px solid #eee;}
.sbs-checkout #payment .payment_methods li:last-child{border-bottom:0;}
.sbs-checkout #payment .payment_methods li input{width:auto;margin:0;}
.sbs-checkout #payment .payment_methods li label{margin:0;font-size:15px;letter-spacing:.01em;text-transform:none;cursor:pointer;}
.sbs-checkout-consent{display:flex;align-items:flex-start;gap:10px;margin:20px 0 0;font-size:13px;line-height:1.6;color:#78716C;cursor:pointer;}
.sbs-checkout-consent input{width:auto;margin:3px 0 0;flex:0 0 auto;}
/* H3: checkout terms at #a3a3a3 (~2.5:1) fails AA. */
.sbs-checkout-terms{font-size:12px;line-height:1.6;color:var(--sbs-muted);margin:0 0 18px;}
.sbs-checkout-terms a{color:#9A6B12;text-decoration:underline;}
.sbs-place-order{width:100%;}

/* Coupons module: "Coupon code" section (between Delivery and Payment) — a text input + Apply
   button side-by-side, replaced by a small "applied" recap + Remove once a code is accepted.
   `.sbs-contact-form .sbs-coupon-row input` matches the (0,2,1) specificity of
   `.sbs-contact-form .sbs-field input` above (which forces width:100%) and, coming later in this
   file, wins the tie to let the input share the row with the button instead of stacking full-width. */
.sbs-coupon-row{display:flex;gap:10px;align-items:flex-start;}
.sbs-contact-form .sbs-coupon-row input{width:auto;flex:1 1 auto;min-width:0;}
.sbs-coupon-apply{flex:0 0 auto;white-space:nowrap;}
.sbs-coupon-applied{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:12px;margin:0;padding:14px 18px;border:1px solid #eee;font-size:14px;color:var(--sbs-body);}
/* ≥44px touch target (site a11y convention) while staying visually a small text link — matched to
   how the audit handled other sub-44px inline controls (inline-flex + min-height + padding, no
   reflow); the -4px block margin keeps the taller tap area from pushing the recap row's height. */
.sbs-coupon-remove{display:inline-flex;align-items:center;justify-content:center;min-height:44px;min-width:44px;margin:-4px 0;border:0;background:none;padding:4px 6px;font-size:12px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--sbs-gold-ink);cursor:pointer;text-decoration:underline;}
.sbs-coupon-remove:hover{color:var(--sbs-ink);}
/* Discount amount reads in the same accessible gold-ink as price/CTA text elsewhere. */
.sbs-order-summary-discount span:last-child{color:var(--sbs-gold-ink);}

/* Order summary sidebar */
.sbs-order-summary{border:1px solid #eee;padding:26px 24px;}
@media (min-width:992px){.sbs-order-summary{margin-left:20px;}}
.sbs-order-summary .sbs-checkout-heading{font-size:20px;}
.sbs-order-summary-items{list-style:none;margin:0 0 8px;padding:0;}
.sbs-order-summary-item{display:flex;align-items:center;gap:14px;padding:12px 0;border-bottom:1px solid #f2f0ee;}
.sbs-order-summary-thumb{position:relative;flex:0 0 auto;width:56px;height:70px;background:#f4f2f0;}
.sbs-order-summary-thumb img{width:100%;height:100%;object-fit:cover;display:block;}
.sbs-order-summary-noimg{display:block;width:100%;height:100%;background:#f4f2f0;}
.sbs-order-summary-qty{position:absolute;top:-8px;right:-8px;min-width:20px;height:20px;padding:0 5px;border-radius:20px;background:#282828;color:#fff;font-size:11px;line-height:20px;text-align:center;}
.sbs-order-summary-name{flex:1 1 auto;min-width:0;font-size:14px;color:#282828;}
/* L1: tabular-nums on every money figure in the summary sidebar. */
.sbs-order-summary-price{flex:0 0 auto;font-size:14px;color:#282828;white-space:nowrap;font-variant-numeric:tabular-nums;}
.sbs-order-summary-totals{margin-top:14px;}
.sbs-order-summary-row{display:flex;justify-content:space-between;align-items:baseline;font-size:14px;color:#44403C;padding:8px 0;font-variant-numeric:tabular-nums;}
.sbs-order-summary-grandtotal{margin-top:4px;padding-top:16px;border-top:1px solid #eee;font-size:17px;color:#282828;font-variant-numeric:tabular-nums;}
.sbs-order-summary-grandtotal strong{font-weight:600;}

/* Mini-cart panel thumbnail placeholder (when a piece has no image) */
.sbs-cart-panel-noimg{display:block;width:100%;height:100%;min-height:75px;background:#f4f2f0;}

/* ============================================================================
   Order confirmation (/order/[id]) — Savoy order-received: overview strip + details table.
   (Base .sbs-order-confirmation centering rules live earlier in this file.)
   ============================================================================ */
.sbs-order-overview{list-style:none;display:flex;flex-wrap:wrap;justify-content:center;gap:14px 40px;margin:0 auto 40px;padding:22px 0;border-top:1px solid #eee;border-bottom:1px solid #eee;max-width:620px;}
/* H3: order labels at #a3a3a3 (~2.5:1) fail AA. */
.sbs-order-overview li{margin:0;font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--sbs-muted);text-align:center;}
.sbs-order-overview li strong{display:block;margin-top:7px;font-size:14px;letter-spacing:.02em;text-transform:none;color:#282828;font-variant-numeric:tabular-nums;} /* L1 */
.woocommerce-order-details{max-width:620px;margin:0 auto;text-align:left;}
.sbs-order-details-title{font-family:var(--font-display);font-size:22px;color:#282828;margin:0 0 16px;}
.sbs-order-confirmation .woocommerce-order-details .shop_table{width:100%;margin:0 0 30px;}
.sbs-order-confirmation .woocommerce-order-details th,.sbs-order-confirmation .woocommerce-order-details td{padding:12px 0;border-bottom:1px solid #eee;}
.sbs-order-confirmation .woocommerce-order-details .product-total,.sbs-order-confirmation .woocommerce-order-details tfoot td{text-align:right;}
.sbs-order-confirmation-buttons{text-align:center;margin:0;}

/* Discreet staff-console entry point — deliberately understated, not a primary nav item.
   Inherits footer-bar link colors (#aaa rest, #eee hover) for proper light-on-dark contrast. */
.nm-footer-staff-link { font-size: 0.6875rem; text-decoration: none; margin-left: 10px; }
.nm-footer-staff-link:hover { text-decoration: underline; }

/* ── Footer newsletter — a quiet "First access to new pieces →" CTA sitting in the footer menu
   row (`.sbs-footer-newsletter-cta`, a <button> styled to match its sibling <Link> menu items,
   inheriting `.nm-footer-bar`'s own #aaa rest / #eee hover — the dark-bar palette Savoy itself
   uses there, not the light-page `--sbs-muted` token, which under-contrasts on this bar) that
   opens NewsletterSignup inside the shared Modal (S5 ④ B2 → superseded by the Modal primitive).
   Once inside the (light) Modal panel, NewsletterSignup reuses the same light-surface
   `.sbs-contact-form .sbs-field`/`.sbs-account-consent` styling every other account/contact form
   on the site already uses — no dark-bg overrides needed here anymore. */
.sbs-footer-newsletter-cta {
  display: inline-block; vertical-align: middle; margin: 0; padding: 0; border: 0; background: none;
  font-family: var(--font-body); font-size: 14px; color: #aaa; cursor: pointer;
}
.sbs-footer-newsletter-cta:hover { color: #eee; }
.sbs-newsletter-copy { margin: 0 0 18px; font-size: 13px; line-height: 1.6; color: var(--sbs-muted); }
.sbs-newsletter-form.sbs-contact-form .sbs-field { margin-bottom: 14px; }

/* ── Savoy product-categories element — "Shop by category" tiles (home) ──
   Static clone (no masonry JS): the block-grid classes lay out the columns; these rules give each
   tile a fixed landscape crop so portrait product photos read cleanly as covers until Shirley
   supplies editorial category photography. This is the FIRST home section, directly under the
   hero `.nm-row` (which carries no bottom margin/padding of its own) — so unlike a section
   sandwiched between two `.nm-home-section` siblings, it can't rely on a previous section's
   bottom padding to open up the gap above it. Previously overridden to `padding-top: 8px`
   (a regression that glued it to the hero banner, 0px visual gap, vs. its own 66px/42px
   `.nm-home-section` bottom); no override here now, so it inherits the same `.nm-home-section`
   top/bottom rhythm (66px desktop / 42px mobile, see line 30) every other home section uses —
   symmetric top/bottom, matching the established scale. */
.sbs-category-tiles .nm-product-categories { margin: 0; }
.sbs-category-tiles .sbs-category-tile-image { display: block; position: relative; aspect-ratio: 1 / 1; overflow: hidden; background: #fff; padding: 6%; box-sizing: border-box; }
.sbs-category-tiles .sbs-category-tile-image img { width: 100%; height: 100%; object-fit: contain; transition: transform 0.6s ease; }
.no-touch .sbs-category-tiles .product-category:hover .sbs-category-tile-image img { transform: scale(1.04); }
/* Savoy layout-default overlays the heading on the image (top-left), which assumes clean landscape
   category art. Our placeholder covers are busy portrait product photos, so drop the heading to a
   legible caption below the image until Shirley supplies editorial category photography. */
.sbs-category-tiles .nm-product-category-text { position: static; padding: 14px 0 0; text-align: center; }
.sbs-category-tiles .nm-product-category-text .nm-product-category-heading { position: static; margin: 0; padding: 0; }

/* ── Savoy nm-banner element — editorial promo tiles (home) ──
   The served elements.css already positions .nm-banner-content over the image and savoy-custom's
   text-color-light gradient keeps the copy legible; these rules force the fluid <img> to cover a
   fixed wide crop and pad the overlaid text. */
.sbs-banner-promos { padding-top: 8px; }
.sbs-banner-promos .nm-banner { height: 100%; }
.sbs-banner-promos .nm-banner-link-full { position: relative; display: block; aspect-ratio: 16 / 9; }
.sbs-banner-promos .nm-banner img { width: 100%; height: 100%; object-fit: cover; }
.sbs-banner-promos .nm-banner-content-inner { padding: 32px 36px; }
.sbs-banner-promos .nm-banner-title { margin: 0; }
.sbs-banner-promos .nm-banner-subtitle { display: block; margin: 6px 0 0; }

/* ── Account (/account/*) — dashboard quick links + order-history status badges ──
   Real Savoy classes (.nm-MyAccount-dashboard, .woocommerce-MyAccount-orders) carry the chrome
   already served by shop.css; these scoped rules only fill gaps Savoy's own CSS doesn't cover —
   spacing the quick-link list, and a small badge for the two order statuses (payment +
   fulfillment) shown side by side per row. Tokens only, mirroring the console's .sbs-console-badge. */
/* Admin "Preview as customer" banner — shown at the top of every /account/* page while
   account.is_preview is true (CustomerAccountShell). A distinct gold-tint bg is deliberate:
   it must never be mistaken for the customer's own view of their account. Tokens only. */
.sbs-preview-banner {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px;
  margin: 0 0 22px; padding: 12px 18px;
  background: color-mix(in srgb, var(--sbs-gold) 14%, var(--sbs-surface));
  border: 1px solid var(--sbs-gold-ink);
  color: var(--sbs-ink); font-size: 13px; line-height: 1.6;
}
.sbs-preview-banner strong { color: var(--sbs-gold-ink); }
.sbs-preview-banner .button { flex: 0 0 auto; }
.sbs-account-dashboard-links { list-style: none; margin: 22px 0 0; padding: 0; }
.sbs-account-dashboard-links li { margin: 0 0 10px; }
.sbs-account-dashboard-links a { font-size: 15px; }
.sbs-order-status-badge {
  display: inline-block; margin: 0 6px 4px 0; padding: 0.15rem 0.5rem;
  border: 1px solid var(--sbs-border); font-size: 0.72rem; text-transform: uppercase;
  letter-spacing: 0.08em; color: var(--sbs-body);
}
.sbs-order-status-badge:last-child { margin-right: 0; }
.sbs-account-empty-cta { margin-top: 18px; }
.sbs-order-status-badge.is-success { color: var(--sbs-success); border-color: var(--sbs-success); }
.sbs-order-status-badge.is-danger { color: var(--sbs-danger); border-color: var(--sbs-danger); }

/* ── Account (/account/addresses) — saved-address book ──
   .woocommerce-Addresses/.woocommerce-Address/address already carry Savoy's chrome (shop.css);
   these scoped rules only add what Savoy doesn't: cards in a responsive grid (via the
   .sbs-address-grid hook class), the label/Default-badge header row, and gaps between the inline
   .button.border actions (Savoy's .button is inline-block with no built-in sibling spacing).
   The card rule is scoped under .woocommerce-edit-address (an ancestor already on this page) so it
   beats shop.css's `.woocommerce-edit-address .addresses > div { padding-top: 0 }` — (0,3,0) over
   (0,2,1); without that extra ancestor the card's top padding is zeroed and the title sits flush
   against the border. Tokens only. */
.sbs-address-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 20rem), 1fr));
  gap: 20px;
  align-items: start;
}
.woocommerce-edit-address .sbs-address-grid .woocommerce-Address {
  border: 1px solid var(--sbs-border);
  padding: 22px 24px;
  margin: 0;
}
.woocommerce-Address-title { display: flex; align-items: baseline; gap: 10px; }
.sbs-address-actions { margin: 10px 0 20px; }
/* Inside a card the 22px bottom padding is the sole bottom gap — drop the actions' own bottom
   margin so the card isn't lopsided (top vs bottom) after the padding fix above. */
.sbs-address-grid .sbs-address-actions { margin-bottom: 0; }
.sbs-address-actions .button,
.sbs-address-form-actions .button { margin: 0 10px 10px 0; }
.sbs-address-add { margin-top: 22px; }

/* ── Account (/account/details) — name + marketing-consent form ──
   Reuses .sbs-contact-form .sbs-field for the name/email/WhatsApp rows; these scoped rules cover
   what that shared markup doesn't: the muted read-only note, and the marketing checkbox row.
   `.sbs-contact-form .sbs-field input` forces width:100%, which would stretch a checkbox full-width
   — this row is a label OUTSIDE `.sbs-field` (mirrors CheckoutForm's `.sbs-checkout-consent`), so
   the checkbox stays `width:auto`. Tokens only. */
.sbs-account-readonly-note { margin: -8px 0 20px; font-size: 13px; line-height: 1.6; color: var(--sbs-muted); }
.sbs-account-consent { display: flex; align-items: flex-start; gap: 10px; margin: 0 0 20px; font-size: 13px; line-height: 1.6; color: var(--sbs-muted); cursor: pointer; }
.sbs-account-consent input { width: auto; margin: 3px 0 0; flex: 0 0 auto; }

/* ── Account (/account/details) — email manager (Customer Accounts v2 Task 11) ──
   Sits above the name/consent form as its own block + its own <form> (add-email is a SEPARATE form
   from the profile save form — nested <form>s are invalid HTML). Reuses .sbs-order-status-badge
   (is-success = Verified) and .sbs-contact-form .sbs-field for the "Add an email" row; these scoped
   rules only add the row layout the shared markup doesn't cover. Tokens only. */
.sbs-account-emails { margin: 0 0 34px; }
.sbs-account-emails-title { margin: 0 0 14px; font-size: 15px; }
.sbs-account-email-list { list-style: none; margin: 0 0 20px; padding: 0; }
.sbs-account-email-row {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  padding: 10px 0; border-bottom: 1px solid var(--sbs-border);
}
.sbs-account-email-row:first-child { border-top: 1px solid var(--sbs-border); }
.sbs-account-email-address { flex: 1 1 auto; min-width: 0; font-size: 14px; color: var(--sbs-body); overflow-wrap: anywhere; }
.sbs-account-add-email { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 14px; }
.sbs-account-add-email .sbs-field { flex: 1 1 240px; margin: 0; }
.sbs-account-add-email .button { flex: 0 0 auto; }

/* Branded consent checkbox — matches the console's custom control (gold-ink fill + surface tick),
   scoped to .sbs-account-consent so it can't touch Savoy's own native controls. Used by the
   newsletter modal, checkout, account details, and the /register page consent boxes. */
.sbs-account-consent input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  flex: 0 0 auto;
  width: 1.125rem;
  height: 1.125rem;
  border: 1px solid var(--sbs-border);
  background: var(--sbs-surface);
  cursor: pointer;
  display: inline-grid;
  place-content: center;
  transition: background-color 120ms ease, border-color 120ms ease;
}
.sbs-account-consent input[type="checkbox"]:checked {
  background: var(--sbs-gold-ink);
  border-color: var(--sbs-gold-ink);
}
.sbs-account-consent input[type="checkbox"]::before {
  content: "";
  width: 0.625rem;
  height: 0.625rem;
  background: var(--sbs-surface);
  clip-path: polygon(14% 44%, 0 65%, 43% 100%, 100% 16%, 84% 0, 40% 62%);
  transform: scale(0);
  transition: transform 120ms ease;
}
.sbs-account-consent input[type="checkbox"]:checked::before { transform: scale(1); }
@media (prefers-reduced-motion: reduce) {
  .sbs-account-consent input[type="checkbox"],
  .sbs-account-consent input[type="checkbox"]::before { transition: none; }
}
.sbs-account-details-actions { margin-top: 4px; }

@media all and (max-width: 767px) {
  .sbs-banner-promos .col-xs-12:first-child .nm-banner { margin-bottom: 20px; }
  /* The shared 90deg left gradient only covers the left edge; on narrow screens the title/subtitle
     wrap across the full width, so switch to a top-anchored gradient that shades the (top-aligned)
     text area edge-to-edge. */
  .sbs-banner-promos .nm-banner.text-color-light::before {
    background: linear-gradient(180deg, rgba(20, 18, 16, 0.6), rgba(20, 18, 16, 0.18) 55%, rgba(20, 18, 16, 0) 82%);
  }
}

/* ── Modal primitive (components/ui/Modal.tsx) — a portal-to-body backdrop + centered panel.
   Shared by ConfirmDialog (replaces window.confirm across the app) and the footer newsletter
   signup. This file is loaded on BOTH the storefront AND the console layouts (SAVOY_CSS_FILES),
   so this one token-based ruleset covers both surfaces — no console.css duplicate needed.
   Tokens only; the backdrop's rgba(28,25,23,…) scrim is `--sbs-ink` at reduced opacity (the
   documented "dark surface" exception, same move as the existing `.mfp-bg` lightbox scrim).
   z-index sits above the mobile nav drawer (1010) and the gallery lightbox (1042-1045) since a
   confirmation can, in principle, be triggered from within either. Sharp corners (radius 0) per
   the design language; buttons reuse Savoy's own `.button`/`.button.border` so they match
   whichever surface (storefront or console) opened the modal. */
.sbs-modal-backdrop {
  position: fixed; inset: 0; z-index: 1060;
  background: rgba(28, 25, 23, 0.6);
  display: flex; align-items: center; justify-content: center;
  padding: 1rem;
}
.sbs-modal-panel {
  position: relative; width: 100%; max-width: 30rem; max-height: calc(100dvh - 2rem);
  overflow-y: auto; background: var(--sbs-surface); border: 1px solid var(--sbs-border);
  border-radius: var(--radius, 0); box-shadow: var(--shadow-pop, 0 8px 30px rgba(28, 25, 23, 0.12));
  font-family: var(--font-body);
}
.sbs-modal-header {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem;
  padding: 1.25rem 1.5rem 0.75rem;
}
.sbs-modal-title { margin: 0; font-family: var(--font-heading); font-size: 1.4rem; line-height: 1.25; color: var(--sbs-ink); }
.sbs-modal-close {
  flex: 0 0 auto; width: 44px; height: 44px; padding: 0; margin: -0.6rem -0.6rem 0 0; border: 0;
  background: none; color: var(--sbs-muted); font-size: 1.5rem; line-height: 1; cursor: pointer;
}
.sbs-modal-close:hover { color: var(--sbs-ink); }
.sbs-modal-body { padding: 0.5rem 1.5rem 1.5rem; color: var(--sbs-body); }

/* ConfirmDialog (components/ui/ConfirmDialog.tsx) — a Modal with a message + Cancel/Confirm row. */
.sbs-confirm-message { margin: 0 0 1.25rem; }
.sbs-confirm-actions { display: flex; justify-content: flex-end; gap: 0.75rem; flex-wrap: wrap; }
.sbs-confirm-destructive { background-color: var(--sbs-danger); border-color: var(--sbs-danger); color: var(--sbs-surface); }
.no-touch .sbs-confirm-destructive:hover { filter: brightness(0.9); color: var(--sbs-surface); }

/* ============================================================================
   UX/UI audit fixes (2026-07-16) — docs/ux-ui-audit-2026-07-16.md
   Additive overrides only; the core Savoy files (style/shop/elements/grid) are never edited.
   This file loads LAST among SAVOY_CSS_FILES (lib/savoyCss.ts), so a same-specificity tie
   against style.css/shop.css/elements.css resolves in our favour by source order alone — most
   rules below rely on that and simply re-declare the competing selector. Where a competing rule
   is MORE specific, or lives in a different stylesheet bucket entirely (app/globals.css, compiled
   by Next separately from the SAVOY_CSS_FILES precedence group, so its cascade position isn't
   guaranteed by anything in this file), the override either exceeds that specificity outright or
   — noted inline, each case deliberate and narrowly scoped — uses !important.
   ============================================================================ */

/* ── C1 — restore visible keyboard focus. THE load-bearing fix: all 7 audit clusters
   independently flagged this as the single highest-leverage a11y defect in the app. Savoy strips
   the focus ring on :focus (not :focus-visible) at several specificities:
     - style.css:231-244  input[type="text"]:focus, ..., input.input-text:focus, select:focus,
                           textarea:focus { outline:0; border-color:...; }
                           → up to (0,2,1) (e.g. input[type="tel"]:focus, input.input-text:focus);
                             select:focus/textarea:focus are (0,1,1)
     - style.css:286-291  input[type=submit]:focus, .button:focus { outline:none; }
                           → (0,2,1) / (0,2,0)
     - style.css:178-179  a { outline:0; }  → (0,0,1), unconditional (not scoped to :focus)
     - app/globals.css:39 .sbs-input:focus { outline:none; border-color:var(--sbs-ink); }
                           → (0,2,0), in the Next/Tailwind-compiled bundle — a DIFFERENT
                             stylesheet bucket than the SAVOY_CSS_FILES precedence group this file
                             belongs to, so its position relative to this file in the cascade is
                             not something source order here can guarantee either way.
   Chasing per-selector specificity across every one of those (plus any future Savoy field type)
   is exactly the kind of fragile CSS that regresses silently; the money/account paths this
   protects (Place order, Checkout, Publish, Confirm sale, the login/capture forms) are too high
   stakes for that risk, so !important is used deliberately here — confirmed to win regardless of
   which of the above it's racing against (see uxfix-T1-report.md for the check). ── */
.button:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
[type=submit]:focus-visible,
a:focus-visible,
.sbs-input:focus-visible {
  outline: 2px solid var(--color-ring) !important;
  outline-offset: 2px !important;
}

/* ── H1 — in-content link text renders Savoy's bright gold. The ported customizer block near the
   top of this file (the long generated selector list) re-declares `a{color:#dc9814}` (≈2.4:1,
   fails AA) — style.css:178 also sets it at (0,0,1). Our redeclaration below is the SAME
   specificity (0,0,1) but sits further down in this file (and this file loads after style.css),
   so it wins the tie by source order alone; no extra specificity needed. More specific existing
   rules (`.nm-footer-bar a`, `.sbs-doc-body a`, hover states, etc.) are untouched and still win
   where they're deliberately gold-on-dark or already correct. ── */
a { color: var(--sbs-gold-ink); }

/* ── C2 — the PDP price (most important number on the page): shop.css:3861
   `.product .summary .price .amount{color:#dc9814}` is ≈2.1:1 on the #eeeeee summary panel —
   the worst contrast failure in the audit. The same selector also renders the "from RM…" range
   price and the resolved single_variation price (product/[slug]/page.tsx + ReserveControls.tsx
   both put their price inside `.summary .price`), so one fix clears all three. (0,4,0) — matched
   below at the same specificity, tie by source order. ── */
.product .summary .price .amount,
.product-summary .price .amount {
  color: var(--sbs-gold-ink);
}

/* ── M25 — active shop-category chip signalled by colour alone (#dc9814 ≈2.4:1, underline removed
   on mobile). style.css:1766-1772 `.nm-shop-menu ul li.current-cat > a` / `.nm-shop-menu ul
   li.active a` is (0,2,3) — matched below at the same specificity, tie by source order. Weight +
   underline give the active state a second, non-colour cue. ── */
.nm-shop-menu ul li a:hover,
.nm-shop-menu ul li.current-cat > a,
.nm-shop-menu ul li.active a {
  color: var(--sbs-gold-ink);
}
.nm-shop-menu ul li.current-cat > a,
.nm-shop-menu ul li.active a {
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* ── M25 — breadcrumb + product-meta (SKU/category) text at #a3a3a3 (≈2.5-2.6:1, fails AA);
   declared in the same ported customizer block as H1 above, at (0,1,0)/(0,1,1)/(0,2,1) —
   matched below, tie by source order. ── */
.woocommerce-breadcrumb,
.product_meta a,
.product_meta span.sku,
.nm-post-meta {
  color: var(--sbs-muted);
}

/* ── H4 — account/notice success #03a678 (3.16:1) / error #f27362 (2.85:1) fail AA; error text
   especially must stay legible. shop.css: `.woocommerce-message{color:#03a678}` (160),
   `.woocommerce-error{color:#f27362}` (177), `.woocommerce-thankyou-order-received{color:#03a678}`
   (7026) are each (0,1,0) — matched below, tie by source order. ── */
.woocommerce-message,
.wc-block-components-notice-banner.is-success,
.woocommerce-thankyou-order-received {
  color: var(--sbs-success);
}
.woocommerce-error,
.wc-block-components-notice-banner.is-error,
.nm-validation-inline-notices .form-row.woocommerce-invalid-required-field:after {
  color: var(--sbs-danger);
}
.form-row.woocommerce-invalid .input-text,
.form-row.woocommerce-invalid select {
  border-color: var(--sbs-danger);
}

/* ── H7 — shop-card quick actions (Add to cart / Enquire / View) sit at opacity:0, revealed only
   on :hover (shop.css:908-909 `.no-touch .nm-products li:hover .nm-shop-loop-actions`) — never
   :focus-within — so keyboard focus lands on a fully transparent control. `li:focus-within
   .nm-shop-loop-actions` is (0,2,1), comfortably above the base `.nm-shop-loop-actions{opacity:0}`
   at (0,1,0); no need to match the hover rule's own (0,4,1), that's a separate interaction state. */
li:focus-within .nm-shop-loop-actions {
  opacity: 1;
  left: 0;
}
.products.has-action-links li:focus-within .price {
  opacity: 0;
}

/* ── H6 — the single biggest mobile conversion gap in the audit: grid-card Add-to-cart/Enquire
   sit at opacity:0 (shop.css:895-911 `.nm-shop-loop-actions`), revealed only by a *sustained*
   `:hover` (shop.css:908-909) that real touch input essentially never produces — phone shoppers
   (the majority of traffic) could not reserve or enquire from the shop grid at all and had to
   open every PDP first. `(hover: none)` matches any device whose primary pointer can't hover —
   unlike the JS-set `.touch`/`.no-touch` classList (SavoyChrome.tsx), it's live from first paint,
   before hydration. `.nm-shop-loop-actions` here is (0,1,0), tied with shop.css's own base rule;
   savoy-custom.css loads last (lib/savoyCss.ts), so this wins the tie by source order — same
   pattern as H1/H7 above, no `!important` needed for it. Switches the flyout from an absolutely-
   positioned hover overlay (which would sit invisibly over the thumbnail) to a normal in-flow
   block below the price, and pads every action to a >=44x44 tap target regardless of which of the
   three ProductCard branches rendered (AddToBag button, WhatsApp-enquire link, or the sold/OOS
   "View piece" link — all three already share the `.nm-shop-loop-actions > a|button` slot, so no
   JSX change was needed, only visibility). The price->action swap is a hover-only affordance with
   nothing to trigger it here, so the price is force-kept visible alongside the action instead of
   being swapped away (the two are stacked, not overlapping, once the action is in-flow) —
   `!important` is deliberate: it only needs to beat a same-file `:hover`-scoped rule some mobile
   browsers apply transiently on tap (shop.css:868-870), not fight cross-file specificity. ── */
@media (hover: none) {
  .products.has-action-links .price {
    opacity: 1 !important;
  }
  .nm-shop-loop-actions {
    position: static;
    opacity: 1;
    left: 0;
    top: auto;
    margin-top: 10px;
  }
  .nm-shop-loop-actions > a,
  .nm-shop-loop-actions > button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    min-width: 44px;
    padding-inline: 14px;
  }
}

/* ── H12 — the focused skip link (components/storefront/SkipLink.tsx; Tailwind's `focus:z-50`
   compiles to `.focus\:z-50:focus{z-index:50}`, (0,2,0)) paints behind the z-1002 fixed header
   (style.css:887 `.nm-header`). `a[href="#main"]:focus` is (0,2,1) — exceeds it outright, so this
   wins regardless of the two stylesheets' relative DOM position. --z-skiplink (theme.tokens.css,
   L26) sits above every named layer including --z-modal (1060). ── */
a[href="#main"]:focus {
  z-index: var(--z-skiplink);
}

/* ── M1 — every field under 16px triggers iOS Safari's auto-zoom on focus (Savoy's
   `.sbs-contact-form .sbs-field input{font-size:15px}` at (0,2,1) above in this same file, plus
   the body-inherited 14px on bare Savoy inputs). !important is deliberate: form fields are styled
   through half a dozen different wrapper classes across the storefront (.sbs-field,
   .sbs-contact-form .sbs-field, .form-row, bare Savoy input[type=x]) and this needs to win on ALL
   of them, unconditionally, on mobile — chasing specificity across every wrapper is exactly the
   fragile, easy-to-regress CSS this rule exists to make unnecessary. Padding trimmed slightly on
   .sbs-input to hold its visual density roughly steady now the font is a touch larger. ── */
@media (max-width: 768px) {
  input, select, textarea, .sbs-input,
  .sbs-field input, .sbs-field select, .sbs-field textarea,
  .form-row input, .form-row select, .form-row textarea {
    font-size: 16px !important;
  }
  .sbs-input { padding-block: 0.65rem; }
}

/* ── M10 — style.css:245-254 strips the native <select> arrow (`appearance:none` under the
   -webkit-min-device-pixel-ratio selector) and points the replacement at
   "assets/img/select-arrow-2x.gif", which 404s (the file never shipped) — every .sbs-field select
   (checkout country/state/saved-address, contact form) looks like a plain text box. Inline SVG
   data-URI chevron instead of an image request. `.sbs-field select` is (0,1,1), exceeding the
   bare `select` (0,0,1) it replaces, so it wins regardless of the webkit media query. ── */
.sbs-field select {
  padding-right: 32px;
  background-color: #fff;
  background-repeat: no-repeat;
  background-position: calc(100% - 12px) 50%;
  background-size: 10px 6px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%23282828' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

/* ── M23/M31 — sub-44px touch targets, fixed via padding/min-height so nothing reflows. ── */

/* Footer-bar menu links + social icons (style.css:6697-6758) carry no vertical padding today
   (~24-28px effective height). */
.nm-footer-bar .menu > li > a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 4px 0;
}
.nm-footer-bar-social a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
}

/* Account nav links (shop.css:7660-7667, ~23px tall today). Also L16: the base rule inherits
   `color:inherit` down to the page's #777 body colour (≈4.48:1, marginally fails AA) —
   --sbs-muted is the confirmed-AA token for the inactive rows (.is-active a already overrides to
   #282828 and is untouched). */
.woocommerce-MyAccount-navigation ul li a {
  display: block;
  min-height: 44px;
  padding: 12px 0;
  color: var(--sbs-muted);
}

/* Orders "View" link — the base .button (style.css:262-280, 14px/16px padding+line-height) is
   already ~44px by itself; this is a defensive floor in case a table-cell context ever compresses
   it, matching the audit's measured ~28px. */
.woocommerce-orders-table__cell-order-actions .button {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Wishlist heart — shop.css only ever sets font-size/line-height (16/17px) on `.nm-wishlist-button`
   at every variant (shop card, PDP); no box size at all. min-width/min-height + flex-centering
   grows the tap area without changing the glyph's own position. The shop-card variant is
   `position:absolute;top:0;right:0` (shop.css:945) — align the icon to that same corner inside
   the now-larger box instead of centering it, so it doesn't visually shift. */
.nm-wishlist-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
}
.products .nm-wishlist-button {
  align-items: flex-start;
  justify-content: flex-end;
}

/* Qty stepper ± — shop.css:4407-4425 `.nm-quantity-wrap .quantity .nm-qty-minus,
   .nm-quantity-wrap .quantity .nm-qty-plus` is 23x42 at (0,3,0) — matched below at the same
   specificity, tie by source order. */
.nm-quantity-wrap .quantity .nm-qty-minus,
.nm-quantity-wrap .quantity .nm-qty-plus {
  width: 44px;
  height: 44px;
  line-height: 44px;
}

/* ── M24 — scroll-lock utility for the mobile drawer / cart panel / search overlays (Savoy's own
   JS scroll-lock isn't run in this port, only a class toggles today). JS wiring — the shared
   `useScrollLock` hook (components/ui/useDialog.ts) toggles this class on `<body>` for the
   lifetime of any open overlay/Modal — shipped in the T3 pass. ── */
body.sbs-noscroll {
  overflow: hidden;
}

/* ── L1 — tabular-nums on every remaining money surface not already covered by the in-place edits
   elsewhere in this file (cart/order-summary rows, order-overview total): the PDP/shop-card
   `.amount`, and the account orders-table total column. ── */
.amount,
.woocommerce-Price-amount,
.woocommerce-orders-table__cell-order-total {
  font-variant-numeric: tabular-nums;
}

/* ── L2 — the journal single-post body (app/(storefront)/journal/[slug]/page.tsx) sets its own
   inline `style={{maxWidth:760}}` and does NOT carry .sbs-doc-body — only the generic
   `.entry-content` class shared by every content surface — so scope through the page's own
   `.nm-single-post` wrapper to avoid touching other `.entry-content` usages. !important for the
   same reason as `.sbs-doc-body` above: an inline style attribute otherwise always wins. ── */
.nm-single-post .entry-content {
  max-width: 680px !important;
}

/* ── M3 — active-location nav indicator (header main menu incl. its mega-menu category links,
   mobile drawer, footer bar): nothing signalled "you are here" before. `aria-current="page"` (set
   in Header.tsx/MobileMenu.tsx/Footer.tsx) is the real fix — announced by AT regardless of any
   CSS — this adds a visible, non-colour-alone cue too (weight + underline), mirroring the M25
   active-chip treatment above, keyed off the same components' new `current-menu-item` class on
   the matching <li>. Scoped selectors avoid MobileMenu's OWN `.menu-item.active` (the unrelated
   open-submenu-panel state) and the M25 shop-sidebar chip rule above (`.nm-shop-menu`, untouched).
   `.nm-main-menu` wraps both Header's top-level items and its mega-menu category links, so one
   selector covers both; likewise `#nm-mobile-menu` for the drawer's top-level + category links. ── */
.nm-main-menu li.current-menu-item > a,
#nm-mobile-menu li.current-menu-item > a,
#nm-footer-bar-menu li.current-menu-item > a {
  color: var(--sbs-gold-ink);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* ── Deferred (no CSS-only hook without a component change — flagged, not silently skipped):
   • M23 capture "favourite style" chips (components/CaptureForm.tsx) — raw Tailwind utility
     classes only, no stable selector; `aria-pressed` is shared with WishlistHeart so isn't a safe
     hook either. Needs a className added in a follow-up task.
   • L8 /shipping "rates being confirmed" note (app/(storefront)/shipping/page.tsx) — a bare <p>
     with only an inline style, no wrapping class more specific than the generic `.nm-row
     .col-xs-12` every content page shares. Same fix: needs a className.
   • M23/M31 POS "recent" links — admin console (/admin/pos/recent), styled via console.css, not
     this (storefront) file; out of scope for this pass. ── */

/* ============================================================================
   T5 — Commerce / money-path UX fixes: checkout (H2/H5/M6/M11/M13/M14/quick-win-12), cart (M11),
   order confirmation (M15/L11/L12), wishlist (M12). See docs/ux-ui-audit-2026-07-16.md.
   ============================================================================ */

/* H2 — the mobile checkout summary/total previously rendered AFTER the Place order button in
   source order, so a phone buyer could reach + tap Place order before ever seeing the total.
   `.nm-row` is normally float-based (grid.css); scoping display:flex to just the checkout's own
   row lets `order` reflow the two columns without touching the shared grid system, and the
   before/after clearfix pseudo-elements (needed for the float layout, not this flex one) are
   neutralised so they don't become two stray empty flex items. Applies identically to the
   post-submit Stripe-reveal view (same `.sbs-checkout`/`.sbs-checkout-main`/
   `.sbs-checkout-summary-col` classes) — seeing the total before paying matters there too. */
@media (max-width: 768px) {
  .sbs-checkout > .nm-row {
    display: flex;
    flex-direction: column;
  }
  .sbs-checkout > .nm-row:before,
  .sbs-checkout > .nm-row:after {
    content: none;
  }
  .sbs-checkout-main {
    order: 2;
  }
  .sbs-checkout-summary-col {
    order: 1;
    margin-bottom: 28px;
  }
}

/* M6 — per-field inline validation (checkout today; the pattern in lib/formValidation.ts is
   meant to be reused by account/content forms later). A visible required-field marker (the
   `required` attribute already carries the semantics for AT) + an inline error message tied to
   the field via aria-describedby. */
.sbs-required-mark {
  color: var(--sbs-muted);
}
.sbs-field-error {
  display: block;
  margin-top: 6px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--sbs-danger);
}

/* M11 — the reservation-hold countdown previously existed only in the slide-out mini-cart
   (untouched — CartPanel.tsx keeps its own copy of this styling too), invisible on /cart and
   /checkout where a shopper actually spends the time. `.is-expiring` (≤2 min remaining) swaps to
   the danger token so the warning isn't colour-alone — the copy itself changes too. */
.sbs-reservation-note {
  margin: 0 0 24px;
  padding: 12px 16px;
  border: 1px solid #eee;
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-align: center;
  color: var(--sbs-muted);
}
.sbs-reservation-note.is-expiring {
  color: var(--sbs-danger);
  border-color: var(--sbs-danger);
}

/* H5 — the Stripe embedded-checkout reveal: previously a bare, unstyled, uncentered iframe with
   no heading/recap/back-to-edit and no mounting spinner, while the order was already "pending"
   server-side (an abandon here stranded the buyer). Now framed with the same checkout-heading
   treatment as every other section + a "Change details" way back to the form. */
.sbs-stripe-reveal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin: 0 0 12px;
  padding-bottom: 12px;
  border-bottom: 1px solid #eee;
}
.sbs-stripe-reveal-header .sbs-checkout-heading {
  margin: 0;
  padding: 0;
  border: 0;
}
.sbs-stripe-back {
  flex: 0 0 auto;
}
.sbs-stripe-reveal-note {
  margin: 0 0 24px;
  font-size: 14px;
  line-height: 1.6;
  color: var(--sbs-muted);
}
.sbs-stripe-mount {
  position: relative;
  min-height: 420px;
}
.sbs-stripe-loading {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  background: var(--sbs-surface);
  color: var(--sbs-muted);
  font-size: 13px;
  letter-spacing: 0.04em;
}
.sbs-spinner {
  width: 32px;
  height: 32px;
  border: 2px solid #eee;
  border-top-color: #282828;
  border-radius: 50%;
  animation: sbs-spin 0.8s linear infinite;
}
.sbs-spinner-sm {
  width: 22px;
  height: 22px;
  border-width: 2px;
}
@keyframes sbs-spin {
  to {
    transform: rotate(360deg);
  }
}
@media (prefers-reduced-motion: reduce) {
  .sbs-spinner {
    animation: none;
    border-top-color: #eee;
  }
}

/* M15 — the order-confirmation status spinner (shown only while `order.status === "pending"`). */
.sbs-order-confirmation-spinner {
  display: flex;
  justify-content: center;
  margin: 0 0 18px;
}

/* L11 — a contact recap on /order/[id] (previously the only reassurance was the truncated
   reference in the overview strip above). */
.sbs-order-contact-recap {
  max-width: 480px;
  margin: 0 auto 30px;
  padding: 18px 20px;
  border: 1px solid #eee;
  text-align: center;
}
.sbs-order-contact-recap-name {
  margin: 0 0 4px;
  font-size: 15px;
  color: #282828;
}
.sbs-order-contact-recap-detail {
  margin: 0 0 8px;
  font-size: 14px;
  font-variant-numeric: tabular-nums;
  color: #44403c;
}
.sbs-order-contact-recap-note {
  margin: 0;
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--sbs-muted);
}
.sbs-order-confirmation-buttons {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 14px;
}

/* M12 — wishlist reconciliation: a saved piece that's since sold renders as a distinct "Sold —
   commission similar" tile (not silently dropped, not shown as if still purchasable); a saved
   slug that no longer resolves to any product at all renders a small removable notice. Both slot
   into the same product grid as ordinary ProductCard tiles, so the grid's own column-width rules
   (shop.css `.small-block-grid-*`) apply unchanged. */
.sbs-wishlist-sold-item {
  padding-bottom: 6px;
}
.sbs-wishlist-sold-thumb {
  position: relative;
  display: block;
  aspect-ratio: 3 / 4;
  overflow: hidden;
  background: #eee;
}
.sbs-wishlist-sold-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
  filter: grayscale(0.15);
  opacity: 0.85;
}
.sbs-wishlist-sold-noimg {
  display: block;
  width: 100%;
  height: 100%;
  background: #eee;
}
.sbs-wishlist-sold-badge {
  position: absolute;
  top: 12px;
  left: 12px;
  padding: 4px 10px;
  background: #282828;
  color: #fff;
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.sbs-wishlist-sold-name {
  margin: 14px 0 4px;
  font-family: var(--font-body);
  font-size: 15px;
  font-weight: normal;
}
.sbs-wishlist-sold-name a {
  color: #282828;
}
.sbs-wishlist-sold-note {
  margin: 0 0 12px;
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--sbs-muted);
}
.sbs-wishlist-sold-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px;
  margin: 0;
}
.sbs-wishlist-sold-remove {
  padding: 0;
  border: 0;
  background: none;
  font-size: 12px;
  text-decoration: underline;
  color: var(--sbs-muted);
  cursor: pointer;
}
.no-touch .sbs-wishlist-sold-remove:hover {
  color: #282828;
}
.sbs-wishlist-missing {
  padding: 20px;
  border: 1px dashed #ccc;
  text-align: center;
  color: #78716c;
}
.sbs-wishlist-missing p {
  margin: 0 0 12px;
  font-size: 14px;
}

/* ============================================================================
   T6 — Account UX fixes: orders mobile reflow (H13), order-detail history view (M16), form
   validation (M6), aria-current + headings (M3/M17), loading/empty states (M5/L13), read-only
   fields (L14), login resend (L15). See docs/ux-ui-audit-2026-07-16.md.
   ============================================================================ */

/* ── H13 — /account/orders mobile reflow ──
   shop.css hides the Total column <=991px and the Date column <=550px with plain display:none and
   no stacked replacement (shop.css:7866-7877), so on a phone the two numbers customers scan order
   history for — the amount and when it happened — are simply gone, with no way to see them short
   of desktop width. First, un-hide both columns unconditionally (these selectors tie shop.css's
   specificity; savoy-custom.css loads last — see lib/savoyCss.ts — so it wins the cascade),
   restoring a normal full desktop table above the new breakpoint below. Then, <=768px, reflow into
   stacked label/value "cards": hide the header row, turn every <td> into a full-width row labelled
   from the `data-title` attribute OrdersList already sets on each cell. */
.woocommerce-MyAccount-orders tr .woocommerce-orders-table__header-order-total,
.woocommerce-MyAccount-orders tr .woocommerce-orders-table__cell-order-total,
.woocommerce-MyAccount-orders tr .woocommerce-orders-table__header-order-date,
.woocommerce-MyAccount-orders tr .woocommerce-orders-table__cell-order-date {
  display: table-cell;
}
@media all and (max-width: 768px) {
  .woocommerce-MyAccount-orders thead {
    display: none;
  }
  .woocommerce-MyAccount-orders,
  .woocommerce-MyAccount-orders tbody,
  .woocommerce-MyAccount-orders tr {
    display: block;
    width: 100%;
  }
  .woocommerce-MyAccount-orders tr {
    margin: 0 0 18px;
    padding: 6px 0 14px;
    border-bottom: 1px solid var(--sbs-border);
  }
  /* `display:block` (not flex) deliberately — the Status cell holds TWO badge spans, not one
     value node, so a flex row with `justify-content:space-between` would spread the label and
     both badges apart individually instead of keeping "label: value(s)" together. Block + an
     inline `::before` label reads as normal wrapping text ("Status: Paid Shipped") regardless of
     how many value nodes a cell holds. */
  .woocommerce-MyAccount-orders td {
    display: block;
    width: 100%;
    padding: 8px 0;
    border: 0;
  }
  .woocommerce-MyAccount-orders td::before {
    content: attr(data-title) ": ";
    font-size: 11px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--sbs-muted);
  }
  .woocommerce-orders-table__cell-order-actions {
    text-align: right;
  }
}

/* ── M5 — sized loading skeletons (AccountSkeleton.tsx), replacing the bare "Loading…" text every
   account body used to render. `.sbs-skeleton` is the shimmering-bar primitive; reduced-motion
   swaps the shimmer for a flat muted fill instead of animating. */
.sbs-skeleton {
  display: block;
  position: relative;
  overflow: hidden;
  background: var(--sbs-border);
}
.sbs-skeleton::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.7), transparent);
  animation: sbs-skeleton-shimmer 1.5s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
  .sbs-skeleton::after {
    animation: none;
    display: none;
  }
}
@keyframes sbs-skeleton-shimmer {
  0% {
    transform: translateX(-100%);
  }
  100% {
    transform: translateX(100%);
  }
}
.sbs-skeleton-shell {
  padding: 10px 0 30px;
}
.sbs-skeleton-shell-line {
  height: 16px;
  max-width: 260px;
  margin: 0 auto 26px;
}
.sbs-skeleton-shell-block {
  height: 160px;
}
.sbs-skeleton-table {
  display: flex;
  flex-direction: column;
  gap: 18px;
  padding: 6px 0 4px;
}
.sbs-skeleton-table-row {
  display: flex;
  align-items: center;
  gap: 20px;
}
.sbs-skeleton-table-row .sbs-skeleton {
  height: 14px;
  flex: 1 1 auto;
}
.sbs-skeleton-table-row .sbs-skeleton:last-child {
  flex: 0 0 72px;
}
.sbs-skeleton-cards {
  display: flex;
  flex-direction: column;
  gap: 22px;
  padding: 4px 0;
}
.sbs-skeleton-card {
  padding: 0 0 18px;
  border-bottom: 1px solid var(--sbs-border);
}
.sbs-skeleton-card .sbs-skeleton {
  height: 12px;
  margin-bottom: 8px;
}
.sbs-skeleton-card .sbs-skeleton:first-child {
  width: 35%;
  height: 14px;
}
.sbs-skeleton-card .sbs-skeleton:last-child {
  width: 55%;
  margin-bottom: 0;
}
.sbs-skeleton-detail-heading {
  height: 22px;
  max-width: 60%;
  margin: 0 auto 26px;
}
.sbs-skeleton-detail-block {
  height: 110px;
}

/* ── L14 — read-only account fields (email/WhatsApp): previously `disabled` (removed from tab
   order, uncopyable) AND visually IDENTICAL to an editable field (no [disabled] input style exists
   in the served Savoy CSS), so the field looked editable but silently ignored input. `readOnly`
   keeps it focusable/selectable/copyable; this gives it a visibly muted, AA-passing treatment
   ("informational, not editable") that isn't colour-alone (a subtle background tint too). */
.sbs-contact-form .sbs-field-readonly input[readonly] {
  background: var(--sbs-bg);
  color: var(--sbs-muted);
  cursor: default;
}

/* ── M16 — /account/orders/[id] history view: a persistent back-to-orders link + a small badge row
   under the heading (payment + fulfillment status). */
.sbs-account-order-back {
  margin: 0 0 20px;
  font-size: 13px;
}
.sbs-order-status-badges {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 6px;
  list-style: none;
  margin: 14px 0 26px;
  padding: 0;
}

/* ── L15 — login "check your email" success state keeps a way back to the form instead of
   stranding a typo'd email with no recovery. */
.sbs-login-resend {
  margin-top: 16px;
  text-align: center;
}

/* ── the login card's "New here? Create an account" link — same spacing rhythm as
   .sbs-login-resend above it, muted so it reads as secondary to the sign-in form. */
.sbs-login-register-link {
  margin-top: 16px;
  text-align: center;
  font-size: 13px;
  color: var(--sbs-muted);
}

/* ── L8 — the /shipping "international rates being confirmed" note was 14px italic muted, too
   quiet for pre-purchase info a buyer needs before checkout. 16px body-ink, no italic. ── */
.sbs-shipping-note {
  max-width: 820px;
  margin: 0 auto;
  font-size: 16px;
  font-style: normal;
  color: var(--sbs-body);
}

/* ============================================================================
   live-QA fixes 2026-07-16 — .superpowers/sdd/qa-live-findings.md
   A follow-up pass over rendered/computed-style assertions taken against the deployed storefront
   (13 pages x {375,768,1280,320}) — real pixel/contrast failures the static code audit above
   (the "UX/UI audit fixes" banner) enumerated but didn't quite land on every selector, or that
   only show up once actual layout/cascade is measured in a browser. Same additive-override
   discipline as above: savoy-custom.css loads LAST among SAVOY_CSS_FILES, so same-specificity
   reselections win by source order alone; higher specificity or !important only where noted.
   NOT fixed here (see the QA doc): hero-overlay-on-photo contrast (can't compute vs an image,
   needs a screenshot check) and the page-title gold-ink@3.15 (likely large-heading text, which
   only needs >=3:1 under WCAG's large-text exception — needs a font-size confirm, not a colour
   change) — both flagged "NEEDS VISUAL/OTHER CHECK", not confirmed failures.
   ============================================================================ */

/* ── Header icon buttons (Menu / Search / Cart) measured 32px WIDE on every page (<44) ──
   CORRECTED 2026-07-16b: the pass above (this same file, same day) tried a centered
   absolutely-positioned `::after` "hit-expander" here — that never rendered as a fix because an
   out-of-flow absolutely-positioned pseudo-element contributes NOTHING to its host anchor's own
   layout box. Live QA re-measured `getBoundingClientRect()` on the real anchors
   (`#nm-menu-search-btn`/`#nm-menu-cart-btn`/`.nm-mobile-menu-button`) and found them still exactly
   the Savoy-cascade box — ~32px wide, no pseudo-expander effect visible at all, because that box
   never grew. Fixing it for real requires growing the anchor's OWN border-box, not painting an
   invisible sibling over it — the same min-width+flex technique this file already uses successfully
   a few rules down for `.nm-footer-bar-social a` (real 44x44, verified) and `.nm-shop-loop-actions >
   a` below, neither of which ever needed a hit-expander.

   Root cause (unchanged): style.css's shared `.nm-menu li a` rule — specificity (0,1,2): 1 class +
   2 types — sets `padding:16px` on every header icon anchor; two later media queries on the SAME
   selector/specificity trim `padding-left` to 2px (<=991px, style.css:1507) then 0px (<=550px,
   style.css:1532), padding-right untouched at 16px throughout. Icon glyph (~16-18px) + ~0-2px left +
   16px right padding = the measured ~32-34px WIDE box (height untouched, stays ~50px via the
   unchanged top/bottom padding — matches the finding calling out WIDTH only). The hamburger
   specifically is ALSO governed by the more specific `.nm-menu li.nm-menu-offscreen a` (style.css:
   1405, specificity (0,2,2): 2 classes + 2 types — `display:inline-block; font-size:0;
   line-height:16px`, padding still inherited from the lower-specificity rule above since this one
   doesn't redeclare it).

   Specificity math for THIS fix (must beat (0,2,2), the highest of the two rules above, on every
   property we redeclare — display/box-sizing/min-width/align-items/justify-content):
     `#nm-menu-search-btn` / `#nm-menu-cart-btn` — plain ID selectors, specificity (1,0,0). An ID
       component always outranks any number of classes/types (CSS compares specificity tuples
       left-to-right: 1 > 0 in the first slot ends the comparison immediately) — wins outright,
       independent of stylesheet load order.
     `.nm-mobile-menu-button` alone is only a class selector, (0,1,0) — LOWER than even the base
       (0,1,2) rule, let alone the offscreen-specific (0,2,2) one; this bare-class shape is exactly
       what would lose the cascade fight regardless of source order. Scoping it to the real `id` its
       `<ul>` ancestor already carries in the DOM (`<ul id="nm-main-menu-ul">`, Header.tsx) —
       `#nm-main-menu-ul .nm-mobile-menu-button` — makes it (1,1,0): the ID component alone (1 > 0)
       outranks (0,2,2) outright, same unconditional win as the two ID selectors above. None of the
       three rely on savoy-custom.css's last-loaded position in SAVOY_CSS_FILES to win a tie.
   `box-sizing:border-box` (Savoy never sets box-sizing on `.nm-menu li a` or its offscreen variant,
   so this is uncontested on any selector) is what keeps `min-width:44px` from adding ON TOP of the
   existing 16-18px of padding — with it, 44px is the anchor's real total rendered width, padding
   included, so at <=550px the box grows only the ~10-12px it actually needs (34px measured -> 44px)
   instead of ballooning to ~60px; at desktop (>991px, full 16px padding both sides) the box is
   already >=44px and doesn't move at all. `display:inline-flex; align-items:center;
   justify-content:center` centers the icon glyph (and, for the cart, its count badge — laid out
   inline exactly as it was under inline-block, just now centered as a group) inside the wider box,
   instead of leaving it flush against whichever side still has 0 padding-left. */
#nm-menu-search-btn,
#nm-menu-cart-btn,
#nm-main-menu-ul .nm-mobile-menu-button {
  box-sizing: border-box;
  min-width: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* ── PDP price contrast: gold-ink measures 4.03:1 on the #eeeeee single-product summary panel ──
   C2 above (this same file) already swapped shop.css's raw `#dc9814` (≈2.1:1) for `--sbs-gold-ink`
   on `.product .summary .price .amount` / `.product-summary .price .amount` — a big improvement,
   but --sbs-gold-ink is only calibrated to >=4.5:1 against white/paper (see its own comment in
   theme.css), and the ENTIRE PDP top area (breadcrumb/gallery/summary — where every price node this
   selector matches actually renders: the base `<p class="price">` AND the resolved single-variation
   price, both inside `.summary`, both inside `.nm-single-product-bg`) sits on
   `--nm--single-product-background-color:#eeeeee` (`.has-bg-color .nm-single-product-bg`,
   shop.css:3211) — a grey backdrop --sbs-gold-ink was never checked against. `--sbs-gold-ink-deep`
   (theme.css, one shade darker, same hue) clears the grey panel at ~4.79:1 while staying
   recognisably the same gold accent — keeps the brand feel the plain audit's C2 fix was going for,
   just calibrated to the actual background it renders on. Same selector as C2, later in this same
   file, so it wins the tie by source order alone — no extra specificity or !important needed.
   Contrast math (WCAG relative-luminance formula):
     #9A6B12 (--sbs-gold-ink)      vs #eeeeee → 4.03:1  (fails AA; matches the QA measurement)
     #8B6010 (--sbs-gold-ink-deep) vs #eeeeee → 4.79:1  (passes AA; also 5.55:1 on white, so no
                                                          regression if this token is ever reused
                                                          on a lighter background too) */
.product .summary .price .amount,
.product-summary .price .amount {
  color: var(--sbs-gold-ink-deep);
}

/* ── PDP tab labels ("Description" / "Additional information") ──
   shop.css:4619 `.woocommerce-tabs .tabs li a{color:#aaa}` is what's actually served, but this
   file's OWN ported-customizer block near the top (the long generated selector list) re-declares
   the SAME selector at the SAME specificity (0,2,2) with `color:#a3a3a3` — and being later in this
   file, THAT's the one that wins the tie today (confirmed: 2.52:1 on white matches the QA
   measurement exactly for #a3a3a3, not #aaa's ~2.32:1). M25 above already swapped a batch of these
   #a3a3a3 selectors (breadcrumb/product_meta/post-meta) for --sbs-muted but didn't include the
   tabs — closing that gap here, later in the same file so it wins the tie against both prior
   declarations. Contrast: #a3a3a3 vs white = 2.52:1 (fails) → --sbs-muted #78716C vs white =
   4.80:1 (passes AA). Touch tail (same rule): shop.css gives the tab `<a>` no vertical padding at
   all (font-size:16px, inline-block, no line-height override beyond the inherited body value) —
   measured h27; inline-flex + min-height:44px pads it out without disturbing the `margin:0 14px`
   horizontal rhythm (untouched, inherited from shop.css) or the centered `.tabs{text-align:center}`
   layout. `.tabs li.active a` (shop.css:4626, `.active` class → (0,3,2), strictly more specific)
   is untouched and keeps its own #282828 ink regardless of source order. */
.woocommerce-tabs .tabs li a {
  color: var(--sbs-muted);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
}

/* ── shop-card + PDP-related-products titles ──
   ProductCard's `<h3 class="woocommerce-loop-product__title">` sets `color:inherit` (shop.css:848)
   with no ancestor override until it reaches `body{color:#777777}` — used identically by the shop
   grid AND the PDP "Related products" grid (`<ul class="nm-products products ...">`, same
   ProductCard). `.products .price .amount` (shop.css:873) is already explicit #282828 (near-black,
   nowhere near a contrast problem) — it's specifically the inherited-#777 TITLE that's under AA, the
   same #777-inherited pattern L16 above already fixed for the account-nav rows. Contrast:
   #777777 vs white = 4.48:1 (marginally fails AA for 16px/normal-weight body text, which needs
   4.5) → --sbs-muted #78716C vs white = 4.80:1 (passes, comfortably). */
.woocommerce-loop-product__title {
  color: var(--sbs-muted);
}

/* ── PDP share buttons (Facebook / X / Pinterest) ──
   CORRECTED 2026-07-16b: same root problem as the header icons above — the original pass here used
   a centered absolutely-positioned `::after` "hit-expander" over `.nm-product-share a`, which does
   not enlarge the anchor's own layout box, so live QA's `getBoundingClientRect()` read on the real
   `<a>` elements still measured the un-padded glyph box (~10-18px) with no expander effect visible.
   `.nm-product-share a` (shop.css:4495) is `display:inline-block; font-size:18px; line-height:1;
   margin-right:15px` — no padding at all, so the tap box IS the glyph itself. This time we actually
   grow the anchor's box: `min-width`/`min-height:44px` + flex-centering, per this task's explicit
   sanction to let the share row widen/space out to hit a real 44x44 (the header controls above stay
   layout-neutral via box-sizing:border-box; these three don't have any existing padding to reclaim,
   so growing the box is the only way to reach 44px — `margin-right:15px` is left untouched, so the
   row simply gets wider, it doesn't compress).

   Specificity: `.nm-product-share a` alone is (0,1,1) — a bare same-selector reselection later in
   this file would only WIN BY SOURCE-ORDER TIE (savoy-custom.css loads last), which is correct but
   fragile if SAVOY_CSS_FILES is ever reordered. Scoping to the real DOM ancestor instead —
   `.nm-product-share-wrap .nm-product-share a` (product/[slug]/page.tsx: the share row's own
   wrapper div, class `nm-product-share-wrap`) — is (0,2,1): 2 classes outranks shop.css's 1 class +
   1 type outright ((0,2,1) > (0,1,1) on the class-count slot alone), independent of load order, and
   still only matches the 3 share anchors, not the sibling `.nm-product-wishlist-button-wrap` heart
   button next door. */
.nm-product-share-wrap .nm-product-share a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
}

/* ── shop "Categories" / "Filter" toggles ──
   `.nm-shop-filter-menu li a` (shop.css:1813) is `font-size:18px; line-height:1.4; margin:0 15px`
   with no padding — height computes to ~18*1.4=25px (measured h19, close enough given rendering
   variance). Both toggles already have generous horizontal breathing room (`margin:0 15px` each
   side, unmodified below), so padding the box out vertically (not the hit-expander trick — these
   ARE the visible pill-style labels, same "block toggle" pattern as the tabs above, not tight icon
   clusters) reads as a natural taller touch target, not a size change to route around. */
.nm-shop-filter-menu li a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
}

/* ── archive/shop/related "View piece" (and Add to cart / Enquire) quick actions on mobile-WIDTH
   viewports ──
   H6 above already solves the real-touch-device case via `(hover: none)` — but a phone/narrow
   viewport reached by a MOUSE-pointer test harness (no touch/pointer emulation — exactly how a
   viewport-resize-only headless run reports itself) never matches `(hover: none)`, so
   `.nm-shop-loop-actions > a` stays at its un-padded base size (~21px tall, matching the QA doc's
   archive "View piece" h21) even though the element is visually present (opacity swap only kicks in
   on `:hover`/`:focus-within`, not display). Widening H6's trigger to ALSO include `(max-width:
   768px)` — our established mobile breakpoint elsewhere in this file (M1, H2) — closes that gap for
   any narrow-viewport visitor, touch-capable-and-detected-as-such or not, without touching H6's own
   `(hover: none)` behaviour for real touch devices at any width. */
@media (max-width: 768px) {
  .products.has-action-links .price {
    opacity: 1 !important;
  }
  .nm-shop-loop-actions {
    position: static;
    opacity: 1;
    left: 0;
    top: auto;
    margin-top: 10px;
  }
  .nm-shop-loop-actions > a,
  .nm-shop-loop-actions > button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    min-width: 44px;
    padding-inline: 14px;
  }
}

/* ── footer social icons (WhatsApp / Instagram / Facebook) ──
   Verified already satisfied — no change: `.nm-footer-bar-social a` (M23/M31 above, this same
   file) already carries unconditional `display:inline-flex; align-items:center;
   justify-content:center; min-width:44px; min-height:44px`, at the same (0,1,1) specificity as
   style.css's own `.nm-footer-bar-social a{color:#eee}` and this file's ported-customizer
   redeclaration of the same colour — this file loads last, so the sizing wins regardless. The
   anchor (the actual tap target) is 44x44 in every browser today; the QA doc's "11-22px" reading
   matches `.nm-footer-bar-social i{font-size:18px}` (style.css:6755) instead — the glyph's own ink
   box, which will always read smaller than its padded parent and isn't the interactive element. */

/* ── footer "Staff" link ── */
/* Deliberately still tiny/quiet by design (see its own comment above: "discreet staff-console
   entry point... not a primary nav item") and sits inline inside a running line of copyright text
   (`<p class="nm-footer-bar-custom-text">`), so literal padding would visibly balloon that text
   line — a centered hit-expander grows the tap target invisibly instead, same trick as the header
   icons/share buttons above. */
.nm-footer-staff-link {
  position: relative;
}
.nm-footer-staff-link::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 44px;
  height: 44px;
  transform: translate(-50%, -50%);
}

/* ── footer "First access to new pieces →" newsletter CTA ──
   Sits as a `<button>` in the same `#nm-footer-bar-menu` row as the ordinary `<a>` menu items
   (About/Journal/FAQ/…), but `.nm-footer-bar .menu > li > a` (M23/M31 above) only matches an `>a`
   child — a `<button>` never matched it, so this one control in the row was skipped by that pass
   (measured h16). Same treatment as its `<a>` siblings so the row stays visually uniform. */
.sbs-footer-newsletter-cta {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 4px 0;
}

/* ============================================================================
   Review star-rating INPUT (components/storefront/ReviewForm.tsx) — a genuinely
   accessible + visually-gold 5-star radio group.

   Deliberately a DISTINCT class, `.sbs-review-stars`, and NOT nested under Savoy's
   `#review_form .comment-form-rating .stars` (shop.css:4749-4794): that selector's
   `.stars span { display:block; font-size:0 }` rule (shop.css:4762) catches ANY
   bare <span> wrapper placed inside `.comment-form-rating .stars` and stacks all 5
   radio options into one 28px overflow:hidden box — a sighted user could only ever
   land on "1 star". `.sbs-review-stars` is a class Savoy's shipped CSS never
   targets, so the collision cannot happen by construction.

   Fill trick: ReviewForm emits the 5 <input>/<label> pairs in DOM order 5,4,3,2,1,
   then this file flips them visually back to 1..5 with `flex-direction:row-reverse`
   on the container. That lets a plain `~` (general sibling) selector fill "this
   star and every star before it" straight off `:checked`/`:hover` — no JS paint
   logic needed, React only owns which input is `checked`. `+` (adjacent sibling)
   is used separately for the focus ring, which must land on exactly the ONE label
   paired with the focused input, not every earlier one too.
   ============================================================================ */
.comment-form-rating {
  display: block;
  float: left;
  width: 100%;
  margin: 0 0 16px;
  padding: 0;
}
.sbs-review-rating-fieldset {
  border: 0;
  margin: 0;
  padding: 0;
  min-width: 0;
}
.sbs-review-rating-fieldset legend {
  display: block;
  width: 100%;
  padding: 0 0 3px;
  font-size: 16px;
  color: #282828;
}
.sbs-review-stars {
  display: inline-flex;
  flex-direction: row-reverse;
  justify-content: flex-end;
  gap: 2px;
}

/* Visually hidden but still focusable/checkable via keyboard — the same clip
   technique as `.nm-visually-hidden` above (this file, line 170), NOT
   display:none, which would pull the input out of the tab order entirely. */
.sbs-review-stars input[type="radio"] {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.sbs-review-stars label {
  position: relative;
  display: inline-block;
  width: 24px;
  height: 24px;
  line-height: 24px;
  text-align: center;
  cursor: pointer;
  color: var(--sbs-border, #E7E5E4);
}
.sbs-review-stars label:before {
  /* Same glyph as Savoy's own read-only `.star-rating span:before` (shop.css:5780-5786). */
  content: "\e606";
  font-family: "nm-font";
  font-size: 22px;
  font-style: normal;
  font-weight: normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Gold fill: the checked star + every star before it. Uses the same token as the
   existing read-only `.star-rating` display (shop.css:5784) so this input matches
   the approved-review list rendered right above it on the same page; a broader
   non-text-contrast pass on that token is a separate, pre-existing concern (see
   the C2 note above on `.product .summary .price .amount`) and out of scope here. */
.sbs-review-stars input:checked ~ label {
  color: var(--nm--shop-rating-color, var(--sbs-gold-ink, #9A6B12));
}

/* Hover preview — gated on .no-touch (SavoyChrome.tsx) so a tap doesn't leave a
   stuck hover fill on touch devices, matching this file's existing convention
   (e.g. `.no-touch .nm-shop-loop-actions > a:hover` above). */
.no-touch .sbs-review-stars label:hover,
.no-touch .sbs-review-stars label:hover ~ label {
  color: var(--nm--shop-rating-color, var(--sbs-gold-ink, #9A6B12));
}

/* Keyboard focus ring on the paired label — the input itself is visually hidden
   (clipped to 1px), so the app-wide `input:focus-visible` rule above (C1) would
   draw an invisible ring on it; redirect the ring to the ONE label immediately
   after the focused input (`+`, not `~`, so only that star gets the ring). */
.sbs-review-stars input:focus-visible + label {
  outline: 2px solid var(--color-ring);
  outline-offset: 2px;
}

/* Account order-history rows: a small piece thumbnail + a few specs beside the name.
   Thumb is contain-on-white to match the square catalogue photos (see the shop-card + tile fix). */
.sbs-order-item{display:flex;align-items:center;gap:14px;}
.sbs-order-item-thumb{width:64px;height:64px;object-fit:contain;background:#fff;border:1px solid #eee;flex:0 0 auto;}
.sbs-order-item-thumb--empty{display:inline-block;background:#f5f5f4;}
.sbs-order-item-text{display:flex;flex-direction:column;gap:3px;min-width:0;}
.sbs-order-item-specs{font-size:12px;color:#78716C;letter-spacing:.2px;}

/* Journal post media layouts. Portrait (vertical) media sits BESIDE the text in a 2-col split
   (stacks on mobile); landscape media + images sit in a full-width band ABOVE the text. */
.sbs-journal-split{display:flex;gap:40px;max-width:1080px;margin:30px auto 0;align-items:flex-start;}
.sbs-journal-split-media{flex:0 0 42%;max-width:42%;}
.sbs-journal-split-body{flex:1 1 auto;min-width:0;}
.sbs-journal-band{max-width:960px;margin:26px auto 36px;}
.sbs-journal-body-narrow{max-width:760px;margin:0 auto;}
.sbs-journal-media{display:block;width:100%;height:auto;background:#eee;}
@media all and (max-width:768px){
  .sbs-journal-split{flex-direction:column;gap:24px;}
  .sbs-journal-split-media{flex-basis:auto;max-width:100%;width:100%;}
}
