/*
 * Satoshi — the real brand typeface, self-hosted (redistribution rights
 * for web use confirmed directly by the site owner before bundling —
 * CLAUDE.md's "use a system-font fallback until confirmed" boundary no
 * longer applies as of that confirmation). Only the three weights this
 * theme's own CSS actually requests are bundled (Regular/Medium/Bold —
 * grepped every font-weight declaration site-wide first, not guessed):
 * body copy uses weight 500 (Medium), headings/buttons use 600, which
 * has no exact Satoshi face and — per the CSS font-matching spec, which
 * searches upward first for targets above 500 — resolves to the nearest
 * one actually shipped here, Bold (700). Shipping only 3 of the type
 * family's 10 weights (raw .otf, ~50KB each — no WOFF2 encoder available
 * in this environment to shrink them further, flagged as a real,
 * disclosed gap, not a silent one) keeps this from becoming the
 * heaviest thing on the page. font-display:swap so real content is
 * never invisible while these load; the system-font stack stays as the
 * fallback chain, not removed.
 */
@font-face{font-family:"Satoshi";src:url("../fonts/Satoshi-Regular.otf") format("opentype");font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:"Satoshi";src:url("../fonts/Satoshi-Medium.otf") format("opentype");font-weight:500;font-style:normal;font-display:swap}
@font-face{font-family:"Satoshi";src:url("../fonts/Satoshi-Bold.otf") format("opentype");font-weight:700;font-style:normal;font-display:swap}

/* --psg-secondary: confirmed via the Elementor kit's global "Sekundær" system color (post 51, _elementor_page_settings) — #7FA287, same value as --psg-leaf. */
/* Design-system tokens (Phase 0). Brand colors are the real, confirmed Elementor-kit values above — everything below builds on them, none are new brand decisions. */
:root{
	--psg-ink:#242424;--psg-copy:#767676;--psg-forest:#3f7a5c;--psg-forest-dark:#2f5f47;--psg-leaf:#7fa287;--psg-sand:#eef1ef;--psg-paper:#fff;--psg-page:#f5f7f8;--psg-line:#dfe4df;--psg-secondary:var(--psg-leaf);
	--psg-error:#b3261e;--psg-success:var(--psg-forest);
	--psg-radius-sm:6px;--psg-radius:10px;--psg-radius-lg:18px;--psg-pill:35px;--psg-shell:1320px;
	--psg-shadow-sm:0 2px 10px rgba(20,35,26,.06);--psg-shadow:0 10px 30px rgba(20,35,26,.08);--psg-shadow-lg:0 24px 60px rgba(20,35,26,.14);
	--psg-space-1:.25rem;--psg-space-2:.5rem;--psg-space-3:.75rem;--psg-space-4:1rem;--psg-space-5:1.5rem;--psg-space-6:2rem;--psg-space-7:3rem;--psg-space-8:4.5rem;
	--psg-font:"Satoshi",-apple-system,BlinkMacSystemFont,"Segoe UI",Arial,sans-serif;
	--psg-ease:cubic-bezier(.4,0,.2,1);
}
*{box-sizing:border-box}html{scroll-behavior:smooth}
/*
 * Round 166 — direct report: rapid taps anywhere (explicitly called out:
 * spamming a product's quantity +/- stepper) make the page zoom in. Real
 * cause: mobile browsers' native "double-tap to zoom" gesture, which
 * fires whenever two taps land close together in time and position —
 * exactly what a fast-repeated tap on a small stepper button is. `touch-
 * action` isn't inherited (confirmed against spec: initial `auto`,
 * `Inherited: no`), so this has to sit on the universal selector, same
 * as `box-sizing` just above, not just `html`/`body`, to reach every
 * element reliably. `manipulation` is the correct value for "kill this
 * gesture, keep everything else": per spec it still allows panning AND
 * pinch-zoom, only removing double-tap-zoom and the ~300ms click-delay
 * browsers otherwise wait to see if a second tap is coming — this is
 * NOT the accessibility-harmful `user-scalable=no`/`maximum-scale=1`
 * viewport-meta approach (which disables pinch-zoom entirely and was
 * deliberately never used on this site, header.php's own viewport tag is
 * untouched) — pinch-to-zoom keeps working everywhere.
 */
*{touch-action:manipulation}
/*
 * Universal overflow guard, added after several real mobile-overflow
 * reports (a checkout field label was one specific cause, fixed at the
 * source in checkout.css, but this class of bug — some element ending
 * up wider than the viewport and forcing the whole page to scroll
 * horizontally — has shown up in more than one place). overflow-x:hidden
 * on body is the actual backstop: it clips any descendant that would
 * otherwise force horizontal scroll, regardless of which element or page
 * is responsible, without needing to find and fix every individual cause
 * first. Deliberately only on body, not html: html is the true root
 * scrolling element in most browsers, and position:sticky (used by the
 * checkout order-summary card) stops working correctly for any
 * descendant of an ancestor whose overflow is anything but visible on
 * both axes — body{overflow-x:hidden} is a widely-used pattern that
 * doesn't trigger that in practice, since body doesn't become a distinct
 * scroll container from the page's own scrolling; setting it on html too
 * would carry more of that risk for no real benefit. overflow-wrap on
 * body catches long unbroken text (a long word, a URL, a long option
 * label) doing the same thing. img's own max-width:100% is extended to
 * the other common wide-media elements that can overflow the same way.
 */
/*
 * overflow-x is declared TWICE on purpose, and the second one is the fix for a
 * bug that took two rounds to understand.
 *
 * `overflow-x:hidden` makes an element a scroll container on BOTH axes — the
 * other axis resolves from `visible` to `auto`. A body that is a scroll
 * container is not propagated to the viewport, so on mobile the page scrolled
 * inside the body box rather than the viewport, and every
 * `body.<state>{overflow:hidden}` lock in this theme governed a box that was
 * not the one scrolling. Working around that by locking the root instead
 * (`html{overflow:hidden}`) stopped the scrolling but changed which element
 * scrolls while an overlay was open, which is what broke the search sheet
 * against the sticky header.
 *
 * `overflow-x:clip` clips without creating a scroll container, so overflow-y
 * stays `visible`, the body propagates to the viewport as normal, and
 * `overflow:hidden` on the body then locks the viewport the ordinary way —
 * same scroller, same offset, nothing moves. The `hidden` line above it is the
 * fallback for browsers without `clip` (pre-16 Safari), which get exactly the
 * behaviour they had before.
 */
body{margin:0;overflow-x:hidden;overflow-x:clip;overflow-wrap:break-word;color:var(--psg-copy);background:var(--psg-page);font:500 16px/1.6 var(--psg-font)}
body.psg-drawer-open{overflow:hidden}
img,svg,video,iframe,table{max-width:100%}
img{height:auto}
a{color:var(--psg-forest);text-underline-offset:.18em}a:hover{color:var(--psg-forest-dark)}
/*
 * Full-width shell with edge padding only — no max-width cap. Previously
 * capped at var(--psg-shell) (1320px, before that 1660px), which read as
 * a narrow boxed layout on any monitor wider than that instead of a
 * genuinely full-width site. --psg-shell itself is kept (still used as
 * a max-width for the rarely-rendered wc-block-cart/checkout markup in
 * woocommerce.css) but no longer constrains .psg-shell itself.
 */
.psg-shell{width:calc(100% - 3rem);margin-inline:auto}
.site-main{min-height:50vh}.psg-content{padding-block:clamp(2rem,5vw,5rem)}.screen-reader-text{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.screen-reader-text:focus{position:fixed!important;top:1rem;left:1rem;width:auto;height:auto;padding:.75rem 1rem;background:#fff;color:#000;clip:auto;z-index:100000}:focus-visible{outline:3px solid var(--psg-leaf);outline-offset:3px;border-radius:2px}
/*
 * Round 166 — direct report: clicking/tapping certain icons leaves the
 * green focus ring showing and it never goes away; it should never
 * appear at all for a pointer interaction (fields being typed into keep
 * their own indicator, which is a different mechanism entirely — see
 * base.css's own `.woocommerce input.input-text:focus` rule further
 * down: that one already sets `outline:none` and shows state via
 * background/border-color/box-shadow instead, so it is untouched by
 * anything here).
 *
 * `:focus-visible` (the rule directly above) is SUPPOSED to handle this
 * on its own — browsers are meant to match it only for keyboard focus,
 * never for a mouse/touch activation. In practice that heuristic is a
 * real, well-known cross-browser inconsistency, not a bug in this site's
 * markup: WebKit in particular has long matched `:focus-visible` on a
 * plain tap of a real `<button>`, which is exactly what these icons are
 * (header cart/account openers, carousel arrows, the qty stepper, tab
 * triggers — all real `<button>` elements). Rather than depend on every
 * browser's heuristic agreeing, `interactions.js` tracks the actual
 * input modality (pointerdown → pointer, Tab/arrow keydown → keyboard)
 * and toggles `.psg-pointer-input` on `<html>`; this rule then hard-
 * suppresses the ring for pointer interactions only. Keyboard focus is
 * completely unaffected — the class is removed the moment a real
 * navigation key is pressed, so `:focus-visible` above keeps working
 * exactly as before for keyboard users, which is the whole reason that
 * ring exists.
 *
 * Scoped `:not()` on real text-entry controls as a second, explicit
 * layer of safety so this can never strip a typing indicator even if a
 * future rule elsewhere starts using `outline` for one.
 */
html.psg-pointer-input :focus:not(input):not(textarea):not(select):not([contenteditable]){outline:none!important}

/* Type scale — fluid clamp() headings, one consistent rhythm reused everywhere instead of per-section overrides. */
h1,h2,h3,h4,h5,h6{color:var(--psg-ink);font-weight:600;line-height:1.15;text-wrap:balance;margin:0 0 var(--psg-space-4)}
h1{font-size:clamp(2.25rem,1.7rem + 2.4vw,3.5rem)}
h2{font-size:clamp(1.75rem,1.4rem + 1.6vw,2.5rem)}
h3{font-size:clamp(1.375rem,1.2rem + .8vw,1.75rem)}
h4{font-size:clamp(1.125rem,1.05rem + .35vw,1.25rem)}
/* Utility/commerce page titles ("Kasse", "Handlekurv", "Min konto", "Om oss" — page.php's entry-header, reused across every plain WP page) were using the full marketing-headline h1 scale (up to 3.5rem), taking up far too much vertical space for a simple page title. Reuses the existing h2 step instead of inventing a new size. */
.entry-header h1{font-size:clamp(1.75rem,1.4rem + 1.6vw,2.5rem)}
p{margin:0 0 var(--psg-space-4)}
.psg-eyebrow{display:inline-block;font-size:.8125rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--psg-forest);margin:0 0 var(--psg-space-2)}
.psg-lede{font-size:clamp(1.0625rem,1rem + .3vw,1.25rem);color:var(--psg-copy);max-width:62ch}

/* Section rhythm — consistent vertical spacing wrapper for original (non-Elementor) content blocks. */
.psg-section{padding-block:clamp(var(--psg-space-7),6vw,var(--psg-space-8))}
.psg-section--tight{padding-block:clamp(var(--psg-space-6),4vw,var(--psg-space-7))}
.psg-section__head{margin-bottom:var(--psg-space-6);max-width:62ch}

/* Card surface — reused by product cards, filter panel, cart drawer, etc. */
.psg-card{background:var(--psg-paper);border:1px solid var(--psg-line);border-radius:var(--psg-radius);box-shadow:var(--psg-shadow-sm);transition:box-shadow .2s var(--psg-ease),transform .2s var(--psg-ease)}
.psg-card--interactive:hover{box-shadow:var(--psg-shadow);transform:translateY(-2px)}

/* Button system — .psg-button stays the default/primary look used everywhere already; modifiers add variants without touching existing markup. */
.psg-button,.woocommerce a.button,.woocommerce button.button,.woocommerce input.button{display:inline-flex;align-items:center;justify-content:center;gap:.5em;min-height:44px;padding:.7rem 1.5rem;border:1px solid transparent;border-radius:var(--psg-pill);background:var(--psg-forest);color:#fff;text-decoration:none;font-weight:700;font-size:.9375rem;cursor:pointer;transition:background-color .2s var(--psg-ease),border-color .2s var(--psg-ease),color .2s var(--psg-ease),transform .06s var(--psg-ease)}
.psg-button:hover,.woocommerce a.button:hover,.woocommerce button.button:hover,.woocommerce input.button:hover{background:var(--psg-forest-dark);color:#fff}
/* Round 213: press feedback must land the same frame the finger does — the
 * .15s transform transition made every press read as lag, not response.
 * .06s down is effectively instant while still avoiding a hard snap; the
 * release keeps the same short curve. Steppers and icon buttons get the
 * same physics: they were the controls called out as feeling slow. */
.psg-button:active,.woocommerce a.button:active,.woocommerce button.button:active{transform:scale(.97)}
.psg-qty-stepper__btn{transition:background-color .15s var(--psg-ease),transform .06s var(--psg-ease)}
.psg-qty-stepper__btn:active{transform:scale(.88)}
.header-cart:active .psg-icon,.header-account:active .psg-icon,.psg-drawer__close:active,.psg-cart-drawer__item-remove:active{transform:scale(.88)}
.header-cart .psg-icon,.header-account .psg-icon,.psg-drawer__close,.psg-cart-drawer__item-remove{transition:transform .06s var(--psg-ease)}
.psg-button--ghost{background:transparent;border-color:var(--psg-ink);color:var(--psg-ink)}
.psg-button--ghost:hover{background:var(--psg-ink);border-color:var(--psg-ink);color:#fff}
.psg-button--subtle{background:var(--psg-sand);color:var(--psg-ink)}
.psg-button--subtle:hover{background:var(--psg-line);color:var(--psg-ink)}
.psg-button--sm{min-height:38px;padding:.5rem 1.1rem;font-size:.875rem}
.psg-button--white{background:#fff;color:var(--psg-forest)}
.psg-button--white:hover{background:var(--psg-sand);color:var(--psg-forest)}
/* Subtle ambient glow — for a white CTA sitting on a dark photo background (the hero), not a general-purpose modifier. No animation/pulse: "subtle" was explicit, a static soft shadow reads as a glow without drawing attention away from the button's own text. */
.psg-button--glow{box-shadow:0 0 24px rgba(255,255,255,.4),0 0 6px rgba(255,255,255,.3)}
.psg-button--glow:hover{box-shadow:0 0 32px rgba(255,255,255,.55),0 0 10px rgba(255,255,255,.4)}
.psg-button:disabled,.woocommerce a.button.disabled,.woocommerce button.button:disabled{opacity:.5;cursor:not-allowed;pointer-events:none}

/*
 * Shared field styling — universal rollout of the floating-label design
 * originally designed and tested on checkout only (assets/css/
 * checkout.css, rounds 43-52: square-rounded corners, a soft grey outline
 * instead of a border that only colors in on focus, sand fill turning
 * white on focus, and the field's own name sitting inside it as a real
 * floating label instead of on a separate line above). Confirmed good on
 * checkout, now the one field design for the whole site: login/register
 * (including B2BKing's own `.b2bking_custom_registration_field` register
 * fields), every My Account page (edit account, addresses, payment
 * methods), checkout, and anywhere else a real WooCommerce field renders.
 * Entirely replaces this rule's own previous design (round 41's fully-
 * rounded pill field) — that design is retired, not kept as an option.
 * The floating-label sync itself (the one thing this CSS can't determine
 * on its own — whether a field already has a real value while it isn't
 * focused) is assets/js/field-labels.js, the site-wide generalization of
 * checkout-fields.js's own original syncFloatingLabel()/
 * syncAllFloatingLabels().
 *
 * Two layers, on purpose. (1) Baseline chrome — fill/border/radius/focus
 * ring — applies to every real input/select/textarea/select2 box under
 * `.woocommerce`, `.form-row`-wrapped or not: this also reaches
 * WooCommerce's own product-review comment box (`.woocommerce textarea`,
 * confirmed via direct template read that it's WordPress core's own
 * comment_form(), not WC's `.form-row` convention at all), so it keeps
 * real chrome instead of losing all styling now that the old pill rule is
 * gone. (2) The floating-label mechanic itself — the label living inside
 * the field, the typing/settled/filled states — only applies where a real
 * `.form-row` wraps a label+field WooCommerce's own markup can be read
 * from via `:has()`; anything outside that convention (the review box)
 * keeps an ordinary resting label instead of attempting to float one that
 * isn't there.
 *
 * `.psg-field`/`.psg-input` (comments.php's own theme-native comment
 * form, not a WooCommerce field) intentionally kept on the old, simpler
 * pill look below — never a WooCommerce form field, out of scope for
 * "every field on the website" as this generalizes from a checkout- and
 * account-specific request.
 */
.psg-field label{display:block;font-size:.875rem;font-weight:600;color:var(--psg-ink);margin-bottom:.4rem}
input[type=text].psg-input,input[type=email].psg-input,input[type=tel].psg-input,input[type=number].psg-input,input[type=search].psg-input,select.psg-input,textarea.psg-input{width:100%;min-height:46px;padding:.7rem 1.35rem;border:1px solid transparent;border-radius:var(--psg-pill);background:var(--psg-sand);color:var(--psg-ink);font:inherit;transition:background-color .2s var(--psg-ease),border-color .2s var(--psg-ease),box-shadow .2s var(--psg-ease)}
input.psg-input:focus,select.psg-input:focus,textarea.psg-input:focus{background:#fff;border-color:var(--psg-forest);outline:none;box-shadow:0 0 0 3px rgba(63,122,92,.15)}

/* --- Layer 1: baseline chrome, every real WooCommerce field, .form-row or not --- */
.woocommerce input.input-text,.woocommerce select,.woocommerce textarea,.woocommerce .select2-selection,.woocommerce input.b2bking_custom_registration_field{width:100%;min-height:52px;padding:.9rem 1.1rem!important;border-width:1px;border-style:solid;border-color:var(--psg-line)!important;border-radius:var(--psg-radius)!important;background-color:var(--psg-sand)!important;color:var(--psg-ink);font:inherit;line-height:1.6!important;transition:border-color .2s var(--psg-ease),background-color .2s var(--psg-ease),padding .2s var(--psg-ease)}
/*
 * Every property above carrying `!important` is a real fix, not a
 * stylistic habit copied from checkout — confirmed there (round 46) via
 * a live injected-stylesheet test that WooCommerce core's own same-value
 * defaults beat even higher-specificity author rules without it, in this
 * exact WooCommerce/WP.com asset-loading setup. Kept here for the same
 * reason, now that this rule reaches every WC field core ships defaults
 * for, not just checkout's.
 */
.woocommerce input.input-text:focus,.woocommerce select:focus,.woocommerce textarea:focus,.woocommerce input.b2bking_custom_registration_field:focus{background-color:#fff!important;border-color:var(--psg-forest)!important;outline:none;box-shadow:0 0 0 3px rgba(63,122,92,.12)}
.woocommerce select{appearance:none;-webkit-appearance:none;-moz-appearance:none;padding-right:2.75rem!important;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23767676' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 1.1rem center;background-size:14px}
.woocommerce .select2-container .select2-selection{min-height:52px;padding:1.35rem 1.1rem .45rem!important;border:1px solid var(--psg-line)!important;border-radius:var(--psg-radius)!important;background:var(--psg-sand)!important;display:flex;align-items:flex-end}
.woocommerce .select2-selection__rendered{position:static!important;padding:0!important;line-height:1.4!important;color:var(--psg-ink)!important}
.woocommerce .select2-selection__arrow{height:52px!important}

/* --- Layer 2: floating label, only where a real .form-row wraps label+field. `:not(.psg-desired-timing)` excludes checkout's own pill-toggle radio group (a different kind of control entirely, not a labeled text field) — harmless everywhere else since that class only ever exists on checkout. --- */
.woocommerce form .form-row:not(.psg-desired-timing):has(input.input-text,select,input.b2bking_custom_registration_field){position:relative}
/*
 * Real, confirmed bug fixed here, sitewide: every `input[type=password]`
 * on the site (login, register, Edit Account, lost/reset password — a
 * real WooCommerce core JS enhancement, not this theme's own markup,
 * confirmed live: the server-rendered template never has it, but a
 * `<span class="password-input">` wrapper appears around the real
 * `<input>` after page load regardless of which template rendered it)
 * comes AFTER this label in DOM order and — despite having no visible
 * background of its own — establishes its own `position:relative`
 * stacking context. Per the CSS2.1 painting-order rules, a later
 * positioned sibling paints ABOVE an earlier one at the same (auto)
 * z-index regardless of DOM order otherwise, so that wrapper (and the
 * real input's own opaque sand-fill background inside it) was painting
 * directly over this absolutely-positioned label — it was never actually
 * invisible, just fully covered. `z-index:1` is enough since both are
 * direct children of the same `position:relative` `.form-row`, no higher
 * stacking context in between to fight.
 */
.woocommerce form .form-row:not(.psg-desired-timing):has(input.input-text,select,input.b2bking_custom_registration_field) label{position:absolute;z-index:1;left:1.1rem;top:50%;transform:translateY(-50%);margin:0;max-width:calc(100% - 2.2rem);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.9375rem;font-weight:400;color:var(--psg-copy);opacity:1;pointer-events:none;transition:top .15s var(--psg-ease),font-size .15s var(--psg-ease),transform .15s var(--psg-ease),opacity .15s var(--psg-ease)}
.woocommerce form .form-row:not(.psg-desired-timing).psg-field-filled:not(:focus-within) input.input-text,
.woocommerce form .form-row:not(.psg-desired-timing).psg-field-filled:not(:focus-within) input.b2bking_custom_registration_field,
.woocommerce form .form-row:not(.psg-desired-timing):has(select):has(label) select{padding:1.35rem 1.1rem .45rem!important}
/*
 * Real, confirmed bug: B2BKing's "Land og stat" register field nests a
 * `<p class="form-row">` *inside* another `<p class="form-row">` in its
 * own raw markup — invalid (a `<p>` can't legally contain block content),
 * so the browser's own HTML parser implicitly closes the outer `<p>` the
 * moment it hits the inner one, confirmed live: the real parsed DOM ends
 * up as two SIBLINGS, not nested. The inner one holds the real `<select>`
 * but no `<label>` of its own (the real label lives only in the now-
 * separate outer `<p>`) — it still matched the settled-padding rule above
 * via plain `:has(select)`, reserving room for a floated caption that
 * will never actually render there, which pushed the select's own value
 * text off-center (measured live: `21.6px`/`7.2px` top/bottom instead of
 * centered). Scoped the rule above to `:has(select):has(label)` and give
 * this genuinely label-less case the same centered padding a resting
 * text input uses instead.
 */
.woocommerce form .form-row:not(.psg-desired-timing):has(select):not(:has(label)) select{padding:.9rem 1.1rem!important}
/*
 * Round 148 — direct report (checkout, mobile): the floated label and
 * the typed text below it read as cramped against each other. This
 * label had no `line-height` of its own, inheriting `body`'s sitewide
 * 1.6 — at `.6875rem` (11px) that's a 17.6px line-box the label doesn't
 * need (real glyph ink at this size is much shorter), eating into the
 * gap before the input's own text starts below it for free, with no
 * benefit to legibility. Tightened to 1.2 (13.2px) — shared here rather
 * than duplicated per-breakpoint since it helps make room on desktop's
 * own taller box too, not just mobile's newly-shortened one.
 */
.woocommerce form .form-row:not(.psg-desired-timing).psg-field-filled:not(:focus-within) label,
.woocommerce form .form-row:not(.psg-desired-timing):has(select) label{top:.6rem!important;transform:translateY(0)!important;font-size:.6875rem!important;font-weight:500!important;line-height:1.2!important;color:var(--psg-copy)!important}
/* Selects excluded on purpose — choosing an option isn't "typing", so a select's label stays floated even while focused; only real text-input focus hides the label entirely. */
.woocommerce form .form-row:not(.psg-desired-timing):has(input.input-text,input.b2bking_custom_registration_field):focus-within label{opacity:0!important}
/*
 * Real, confirmed gap: browser password-manager autofill (Chrome filling
 * a saved credential into `password_current` etc. on the Edit Account
 * page, confirmed live) never dispatches a real `input` event — field-
 * labels.js's own `.psg-field-filled` sync never runs, so the label stays
 * in its resting, vertically-centered position, directly behind the
 * filled value's own opaque background (the exact overlap bug this whole
 * mechanism exists to prevent). This empty, no-visual-effect animation is
 * the standard, well-known way to detect WebKit/Blink autofill with no
 * `input` event involved at all — Chrome/Edge/Safari apply it to any
 * autofilled field, and field-labels.js listens for the resulting
 * `animationstart` event to force a real sync at that exact moment.
 */
@keyframes psgAutofill{from{opacity:1}to{opacity:1}}
.woocommerce input.input-text:-webkit-autofill,.woocommerce input.b2bking_custom_registration_field:-webkit-autofill{animation-name:psgAutofill}
/*
 * Round 160 — real, confirmed sitewide gap found while investigating a
 * "field goes yellow after autofill" report on the new custom Card fields
 * (checkout-card-custom.js's own ghost `input.input-text`, a real, same-
 * origin element — genuinely fixable, unlike Stripe's own cross-origin
 * iframe content). The rule above only ever hooked autofill for JS
 * DETECTION (an empty animation, no visual effect of its own) — nothing
 * on this SITE has ever actually overridden the browser's own native
 * `:-webkit-autofill` yellow/cream background, on ANY real field, not
 * just Card's. The standard, well-known override: an absurdly large inset
 * `box-shadow` in this design's own real resting background paints OVER
 * the native yellow (plain `background-color` cannot beat `:-webkit-
 * autofill`'s own internal styling, confirmed a real browser limitation,
 * not a specificity issue), `-webkit-text-fill-color` keeps the typed
 * text itself the real ink color instead of the browser's own autofill
 * text color, and the absurdly long `transition` delays the browser's own
 * autofill-yellow paint long enough that the override above is already
 * in place before it would ever show.
 */
.woocommerce input.input-text:-webkit-autofill,.woocommerce input.b2bking_custom_registration_field:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px var(--psg-sand) inset!important;box-shadow:0 0 0 1000px var(--psg-sand) inset!important;-webkit-text-fill-color:var(--psg-ink)!important;caret-color:var(--psg-ink);transition:background-color 5000s ease-in-out 0s}

/* Textarea variant — label fixed top-left (a tall box centering a floated caption looks wrong the moment typing starts on the first line), no .psg-field-filled/JS needed: a plain WC/WP field never forces placeholder="", so its own real placeholder keeps :placeholder-shown reliable here. */
.woocommerce form .form-row:not(.psg-desired-timing):has(textarea){position:relative}
.woocommerce form .form-row:not(.psg-desired-timing) textarea{padding:1.75rem 1.1rem .85rem!important;line-height:1.5}
.woocommerce form .form-row:not(.psg-desired-timing) textarea::placeholder{color:transparent}
.woocommerce form .form-row:not(.psg-desired-timing):has(textarea) label{position:absolute;left:1.1rem;top:.95rem;margin:0;max-width:calc(100% - 2.2rem);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.9375rem;font-weight:400;color:var(--psg-copy);opacity:1;pointer-events:none;transition:top .15s var(--psg-ease),font-size .15s var(--psg-ease),opacity .15s var(--psg-ease)}
.woocommerce form .form-row:not(.psg-desired-timing):has(textarea:not(:placeholder-shown)):not(:focus-within) label{top:.6rem!important;font-size:.6875rem!important;font-weight:500!important;color:var(--psg-copy)!important}
.woocommerce form .form-row:not(.psg-desired-timing):has(textarea):focus-within label{opacity:0!important}
input[type=checkbox].psg-check,input[type=radio].psg-check{width:18px;height:18px;accent-color:var(--psg-forest);cursor:pointer}
input[type=range].psg-range{accent-color:var(--psg-forest)}
