/* ============================================
   CATEGORY IMAGE & CAPTION
   ============================================ */

.page-listing-image .container-fluid {
    display: flex;
    justify-content: center;
}

.page-listing-image figure {
    display: table;
    margin: 0 auto;
}

.page-listing-image figure img.category-image {
    display: block;
}

.page-listing-image figcaption {
    display: table-caption;
    caption-side: bottom;
    min-width: 200px;
    text-align: center;
}

/* ============================================
   BLOG CARD (editorial portrait plate)
   The blog card mirrors the module_team_card box model: a centered photo plate
   above a centered body. The photo is a fixed 80% of the card width so it reads
   as a portrait plate rather than a full-bleed banner. The aspect ratio comes
   from the --listing-aspect custom property set on the section by the renderer.
   Palette flows from the template :root tokens — no hardcoded fallback colors,
   which would leak another template's palette if a token ever resolved late.
   ============================================ */

.listing-blog-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    background: var(--bg-color);
    border: var(--rule-w, 1px) solid var(--border-color);
    border-radius: var(--listing-radius, 0);
    padding: 28px 20px;
    /* Shadow-Is-State: the resting elevation comes from the Bootstrap shadow-*
       utility class on the element (card_shadow knob); the hover lift / glow
       effects own their own shadow on engagement via :hover specificity. */
    transition: transform 0.25s ease, box-shadow 0.25s ease, border-color 0.25s ease;
    width: 100%;
    height: 100%;
}

/* The photo plate: 80% of the card width, centered. aspect-ratio keeps the box
   proportional so object-fit never distorts; the radius + overflow clip let the
   hover wash / ring stay contained. position:relative anchors the ::after wash /
   ring (overlay / glow) to THIS box, not the card or page. */
.listing-blog-photo {
    position: relative;
    width: 80%;
    aspect-ratio: var(--listing-aspect, 16/9);
    margin: 0 auto 16px;
    overflow: hidden;
    background: var(--surface-sunken);
    border-radius: var(--listing-radius, 0);
    flex-shrink: 0;
}

.listing-blog-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.listing-blog-body {
    width: 100%;
}

.listing-blog-title {
    font-size: var(--fs-lead);
    font-weight: 700;
    line-height: 1.3;
    margin: 0 0 4px;
    color: var(--text-ink);
    letter-spacing: -0.01em;
}

.listing-blog-text {
    font-size: var(--fs-subtitle);
    line-height: 1.5;
    margin: 0 0 8px;
    color: var(--text-muted);
}

.listing-blog-readmore,
.listing-list-readmore {
    display: inline-flex;
    align-items: center;
    margin-top: 12px;
    padding: 0.45rem 1rem;
    border-radius: var(--radius-xs);
    font-size: var(--fs-label);
    font-weight: 600;
    line-height: 1.2;
    letter-spacing: 0.02em;
    color: var(--on-primary);
    background-color: var(--primary-color);
    border: var(--rule-w, 1px) solid transparent;
    transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}

.listing-list-readmore {
    margin-top: 8px;
}

.listing-blog-link:hover .listing-blog-readmore,
.listing-list-link:hover .listing-list-readmore {
    background-color: var(--primary-deep);
}

/* Text-link read-more variant: a bare primary-colored text link with a Lisbon
   Orange arrow underline on hover — the broadsheet "continued on" mark. */
.listing-blog-readmore-text,
.listing-list-readmore-text {
    display: inline-flex;
    align-items: center;
    margin-top: 12px;
    padding: 0;
    border: 0;
    border-radius: 0;
    font-size: var(--fs-label);
    font-weight: 600;
    line-height: 1.2;
    letter-spacing: 0.02em;
    color: var(--primary-color);
    background-color: transparent;
    text-decoration: none;
    transition: color 0.2s ease;
}

.listing-list-readmore-text {
    margin-top: 8px;
}

.listing-blog-link:hover .listing-blog-readmore-text,
.listing-list-link:hover .listing-list-readmore-text {
    color: var(--accent-color);
}

/* Frameless: strip only the card chrome (border/background). The image keeps
   its own corner radius and the hover overlay/glow ring still paints on the
   photo. The resting shadow comes from the shadow-none utility class emitted
   alongside this modifier; the lift hover shadow is suppressed too — a
   borderless card has no lift. */
.listing-blog-card--frameless {
    background: transparent;
    border: none;
    padding: 4px 0;
}

[data-bs-theme="dark"] .listing-blog-card--frameless {
    background: transparent;
}

.listing-blog-card--frameless[data-hover-effect="lift"]:hover {
    box-shadow: none;
}

/* ============================================
   LISTING THUMBNAIL IMAGE (list layout)
   The photo wrapper carries the box size (admin width knob + aspect ratio),
   overflow clip and corner radius so the hover wash / image scale stay
   contained; position:relative anchors the overlay ::after wash. The img fills
   the wrapper.
   ============================================ */

.listing-thumb-photo {
    position: relative;
    width: var(--listing-thumb-width, 150px);
    aspect-ratio: var(--listing-aspect, 16/9);
    overflow: hidden;
    background: var(--surface-sunken);
    border-radius: var(--listing-radius, 0);
}

.listing-thumb-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* ============================================
   LIST CARD (list layout)
   Each row is a standalone card (border + background + radius + resting
   elevation) so the --listing-gap knob spaces them apart. The resting elevation
   comes from the Bootstrap shadow-* utility class emitted alongside (the
   card_shadow knob); the hover lift / glow effects override it on engagement.
   The card mirrors the blog card's chrome tokens (card-bg / border-color /
   listing-radius) so the two layouts read as one family. The inner flex row
   holds the thumb on the left, the title/preview body in the middle, and the
   chevron on the right.
   ============================================ */

.listing-list-card {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    background: var(--bg-color);
    border: var(--rule-w, 1px) solid var(--border-color);
    border-radius: var(--listing-radius, 0);
    padding: 14px 18px;
    transition: transform 0.25s ease, box-shadow 0.25s ease, border-color 0.25s ease;
}

/* List layout frameless: same chrome strip as the blog card — transparent
   background, no border, no resting shadow — so the row floats bare while the
   thumb keeps its own corner radius and hover ring. The lift hover shadow is
   suppressed too, mirroring the blog frameless behavior. This rule must come
   AFTER .listing-list-card so it wins the equal-specificity source-order tie. */
.listing-list-card--frameless {
    background: transparent;
    border: none;
    padding: 6px 0;
}

[data-bs-theme="dark"] .listing-list-card--frameless {
    background: transparent;
}

.listing-list-card--frameless[data-hover-effect="lift"]:hover {
    box-shadow: none;
}

.listing-list-title {
    font-size: var(--fs-title);
    font-weight: 700;
    line-height: 1.3;
    margin: 0;
    color: var(--text-ink);
    letter-spacing: -0.005em;
}

.listing-list-text {
    font-size: var(--fs-subtitle);
    line-height: 1.4;
    margin: 2px 0 0;
    color: var(--text-muted);
}

.listing-list-chevron {
    flex-shrink: 0;
    font-size: var(--fs-body);
    color: var(--text-muted);
}

/* ============================================
   CARD META BYLINE (card_* display flags)
   An optional framed meta strip under the card title: category / author /
   created + updated dates, each rendered as icon + value (icons carry the
   meaning — no text labels — so the row stays quiet on a card). Mirrors the
   page-detail byline frame vocabulary (page-meta.css) at card scale — a tonal
   sunken surface with a hairline rule — with breathing room above (title) and
   below (preview text). The category reads as primary-colored text, not a
   nested chip: the strip is already the frame, chip-in-chip would double it.
   The category is link-less by design: the whole card is already the link to
   the page. Palette flows from the template :root tokens — no hardcoded
   fallback colors, which would leak another template's palette if a token ever
   resolved late.
   ============================================ */

.listing-card-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    /* Blog card body is centered; the list row body overrides to left. */
    justify-content: center;
    gap: 0.3rem 0.9rem;
    margin: 8px 0 10px;
    padding: 0.45rem 0.875rem;
    background-color: var(--surface-sunken);
    border: var(--rule-w, 1px) solid var(--border-color);
    border-radius: var(--radius-xs);
    transition: border-color 0.25s ease;
}

/* The frame's rule deepens on card hover (No-Lift-Reflex, the byline
   behaviour) so the strip quietly participates in the card engagement. */
.listing-page-card:hover .listing-card-meta {
    border-color: var(--border-strong);
}

.listing-list-card .listing-card-meta {
    justify-content: flex-start;
    margin: 6px 0 8px;
}

.listing-card-meta-item {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: var(--fs-label);
    line-height: 1.3;
    color: var(--text-muted);
}

.listing-card-meta-item .bi {
    font-size: 0.85em;
    opacity: 0.75;
}

.listing-card-meta-item--category {
    color: var(--primary-color);
    font-weight: 500;
}

/* ============================================
   GRID SPACING
   Driven by the --listing-gap custom property. The blog grid uses the
   Bootstrap row gutter; the list stack is a flex column whose gap is the knob.
   ============================================ */

.page-listing-blog .row {
    --bs-gutter-x: var(--listing-gap, 20px);
}

.listing-list-stack {
    display: flex;
    flex-direction: column;
    gap: var(--listing-gap, 20px);
}

/* ============================================
   HOVER EFFECTS
   Mirrors the team-card family vocabulary (none / overlay / lift / zoom /
   glow / tilt) driven by the data-hover-effect attribute. The accent color
   reuses the template's --primary-color token so it tracks dark mode too. Like
   team-card, each effect also repaints the title to primary, so the engaged card
   reads as "coming alive" — not just the image.

   The listing card lives inside an <a>, which the template's generic
   "a > .card:hover" rule would lift (translateY) on every hover. That reflex is
   suppressed here so each hover_effect owns its own motion.
   ============================================ */

a > .listing-page-card:hover,
.is-clickable > .listing-page-card:hover {
    transform: none;
    box-shadow: none;
}

@media (prefers-reduced-motion: no-preference) {
    a > .listing-page-card:hover,
    .is-clickable > .listing-page-card:hover {
        transform: none;
    }
}

.listing-page-card[data-hover-effect="none"] {
    transition: none;
}

/* lift — the signature featured-card motion. Border deepens (not fades) so the
   card chrome stays visible at rest and reads as "lifting" on hover. */
.listing-page-card[data-hover-effect="lift"]:hover {
    transform: translateY(-4px);
    border-color: var(--border-strong);
    box-shadow:
        0 2px 4px rgba(33, 37, 41, 0.06),
        0 8px 16px rgba(33, 37, 41, 0.12);
}

.listing-page-card[data-hover-effect="lift"]:hover .listing-blog-title,
.listing-page-card[data-hover-effect="lift"]:hover .listing-list-title {
    color: var(--primary-color);
}

/* overlay — a tonal wash sits ON TOP OF THE IMAGE ONLY. The card body text
   stays clean; the wash lives in the photo wrapper, layered above the image
   (z-index 1). */
.listing-page-card[data-hover-effect="overlay"] .listing-blog-photo::after,
.listing-page-card[data-hover-effect="overlay"] .listing-thumb-photo::after {
    content: "";
    position: absolute;
    inset: 0;
    background-color: var(--primary-color);
    opacity: 0;
    transition: opacity 0.3s ease;
    pointer-events: none;
    z-index: 1;
}

.listing-page-card[data-hover-effect="overlay"]:hover .listing-blog-photo::after,
.listing-page-card[data-hover-effect="overlay"]:hover .listing-thumb-photo::after {
    opacity: 0.35;
}

.listing-page-card[data-hover-effect="overlay"]:hover {
    border-color: var(--primary-color);
}

.listing-page-card[data-hover-effect="overlay"]:hover .listing-blog-title,
.listing-page-card[data-hover-effect="overlay"]:hover .listing-list-title {
    color: var(--primary-deep);
}

/* zoom — the image scales up inside its overflow-hidden photo wrapper */
.listing-page-card[data-hover-effect="zoom"] .listing-blog-img,
.listing-page-card[data-hover-effect="zoom"] .listing-thumb-img {
    transition: transform 0.4s ease;
}

.listing-page-card[data-hover-effect="zoom"]:hover .listing-blog-img,
.listing-page-card[data-hover-effect="zoom"]:hover .listing-thumb-img {
    transform: scale(1.08);
}

.listing-page-card[data-hover-effect="zoom"]:hover {
    border-color: var(--border-strong);
}

.listing-page-card[data-hover-effect="zoom"]:hover .listing-blog-title,
.listing-page-card[data-hover-effect="zoom"]:hover .listing-list-title {
    color: var(--primary-color);
}

/* glow — a steel-blue halo rings the CARD edge (not the image). The ::after
   layer paints an inset 2px primary ring stacked above the card content
   (z-index: 2) so the title/photo never cover it. The halo tint is derived
   from the primary token via color-mix so it tracks every theme + dark mode
   instead of hardcoding a single palette's RGB. */
.listing-page-card[data-hover-effect="glow"] {
    position: relative;
}

.listing-page-card[data-hover-effect="glow"]::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    box-shadow: inset 0 0 0 2px var(--primary-color);
    opacity: 0;
    transition: opacity 0.3s ease;
    pointer-events: none;
    z-index: 2;
}

.listing-page-card[data-hover-effect="glow"]:hover::after {
    opacity: 1;
}

.listing-page-card[data-hover-effect="glow"]:hover {
    box-shadow: 0 4px 12px color-mix(in srgb, var(--primary-color) 28%, transparent);
}

.listing-page-card[data-hover-effect="glow"]:hover .listing-blog-title,
.listing-page-card[data-hover-effect="glow"]:hover .listing-list-title {
    color: var(--primary-color);
}

/* tilt — grayscale to color swing on the image */
.listing-page-card[data-hover-effect="tilt"] .listing-blog-img,
.listing-page-card[data-hover-effect="tilt"] .listing-thumb-img {
    filter: grayscale(1) contrast(0.95) brightness(1.02);
    transition: filter 0.45s ease, transform 0.45s ease;
}

.listing-page-card[data-hover-effect="tilt"]:hover .listing-blog-img,
.listing-page-card[data-hover-effect="tilt"]:hover .listing-thumb-img {
    filter: grayscale(0) contrast(1) brightness(1);
    transform: scale(1.06);
}

.listing-page-card[data-hover-effect="tilt"]:hover {
    border-color: var(--border-strong);
}

.listing-page-card[data-hover-effect="tilt"]:hover .listing-blog-title,
.listing-page-card[data-hover-effect="tilt"]:hover .listing-list-title {
    color: var(--primary-color);
}

/* Keyboard focus visibility */
.listing-page-card:focus-within {
    outline: 2px solid var(--primary-color);
    outline-offset: 2px;
}


/* Author avatar + position inside the card meta row (extended user profile).
   Mirrors the page-detail byline pieces at the card's smaller scale. */
.listing-card-meta-avatar {
    width: 18px;
    height: 18px;
    border-radius: 50%;
    object-fit: cover;
    display: inline-block;
    vertical-align: -0.25em;
    flex-shrink: 0;
}

.listing-card-meta-author-position {
    color: var(--text-muted);
}
