/* ============================================================
   JS Jobs — Showcase modules/plugins stylesheet (token-based).
   Self-contained: modules render OUTSIDE #js_jobs_main_wrapper, so the
   design tokens are (re)declared on .jsjobs-showcase with the same
   palette as jsjobs-modern-tokens.css. Zero !important by design.
   One design system for every extension; sources differ by accents:
   gold border/pill, featured pill, hot/top stat chips.
   ============================================================ */

.jsjobs-showcase {
    --jsx-primary: #4f46e5;
    --jsx-primary-soft: #eef2ff;
    --jsx-ink: #111827;
    --jsx-text: #374151;
    --jsx-muted: #6b7280;
    --jsx-border: #e5e7eb;
    --jsx-border-soft: #eef0f3;
    --jsx-surface: #ffffff;
    --jsx-surface-muted: #f3f4f6;
    --jsx-gold: #b45309;
    --jsx-gold-soft: #fef3c7;
    --jsx-gold-border: #f59e0b;
    --jsx-success: #16a34a;
    --jsx-radius: 14px;
    --jsx-radius-sm: 8px;
    --jsx-shadow: 0 1px 2px rgba(17, 24, 39, .06);
    --jsx-shadow-hover: 0 10px 24px rgba(17, 24, 39, .10);

    font-size: var(--jsx-font, 14px);
    line-height: 1.5;
    color: var(--jsx-text);
}

/* ---------- list container ---------- */
.jsjobs-showcase__list {
    display: flex;
    flex-direction: column;
    gap: var(--jsx-gap, 12px);
    margin: 0;
    padding: 0;
    list-style: none;
}
/* Grid layout ("Columns" setting).
   The track floor is what keeps the setting honest: the requested number of
   columns once there is room for them, fewer as soon as a column would drop
   under 210px. It has to be measured against the CONTAINER (100%), not the
   viewport: this used to be repeat(N, minmax(0, 1fr)) with @media (max-width)
   collapses, and a media query asks how wide the WINDOW is. A 284px sidebar on
   a 1400px desktop tripped none of them, so a 3-column resume grid rendered
   three 85px-wide, 428px-tall slivers. Same technique as the browse-by tiles.
   First declaration is the fallback for engines without max()/calc() in
   minmax(). */
.jsjobs-showcase--grid .jsjobs-showcase__list {
    display: grid;
    --jsx-card-gap: var(--jsx-gap, 14px);
    --jsx-card-cols: 2;
    grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
    grid-template-columns: repeat(auto-fill, minmax(max(210px, calc((100% - (var(--jsx-card-cols) - 1) * var(--jsx-card-gap)) / var(--jsx-card-cols))), 1fr));
    gap: var(--jsx-card-gap);
}
.jsjobs-showcase--grid .jsjobs-showcase__cols-3 { --jsx-card-cols: 3; }
.jsjobs-showcase--grid .jsjobs-showcase__cols-4 { --jsx-card-cols: 4; }
/* Phones: one profile per row regardless of how wide the floor would allow. */
@media (max-width: 560px) {
    .jsjobs-showcase--grid .jsjobs-showcase__list,
    .jsjobs-showcase--grid .jsjobs-showcase__cols-3,
    .jsjobs-showcase--grid .jsjobs-showcase__cols-4 { grid-template-columns: 1fr; }
}

/* ---------- card ----------
   The card is its own container so narrow-card rules can key off the space the
   card actually has. A viewport media query is the wrong tool here: in a 3-column
   grid on a wide screen the module is wide but each CELL is ~340px, so the query
   never fires and the row layout overflows. Naming the container (jsjobs-card)
   keeps it distinct from the module-level `jsjobs-showcase` container. */
.jsjobs-showcase__card {
    display: flex;
    flex-wrap: wrap;
    container-type: inline-size;
    container-name: jsjobs-card;
    gap: var(--jsx-gap, 14px);
    align-items: flex-start;
    padding: var(--jsx-pad, 16px);
    background: var(--jsx-surface);
    border: 1px solid var(--jsx-border-soft);
    border-radius: var(--jsx-radius);
    box-shadow: var(--jsx-shadow);
    transition: box-shadow .18s ease, transform .18s ease, border-color .18s ease;
}
.jsjobs-showcase__card:hover {
    transform: translateY(-2px);
    box-shadow: var(--jsx-shadow-hover);
    border-color: var(--jsx-border);
}
/* Gold accent: warm left edge */
.jsjobs-showcase__card.is-gold {
    border-left: 3px solid var(--jsx-gold-border);
}

/* compact layout: tighter rows, no logo column.
   The spacing is declared as tokens on the WRAPPER rather than as padding on
   the card, so the "Spacing" styling option - which lands inline on that same
   element - overrides it instead of losing to it. */
.jsjobs-showcase--compact { --jsx-pad: 10px 14px; --jsx-gap: 8px; }
.jsjobs-showcase--compact .jsjobs-showcase__card { border-radius: var(--jsx-radius-sm); }

/* ---------- logo / avatar ---------- */
.jsjobs-showcase__logo {
    flex: 0 0 52px;
    width: 52px;
    height: 52px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    border: 1px solid var(--jsx-border-soft);
    border-radius: var(--jsx-radius-sm);
    background: var(--jsx-surface);
    text-decoration: none;
}
.jsjobs-showcase__logo img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}
.jsjobs-showcase__avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    background: var(--jsx-primary-soft);
    color: var(--jsx-primary);
    font-size: calc(var(--jsx-fs, 1) * 20px);
    font-weight: 800;
}

/* ---------- body ----------
   min-width was 0, which let the text column collapse to nothing whenever the
   non-shrinkable CTA claimed the width - the company name then broke mid-word
   ("Solutio / n"). A floor of 170px makes the flex row wrap the CTA onto its own
   line instead; min() keeps the card usable if it is ever narrower than that. */
.jsjobs-showcase__body { flex: 1 1 auto; min-width: min(100%, 170px); }

.jsjobs-showcase__topline {
    display: flex;
    align-items: baseline;
    gap: 8px;
    flex-wrap: wrap;
}
.jsjobs-showcase__title {
    color: var(--jsx-ink);
    font-size: calc(var(--jsx-fs, 1) * 15px);
    font-weight: 700;
    text-decoration: none;
    /* break-word, not anywhere: only split a word when it genuinely cannot fit,
       so a name wraps between words first. */
    overflow-wrap: break-word;
}
.jsjobs-showcase__title:hover { color: var(--jsx-primary); text-decoration: none; }

/* Never shrink the badge strip - it was being squeezed to "F...". The title
   wraps instead, which is the readable trade. */
.jsjobs-showcase__badges { display: inline-flex; flex: 0 0 auto; gap: 6px; }
.jsjobs-showcase__badge {
    display: inline-flex;
    align-items: center;
    padding: 2px 9px;
    border-radius: 999px;
    font-size: calc(var(--jsx-fs, 1) * 10.5px);
    font-weight: 800;
    letter-spacing: .03em;
    text-transform: uppercase;
}
.jsjobs-showcase__badge--gold { background: var(--jsx-gold-soft); color: var(--jsx-gold); }
.jsjobs-showcase__badge--featured { background: var(--jsx-primary-soft); color: var(--jsx-primary); }

.jsjobs-showcase__company {
    margin-top: 2px;
    color: var(--jsx-muted);
    font-size: calc(var(--jsx-fs, 1) * 13px);
    font-weight: 600;
}

/* ---------- meta line ---------- */
.jsjobs-showcase__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 14px;
    margin-top: 8px;
    color: var(--jsx-muted);
    font-size: calc(var(--jsx-fs, 1) * 12.5px);
}
.jsjobs-showcase__meta-item { display: inline-flex; align-items: center; gap: 4px; }
.jsjobs-showcase__icon { flex: 0 0 auto; opacity: .75; }
.jsjobs-showcase__chip {
    display: inline-flex;
    align-items: center;
    padding: 2px 10px;
    border: 1px solid var(--jsx-border);
    border-radius: 999px;
    background: var(--jsx-surface-muted);
    color: var(--jsx-text);
    font-size: calc(var(--jsx-fs, 1) * 11.5px);
    font-weight: 700;
}
.jsjobs-showcase__salary { color: var(--jsx-success); font-weight: 700; }
.jsjobs-showcase__stat {
    display: inline-flex;
    align-items: center;
    padding: 2px 10px;
    border-radius: 999px;
    background: var(--jsx-primary-soft);
    color: var(--jsx-primary);
    font-size: calc(var(--jsx-fs, 1) * 11.5px);
    font-weight: 700;
}

/* ---------- companies variant: brand-forward silhouette ----------
   Same family, different shape: round larger logo, "Since YYYY", and the
   open-jobs count as a right-side CTA pill instead of a meta chip. */
.jsjobs-showcase--companies .jsjobs-showcase__card { align-items: center; }
.jsjobs-showcase--companies .jsjobs-showcase__logo {
    flex-basis: 64px;
    width: 64px;
    height: 64px;
    border-radius: 999px;
}
.jsjobs-showcase--companies .jsjobs-showcase__avatar { font-size: calc(var(--jsx-fs, 1) * 24px); }
.jsjobs-showcase__aside {
    flex: 0 1 auto;
    display: inline-flex;
    align-items: center;
    align-self: center;
    margin-inline-start: auto;
}
.jsjobs-showcase__cta {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 8px 16px;
    border: 1px solid var(--jsx-border);
    border-radius: 999px;
    background: var(--jsx-surface);
    color: var(--jsx-primary);
    font-size: calc(var(--jsx-fs, 1) * 12.5px);
    font-weight: 700;
    text-decoration: none;
    white-space: nowrap;
    transition: background .18s ease, border-color .18s ease, color .18s ease;
}
.jsjobs-showcase__cta:hover {
    background: var(--jsx-primary);
    border-color: var(--jsx-primary);
    color: #fff;
    text-decoration: none;
}
/* Narrow CARD (grid cell, sidebar, or a plugin inside a narrow article column):
   the open-jobs CTA drops onto its own full-width line under the logo + name
   instead of competing with them for the row. Replaces a max-width:560px media
   query that could not see the cell width in a multi-column grid. */
@container jsjobs-card (max-width: 400px) {
    .jsjobs-showcase__aside {
        flex: 1 1 100%;
        margin-inline-start: 0;
        margin-top: 4px;
    }
    .jsjobs-showcase__aside .jsjobs-showcase__cta {
        width: 100%;
        justify-content: center;
    }
}

/* ---------- resumes variant: candidate profile tile ----------
   Third silhouette: vertical centered card — round photo with a live
   availability dot, name + headline, centered meta, View Resume button.
   Gold accent moves to the TOP edge on tiles. */
.jsjobs-showcase__card--profile {
    flex-direction: column;
    align-items: center;
    gap: 8px;
    padding: 22px 16px 16px;
    text-align: center;
}
.jsjobs-showcase__card--profile.is-gold {
    border-left: 1px solid var(--jsx-border-soft);
    border-top: 3px solid var(--jsx-gold-border);
}
.jsjobs-showcase__photo {
    position: relative;
    width: 72px;
    height: 72px;
}
.jsjobs-showcase__photo > a {
    display: block;
    width: 100%;
    height: 100%;
    overflow: hidden;
    border: 2px solid var(--jsx-border-soft);
    border-radius: 999px;
    background: var(--jsx-surface);
}
.jsjobs-showcase__photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}
.jsjobs-showcase__photo .jsjobs-showcase__avatar {
    border-radius: 999px;
    font-size: calc(var(--jsx-fs, 1) * 26px);
}
.jsjobs-showcase__presence {
    position: absolute;
    right: 2px;
    bottom: 2px;
    width: 15px;
    height: 15px;
    border: 2.5px solid var(--jsx-surface);
    border-radius: 999px;
    background: #9ca3af;
}
.jsjobs-showcase__presence.is-on { background: #22c55e; }
.jsjobs-showcase__card--profile .jsjobs-showcase__topline { justify-content: center; }
.jsjobs-showcase__headline {
    color: var(--jsx-muted);
    font-size: calc(var(--jsx-fs, 1) * 12.5px);
    font-weight: 600;
}
.jsjobs-showcase__card--profile .jsjobs-showcase__meta {
    justify-content: center;
    margin-top: 4px;
}
.jsjobs-showcase__cta--wide {
    margin-top: 8px;
    align-self: stretch;
    justify-content: center;
}

/* ---------- browse-by variant: link tiles with live counts ----------
   Fourth silhouette: a responsive grid of pill links (category / city /
   state / country) with a job-count badge that lights up on hover. */
/* Heading for the browse-by PLUGINS ("Title" + "Show Title" params). Modules
   never set these - Joomla's module chrome draws their heading. */
.jsjobs-showcase__heading {
    margin: 0 0 12px;
    color: var(--jsx-heading, var(--jsx-ink));
    font-size: calc(var(--jsx-fs, 1) * 16px);
    font-weight: 800;
    line-height: 1.3;
}
.jsjobs-showcase__links {
    display: grid;
    --jsx-browse-gap: var(--jsx-gap, 10px);
    grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
    gap: var(--jsx-browse-gap);
    margin: 0;
    padding: 0;
    list-style: none;
}
/* "Column Per Row". Gated behind a class the renderer only adds when the
   setting is actually set: an unset (0) count would make the division below
   invalid at computed-value time, and that resolves to `none` rather than
   falling back to the declaration above. Same floor trick as the search
   widget - exactly N columns when there is room, fewer once a column would get
   too narrow, so the setting never breaks a sidebar. */
.jsjobs-showcase--cols .jsjobs-showcase__links {
    grid-template-columns: repeat(auto-fill, minmax(max(150px, calc((100% - (var(--jsx-browse-cols) - 1) * var(--jsx-browse-gap)) / var(--jsx-browse-cols))), 1fr));
}

/* "Show the line separator = No": drop the tile chrome for a plain list. */
.jsjobs-showcase--flat .jsjobs-showcase__link {
    border-color: transparent;
    background: transparent;
    box-shadow: none;
    padding-inline: 2px;
}
.jsjobs-showcase--flat .jsjobs-showcase__link:hover {
    transform: none;
    border-color: transparent;
    box-shadow: none;
}
.jsjobs-showcase__link {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: var(--jsx-pad, 11px 14px);
    border: 1px solid var(--jsx-border-soft);
    border-radius: var(--jsx-radius-sm);
    background: var(--jsx-surface);
    box-shadow: var(--jsx-shadow);
    color: var(--jsx-text);
    font-size: calc(var(--jsx-fs, 1) * 13px);
    font-weight: 600;
    text-decoration: none;
    transition: border-color .18s ease, box-shadow .18s ease, transform .18s ease;
}
.jsjobs-showcase__link:hover {
    transform: translateY(-1px);
    border-color: var(--jsx-primary);
    box-shadow: var(--jsx-shadow-hover);
    color: var(--jsx-primary);
    text-decoration: none;
}
.jsjobs-showcase__link-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.jsjobs-showcase__count {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 26px;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--jsx-surface-muted);
    color: var(--jsx-muted);
    font-size: calc(var(--jsx-fs, 1) * 11.5px);
    font-weight: 700;
    transition: background .18s ease, color .18s ease;
}
.jsjobs-showcase__link:hover .jsjobs-showcase__count {
    background: var(--jsx-primary-soft);
    color: var(--jsx-primary);
}

/* ============================================================
   Utility widgets (search / resume search / login / stats / map)
   Same token family; namespace .jsjobs-widget.
   ============================================================ */
.jsjobs-widget {
    --jsx-primary: #4f46e5;
    --jsx-primary-soft: #eef2ff;
    --jsx-ink: #111827;
    --jsx-text: #374151;
    --jsx-muted: #6b7280;
    --jsx-border: #e5e7eb;
    --jsx-border-soft: #eef0f3;
    --jsx-surface: #ffffff;
    --jsx-surface-muted: #f3f4f6;
    --jsx-radius: 14px;
    --jsx-radius-sm: 8px;
    --jsx-shadow: 0 1px 2px rgba(17, 24, 39, .06);

    display: block;
    padding: var(--jsx-pad, 18px);
    border: 1px solid var(--jsx-border-soft);
    border-radius: var(--jsx-radius);
    background: var(--jsx-surface);
    box-shadow: var(--jsx-shadow);
    color: var(--jsx-text);
    font-size: var(--jsx-font, 14px);
    line-height: 1.5;
}

/* Heading for the search PLUGINS ("Title" + "Show Title" params). Modules leave
   these empty - Joomla's module chrome draws their heading. */
.jsjobs-widget__heading {
    margin: 0 0 14px;
    color: var(--jsx-heading, var(--jsx-ink));
    font-size: calc(var(--jsx-fs, 1) * 16px);
    font-weight: 800;
    line-height: 1.3;
}

/* form grid
   --jsx-widget-cols comes from the module's "Column Per Row" setting (inline on
   the wrapper). The track floor keeps that honest: the requested number of
   columns at full width, fewer once a column would drop under 170px, so the
   setting works without breaking the form in a narrow sidebar.
   First declaration is the fallback for engines without calc()-in-minmax. */
.jsjobs-widget__fields {
    display: grid;
    --jsx-widget-gap: 14px;
    grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    grid-template-columns: repeat(auto-fill, minmax(max(170px, calc((100% - (var(--jsx-widget-cols, 3) - 1) * var(--jsx-widget-gap)) / var(--jsx-widget-cols, 3))), 1fr));
    gap: var(--jsx-gap, 12px) var(--jsx-widget-gap);
}
.jsjobs-widget__field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }

/* Two controls that belong to one label - salary from/to, currency + salary
   type, experience min/max. The models return them as separate <select>s, and
   with the widget's width:100% they stacked vertically under the label. */
.jsjobs-widget__pair { display: flex; align-items: center; gap: 8px; min-width: 0; }
.jsjobs-widget__pair > * { flex: 1 1 0; min-width: 0; }
.jsjobs-widget__pair select,
.jsjobs-widget__pair input { width: 100%; }
.jsjobs-widget__label {
    color: var(--jsx-ink);
    font-size: calc(var(--jsx-fs, 1) * 12.5px);
    font-weight: 700;
}
.jsjobs-widget__field input[type="text"],
.jsjobs-widget__field input[type="password"],
.jsjobs-widget__field select,
.jsjobs-widget__field .inputbox {
    width: 100%;
    min-height: 40px;
    padding: 8px 12px;
    border: 1px solid var(--jsx-border);
    border-radius: var(--jsx-radius-sm);
    background: var(--jsx-surface);
    color: var(--jsx-ink);
    font-size: calc(var(--jsx-fs, 1) * 13px);
    box-sizing: border-box;
}
.jsjobs-widget__field input:focus,
.jsjobs-widget__field select:focus {
    outline: none;
    border-color: var(--jsx-primary);
    box-shadow: 0 0 0 3px rgba(79, 70, 229, .15);
}
.jsjobs-widget__check {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    color: var(--jsx-text);
    font-size: calc(var(--jsx-fs, 1) * 13px);
    font-weight: 600;
}
.jsjobs-widget__check input[type="checkbox"] { width: 16px; height: 16px; accent-color: var(--jsx-primary); }
/* Match the height of a real control so the checkbox lines up with its row. */
.jsjobs-widget__field .jsjobs-widget__check { min-height: 40px; }

/* Calendar fields (start/stop publishing). HTMLHelper 'calendar' emits a
   Bootstrap .input-group, but Bootstrap's CSS is not part of the widget's token
   stack - so the input took the full row and the trigger button dropped onto
   the next line. Lay the group out ourselves and style the button to match. */
.jsjobs-widget__field .field-calendar { width: 100%; min-width: 0; }
.jsjobs-widget__field .input-group {
    display: flex;
    align-items: stretch;
    width: 100%;
    min-width: 0;
}
.jsjobs-widget__field .input-group > input {
    flex: 1 1 auto;
    width: auto;
    min-width: 0;
    border-start-end-radius: 0;
    border-end-end-radius: 0;
}
.jsjobs-widget__field .input-group > button,
.jsjobs-widget__field .input-group > .btn {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 40px;
    padding: 0 12px;
    border: 1px solid var(--jsx-border);
    border-inline-start: 0;
    border-start-end-radius: var(--jsx-radius-sm);
    border-end-end-radius: var(--jsx-radius-sm);
    background: var(--jsx-surface-muted);
    color: var(--jsx-text);
    font-size: calc(var(--jsx-fs, 1) * 13px);
    cursor: pointer;
}
.jsjobs-widget__field .input-group > button:hover,
.jsjobs-widget__field .input-group > .btn:hover {
    background: var(--jsx-primary-soft);
    color: var(--jsx-primary);
}

/* actions */
.jsjobs-widget__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    margin-top: 16px;
}
.jsjobs-widget__btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    min-height: 42px;
    padding: 0 22px;
    border: 1px solid transparent;
    border-radius: var(--jsx-radius-sm);
    background: var(--jsx-primary);
    color: #fff;
    font-size: calc(var(--jsx-fs, 1) * 13.5px);
    font-weight: 700;
    text-decoration: none;
    cursor: pointer;
    transition: filter .18s ease, transform .18s ease;
}
.jsjobs-widget__btn:hover { filter: brightness(.94); transform: translateY(-1px); color: #fff; text-decoration: none; }
.jsjobs-widget__btn--ghost {
    background: var(--jsx-surface);
    border-color: var(--jsx-border);
    color: var(--jsx-primary);
}
.jsjobs-widget__btn--ghost:hover { background: var(--jsx-primary-soft); filter: none; }

/* links row (login: forgot / register) */
.jsjobs-widget__links {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 16px;
    margin: 14px 0 0;
    padding: 12px 0 0;
    border-top: 1px solid var(--jsx-border-soft);
    list-style: none;
}
.jsjobs-widget__links a {
    color: var(--jsx-muted);
    font-size: calc(var(--jsx-fs, 1) * 12.5px);
    font-weight: 600;
    text-decoration: none;
}
.jsjobs-widget__links a:hover { color: var(--jsx-primary); }
.jsjobs-widget__greeting { margin-bottom: 12px; color: var(--jsx-ink); font-weight: 700; }

/* stats tiles */
.jsjobs-widget--stats { padding: 0; border: 0; background: transparent; box-shadow: none; }
.jsjobs-stats-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: var(--jsx-gap, 12px);
    margin: 0;
    padding: 0;
    list-style: none;
}
.jsjobs-stats-grid li {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: var(--jsx-pad, 16px);
    padding-inline-start: 20px;
    border: 1px solid var(--jsx-border-soft);
    border-radius: var(--jsx-radius, 14px);
    background: var(--jsx-surface);
    box-shadow: var(--jsx-shadow);
}
.jsjobs-stats-grid li::before {
    content: "";
    position: absolute;
    left: 0;
    top: 12px;
    bottom: 12px;
    width: 4px;
    border-radius: 999px;
    background: #4f46e5;
}
.jsjobs-stats-grid li:nth-child(2)::before { background: #16a34a; }
.jsjobs-stats-grid li:nth-child(3)::before { background: #f59e0b; }
.jsjobs-stats-grid li:nth-child(4)::before { background: #db2777; }
.jsjobs-stats-grid li:nth-child(5)::before { background: #0ea5e9; }
.jsjobs-stats-grid li:nth-child(6)::before { background: #7c3aed; }
.jsjobs-stats-grid .jsjobs-stats-num {
    color: var(--jsx-ink);
    font-size: calc(var(--jsx-fs, 1) * 26px);
    font-weight: 900;
    line-height: 1.1;
    letter-spacing: -.02em;
}
.jsjobs-stats-grid .jsjobs-stats-label { color: var(--jsx-muted); font-size: calc(var(--jsx-fs, 1) * 12.5px); font-weight: 600; }

/* map */
.jsjobs-widget--map { padding: 8px; }
.jsjobs-widget--map .map-canvas-module { border-radius: 10px; overflow: hidden; }

/* ---------- RTL flips ----------
   Flex/grid auto-flip with dir="rtl"; only physical properties here. */
[dir="rtl"] .jsjobs-showcase__card.is-gold {
    border-left: 1px solid var(--jsx-border-soft);
    border-right: 3px solid var(--jsx-gold-border);
}
[dir="rtl"] .jsjobs-showcase__card--profile.is-gold {
    border-right: 1px solid var(--jsx-border-soft);
    border-left: 1px solid var(--jsx-border-soft);
    border-top: 3px solid var(--jsx-gold-border);
}
[dir="rtl"] .jsjobs-showcase__presence { right: auto; left: 2px; }
[dir="rtl"] .jsjobs-stats-grid li::before { left: auto; right: 0; }
/* No RTL override needed for the aside any more - it uses margin-inline-start,
   which already flips with the writing direction. */

/* ---------- empty state ---------- */
.jsjobs-showcase__empty {
    padding: 26px 18px;
    border: 1px dashed var(--jsx-border);
    border-radius: var(--jsx-radius);
    background: var(--jsx-surface);
    color: var(--jsx-muted);
    font-size: calc(var(--jsx-fs, 1) * 13px);
    text-align: center;
}

/* ============================================================
   Package widget (mod_jsjobspackage)
   Pricing cards for employer / job seeker packages. Uses the --jsx-* tokens
   declared on .jsjobs-widget, so it inherits the same palette as every other
   JS Jobs extension and needs no separate stylesheet.
   ============================================================ */
.jsjobs-widget__intro {
    margin: 0 0 12px;
    color: var(--jsx-muted);
    font-size: calc(var(--jsx-fs, 1) * 13px);
    line-height: 1.55;
}

.jsjobs-package__list {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 12px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.jsjobs-package__card {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 16px;
    border: 1px solid var(--jsx-border-soft);
    border-radius: var(--jsx-radius);
    background: var(--jsx-surface);
    box-shadow: var(--jsx-shadow);
}

.jsjobs-package__head {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding-bottom: 10px;
    border-bottom: 1px solid var(--jsx-border-soft);
}
.jsjobs-package__name {
    color: var(--jsx-ink);
    font-size: calc(var(--jsx-fs, 1) * 14px);
    font-weight: 800;
    line-height: 1.3;
}
.jsjobs-package__price {
    color: var(--jsx-primary);
    font-size: calc(var(--jsx-fs, 1) * 22px);
    font-weight: 900;
    line-height: 1.15;
    letter-spacing: -.02em;
}
.jsjobs-package__cur {
    margin-inline-end: 1px;
    font-size: calc(var(--jsx-fs, 1) * 14px);
    font-weight: 800;
    vertical-align: super;
}

.jsjobs-package__features {
    margin: 0;
    padding: 0;
    list-style: none;
}
.jsjobs-package__feature {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    padding: 5px 0;
    font-size: calc(var(--jsx-fs, 1) * 12.5px);
}
.jsjobs-package__feature + .jsjobs-package__feature {
    border-top: 1px solid var(--jsx-border-soft);
}
.jsjobs-package__feature-label { color: var(--jsx-muted); }
.jsjobs-package__feature-value {
    color: var(--jsx-text);
    font-weight: 700;
    white-space: nowrap;
}

.jsjobs-package__note {
    margin: 0;
    color: var(--jsx-muted);
    font-size: calc(var(--jsx-fs, 1) * 12px);
    line-height: 1.5;
}

/* Sidebar positions are narrow - one card per row below this width. */
@media (max-width: 420px) {
    .jsjobs-package__list { grid-template-columns: minmax(0, 1fr); }
}

/* ============================================================
   Profile cards in a WIDE container (resume list at full page width)

   .jsjobs-showcase__card--profile is a centred column, which is right in a grid
   cell and right in a sidebar, but at full page width it left a huge empty gutter
   with the CTA stretched across it. There was no .jsjobs-showcase--list rule at
   all, so "list" and "grid" rendered identically and only the width differed.

   A media query cannot fix this: a sidebar on a 1920px screen is narrow, so the
   viewport tells us nothing about the space the card actually has. Container
   queries measure the module's own width, so the same setting looks right in
   every position. Browsers without @container simply keep the portrait card -
   i.e. today's behaviour, so there is no regression.
   ============================================================ */
.jsjobs-showcase {
    container-type: inline-size;
    container-name: jsjobs-showcase;
}

@container jsjobs-showcase (min-width: 620px) {
    .jsjobs-showcase--list .jsjobs-showcase__card--profile {
        flex-direction: row;
        align-items: center;
        text-align: start;
        gap: 16px;
        padding: 14px 18px;
    }
    /* Name + headline + meta become the flexible middle column. */
    .jsjobs-showcase--list .jsjobs-showcase__card--profile .jsjobs-showcase__topline,
    .jsjobs-showcase--list .jsjobs-showcase__card--profile .jsjobs-showcase__headline,
    .jsjobs-showcase--list .jsjobs-showcase__card--profile .jsjobs-showcase__meta {
        width: auto;
        justify-content: flex-start;
    }
    .jsjobs-showcase--list .jsjobs-showcase__card--profile .jsjobs-showcase__photo {
        flex: 0 0 auto;
    }
    /* Everything except photo and CTA shares one growing column. */
    .jsjobs-showcase--list .jsjobs-showcase__card--profile > :not(.jsjobs-showcase__photo):not(.jsjobs-showcase__cta) {
        align-self: stretch;
    }
    .jsjobs-showcase--list .jsjobs-showcase__card--profile .jsjobs-showcase__topline {
        margin-inline-end: auto;
    }
    /* The CTA sits at the end instead of spanning the card. */
    .jsjobs-showcase--list .jsjobs-showcase__card--profile .jsjobs-showcase__cta--wide {
        width: auto;
        margin-inline-start: auto;
        align-self: center;
        white-space: nowrap;
    }
}

/* One card per row in list layout regardless of the columns setting - "list"
   should not silently inherit a 2/3/4 column grid. */
.jsjobs-showcase--list .jsjobs-showcase__list,
.jsjobs-showcase--list .jsjobs-showcase__cols-3,
.jsjobs-showcase--list .jsjobs-showcase__cols-4 {
    grid-template-columns: minmax(0, 1fr);
}

/* ============================================================
   STYLING OPTIONS
   The "Styling" fieldset that every JS Jobs module/plugin declares. Values
   arrive from classes/showcase/style.php as custom properties (colours and the
   corner/spacing/type scales, applied inline on the wrapper) plus the modifier
   classes below, for the things a property cannot express.

   Everything here is opt-in: an extension whose styling options are untouched
   emits no class and no inline property, so it renders exactly as before.

   Precedence is deliberate. Scales are declared on the WRAPPER so an admin's
   inline choice beats a layout default on the same element; the palette below
   is likewise wrapper-level, so a hand-picked accent (inline) still wins over
   a chosen colour scheme.
   ============================================================ */

/* ---------- colour scheme ---------- */
.jsjobs-showcase.jsx-theme-dark,
.jsjobs-widget.jsx-theme-dark {
    --jsx-primary-soft: #1e1b4b;
    --jsx-ink: #f3f4f6;
    --jsx-text: #d1d5db;
    --jsx-muted: #9ca3af;
    --jsx-border: #374151;
    --jsx-border-soft: #2b3444;
    --jsx-surface: #111827;
    --jsx-surface-muted: #1f2937;
    --jsx-gold-soft: #3b2f0b;
    --jsx-gold: #fbbf24;
    --jsx-shadow: 0 1px 2px rgba(0, 0, 0, .5);
    --jsx-shadow-hover: 0 10px 24px rgba(0, 0, 0, .55);
}
/* "Follow the visitor's device" - same palette, only when the OS asks for it. */
@media (prefers-color-scheme: dark) {
    .jsjobs-showcase.jsx-theme-auto,
    .jsjobs-widget.jsx-theme-auto {
        --jsx-primary-soft: #1e1b4b;
        --jsx-ink: #f3f4f6;
        --jsx-text: #d1d5db;
        --jsx-muted: #9ca3af;
        --jsx-border: #374151;
        --jsx-border-soft: #2b3444;
        --jsx-surface: #111827;
        --jsx-surface-muted: #1f2937;
        --jsx-gold-soft: #3b2f0b;
        --jsx-gold: #fbbf24;
        --jsx-shadow: 0 1px 2px rgba(0, 0, 0, .5);
        --jsx-shadow-hover: 0 10px 24px rgba(0, 0, 0, .55);
    }
}

/* ---------- container style ----------
   One vocabulary across the four panel silhouettes: job/company/resume cards,
   browse-by tiles, stat tiles, and the widget panel itself. */
.jsx-frame-elevated .jsjobs-showcase__card,
.jsx-frame-elevated .jsjobs-showcase__link,
.jsx-frame-elevated .jsjobs-stats-grid li,
.jsx-frame-elevated .jsjobs-package__card,
.jsjobs-widget.jsx-frame-elevated {
    border: 1px solid var(--jsx-border-soft);
    box-shadow: var(--jsx-shadow);
}
.jsx-frame-bordered .jsjobs-showcase__card,
.jsx-frame-bordered .jsjobs-showcase__link,
.jsx-frame-bordered .jsjobs-stats-grid li,
.jsx-frame-bordered .jsjobs-package__card,
.jsjobs-widget.jsx-frame-bordered {
    border: 1px solid var(--jsx-border);
    box-shadow: none;
}
.jsx-frame-plain .jsjobs-showcase__card,
.jsx-frame-plain .jsjobs-showcase__link,
.jsx-frame-plain .jsjobs-stats-grid li,
.jsx-frame-plain .jsjobs-package__card,
.jsjobs-widget.jsx-frame-plain {
    border: 0;
    background: transparent;
    box-shadow: none;
}
/* The stats module's panel is deliberately chrome-less - its TILES carry the
   frame - so a container choice must not draw a second box around the grid. */
.jsjobs-widget--stats.jsx-frame-elevated,
.jsjobs-widget--stats.jsx-frame-bordered,
.jsjobs-widget--stats.jsx-frame-plain {
    padding: 0;
    border: 0;
    background: transparent;
    box-shadow: none;
}

/* Plain rows still need to read as rows, so keep a hairline between them. */
.jsjobs-showcase--list.jsx-frame-plain .jsjobs-showcase__card + .jsjobs-showcase__card,
.jsjobs-showcase--compact.jsx-frame-plain .jsjobs-showcase__card + .jsjobs-showcase__card {
    border-top: 1px solid var(--jsx-border-soft);
}
/* The gold left edge is a listing tier, not chrome - it survives every frame. */
.jsx-frame-elevated .jsjobs-showcase__card.is-gold,
.jsx-frame-bordered .jsjobs-showcase__card.is-gold,
.jsx-frame-plain .jsjobs-showcase__card.is-gold {
    border-left: 3px solid var(--jsx-gold-border);
}
[dir="rtl"] .jsx-frame-elevated .jsjobs-showcase__card.is-gold,
[dir="rtl"] .jsx-frame-bordered .jsjobs-showcase__card.is-gold,
[dir="rtl"] .jsx-frame-plain .jsjobs-showcase__card.is-gold {
    border-left: 0;
    border-right: 3px solid var(--jsx-gold-border);
}

/* ---------- hover effect ---------- */
.jsx-hover-lift .jsjobs-showcase__card:hover,
.jsx-hover-lift .jsjobs-showcase__link:hover {
    transform: translateY(-2px);
    box-shadow: var(--jsx-shadow-hover);
}
.jsx-hover-highlight .jsjobs-showcase__card:hover,
.jsx-hover-highlight .jsjobs-showcase__link:hover {
    transform: none;
    border-color: var(--jsx-primary);
    box-shadow: none;
}
.jsx-hover-none .jsjobs-showcase__card:hover,
.jsx-hover-none .jsjobs-showcase__link:hover {
    transform: none;
    border-color: var(--jsx-border-soft);
    box-shadow: var(--jsx-shadow);
}
/* A card that cannot lift should not animate either. */
.jsx-hover-none .jsjobs-showcase__card,
.jsx-hover-none .jsjobs-showcase__link { transition: none; }

/* ---------- logo / photo shape ---------- */
.jsx-img-rounded .jsjobs-showcase__logo,
.jsx-img-rounded .jsjobs-showcase__photo > a,
.jsx-img-rounded .jsjobs-showcase__photo .jsjobs-showcase__avatar { border-radius: var(--jsx-radius-sm); }
.jsx-img-circle .jsjobs-showcase__logo,
.jsx-img-circle .jsjobs-showcase__photo > a,
.jsx-img-circle .jsjobs-showcase__photo .jsjobs-showcase__avatar { border-radius: 999px; }
.jsx-img-square .jsjobs-showcase__logo,
.jsx-img-square .jsjobs-showcase__photo > a,
.jsx-img-square .jsjobs-showcase__photo .jsjobs-showcase__avatar { border-radius: 0; }
/* A circular company logo should crop rather than letterbox. */
.jsx-img-circle .jsjobs-showcase__logo img { width: 100%; height: 100%; object-fit: cover; }

/* ---------- button style (search / login widgets) ---------- */
.jsx-btn-solid .jsjobs-widget__btn {
    background: var(--jsx-primary);
    border-color: transparent;
    color: #fff;
}
.jsx-btn-outline .jsjobs-widget__btn {
    background: transparent;
    border-color: var(--jsx-primary);
    color: var(--jsx-primary);
}
.jsx-btn-outline .jsjobs-widget__btn:hover {
    background: var(--jsx-primary-soft);
    color: var(--jsx-primary);
    filter: none;
}
/* Full width: one button per line, which is what a narrow sidebar wants. */
.jsx-btn-block .jsjobs-widget__actions { display: block; }
.jsx-btn-block .jsjobs-widget__btn { width: 100%; }
.jsx-btn-block .jsjobs-widget__btn + .jsjobs-widget__btn { margin-top: 8px; }
.jsx-btn-block .jsjobs-widget__check { margin-top: 10px; }

/* ---------- stats tiles ----------
   Same floor trick as the search grid: exactly N columns when there is room,
   fewer once a tile would get too narrow, so the setting never breaks a sidebar. */
.jsx-stats-cols .jsjobs-stats-grid {
    grid-template-columns: repeat(auto-fill, minmax(max(120px, calc((100% - (var(--jsx-stats-cols) - 1) * var(--jsx-gap, 12px)) / var(--jsx-stats-cols))), 1fr));
}
.jsx-stats-nobar .jsjobs-stats-grid li::before { content: none; }
.jsx-stats-nobar .jsjobs-stats-grid li { padding-inline-start: var(--jsx-pad, 16px); }

/* ---------- reduced motion ----------
   The hover options animate; honour the visitor's own preference over them. */
@media (prefers-reduced-motion: reduce) {
    .jsjobs-showcase__card,
    .jsjobs-showcase__link,
    .jsjobs-widget__btn {
        transition: none;
    }
    .jsjobs-showcase__card:hover,
    .jsjobs-showcase__link:hover,
    .jsjobs-widget__btn:hover {
        transform: none;
    }
}


/* ============================================================
   FIXES — reported by the site owner while testing
   ------------------------------------------------------------
   1. "Text size" only moved the wrapper's own font-size; every individual
      size in this file was a fixed px value, so nothing visibly changed.
      They are now calc(var(--jsx-fs) * Npx) — one multiplier scales the lot.
   2. "Background colour"/"Border colour" silently did nothing when
      "Container style: Plain" was also set, because Plain strips background
      and border. An explicitly picked colour is the more specific
      instruction, so it now wins over the frame's reset.
   ============================================================ */
.jsx-frame-plain.jsx-has-surface .jsjobs-showcase__card,
.jsx-frame-plain.jsx-has-surface .jsjobs-showcase__link,
.jsx-frame-plain.jsx-has-surface .jsjobs-stats-grid li,
.jsjobs-widget.jsx-frame-plain.jsx-has-surface {
    background: var(--jsx-surface);
}
.jsx-frame-plain.jsx-has-border .jsjobs-showcase__card,
.jsx-frame-plain.jsx-has-border .jsjobs-showcase__link,
.jsx-frame-plain.jsx-has-border .jsjobs-stats-grid li,
.jsjobs-widget.jsx-frame-plain.jsx-has-border {
    border: 1px solid var(--jsx-border);
}

/* ---------- title (plugins draw their own heading) ----------
   Modules get the identical declarations through header_class instead; see
   JSJobsShowcaseStyle::title(). Tokens are unset by default, so an untouched
   extension keeps exactly the heading it has today. */
.jsjobs-showcase__heading,
.jsjobs-widget__heading {
    color: var(--jsx-title-color, var(--jsx-heading, var(--jsx-ink)));
    font-size: var(--jsx-title-font-size, calc(var(--jsx-fs, 1) * 16px));
    font-weight: var(--jsx-title-font-weight, 800);
    text-align: var(--jsx-title-text-align, start);
    text-transform: var(--jsx-title-text-transform, none);
    letter-spacing: var(--jsx-title-letter-spacing, normal);
    border-bottom: var(--jsx-title-border-bottom, 0);
    padding-bottom: var(--jsx-title-padding-bottom, 0);
    border-inline-start: var(--jsx-title-border-inline-start, 0);
    padding-inline-start: var(--jsx-title-padding-inline-start, 0);
}
