/* ============================================================================
   StudioPlus PublicWeb — shared public design language
   Served from _content/StudioPlus.PublicWeb.Shared/css/sp-core.css

   This is the single source of truth for the chrome and controls that every
   public-facing surface shares: the page shell, the hosted header, buttons,
   navigation rows, and web-form fields.

   It exists because these rules used to live only in
   Bookings/wwwroot/css/booking.css. Forms is a SIBLING project — it cannot
   reference Bookings — so the standalone form page at /form/{tenant}/{token}
   shipped emitting class names that no stylesheet anywhere defined, and
   rendered as raw browser defaults (bug 049). Anything that both the booking
   flow and a standalone form need belongs here; anything specific to one flow
   stays in that flow's own stylesheet.

   TWO NAMES FOR THE SAME BOX: rules below are written against a neutral name
   (.sp-shell, .sp-main, .sp-step) and the original booking name
   (.sp-booking-shell, .sp-booking-main, .sp-booking-step) together. The
   booking markup and its tests predate this file and are left untouched; new
   surfaces use the neutral name, because "booking shell" wrapping a contact
   form reads as a bug to the next person in here.

   Every colour resolves through the branding custom properties emitted by
   BrandingCssGenerator, with the same fallbacks the booking flow already
   used, so a tenant's palette lands identically on both surfaces.
   ============================================================================ */

*,
*::before,
*::after {
    box-sizing: border-box;
}

/* ------------------------------------------------- surface-resolved text --- */

/*
 * Bugs 049, 053, 079, 082 and 1001 were all the same fault: a colour painted onto a surface
 * that nothing had measured it against. A CSS rule cannot do that measurement, because it has
 * no way to ask what is behind it - bug 1001's links read the correct brand variable and still
 * came out at 1.52:1 on the studio's own ground.
 *
 * So the measurement moved into BrandingCssGenerator, which knows every surface the studio
 * configured and emits each foreground role already solved against each one:
 * --sp-fg-{role}-on-{surface}. What is left for CSS is the one thing CSS is actually good at -
 * knowing which container you are inside.
 *
 * Every element that PAINTS a ground re-points the role variables to that ground's solved
 * set below. Ordinary inheritance then carries the right value down, and a rule deep inside
 * simply reads var(--sp-fg-muted) without knowing or caring where it ended up. Nesting works:
 * a card inside the page re-points them again for its own subtree.
 *
 * The rule for authors is therefore: paint text with a --sp-fg-* variable, never with a raw
 * brand variable. FixedTintPanelContrastTests enforces exactly that.
 *
 * Fallbacks are the values for the default all-white configuration, so a page still renders
 * legibly if the generated block is missing entirely.
 */

html,
body,
.sp-ground-page {
    --sp-fg-text: var(--sp-fg-text-on-page, #212529);
    --sp-fg-muted: var(--sp-fg-muted-on-page, #4d5761);
    --sp-fg-link: var(--sp-fg-link-on-page, #0a55c0);
    --sp-fg-accent: var(--sp-fg-accent-on-page, #7a4f00);
    --sp-fg-error: var(--sp-fg-error-on-page, #b3261e);
    --sp-fg-warning: var(--sp-fg-warning-on-page, #7a4f00);
    --sp-fg-success: var(--sp-fg-success-on-page, #1d6a2a);
    --sp-fg-edge: var(--sp-fg-edge-on-page, #14477d);
}

/* The shell and the main column paint --sp-form-background, so everything inside them is on
   the form ground rather than the page ground. On the studio in bugs 049 and 1001 those two
   are different colours, which is why the same coral measured 1.52:1 inside the form and
   3.30:1 on the footer outside it. */
.sp-shell,
.sp-booking-shell,
.sp-main,
.sp-booking-main,
.sp-ground-form {
    --sp-fg-text: var(--sp-fg-text-on-form, #212529);
    --sp-fg-muted: var(--sp-fg-muted-on-form, #4d5761);
    --sp-fg-link: var(--sp-fg-link-on-form, #0a55c0);
    --sp-fg-accent: var(--sp-fg-accent-on-form, #7a4f00);
    --sp-fg-error: var(--sp-fg-error-on-form, #b3261e);
    --sp-fg-warning: var(--sp-fg-warning-on-form, #7a4f00);
    --sp-fg-success: var(--sp-fg-success-on-form, #1d6a2a);
    --sp-fg-edge: var(--sp-fg-edge-on-form, #14477d);
}

/* Form controls paint --sp-textbox-bg, which a studio can set independently of the form. */
input,
select,
textarea,
.sp-input,
.sp-ground-input {
    --sp-fg-text: var(--sp-fg-text-on-input, #212529);
    --sp-fg-muted: var(--sp-fg-muted-on-input, #4d5761);
    --sp-fg-link: var(--sp-fg-link-on-input, #0a55c0);
    --sp-fg-accent: var(--sp-fg-accent-on-input, #7a4f00);
    --sp-fg-error: var(--sp-fg-error-on-input, #b3261e);
    --sp-fg-warning: var(--sp-fg-warning-on-input, #7a4f00);
    --sp-fg-success: var(--sp-fg-success-on-input, #1d6a2a);
    --sp-fg-edge: var(--sp-fg-edge-on-input, #14477d);
}

/* The branded header paints --sp-header-bg. Its default is a mid blue, on which only plain
   white clears 4.5:1 - the tinted variants used elsewhere all fall short of it. */
.sp-hosted-header--branded,
.sp-ground-header {
    --sp-fg-text: var(--sp-fg-text-on-header, #ffffff);
    --sp-fg-muted: var(--sp-fg-muted-on-header, #ffffff);
    --sp-fg-link: var(--sp-fg-link-on-header, #ffffff);
    --sp-fg-accent: var(--sp-fg-accent-on-header, #ffffff);
    --sp-fg-error: var(--sp-fg-error-on-header, #ffffff);
    --sp-fg-warning: var(--sp-fg-warning-on-header, #ffffff);
    --sp-fg-success: var(--sp-fg-success-on-header, #ffffff);
    --sp-fg-edge: var(--sp-fg-edge-on-header, #ffffff);
}

/*
 * A panel that paints its own FIXED pale tint is its own ground, and the tenant's solved values
 * are wrong inside it - that is precisely bug 079, where a dark-branded studio's light text
 * landed on a near-white payment card. Such panels re-point the roles to a fixed dark set,
 * which clears its target on every fixed tint used in these stylesheets - 4.89:1 at worst,
 * which is the error red on the palest of the error tints.
 */
.sp-ground-fixed-light {
    --sp-fg-text: #212529;
    --sp-fg-muted: #4d5761;
    --sp-fg-link: #0a55c0;
    --sp-fg-accent: #7a4f00;
    --sp-fg-error: #b3261e;
    --sp-fg-warning: #7a4f00;
    --sp-fg-success: #1d6a2a;
    --sp-fg-edge: #14477d;
}

/* The same idea for a panel whose fixed tint is DARK rather than pale - register.css uses one
   for its field help. The light set above would be invisible on it. */
.sp-ground-fixed-dark {
    --sp-fg-text: #f8f9fa;
    --sp-fg-muted: #d3d8de;
    --sp-fg-link: #9ec5fe;
    --sp-fg-accent: #ffd88a;
    --sp-fg-error: #ffb3ad;
    --sp-fg-warning: #ffd88a;
    --sp-fg-success: #9be3a8;
    --sp-fg-edge: #9ec5fe;
}

html {
    /* Body text uses the tenant's Secondary font ("Body text font" in the
       branding editor, and what the admin live preview renders). */
    font-family: var(--sp-font-family, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif);
    color: var(--sp-fg-text);
    background: var(--sp-page-background, #ffffff);
}

body {
    margin: 0;
    min-height: 100vh;
    background: var(--sp-page-background, #ffffff);
}

/* Embedded: drop the viewport floor. Inside an iframe 100vh resolves to the
   frame's OWN height, so the body box can never measure smaller than the frame
   it is already in. iframe-resize.js measures the body precisely to avoid that
   floor, so leaving this rule on would let the frame grow and never shrink —
   every step after a tall one would render at the top of a band of whitespace
   (bug 032). Standalone keeps the floor so a short step still paints a full
   page of background. */
body.sp-embedded {
    min-height: 0;
}

/* ---------------------------------------------------------------- shell --- */

.sp-shell,
.sp-booking-shell {
    width: 100%;
}

.sp-standalone .sp-shell,
.sp-standalone .sp-booking-shell {
    max-width: 1120px;
    margin: 1.75rem auto;
    overflow: hidden;
    border: 1px solid var(--sp-border-color, #e0e0e0);
    border-radius: 8px;
    background: var(--sp-form-background, var(--sp-surface-color, #ffffff));
    box-shadow: 0 1px 4px rgb(0 0 0 / 10%);
}

/* --------------------------------------------------------- hosted header --- */

.sp-hosted-header {
    background: var(--portal-header-bg, #ffffff);
    color: var(--sp-fg-text);
    border-bottom: 1px solid var(--portal-header-border, #e5e7eb);
}

.sp-hosted-header--minimal {
    border-bottom-color: transparent;
}

.sp-hosted-header--branded {
    background: var(--portal-header-branded-bg, var(--sp-header-bg, #1976d2));
    color: var(--sp-fg-text);
    border-bottom-color: transparent;
}

.sp-hosted-header-content {
    min-height: 72px;
    padding: 0 1.5rem;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1.5rem;
}

.sp-center-align .sp-hosted-header-content {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
}

.sp-hosted-brand {
    min-width: 0;
    display: flex;
    align-items: center;
}

.sp-center-align .sp-hosted-brand {
    grid-column: 2;
    justify-self: center;
}

.sp-hosted-logo {
    display: block;
    max-width: min(220px, 48vw);
    max-height: 40px;
    object-fit: contain;
    background: transparent;
}

.sp-hosted-business-name {
    max-width: min(320px, 52vw);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: currentColor;
    font-family: var(--sp-font-primary, inherit);
    font-size: 1.15rem;
    font-weight: 700;
    line-height: 1.2;
}

.sp-hosted-header-actions {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-space-4, 1rem);
    min-width: 44px;
}

.sp-hosted-utility-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-space-2, 0.5rem);
    min-width: var(--sp-touch-min, 44px);
    min-height: var(--sp-touch-min, 44px);
    max-width: min(14rem, 32vw);
    padding: var(--sp-space-3, 0.75rem) var(--sp-space-2, 0.5rem);
    overflow: hidden;
    color: var(--sp-fg-muted);
    font-size: var(--sp-text-sm, 0.875rem);
    font-weight: 500;
    line-height: 1.25rem;
    text-align: left;
    text-decoration: none;
    text-overflow: ellipsis;
    white-space: nowrap;
    transition: text-decoration-color 0.15s ease;
}

.sp-hosted-utility-icon {
    flex: 0 0 auto;
}

.sp-hosted-utility-link span {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sp-center-align .sp-hosted-header-actions {
    grid-column: 3;
    justify-self: end;
}

.sp-hosted-utility-link:hover,
.sp-hosted-utility-link:focus-visible {
    color: var(--sp-fg-text);
    text-decoration: underline;
    text-underline-offset: 3px;
    text-decoration-thickness: 1px;
}

.sp-hosted-utility-link:focus-visible {
    outline: 0;
    border-radius: 4px;
    box-shadow: var(--sp-shadow-focus, 0 0 0 3px color-mix(in oklch, var(--tenant-text, var(--sp-text, #111827)) 38%, transparent));
}

/* Branded mode paints the header with the tenant's own header colours, which are
   routinely dark. The base rule above colours the utility link from --tenant-text
   — the PAGE body text colour — so on a dark branded header the "Return to
   website" and "My account" links render dark-on-dark and effectively disappear.
   In branded mode they must follow the header's own text colour instead. Same
   class of defect as bug 053 (unreadable prompts on a dark surface); it predates
   this file and applies to the booking flow too, which is why the fix lives here
   rather than in either flow's own stylesheet. */
/* The resting state used to fade the header text to 78% opacity to de-emphasise it, which is a
   contrast reduction with no floor under it - on a mid-toned header that fade is what takes a
   passing colour below AA. --sp-fg-muted keeps the de-emphasis and is solved against the header
   ground, so the quieter colour is still a legible one. */
.sp-hosted-header--branded .sp-hosted-utility-link {
    color: var(--sp-fg-muted);
}

.sp-hosted-header--branded .sp-hosted-utility-link:hover,
.sp-hosted-header--branded .sp-hosted-utility-link:focus-visible {
    color: var(--sp-fg-text);
}

.sp-hosted-header--branded .sp-hosted-utility-link:focus-visible {
    box-shadow: 0 0 0 3px color-mix(in oklch, var(--portal-header-branded-text, var(--sp-header-text, #ffffff)) 38%, transparent);
}

.sp-hosted-header-accent {
    height: 3px;
    background: var(--portal-header-accent, var(--sp-button-color, #1976d2));
}

/* ------------------------------------------------------- main + heading --- */

.sp-main,
.sp-booking-main {
    width: 100%;
    min-height: calc(100vh - 72px);
    padding: 3rem 2.25rem;
    background: var(--sp-form-background, var(--sp-surface-color, #ffffff));
}

.sp-center-align .sp-main,
.sp-center-align .sp-booking-main {
    text-align: var(--sp-content-align, center);
}

.sp-standalone .sp-main,
.sp-standalone .sp-booking-main {
    min-height: auto;
}

/* No viewport floor here either — same reason as body.sp-embedded above, and this
   one is the more dangerous of the two because it is embed-specific and reads as
   deliberate. It was written when the frame was a fixed box and filling it was the
   goal; now that the frame sizes itself to this content, a 100vh floor makes the
   content as tall as the frame it is measuring, so the frame can only ever grow.
   Height comes from the content; the frame follows it. */
.sp-embedded .sp-main,
.sp-embedded .sp-booking-main {
    min-height: 0;
    padding: 1rem;
}

.sp-step,
.sp-booking-step {
    max-width: 960px;
    margin: 0 auto;
}

.sp-step-heading {
    margin: 0 0 1rem;
    color: var(--sp-fg-text);
    font-family: var(--sp-font-primary, inherit);
    font-size: clamp(1.75rem, 4vw, 2.4rem);
    line-height: 1.15;
}

.sp-step-description {
    margin: 0 0 2rem;
    color: var(--sp-fg-muted);
    font-size: clamp(1rem, 2vw, 1.25rem);
    line-height: 1.5;
}

/* ------------------------------------------------------------- buttons --- */

.sp-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    min-width: 44px;
    padding: 0.75rem 2rem;
    border: 1px solid transparent;
    border-radius: 4px;
    font-family: var(--sp-font-family, inherit);
    font-size: 1rem;
    font-weight: 600;
    line-height: 1.2;
    text-align: center;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease, opacity 0.15s ease;
}

/*
 * Bug 049 retest 1. .sp-btn above sets `border: 1px solid transparent`, and this rule only
 * ever set a background taken from the studio's own --sp-button-color. A studio whose brand
 * colour is also the ground the form sits on rendered Submit as bare floating text - same
 * colour as the surface, transparent border, nothing to see until hover changed the
 * background. Finish Later escaped it only because .sp-btn-back carries a border of its own.
 *
 * The first repair mixed the rim from the button's own colour, 82% toward black. MattR
 * measured that at 1.51:1 against a 3:1 requirement and generalised the problem correctly: a
 * brand that is already dark has no headroom left to darken. Measured afterwards across nine
 * plausible brands the mix cleared 3:1 for none of them - it was not that this studio was
 * unlucky, it was that a fixed percentage cannot express a ratio at all.
 *
 * --sp-button-rim is solved in BrandingCssGenerator against the button's OWN fill, so the edge
 * reads whatever is behind the button, including the case where the surface IS the fill. The
 * search darkens where there is room and lightens where there is not.
 */
.sp-btn-primary {
    border-color: var(--sp-button-rim, #14477d);
    background: var(--sp-button-color, var(--sp-button-primary, #1976d2));
    color: var(--sp-fg-button-label, #ffffff);
}

.sp-btn-primary:hover:not(:disabled) {
    border-color: var(--sp-button-rim-hover, #0f3a68);
    background: var(--sp-button-hover-bg, var(--sp-button-primary-hover, #1565c0));
}

/* The booking pages have always emitted these two variants (locations search, zip
   reset, the cancel flow's confirm/keep pair), but only the cancel pages' own
   stylesheet defined them — everywhere else they rendered as bare .sp-btn. */
/* The secondary button paints its own fill, so its label and its edge are measured against that
   fill rather than against whatever is behind the button - the same reasoning as the primary's
   rim. Both variables are solved in BrandingCssGenerator; the raw branding fields they come from
   are the fallbacks, so a studio that never configured them is unaffected. */
.sp-btn-secondary {
    border-color: var(--sp-secondary-rim, var(--sp-secondary-button-border-color, var(--sp-border-color, #bdbdbd)));
    background: var(--sp-secondary-bg, var(--sp-surface-color, #ffffff));
    color: var(--sp-fg-secondary-label, var(--sp-secondary-button-text-color, #757575));
}

.sp-btn-secondary:hover:not(:disabled) {
    background: var(--sp-secondary-hover-bg, #f2f2f2);
}

.sp-btn-danger {
    background: var(--sp-danger-color, #d32f2f);
    color: var(--sp-fg-danger-label);
}

.sp-btn-danger:hover:not(:disabled) {
    background: var(--sp-danger-hover-color, #c62828);
}

.sp-btn-back,
.sp-back-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    min-width: 9rem;
    padding: 0.75rem 2rem;
    border: 1px solid var(--sp-secondary-button-border-color, var(--sp-back-button-border-color, var(--sp-border-color, #bdbdbd)));
    border-radius: 4px;
    background: var(--sp-secondary-bg, var(--sp-surface-color, #ffffff));
    color: var(--sp-fg-secondary-label, #757575);
    font-family: var(--sp-font-family, inherit);
    font-size: 1rem;
    font-weight: 600;
    line-height: 1.2;
    text-align: center;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease, opacity 0.15s ease;
}

.sp-btn-back:hover,
.sp-btn-back:focus,
.sp-back-link:hover,
.sp-back-link:focus {
    background: var(--sp-secondary-hover-bg, #f2f2f2);
    border-color: var(--sp-fg-edge);
    color: var(--sp-fg-secondary-label, #757575);
    text-decoration: none;
}

/* Compact variant — the signature pad's Clear control on both surfaces. The
   double-hyphen spelling is what the existing web-form field partials emit. */
.sp-btn-small,
.sp-btn--small {
    min-width: 0;
    min-height: 36px;
    padding: 0.375rem 0.875rem;
    border-color: var(--sp-fg-edge);
    background: var(--sp-secondary-bg, var(--sp-surface-color, #ffffff));
    color: var(--sp-fg-secondary-label, #757575);
    font-size: 0.875rem;
}

.sp-btn-small:hover:not(:disabled),
.sp-btn--small:hover:not(:disabled) {
    background: var(--sp-secondary-hover-bg, #f2f2f2);
}

.sp-btn:focus-visible,
.sp-back-link:focus-visible {
    outline: 3px solid var(--sp-button-focus-outline, var(--sp-focus-color, #1976d2));
    outline-offset: 2px;
}

.sp-btn:disabled,
.sp-continue-button:disabled {
    opacity: 0.65;
    cursor: not-allowed;
}

.sp-spinner {
    display: inline-block;
    width: 16px;
    height: 16px;
    border: 2px solid currentColor;
    border-right-color: transparent;
    border-radius: 50%;
    animation: sp-spin 0.75s linear infinite;
}

@keyframes sp-spin {
    to { transform: rotate(360deg); }
}

/* In-button loading state applied by button-loading.js when a form submits
   and navigates the page. The spinner inherits the button text colour via
   currentColor. */
.sp-btn-spinner {
    margin-left: 0.5rem;
    vertical-align: middle;
}

.sp-btn-loading {
    pointer-events: none;
    cursor: progress;
    opacity: 0.85;
}

@media (prefers-reduced-motion: reduce) {
    .sp-spinner {
        animation-duration: 1.5s;
    }
}

/* ---------------------------------------------------------- navigation --- */

.sp-step-navigation,
.sp-nav-buttons {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
}

.sp-step-navigation {
    padding-top: 1rem;
    border-top: 1px solid var(--sp-border-color, #e5e7eb);
}

.sp-nav-buttons {
    margin-top: 2rem;
}

.sp-nav-form {
    margin: 0;
}

/* --------------------------------------------------------- form fields --- */

/* Question-style form steps: the booking flow's session-promotion and
   inline-question steps, and every page of a standalone web form. Labels sit
   above full-width controls in a single left-aligned column, with breathing
   room before the navigation divider. */
.sp-question-fields {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
    max-width: 480px;
    margin: 0 0 2rem;
    text-align: left;
}

/* Center the column itself (not its text) for center-aligned tenants. */
.sp-center-align .sp-question-fields {
    margin-inline: auto;
}

.sp-question-field label {
    display: block;
    margin-bottom: 0.375rem;
    font-weight: 500;
    font-size: 0.9375rem;
    color: var(--sp-fg-text);
}

.sp-question-field .sp-input,
.sp-question-field .sp-select,
.sp-question-field .sp-textarea {
    width: 100%;
    padding: 0.625rem 0.75rem;
    font-size: 1rem;
    font-family: inherit;
    color: var(--sp-fg-text);
    background: var(--sp-input-background, var(--sp-surface-color, #ffffff));
    border: 1px solid var(--sp-border-color, #d1d5db);
    border-radius: var(--sp-radius, 8px);
    min-height: 44px;
}

.sp-question-field .sp-textarea {
    min-height: 96px;
    resize: vertical;
}

.sp-question-field .sp-input:focus,
.sp-question-field .sp-select:focus,
.sp-question-field .sp-textarea:focus {
    outline: none;
    border-color: var(--sp-fg-edge);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--sp-button-color, #1976d2) 22%, transparent);
}

.sp-question-field .sp-checkbox-wrapper {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
}

.sp-question-field .sp-checkbox {
    flex: 0 0 auto;
    width: 1.125rem;
    height: 1.125rem;
    margin-top: 0.125rem;
    accent-color: var(--sp-button-color, #1976d2);
}

.sp-question-field .sp-checkbox-label {
    margin-bottom: 0;
    font-weight: 400;
}

.sp-question-field .sp-required {
    margin-left: 0.25rem;
    color: var(--sp-fg-error);
}

.sp-question-field .sp-number-hint {
    display: block;
    margin-top: 0.25rem;
    font-size: 0.8125rem;
    color: var(--sp-fg-muted);
}

.sp-question-field .sp-field-error {
    display: block;
    margin-top: 0.375rem;
    font-size: 0.875rem;
    color: var(--sp-fg-error);
}

.sp-question-field.sp-field-error-state .sp-input,
.sp-question-field.sp-field-error-state .sp-select,
.sp-question-field.sp-field-error-state .sp-textarea {
    border-color: var(--sp-fg-error);
}

/* Radio groups, file pickers, signature pads, spacers and display text were
   emitted by both web-form field partials but had no rules anywhere, so they
   fell back to browser defaults on the booking flow as well as the standalone
   form. Defining them here fixes both surfaces at once. */
.sp-question-field .sp-field-radio-group {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.sp-question-field .sp-field-radio-option {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.sp-question-field .sp-field-radio-option label {
    margin-bottom: 0;
    font-weight: 400;
}

.sp-question-field .sp-field-radio {
    flex: 0 0 auto;
    width: 1.125rem;
    height: 1.125rem;
    accent-color: var(--sp-button-color, #1976d2);
}

.sp-question-field .sp-field-file {
    width: 100%;
    min-height: 44px;
    padding: 0.5rem 0.75rem;
    font-size: 0.9375rem;
    font-family: inherit;
    color: var(--sp-fg-text);
    background: var(--sp-input-background, var(--sp-surface-color, #ffffff));
    border: 1px dashed var(--sp-border-color, #d1d5db);
    border-radius: var(--sp-radius, 8px);
}

.sp-question-field .sp-field-help {
    display: block;
    margin-top: 0.375rem;
    font-size: 0.8125rem;
    line-height: 1.4;
    color: var(--sp-fg-muted);
}

.sp-signature-canvas {
    display: block;
    width: 100%;
    max-width: 100%;
    height: auto;
    margin-bottom: 0.5rem;
    background: var(--sp-input-background, var(--sp-surface-color, #ffffff));
    border: 1px solid var(--sp-border-color, #d1d5db);
    border-radius: var(--sp-radius, 8px);
    /* Without this a drag on a touch device scrolls the page instead of drawing. */
    touch-action: none;
}

.sp-signature-typed {
    margin-top: 0.5rem;
}

.sp-form-spacer,
.sp-question-field .sp-form-spacer {
    margin: 0.5rem 0;
    border: 0;
    border-top: 1px solid var(--sp-border-color, #e5e7eb);
}

.sp-form-display-text {
    color: var(--sp-fg-text);
    line-height: 1.6;
}

.sp-form-display-text > :first-child {
    margin-top: 0;
}

.sp-form-display-text > :last-child {
    margin-bottom: 0;
}

/* ------------------------------------------- studio header and footer --- */

/* Chrome for the _StudioHeader / _StudioHeaderEmbedded / _StudioFooter partials,
   which live in this project alongside these rules. The Host's site.css still
   carries its own copy for the pages on the generic Host layout (signup,
   payments); those pages do not load this file yet. When they adopt it, delete
   the copy in site.css rather than leaving the two to drift. */

.sp-header {
    background-color: var(--sp-header-bg);
    padding: 1rem;
    min-height: 80px;
    display: flex;
    align-items: center;
}

.sp-header-content {
    max-width: 960px;
    margin: 0 auto;
    width: 100%;
}

.sp-header-embedded {
    min-height: 50px;
    padding: 0.5rem;
}

.sp-logo {
    max-height: 80px;
    max-width: 300px;
    object-fit: contain;
    display: block;
}

.sp-logo-embedded {
    max-height: 50px;
}

.sp-logo-fallback,
.sp-business-name {
    font-family: var(--sp-font-primary);
    font-size: 1.5rem;
    color: var(--sp-fg-text);
    font-weight: 600;
    max-width: 300px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sp-footer {
    padding: 1rem;
    text-align: center;
    color: var(--sp-fg-muted);
    font-size: 0.875rem;
}

.sp-footer-content {
    max-width: 960px;
    margin: 0 auto;
}

.sp-footer-phone {
    margin-right: 1rem;
}

.sp-footer-copyright {
    display: block;
    margin-top: 0.5rem;
}

.sp-footer a,
.sp-return-link {
    margin-right: 1rem;
    color: var(--sp-fg-link);
}

/* ------------------------------------------------------------ utility --- */

/* Visually-hidden utility for screen-reader-only content. Lives here rather
   than in a page stylesheet so every surface that loads the core sheet gets
   it, instead of only the handful of pages that defined their own copy. */
.sp-sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* --------------------------------------------------------- responsive --- */

@media (max-width: 767px) {
    .sp-standalone .sp-shell,
    .sp-standalone .sp-booking-shell {
        margin: 0;
        border-radius: 0;
        border-left: 0;
        border-right: 0;
    }

    .sp-hosted-header-content {
        min-height: 60px;
        padding: 0 1rem;
    }

    .sp-hosted-logo {
        max-width: min(180px, 54vw);
        max-height: 32px;
    }

    .sp-center-align .sp-hosted-header-content {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: var(--sp-space-2, 0.5rem);
        min-height: auto;
        padding: var(--sp-space-3, 0.75rem) var(--sp-space-4, 1rem);
    }

    .sp-center-align .sp-hosted-brand,
    .sp-center-align .sp-hosted-header-actions {
        grid-column: auto;
        justify-self: center;
    }

    .sp-center-align .sp-hosted-header-actions {
        width: 100%;
        justify-content: center;
        flex-wrap: wrap;
        gap: var(--sp-space-2, 0.5rem) var(--sp-space-4, 1rem);
    }

    .sp-center-align .sp-hosted-utility-link {
        max-width: 100%;
    }

    .sp-main,
    .sp-booking-main {
        padding: 1.5rem 1rem;
    }

    .sp-step-navigation,
    .sp-nav-buttons {
        align-items: stretch;
        flex-direction: column;
    }

    .sp-step-navigation .sp-btn,
    .sp-step-navigation .sp-back-link,
    .sp-step-navigation .sp-continue-button,
    .sp-nav-buttons .sp-btn,
    .sp-nav-form,
    .sp-nav-form .sp-btn {
        width: 100%;
    }
}

@media (max-width: 479px) {
    .sp-hosted-header-content,
    .sp-center-align .sp-hosted-header-content {
        display: flex;
        flex-direction: column;
        align-items: flex-start;
        justify-content: center;
        gap: var(--sp-space-3, 0.75rem);
        min-height: auto;
        padding: var(--sp-space-3, 0.75rem) var(--sp-space-4, 1rem);
    }

    .sp-center-align .sp-hosted-brand,
    .sp-center-align .sp-hosted-header-actions {
        grid-column: auto;
        justify-self: start;
    }

    .sp-hosted-header-actions {
        width: 100%;
        max-width: none;
        flex-direction: column;
        align-items: flex-start;
        gap: var(--sp-space-1, 0.25rem);
    }

    .sp-hosted-utility-link {
        max-width: 100%;
        justify-content: flex-start;
    }
}
