/**
 * core_jsc_service_provider — cjsc- design system CSS.
 *
 * Base tokens and the generic card/table/badge/button/form/empty-state
 * components below are the same shared design-system values already used
 * by core_jsc_paid_registration's own cjsc-core-styles.css in this batch —
 * each addon keeps its own copy rather than sharing one stylesheet across
 * addons (established convention, not an oversight).
 *
 * THEMING. Every token below resolves from the store's own Theme Editor
 * variables first and falls back to a hardcoded value only if the active
 * theme does not publish that variable. Those --cs-* properties are what
 * Design > Theme editor writes: change the brand colour, the body font, the
 * heading size or the corner radius there and this addon follows, on any
 * theme, with no edit to this file. The fallbacks exist because older themes
 * predate the variables - they are the floor, not the design.
 *
 * Two things are deliberately NOT taken from the theme:
 *   - Layout ceilings and the control height are readability and
 *     accessibility floors, not brand choices. A theme is free to be
 *     full-bleed; a 200-character line and a 32px tap target are defects
 *     regardless of brand, so those are enforced with max().
 *   - Semantic status colours (success / danger / warning) bind only where
 *     the theme publishes a matching semantic variable, never to the brand
 *     accent, because a merchant's accent must not end up meaning "deleted".
 *
 * New component groups below the shared base (not present in
 * paid_registration's copy): the Services landing type-tile grid, the
 * provider directory grid, the provider profile layout, and the vendor
 * dashboard's own service-card grid.
 */

/* ===== LIGHT MODE (default) ===== */
:root {
    /* Brand. --cs-primary-button is the colour the merchant picked for the
       store's primary action, so the addon's primary action is that colour
       too rather than a blue of its own choosing. */
    --cjsc-primary:         var(--cs-primary-button, #2563eb);
    --cjsc-primary-hover:   var(--cs-primary-button-hover, #1d4ed8);
    --cjsc-primary-text:    var(--cs-btn-primary-color, #ffffff);
    --cjsc-primary-light:   var(--cs-tertiary-button, #e0e7ff);
    --cjsc-primary-border:  var(--cs-base, #bfdbfe);
    --cjsc-link:            var(--cs-links, #2563eb);
    --cjsc-link-hover:      var(--cs-links-hover, #1d4ed8);
    --cjsc-success:         var(--cs-success-text, #059669);
    --cjsc-success-light:   var(--cs-success-background, #ecfdf5);
    --cjsc-success-border:  var(--cs-success-border, #a7f3d0);
    --cjsc-danger:          var(--cs-checkout-error, var(--cs-error-text, #dc2626));
    --cjsc-danger-light:    var(--cs-error-background, #fef2f2);
    --cjsc-danger-border:   var(--cs-error-border, #fecaca);
    --cjsc-warning:         var(--cs-shipping-label, var(--cs-warning-text, #d97706));
    --cjsc-warning-light:   var(--cs-warning-background, #fffbeb);
    --cjsc-warning-border:  var(--cs-warning-border, #fde68a);
    --cjsc-info:            var(--cs-decorative, var(--cs-info-text, #0284c7));
    --cjsc-info-light:      var(--cs-info-background, #f0f9ff);
    --cjsc-info-border:     var(--cs-info-border, #bae6fd);
    --cjsc-white:           var(--cs-content-bg, var(--cs-content-background, #ffffff));
    --cjsc-bg:              var(--cs-table-background-accent, #f8fafc);
    --cjsc-bg-hover:        var(--cs-menu-hover, var(--cs-table-background-hover, #f1f5f9));
    --cjsc-border:          var(--cs-base, var(--cs-table-border, #e2e8f0));
    --cjsc-border-light:    var(--cs-input-border, #f1f5f9);
    --cjsc-text:            var(--cs-font, var(--cs-text-color, #0f172a));
    --cjsc-text-secondary:  var(--cs-secondary-text, var(--cs-gray-light, #475569));
    --cjsc-text-muted:      var(--cs-input-placeholder, #94a3b8);
    /* Typefaces. The store's own font roles, each with the previous
       hardcoded stack as its fallback. A merchant who sets a brand font in
       the theme editor gets it here too, including for prices and headings,
       which CS-Cart lets them style separately from body text. */
    --cjsc-font:            var(--cs-body-font, var(--cs-base-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif));
    --cjsc-font-headings:   var(--cs-headings-font, var(--cs-base-font-family, var(--cjsc-font)));
    --cjsc-font-price:      var(--cs-price-font, var(--cs-base-font-family, var(--cjsc-font)));
    --cjsc-font-buttons:    var(--cs-buttons-font, var(--cs-base-font-family, var(--cjsc-font)));
    --cjsc-weight-headings: var(--cs-headings-font-weight, 700);
    --cjsc-weight-price:    var(--cs-price-font-weight, 800);
    --cjsc-weight-buttons:  var(--cs-buttons-font-weight, 600);
    --cjsc-shadow:          var(--cs-shadow, 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04));
    --cjsc-shadow-hover:    var(--cs-shadow, 0 4px 12px rgba(0,0,0,0.08));
    /* Elevation for things that genuinely float above the page — a dialog,
       never a card. Kept separate from --cjsc-shadow precisely so the
       storefront can switch cards flat (see .cjsc-storefront) without also
       flattening a modal, which would then have nothing separating it from
       the page behind it. */
    --cjsc-shadow-overlay:  var(--cs-shadow, 0 16px 48px rgba(0,0,0,0.15));
    /* How a card separates itself from the page. Indirected through these
       two tokens rather than written into each card rule, because the two
       areas answer it differently: the admin outlines a white panel, the
       storefront fills a tinted one. Every card rule reads these; only the
       area scope below changes them. */
    --cjsc-card-bg:         var(--cjsc-white);
    --cjsc-card-bg-hover:   var(--cjsc-white);
    --cjsc-card-border:     var(--cjsc-border);
    --cjsc-radius:          var(--cs-base-rounded-corners-radius, var(--cs-base-border-radius, 10px));
    --cjsc-radius-sm:       var(--cs-input-rounded-corners-radius, var(--cs-input-border-radius, 6px));
    --cjsc-radius-btn:      var(--cs-base-rounded-corners-radius, var(--cs-base-border-radius, 6px));
    /* Spacing comes from the store's own scale. The storefront publishes
       --space-xxxs..-xxxxl (2/5/10/20/30/40/50/60/70/80); the admin publishes
       none, so the fallbacks below are what it uses and they are the values
       this addon already had there. Inventing a third rhythm alongside the
       platform's is the same defect as inventing a brand colour. */
    --cjsc-gap:             var(--space-s, 16px);
    --cjsc-pad:             var(--space-s, 20px);
    --cjsc-pad-sm:          var(--space-xs, 12px);
    --cjsc-gap-sm:          var(--space-xs, 8px);
    /* Type scale. CS-Cart already publishes a merchant-editable scale plus
       separate price and heading sizes, so the addon uses that scale rather
       than inventing a parallel one. The px values are the fallback for
       themes that publish no scale of their own.

       The scale here was previously 13/14/18: three steps, ceiling 18px, so
       every element on every page landed within 5px of every other and
       nothing could carry visual weight. The only escape had been a
       hardcoded 30px price, which is the tell that a scale is inadequate.
       No font-size outside these tokens belongs anywhere in this file. */
    --cjsc-fs-xs:           var(--cs-font-size-mini, 12px);
    --cjsc-fs-sm:           var(--cs-font-size-small, 13px);
    --cjsc-fs-base:         var(--cs-body-font-size, var(--cs-base-font-size, 14px));
    --cjsc-fs-lg:           var(--cs-font-size-large, 20px);
    --cjsc-fs-xl:           var(--cs-price-font-size, var(--cs-font-size-large, 28px));
    --cjsc-fs-display:      var(--cs-headings-font-size, var(--cs-font-size-large, 36px));

    /* Controls carry the theme's own button size, floored at 15px: below
       that a primary action stops being comfortably readable whatever the
       theme says, and that is an accessibility floor rather than a taste. */
    --cjsc-fs-md:           max(var(--cs-buttons-font-size, var(--cs-base-font-size, 16px)), 15px);

    /* The addon sets no widths at all. Card and container widths come from
       the theme's own column system - see the GRIDS section. The reading
       measure that used to live here was the addon's own judgement, and the
       platform publishes no equivalent, so there is none. */

    /* No control-height tokens live here any more. Controls are the
       platform's own components, so their height is the platform's decision.
       The 44px floor this used to declare was only defensible while the addon
       was drawing the controls itself. */
}

/* ===== DARK MODE ===== */
:root.cs-dark-theme {
    --cjsc-primary:         var(--cs-primary-button, #8dcffb);
    --cjsc-primary-hover:   var(--cs-primary-button-hover, #a8d9fc);
    --cjsc-primary-light:   var(--cs-tertiary-button, #1a2d3d);
    --cjsc-primary-border:  var(--cs-base, #2d5a7a);
    /* Missing here through 3.4.8 - every other token in this block has a
       dark-mode fallback in case the platform doesn't publish its own
       --cs-links for the active theme; --cjsc-link/-hover did not, so a
       theme with no dark --cs-links would render this addon's own links in
       the light-mode blue against a dark background. Same lighter-tint
       pattern already used for --cjsc-primary above. */
    --cjsc-link:            var(--cs-links, #8dcffb);
    --cjsc-link-hover:      var(--cs-links-hover, #a8d9fc);
    --cjsc-success:         var(--cs-success-text, #6fcf97);
    --cjsc-success-light:   var(--cs-success-background, #1a3a1a);
    --cjsc-success-border:  var(--cs-success-border, #2d6a2d);
    --cjsc-danger:          var(--cs-checkout-error, var(--cs-error-text, #f28b82));
    --cjsc-danger-light:    var(--cs-error-background, #3a1a1a);
    --cjsc-danger-border:   var(--cs-error-border, #6a2d2d);
    --cjsc-warning:         var(--cs-shipping-label, var(--cs-warning-text, #f9ab00));
    --cjsc-warning-light:   var(--cs-warning-background, #3a2d1a);
    --cjsc-warning-border:  var(--cs-warning-border, #6a5a2d);
    --cjsc-info:            var(--cs-decorative, var(--cs-info-text, #6fc3df));
    --cjsc-info-light:      var(--cs-info-background, #1a2d3a);
    --cjsc-info-border:     var(--cs-info-border, #2d5a6a);
    --cjsc-white:           var(--cs-content-bg, var(--cs-content-background, #1a1d20));
    --cjsc-bg:              var(--cs-table-background-accent, #282c2f);
    --cjsc-bg-hover:        var(--cs-menu-hover, var(--cs-table-background-hover, #35393b));
    --cjsc-border:          var(--cs-base, var(--cs-table-border, #454a4f));
    --cjsc-border-light:    var(--cs-input-border, #35393b);
    --cjsc-text:            var(--cs-font, var(--cs-text-color, #e3e3e3));
    --cjsc-text-secondary:  var(--cs-secondary-text, var(--cs-gray-light, #a0a4a8));
    --cjsc-text-muted:      var(--cs-input-placeholder, #606366);
    --cjsc-shadow:          var(--cs-shadow, 0 1px 3px rgba(0,0,0,0.3), 0 1px 2px rgba(0,0,0,0.2));
    --cjsc-shadow-hover:    var(--cs-shadow, 0 4px 12px rgba(0,0,0,0.4));
    --cjsc-shadow-overlay:  var(--cs-shadow, 0 16px 48px rgba(0,0,0,0.5));
    --cjsc-card-bg:         var(--cjsc-white);
    --cjsc-card-bg-hover:   var(--cjsc-white);
    --cjsc-card-border:     var(--cjsc-border);
}

/* ===== STOREFRONT SCOPE =====
   Carried by the wrapper of every public template this addon owns, and by
   none of its admin ones.

   Why it exists. This stylesheet is shared by both areas — sixteen admin
   templates load the same file — and the two areas separate a card from the
   page in opposite ways. Measured on the live store: across its homepage,
   its "Become a Seller" page, its vendor list, a category page and its About
   page, the storefront paints exactly two drop shadows, and both are on
   things that float over the page (the chat launcher and the cookie notice).
   Nothing that sits ON a page carries one. Its cards are separated by a
   tinted fill and no border at all; the theme's own large shadow token is
   spent only on dialogs, dropdowns and select panels.

   This addon was doing the reverse on every public page: white card, grey
   outline, and the theme's dialog shadow — four elevated boxes on a page
   where the host paints none, and thirty-three once the directory is full.
   That is what made the pages read as a different product bolted on.

   Only the tokens change here. Every card rule already reads them, so the
   whole public side flips flat without a single component rule being
   duplicated, and the admin keeps the outlined-white panels that match the
   admin's own design. */
.cjsc-storefront {
    --cjsc-shadow:        none;
    --cjsc-shadow-hover:  none;
    --cjsc-card-bg:       var(--cs-table-background-accent, #f5f5f5);
    --cjsc-card-bg-hover: var(--cs-table-background-hover, #ececec);
    --cjsc-card-border:   transparent;
    font-family: var(--cjsc-font);
    color: var(--cjsc-text);
}

/* ===== BOX MODEL =====
   Every element this addon owns measures what it declares. Without this,
   max-width caps the CONTENT box: a card declared max-width 340px with 20px
   of padding and a 1px border renders 382px, so a "capped" card silently
   overshoots its cap by the width of its own chrome. This is the same defect
   class as an <a> and a <button> disagreeing about their height. */
[class^="cjsc-"],
[class*=" cjsc-"],
[class^="cjsc-"]::before,
[class^="cjsc-"]::after,
[class*=" cjsc-"]::before,
[class*=" cjsc-"]::after {
    box-sizing: border-box;
}
/* ===== LAYOUT ===== */
.cjsc-layout {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--cjsc-gap);
    font-family: var(--cjsc-font);
    color: var(--cjsc-text);
}

/* Any run of text sets its own reading measure, independent of how wide the
   surrounding container happens to be. */
.cjsc-prose,
.cjsc-page-subtitle,
.cjsc-empty-text,
.cjsc-plan-card-description,
.cjsc-service-card-description {
    max-width: 60ch;
    line-height: 1.5;
    color: var(--cjsc-text-secondary);
}

.cjsc-layout-split {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--cjsc-gap);
    font-family: var(--cjsc-font);
    color: var(--cjsc-text);
}

.cjsc-layout-triple {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(260px, 1fr);
    gap: var(--cjsc-gap);
    font-family: var(--cjsc-font);
    color: var(--cjsc-text);
}

/* ===== GENERIC CARD ===== */
.cjsc-card {
    background: var(--cjsc-card-bg);
    border: 1px solid var(--cjsc-card-border);
    border-radius: var(--cjsc-radius);
    box-shadow: var(--cjsc-shadow);
    overflow: hidden;
}

.cjsc-card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--cjsc-gap);
    padding: var(--cjsc-pad-sm) var(--cjsc-pad);
    border-bottom: 1px solid var(--cjsc-border-light);
}

.cjsc-card-header h4 {
    margin: 0;
    font-size: var(--cjsc-fs-lg);
    font-weight: 700;
    color: var(--cjsc-text);
    display: flex;
    align-items: center;
    gap: var(--space-xxs, 8px);
}

.cjsc-icon {
    color: var(--cjsc-primary);
}

.cjsc-card-body {
    padding: var(--cjsc-pad);
}

.cjsc-card-footer {
    display: flex;
    gap: var(--space-xs, 10px);
    padding: var(--cjsc-pad-sm) var(--cjsc-pad);
    border-top: 1px solid var(--cjsc-border-light);
}

/* ===== TABLES ===== */
.cjsc-table-wrap {
    border: 1px solid var(--cjsc-border);
    border-radius: var(--cjsc-radius-sm);
    overflow-x: auto;
}

.cjsc-table {
    width: 100%;
    border-collapse: collapse;
}

.cjsc-table th,
.cjsc-table td {
    text-align: left;
    padding: var(--space-xs, 10px);
    border-bottom: 1px solid var(--cjsc-border-light);
    color: var(--cjsc-text);
}

.cjsc-table th {
    background: var(--cjsc-bg);
    color: var(--cjsc-text-secondary);
    font-weight: 600;
}

.cjsc-table tbody tr:hover {
    background: var(--cjsc-bg-hover);
}

.cjsc-table tbody tr:last-child td {
    border-bottom: none;
}

/* ===== BADGES ===== */
.cjsc-badge {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xxs, 6px);
    padding: var(--space-xxs, 4px) var(--space-xs, 12px);
    border-radius: 100px;
    font-size: var(--cjsc-fs-sm);
    font-weight: 600;
    border: 1px solid transparent;
}

.cjsc-badge::before {
    content: "";
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
}

.cjsc-badge-warning { background: var(--cjsc-warning-light); border-color: var(--cjsc-warning-border); color: var(--cjsc-warning); }
.cjsc-badge-success { background: var(--cjsc-success-light); border-color: var(--cjsc-success-border); color: var(--cjsc-success); }
.cjsc-badge-danger  { background: var(--cjsc-danger-light);  border-color: var(--cjsc-danger-border);  color: var(--cjsc-danger); }
.cjsc-badge-info    { background: var(--cjsc-info-light);    border-color: var(--cjsc-info-border);    color: var(--cjsc-info); }

/* ===== ALERTS ===== */
.cjsc-alert {
    display: flex;
    align-items: flex-start;
    gap: var(--space-xs, 10px);
    padding: var(--cjsc-pad-sm) var(--cjsc-pad);
    border-radius: var(--cjsc-radius-sm);
    border: 1px solid transparent;
    font-size: var(--cjsc-fs-base);
}

.cjsc-alert-icon { flex-shrink: 0; }
.cjsc-alert-danger  { background: var(--cjsc-danger-light);  border-color: var(--cjsc-danger-border);  color: var(--cjsc-danger); }
.cjsc-alert-warning { background: var(--cjsc-warning-light); border-color: var(--cjsc-warning-border); color: var(--cjsc-warning); }
.cjsc-alert-info    { background: var(--cjsc-info-light);    border-color: var(--cjsc-info-border);    color: var(--cjsc-info); }

.cjsc-error-list {
    margin: var(--space-xxs, 4px) 0 0;
    padding-left: 18px;
}

/* ===== PAYMENT METHOD CHOOSER =====
   Peer-reported live (3.4.20): these two selectors had zero rules — the
   radio choice on the money screen (register/request payment step)
   rendered as bare inline labels under plain, unstyled inputs. */
.cjsc-payment-method-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs, 10px);
}

.cjsc-payment-method-item {
    display: flex;
    align-items: center;
    gap: var(--space-xs, 10px);
    padding: var(--cjsc-pad-sm) var(--cjsc-pad);
    border: 1px solid var(--cjsc-border);
    border-radius: var(--cjsc-radius-sm);
    cursor: pointer;
    font-size: var(--cjsc-fs-base);
}

.cjsc-payment-method-item:has(input:checked) {
    border-color: var(--cjsc-primary, var(--cs-link-color, #2b7de9));
}

/* ===== FORMS ===== */
.cjsc-form-section {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--cjsc-gap);
}

.cjsc-form-item {
    display: flex;
    flex-direction: column;
    gap: var(--space-xxs, 6px);
}

.cjsc-form-item-full { grid-column: 1 / -1; }

.cjsc-form-item label {
    font-size: var(--cjsc-fs-sm);
    font-weight: 600;
    color: var(--cjsc-text-secondary);
}

.cjsc-help {
    font-size: var(--cjsc-fs-xs);
    color: var(--cjsc-text-muted);
}

/* ===== FORM CONTROLS =====
   Like buttons, these are not the addon's to style. CS-Cart styles input,
   select and textarea natively in both the admin and every storefront theme,
   so the addon sets width - a layout concern the platform has no opinion
   about - and nothing else.

   What was here before is a good illustration of why. The select drew its own
   dropdown arrow as an inline SVG with the arrow colour hardcoded twice, once
   light and once dark, which meant a merchant on any other palette got an
   arrow in a colour their theme never chose; and the inputs painted an opaque
   background where the platform's own inputs are transparent, so they sat
   visibly differently on any striped or tinted row. Both are invisible in
   isolation and obvious the moment an addon field sits next to a native one.

   Because the platform's own selectors target the elements directly, the
   markup keeps these class names only as layout hooks. */
.cjsc-input,
.cjsc-select,
textarea.cjsc-input {
    width: 100%;
}

.cjsc-textarea {
    resize: vertical;
    min-height: 90px;
}

/* There is deliberately no rule here for input[type="email"].
   An earlier version of this file re-declared the theme's input properties for
   that type, because the storefront theme styles text, password, tel, number,
   textarea and select but not email, so the field rendered as a raw browser
   default between two theme-styled neighbours. That fix made the field measure
   the same while still being a different control imitating the others, and a
   full computed-style diff caught it drifting immediately: the copy declared a
   text colour the theme deliberately leaves alone.

   The markup now follows CS-Cart's own convention instead - type="text" with
   the cm-email validator on the label, as gift_certificates, call_requests and
   hybrid_auth all do - so the field IS the control the theme already styles.
   Nothing here needs to imitate it. */
/* ===== BUTTONS =====
   This addon does not style buttons. The backend uses CS-Cart's own .btn
   family and the storefront uses the theme's .ty-btn family, so every action
   is the platform's component rather than a lookalike.

   The addon used to paint its own: its own colour, size, weight, radius and
   padding. Binding those to the theme's variables was still not enough - in
   the admin the result was 44px tall with 16px/600 white text where the
   native button is ~30px with 14px/400 near-black text on the same
   background, because CS-Cart derives a button's foreground from its
   background rather than publishing it. Matching a colour is not the same as
   being the component, and the difference is exactly what reads as foreign.

   Using the platform's classes also inherits its hover, focus, active and
   disabled states, which this addon never implemented.

   The one thing left is width, which is a layout concern the platform's
   button classes deliberately have no opinion about. */
.cjsc-btn-wide {
    display: flex;
    width: 100%;
    justify-content: center;
    text-align: center;
}

/* Row actions.
   align-items must be explicit. A flex container stretches its items by
   default, so a bare action grows to the tallest thing in the row while one
   wrapped in its own <form> keeps the height it declared - which is why an
   Edit link and a Delete button with identical classes measured 52px and 32px
   side by side. Centring makes every action keep its own height regardless of
   what wraps it, and the nested <form> that CS-Cart requires around a POST
   action must not become a layout box of its own either. */
.cjsc-table-actions {
    display: flex;
    align-items: center;
    gap: var(--space-xxs, 6px);
}

.cjsc-table-actions > form {
    display: flex;
    align-items: center;
    margin: 0;
}

.cjsc-code {
    font-family: monospace;
    background: var(--cjsc-bg);
    border: 1px solid var(--cjsc-border);
    border-radius: 4px;
    padding: var(--space-xxxs, 2px) var(--space-xxs, 6px);
    font-size: var(--cjsc-fs-sm);
}

.cjsc-status-detail-row {
    display: flex;
    gap: var(--space-xxs, 8px);
    padding: var(--space-xxs, 6px) 0;
    border-top: 1px solid var(--cjsc-border-light);
    font-size: var(--cjsc-fs-sm);
}

.cjsc-status-detail-row:first-of-type { border-top: none; }

.cjsc-status-detail-label {
    font-weight: 600;
    color: var(--cjsc-text-secondary);
    min-width: 120px;
}

/* ===== EMPTY STATE ===== */
.cjsc-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 48px var(--cjsc-pad);
    border: 1px dashed var(--cjsc-border);
    border-radius: var(--cjsc-radius);
    background: var(--cjsc-bg);
}

.cjsc-empty-icon { font-size: var(--cjsc-fs-display); margin-bottom: 8px; opacity: 0.7; }
.cjsc-empty-text { margin: 0; color: var(--cjsc-text-secondary); font-size: var(--cjsc-fs-base); }

.cjsc-back-link { margin: 0; }
.cjsc-back-link a { font-size: var(--cjsc-fs-sm); color: var(--cjsc-text-secondary); text-decoration: none; }
.cjsc-back-link a:hover { color: var(--cjsc-primary); }

/* ===== PAGE HEADER (shared by pricing/directory/profile pages) ===== */
.cjsc-page-header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--cjsc-gap);
    background: var(--cjsc-card-bg);
    border: 1px solid var(--cjsc-card-border);
    border-radius: var(--cjsc-radius);
    box-shadow: var(--cjsc-shadow);
    padding: var(--cjsc-pad);
}

.cjsc-page-title { margin: 0 0 6px; font-family: var(--cjsc-font-headings); font-size: var(--cjsc-fs-display); font-weight: var(--cjsc-weight-headings); line-height: 1.15; color: var(--cjsc-text); }
.cjsc-page-subtitle { margin: 0; font-size: var(--cjsc-fs-md); color: var(--cjsc-text-secondary); }

/* ===== PROVIDER PROFILE HEADER (core_jsc_service_directory/provider.tpl) =====
   Referenced since the first version of this template, never styled — the
   logo/title/rating block rendered as a plain unlaid-out block, readable
   only because native h1/badge styles carried it. 3.4.6 adds the actual
   logo+text row layout this header needs now that it also shows a rating
   and a bio line. */
.cjsc-profile-header {
    display: flex;
    align-items: flex-start;
    gap: var(--cjsc-gap);
    margin-bottom: var(--cjsc-gap);
}

.cjsc-profile-header img,
.cjsc-profile-header .ty-no-image {
    width: 72px !important;
    /* Peer-reported live (3.4.20), applied on production already: the
       theme's own .ty-no-image carries min-width: 100%, and min-width beats
       width regardless of !important — a 72px-tall element was forced to
       the container's full width. 72px matches image_width=72 in
       provider.tpl, nothing invented. */
    min-width: 72px !important;
    max-width: 72px !important;
    height: 72px !important;
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
    background: var(--cjsc-bg);
}

.cjsc-profile-title { margin: 4px 0; font-size: var(--cjsc-fs-display); color: var(--cjsc-text); }

.cjsc-profile-header-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--cjsc-gap-sm);
    margin-bottom: 4px;
}

.cjsc-profile-bio { margin: 4px 0 0; max-width: 60ch; line-height: 1.5; color: var(--cjsc-text-secondary); }

.cjsc-reviews-section {
    display: flex;
    flex-direction: column;
    gap: var(--cjsc-gap);
    margin-bottom: var(--cjsc-gap);
}



.cjsc-type-tile {
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    background: var(--cjsc-card-bg);
    border: 1px solid var(--cjsc-card-border);
    border-radius: var(--cjsc-radius);
    box-shadow: var(--cjsc-shadow);
    padding: var(--cjsc-pad);
    text-decoration: none;
}

/* Hover deepens the fill and shows the border. On the storefront the border
   is transparent at rest, so this is the only thing that moves — which is how
   the host's own tiles answer a hover. Lifting the card on a shadow is the
   admin's answer, and stays the admin's. */
.cjsc-type-tile:hover {
    background: var(--cjsc-card-bg-hover);
    box-shadow: var(--cjsc-shadow-hover);
    border-color: var(--cjsc-primary-border);
    text-decoration: none;
}

.cjsc-type-tile-image {
    width: 96px;
    height: 96px;
    border-radius: var(--cjsc-radius-sm);
    object-fit: cover;
    background: var(--cjsc-bg);
    margin-bottom: var(--cjsc-pad-sm);
}

.cjsc-type-tile-image-placeholder {
    width: 96px;
    height: 96px;
    border-radius: var(--cjsc-radius-sm);
    background: var(--cjsc-bg);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--cjsc-fs-display);
    margin-bottom: var(--cjsc-pad-sm);
}

.cjsc-type-tile-name { font-size: var(--cjsc-fs-base); font-weight: 600; color: var(--cjsc-text); }

/* No per-entity placeholder lives here any more.

   It used to generate a colour per record - hsl() driven by a hue derived from
   the record id - which put colours on the page that exist in no store's
   palette. CS-Cart already answers "this entity has no image": common/image.tpl
   renders its own <span class="ty-no-image"> with the theme's icon, and the
   templates now let it. */

.cjsc-type-tile-image-placeholder .cs-icon,
.cjsc-type-tile-image-placeholder .ty-icon,
.cjsc-service-card-image-placeholder .cs-icon,
.cjsc-service-card-image-placeholder .ty-icon {
    color: var(--cjsc-text-muted);
    font-size: var(--cjsc-fs-display);
    width: 36px;
    height: 36px;
}

/* The empty-state / placeholder wrappers previously sized a text glyph via
   font-size; with a real icon element inside, they only need to center it. */
.cjsc-empty-icon,
.cjsc-type-tile-image-placeholder,
.cjsc-service-card-image-placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
}

/* The vendor dashboard (manage.tpl) prints a plain <img>, not a
   common/image.tpl include, since it reads a straight image_path off the
   already-fetched pair rather than re-resolving it — this class and its
   placeholder sibling above never had a height, so a single service card's
   image area sized itself off nothing but the 36px icon glyph, leaving the
   rest of the visible "empty space" the vendor reported. */
.cjsc-service-card-image,
.cjsc-service-card-image-placeholder {
    width: 100%;
    height: 150px;
}

.cjsc-service-card-image {
    display: block;
    object-fit: cover;
}

/* 3.4.7: the edit/delete menu used to sit as an absolutely-positioned
   overlay directly on top of the photo (copied from the native product
   grid's hover-reveal thumbnail pattern, which fits a small square admin
   thumbnail - it does not fit this card's large content photo, and "the
   photo has a control floating on it" was flagged as wrong on sight).
   Moved into the card body instead, sharing a row with the status badge -
   both are card metadata, they belong together, and nothing should ever
   render on top of the photo itself. align-items:stretch (the flex column
   default) is what stretched the badge to the card's full width before;
   this row opts both children out with their own natural width. */
.cjsc-dashboard-service-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--cjsc-gap-sm);
}

.cjsc-dashboard-service-row .cjsc-badge {
    align-self: flex-start;
}

/* ===== GRID CONTAINERS (3.4.6) =====
   Every one of these grids used to depend on the storefront's native
   ty-columnN wrapper divs for actual column layout, but only providers.tpl
   and provider.tpl ever added that wrapper — manage.tpl (vendor dashboard)
   never did, so its single-service case rendered one card stretched to the
   full panel width with no way to ever show a second item beside it. Fixed
   by giving each grid a real CSS Grid of its own: every card gets a natural
   max width and multiple items wrap into columns on their own, regardless
   of which template renders them or how many items there are. */
.cjsc-provider-grid,
.cjsc-service-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: var(--cjsc-gap);
}

/* The service-type grid. It had no rule of its own at all and leaned on the
   storefront's native ty-columnN wrappers, which are fixed fractions of
   sixteen — so a store with three service types (Expolinko has exactly
   three) rendered three quarter-width tiles and left the last quarter of
   the row empty. Column count follows the item count here instead, so the
   row is always full whether there are two types or seven. */
.cjsc-type-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: var(--cjsc-gap);
}

/* Pricing tables are conventionally one row, side by side, so a shopper can
   compare every plan at a glance without scrolling vertically between them
   — never a stacked list of boxes.

   This was a horizontal scroller with fixed 272px cards. With three plans in
   a 1385px content area that left roughly 40% of the row blank and put the
   comparison in a scrollport nobody needed to scroll. A grid whose columns
   follow the plan count fills the row at three, and wraps to a second row
   rather than hiding plans off-screen once there are more than fit. */
.cjsc-plan-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    align-items: stretch;
    gap: var(--cjsc-gap);
    /* Room for .cjsc-plan-card-badge, which is positioned to float above its
       card's top edge. Reserved on the container, since the badge would
       otherwise be clipped by it. */
    padding-top: 16px;
}

/* ===== PROVIDER DIRECTORY CARD (core_jsc_service_directory/providers.tpl) =====
   3.4.6: rebuilt from a bare name+link into a real comparison card — logo,
   rating, bio and a services-offered/city meta row, so a shopper can
   compare providers against each other without opening every profile. */
.cjsc-provider-card {
    display: flex;
    flex-direction: column;
    background: var(--cjsc-card-bg);
    border: 1px solid var(--cjsc-card-border);
    border-radius: var(--cjsc-radius);
    box-shadow: var(--cjsc-shadow);
    overflow: hidden;
    text-decoration: none;
    scroll-snap-align: start;
}

.cjsc-provider-card:hover {
    background: var(--cjsc-card-bg-hover);
    box-shadow: var(--cjsc-shadow-hover);
    border-color: var(--cjsc-primary-border);
    text-decoration: none;
}

.cjsc-provider-card .ty-no-image,
.cjsc-provider-card img {
    /* Flex items stretch to the container's cross-axis size by default -
       without an explicit square width/height and align-self:center, this
       flexed to the full card width and border-radius:50% turned it into
       an ellipse rather than a circular avatar. */
    display: block;
    align-self: center;
    width: 88px !important;
    /* Peer-reported live (3.4.20): same min-width-beats-width shape as
       .cjsc-profile-header above — this one computed 276x88, an ellipse,
       not the 88px circle its own comment already intended. */
    min-width: 88px !important;
    max-width: 88px !important;
    height: 88px !important;
    margin: var(--cjsc-pad) auto 0;
    border-radius: 50%;
    object-fit: cover;
    background: var(--cjsc-bg);
}

.cjsc-provider-card-body {
    display: flex;
    flex: 1;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    text-align: center;
    padding: var(--cjsc-pad-sm) var(--cjsc-pad) var(--cjsc-pad);
}

.cjsc-provider-card-name {
    margin: 0;
    font-size: var(--cjsc-fs-base);
    font-weight: var(--cjsc-weight-headings);
    color: var(--cjsc-text);
}

.cjsc-provider-card-bio {
    margin: 0;
    font-size: var(--cjsc-fs-sm);
    color: var(--cjsc-text-secondary);
    line-height: 1.4;
}

.cjsc-provider-card-meta {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 4px var(--cjsc-gap-sm);
    font-size: var(--cjsc-fs-xs);
    color: var(--cjsc-text-muted);
}

.cjsc-provider-card-cta {
    margin-top: auto;
    padding-top: 6px;
    font-size: var(--cjsc-fs-sm);
    font-weight: var(--cjsc-weight-buttons);
    color: var(--cjsc-link);
}

/* Compact "★ 4.5 (12)" rating readout — shared by the provider card, the
   service card and the profile header. Deliberately its own class rather
   than .cjsc-badge: that component always prefixes a status dot, which
   reads wrong paired with a star glyph. */
.cjsc-rating-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: var(--cjsc-fs-sm);
    font-weight: var(--cjsc-weight-buttons);
    color: var(--cjsc-warning);
}

.cjsc-rating-badge .ty-icon,
.cjsc-rating-badge .cs-icon {
    color: var(--cjsc-warning);
}

.cjsc-rating-badge-count {
    font-weight: 400;
    color: var(--cjsc-text-muted);
}

/* ===== SERVICE CARD (core_jsc_service_directory/provider.tpl,
   core_jsc_service_provider_dashboard/manage.tpl) ===== */
.cjsc-service-card {
    display: flex;
    flex-direction: column;
    height: 100%;
    background: var(--cjsc-card-bg);
    border: 1px solid var(--cjsc-card-border);
    border-radius: var(--cjsc-radius);
    box-shadow: var(--cjsc-shadow);
    overflow: hidden;
}

.cjsc-service-card .ty-no-image {
    /* common/image.tpl's own no-image span carries its own inline
       height/width (image_width/image_height from the include call) - this
       only adds the background this card family already uses elsewhere,
       consistent with .cjsc-type-tile-image-placeholder. */
    background: var(--cjsc-bg);
    /* Peer-reported live (3.4.20): same min-width-beats-width shape as
       .cjsc-profile-header/.cjsc-provider-card above — the theme's own
       .ty-no-image carries min-width: 100%, which silently wins over the
       inline width/height this span carries from image_width=200
       image_height=150 (provider.tpl) unless pinned here too. */
    min-width: 200px !important;
    max-width: 200px !important;
    min-height: 150px !important;
    max-height: 150px !important;
}

/* common/image.tpl's <img> (native ty-pict) carries the requested
   image_width/image_height as literal HTML attributes (200x150 here) and
   nothing in this file ever overrode them — so on any card wider than
   200px (every card in a responsive grid, past a certain viewport) the
   image stayed pinned at its fixed native size while the card grew around
   it, leaving unfilled space to one side. Same defect and same fix as
   .cjsc-service-card-image below (the vendor-dashboard <img>), just never
   applied here because this one renders through common/image.tpl instead
   of a raw <img> tag - width:100% + a matching aspect-ratio makes it fill
   the card at any width without cropping, since the ratio here (4:3)
   matches this addon's own generated service images exactly. */
.cjsc-service-card img {
    width: 100% !important;
    height: auto !important;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    display: block;
}

.cjsc-service-card-body {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: var(--cjsc-gap-sm);
    padding: var(--cjsc-pad);
}

.cjsc-service-card-name {
    margin: 0;
    font-size: var(--cjsc-fs-base);
    font-weight: var(--cjsc-weight-headings);
    color: var(--cjsc-text);
}

.cjsc-service-card-price {
    margin-top: auto;
    font-family: var(--cjsc-font-price);
    font-weight: var(--cjsc-weight-price);
    font-size: var(--cjsc-fs-lg);
    color: var(--cjsc-text);
}

/* ===== PRICING PLAN CARD (core_jsc_service_provider_register/pricing.tpl) =====
   3.4.6: rebuilt as a real side-by-side comparison table (see .cjsc-plan-grid
   above) instead of stacked generic cards — a fixed comfortable width per
   plan, a taller/elevated featured plan, and a distinct "best value" ribbon
   on top of the existing "most popular" one, the two badges this pattern is
   built around everywhere it appears. */
.cjsc-plan-card {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--cjsc-gap-sm);
    background: var(--cjsc-card-bg);
    border: 1px solid var(--cjsc-card-border);
    border-radius: var(--cjsc-radius);
    box-shadow: var(--cjsc-shadow);
    padding: var(--cjsc-pad);
}

/* The recommended plan is marked by the brand accent, and only by it: a
   2px border in the store's own primary colour plus its ribbon. It used to
   also lift 8px and carry a heavier shadow — but the host marks emphasis
   with colour and never with elevation, and a card that stands physically
   proud of its neighbours stops reading as one row of comparable options,
   which is the entire job of a pricing table. */
.cjsc-plan-card-featured {
    border-color: var(--cjsc-primary);
    border-width: 2px;
}

/* 3.4.7 briefly moved this into normal flow (align-self:flex-start,
   no absolute positioning) to dodge a clipping bug rather than fix it -
   that changed the actual visual design instead of solving the real
   problem, and was reverted the same release. The floating-ribbon-above-
   the-border look is restored here; the fix is .cjsc-plan-grid's own
   28px top padding above (with a matching negative margin so the section
   doesn't visually shift down) - see that rule's comment for the exact
   math. Root cause was never the badge's own positioning; it was the
   scrollport never reserving room for content its own children are
   deliberately positioned to render outside of. */
.cjsc-plan-card-badge {
    position: absolute;
    top: 0;
    right: var(--cjsc-pad);
    transform: translateY(-50%);
    background: var(--cjsc-primary);
    color: var(--cjsc-primary-text);
    font-size: var(--cjsc-fs-xs);
    font-weight: var(--cjsc-weight-buttons);
    line-height: 1;
    padding: 5px 10px;
    border-radius: var(--cjsc-radius-sm);
    white-space: nowrap;
}

.cjsc-plan-card-badge-value {
    background: var(--cjsc-success);
}

.cjsc-plan-card-name {
    margin: 0 0 4px;
    font-size: var(--cjsc-fs-lg);
    font-weight: var(--cjsc-weight-headings);
    color: var(--cjsc-text);
}

.cjsc-plan-price {
    display: flex;
    align-items: baseline;
    gap: var(--cjsc-gap-sm);
}

.cjsc-plan-price-amount {
    font-family: var(--cjsc-font-price);
    font-weight: var(--cjsc-weight-price);
    font-size: var(--cjsc-fs-xl);
    color: var(--cjsc-text);
}

.cjsc-plan-price-currency {
    font-size: var(--cjsc-fs-base);
}

.cjsc-plan-features {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: var(--cjsc-gap-sm);
    margin: 0;
    padding: 0;
    list-style: none;
}

.cjsc-plan-feature {
    display: flex;
    align-items: flex-start;
    gap: var(--cjsc-gap-sm);
    font-size: var(--cjsc-fs-base);
    color: var(--cjsc-text-secondary);
}

.cjsc-plan-feature-check {
    flex-shrink: 0;
    color: var(--cjsc-success);
}

.cjsc-plan-card-footer {
    margin-top: auto;
}

/* ===== REVIEW MODALS + HALF-STAR WIDGET (3.4.7) =====
   provider.tpl used to render every review, for every service, inline —
   a section whose length scales with user-submitted content must never
   sit inline on a page whose job is showing many *other* things (see that
   template's own docblock). Both dialogs below are shared and populated by
   cjsc-reviews.js; this file only owns their static chrome. */
.cjsc-modal {
    max-width: 480px;
    width: calc(100% - 32px);
    border: none;
    border-radius: var(--cjsc-radius);
    /* The one place on the public side that keeps a shadow. A dialog really
       does float over the page, which is the same category the theme itself
       reserves its large shadow for. Reads --cjsc-shadow-overlay, not
       --cjsc-shadow, so the storefront's flat-card scope cannot flatten it. */
    box-shadow: var(--cjsc-shadow-overlay);
    padding: 0;
    color: var(--cjsc-text);
    background: var(--cjsc-white);
}

.cjsc-modal::backdrop {
    background: rgba(0, 0, 0, 0.5);
}

.cjsc-modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--cjsc-gap-sm);
    padding: var(--cjsc-pad);
    border-bottom: 1px solid var(--cjsc-border-light);
}

.cjsc-modal-title {
    margin: 0;
    font-size: var(--cjsc-fs-lg);
    font-weight: var(--cjsc-weight-headings);
}

.cjsc-modal-close {
    background: none;
    border: none;
    cursor: pointer;
    color: var(--cjsc-text-muted);
    font-size: var(--cjsc-fs-lg);
    line-height: 1;
    padding: 4px;
}

.cjsc-modal-body {
    padding: var(--cjsc-pad);
    max-height: 60vh;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: var(--cjsc-gap-sm);
}

.cjsc-review-row {
    padding-bottom: var(--cjsc-pad-sm);
    border-bottom: 1px solid var(--cjsc-border-light);
}

.cjsc-review-row:last-child {
    border-bottom: none;
    padding-bottom: 0;
}

.cjsc-review-row-head {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--cjsc-gap-sm);
}

.cjsc-review-row-message {
    margin: 4px 0 0;
    color: var(--cjsc-text-secondary);
}

/* Badge and "Write a review" trigger sit in one row under the service
   name, both sized to their own content (never the card's full width -
   the same align-self:flex-start fix .cjsc-dashboard-service-row above
   documents, needed again here for the same reason: any child of a
   flex-column card inherits align-items:stretch unless it opts out). */
.cjsc-service-card-rating-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--cjsc-gap-sm);
}

/* 3.4.13, independently peer-verified at 375px width: both of these
   measured 17px tall (the text's own line box, padding:0), well under the
   ~44px real-fingertip touch-target floor - and both are the PRIMARY
   call-to-action on a service card, not a minor secondary link. Same
   floor already applied to the half-star widget (design-system.md Lesson
   21), just never extended to a native text button. Padding expands the
   real clickable/tappable area; the matching negative margin cancels the
   padding's effect on layout, so the row's own spacing/alignment does not
   visibly change - only the invisible hit area grows. */
.cjsc-rating-badge-btn {
    background: none;
    border: none;
    padding: 13px 4px;
    margin: -13px -4px;
    cursor: pointer;
    font-family: inherit;
}

.cjsc-write-review-link {
    background: none;
    border: none;
    padding: 13px 4px;
    margin: -13px -4px;
    cursor: pointer;
    font-family: inherit;
    font-size: var(--cjsc-fs-sm);
    font-weight: var(--cjsc-weight-buttons);
    color: var(--cjsc-link);
}

.cjsc-star-widget {
    display: flex;
    gap: 6px;
}

/* 40px, not the 32px this shipped with initially: half of a 32px star is a
   16px-wide tap target, well under the ~44px minimum a real fingertip can
   hit precisely - the half-star click precision (see cjsc-reviews.js) only
   actually works with a mouse at that size. 40px keeps 5 stars comfortable
   on any phone width (5x40 + 4x6 gap = 224px) while giving each half a
   fighting chance on touch. */
.cjsc-star {
    position: relative;
    display: inline-block;
    width: 40px;
    height: 40px;
    font-size: 40px;
    line-height: 1;
    cursor: pointer;
}

.cjsc-star-empty {
    color: var(--cjsc-border);
}

/* Admin-only "here's the URL, copy it yourself" panel (Service Types list
   screen) - this addon deliberately never edits the storefront's own
   menus/CMS, so this is the discovery mechanism for a page with no
   in-store link otherwise. */
.cjsc-registration-link-row {
    display: flex;
    gap: var(--cjsc-gap-sm);
    align-items: center;
}

.cjsc-registration-link-row .cjsc-input {
    flex: 1;
}

.cjsc-star-fill {
    position: absolute;
    top: 0;
    left: 0;
    width: 0;
    height: 100%;
    overflow: hidden;
    color: var(--cjsc-warning);
    pointer-events: none;
    white-space: nowrap;
}

/* ==========================================================================
   PUBLIC PAGE STRUCTURE
   --------------------------------------------------------------------------
   Everything below applies only inside .cjsc-storefront.

   The addon's public pages used to be built from one shape: a bordered,
   rounded, elevated box, used for the page title, for each section, and for
   each item inside those sections. The host builds its pages from a
   different shape: a stack of unboxed bands, each 30px of vertical padding,
   separated by a heading and by space — and it puts boxes only around
   things that are genuinely comparable items, like a card in a grid.

   These are the band, the heading, the intro paragraph and the content
   patterns (numbered steps, benefit points, a status timeline) those pages
   need, so that a section can be a section without being a box.
   ========================================================================== */

/* A band. The host's own sections are 30px top and bottom, no background,
   no border. --space-m is the storefront's own 30px step; the fallback is
   for the admin, which publishes no spacing scale (and never uses this). */
.cjsc-storefront .cjsc-section {
    padding: var(--space-m, 30px) 0;
}

.cjsc-storefront .cjsc-section:first-child {
    padding-top: 0;
}

.cjsc-storefront .cjsc-section + .cjsc-section {
    border-top: 1px solid var(--cjsc-border-light);
}

/* Section heading. Steps down from the platform's own page title (which the
   templates now render through ty-mainbox-title) using the theme's large
   type size, and stays at weight 400 because the host's headings are not
   bold — its page titles measure 28px/400, where a bare h2 in the same
   theme measures 28px/700. */
.cjsc-storefront .cjsc-section-title {
    margin: 0 0 var(--space-xs, 10px);
    font-family: var(--cjsc-font-headings);
    font-size: var(--cjsc-fs-lg);
    font-weight: 400;
    line-height: 1.3;
    color: var(--cjsc-text);
}

/* Title row: heading left, controls right — the host's own section-header
   pattern. */
.cjsc-storefront .cjsc-section-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--cjsc-gap-sm);
    margin-bottom: var(--space-xs, 10px);
}

.cjsc-storefront .cjsc-section-head .cjsc-section-title {
    margin-bottom: 0;
}

/* The sentence under a page title. A paragraph, not a subtitle inside a
   header box. */
.cjsc-storefront .cjsc-lead {
    max-width: 70ch;
    margin: 0 0 var(--space-s, 20px);
    font-size: var(--cjsc-fs-md);
    line-height: 1.55;
    color: var(--cjsc-text-secondary);
}

/* The page title itself is the platform's h1.ty-mainbox-title, so it needs
   no rule here. This only closes the gap the templates left when they
   stopped drawing their own header box: the title sat 6px above its
   subtitle, where every other page on the store leaves 10px. */
.cjsc-storefront .ty-mainbox-title {
    margin-bottom: var(--space-xs, 10px);
}

/* Numbered steps — "how it works". Numbers come from a counter rather than
   from the markup, so the sequence cannot go out of order when a step is
   added or removed. */
.cjsc-storefront .cjsc-steps {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: var(--cjsc-gap);
    margin: 0;
    padding: 0;
    list-style: none;
    counter-reset: cjsc-step;
}

.cjsc-storefront .cjsc-step {
    counter-increment: cjsc-step;
    padding-top: var(--space-xs, 10px);
    border-top: 2px solid var(--cjsc-primary);
}

.cjsc-storefront .cjsc-step::before {
    content: counter(cjsc-step);
    display: block;
    margin-bottom: 4px;
    font-family: var(--cjsc-font-headings);
    font-size: var(--cjsc-fs-sm);
    font-weight: 700;
    color: var(--cjsc-primary);
}

.cjsc-storefront .cjsc-step-title {
    display: block;
    margin-bottom: 2px;
    font-weight: 600;
    color: var(--cjsc-text);
}

.cjsc-storefront .cjsc-step-text {
    display: block;
    font-size: var(--cjsc-fs-base);
    line-height: 1.5;
    color: var(--cjsc-text-secondary);
}

/* Benefit points. Same grid, no numbering, a check in the brand colour —
   the same tick the pricing table already uses for plan features, so the
   two pages agree about what "included" looks like. */
.cjsc-storefront .cjsc-points {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: var(--cjsc-gap-sm) var(--cjsc-gap);
    margin: 0;
    padding: 0;
    list-style: none;
}

.cjsc-storefront .cjsc-point {
    display: flex;
    align-items: flex-start;
    gap: var(--cjsc-gap-sm);
    font-size: var(--cjsc-fs-base);
    line-height: 1.5;
    color: var(--cjsc-text);
}

.cjsc-storefront .cjsc-point-icon {
    flex: 0 0 auto;
    color: var(--cjsc-primary);
}

/* Form pages. The platform's own application form is a half-width column
   with a short supporting panel beside it (companies.apply_for_vendor
   renders in span8, 678px of 1385px). These pages ran the full width, which
   put a 1343px-wide message textarea on the booking page — no form anywhere
   else on the store is anything like that wide. */
.cjsc-storefront .cjsc-form-layout {
    display: grid;
    /* Two equal columns, which is literally the platform's own arrangement:
       companies.apply_for_vendor renders as span8 + span8, 678px each in a
       1385px content area. Matching the ratio rather than inventing one is
       what makes the two application forms read as the same store. */
    grid-template-columns: minmax(0, 1fr) minmax(240px, 1fr);
    gap: var(--space-m, 30px);
    align-items: start;
}

@media (max-width: 979px) {
    .cjsc-storefront .cjsc-form-layout {
        grid-template-columns: 1fr;
    }
}

/* The supporting column: what you are buying, or what you are booking. */
.cjsc-storefront .cjsc-aside {
    background: var(--cjsc-card-bg);
    border: 1px solid var(--cjsc-card-border);
    border-radius: var(--cjsc-radius);
    padding: var(--cjsc-pad);
}

.cjsc-storefront .cjsc-aside-title {
    margin: 0 0 var(--space-xs, 10px);
    font-family: var(--cjsc-font-headings);
    font-size: var(--cjsc-fs-base);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--cjsc-text-secondary);
}

.cjsc-storefront .cjsc-aside-price {
    font-family: var(--cjsc-font-price);
    font-size: var(--cjsc-fs-xl);
    font-weight: var(--cjsc-weight-price);
    color: var(--cjsc-text);
}

/* A status page is a definition list, not a box: label above value, in
   columns, the way an order summary reads. */
.cjsc-storefront .cjsc-facts {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: var(--cjsc-gap);
    margin: 0;
}

.cjsc-storefront .cjsc-facts dt {
    margin: 0 0 2px;
    font-size: var(--cjsc-fs-sm);
    color: var(--cjsc-text-secondary);
}

.cjsc-storefront .cjsc-facts dd {
    margin: 0;
    font-size: var(--cjsc-fs-base);
    color: var(--cjsc-text);
}

/* Request timeline. The addon already knows every state a request passes
   through; the status page used to print only the current one as a badge,
   which answers "what is it now" and never "what happens next". */
.cjsc-storefront .cjsc-timeline {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
    gap: var(--cjsc-gap-sm);
    margin: 0 0 var(--space-s, 20px);
    padding: 0;
    list-style: none;
}

.cjsc-storefront .cjsc-timeline-step {
    padding-top: var(--space-xs, 10px);
    border-top: 3px solid var(--cjsc-border);
    font-size: var(--cjsc-fs-sm);
    color: var(--cjsc-text-muted);
}

.cjsc-storefront .cjsc-timeline-step--done {
    border-top-color: var(--cjsc-primary);
    color: var(--cjsc-text-secondary);
}

.cjsc-storefront .cjsc-timeline-step--current {
    border-top-color: var(--cjsc-primary);
    font-weight: 700;
    color: var(--cjsc-text);
}

.cjsc-storefront .cjsc-timeline-step--cancelled {
    border-top-color: var(--cjsc-danger);
    font-weight: 700;
    color: var(--cjsc-danger);
}

/* The one action a customer ever has to take on a status page (confirming
   receipt) gets a band of its own, so it cannot be mistaken for more status
   text. */
.cjsc-storefront .cjsc-action-band {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--cjsc-gap);
    padding: var(--cjsc-pad);
    background: var(--cjsc-card-bg);
    border-radius: var(--cjsc-radius);
}

.cjsc-storefront .cjsc-action-band p {
    margin: 0;
    max-width: 60ch;
    color: var(--cjsc-text-secondary);
}

/* An empty state is a real page state here, not an edge case: on a store
   whose directory has just opened, every service type has no providers yet,
   so this is the page most visitors will actually see. */
.cjsc-storefront .cjsc-empty {
    padding: var(--space-l, 40px) var(--cjsc-pad);
    background: var(--cjsc-card-bg);
    border-radius: var(--cjsc-radius);
    text-align: center;
}

.cjsc-storefront .cjsc-empty-icon {
    font-size: var(--cjsc-fs-display);
    color: var(--cjsc-text-muted);
}

.cjsc-storefront .cjsc-empty-text {
    max-width: 60ch;
    margin: 0 auto var(--space-s, 20px);
}
