/* Property cards.
   Shared by the homepage featured list and the property search results, so
   the two cannot drift. Lifted out of index.php page styles when the search
   page was rebuilt on the same component.

   ICONS: Font Awesome is a kit (SVG+JS) and replaces <i> with <svg>, so icon
   rules name both. */

/* ------------------------------------------------------------------
   FEATURED PROPERTIES
   One hero image per card. There is deliberately no slideshow, dot nav,
   photo count or "View Gallery" button here: the whole card is a single
   link to the listing, and the gallery lives on the detail page. Adding
   a clickable control back inside the card nests interactive content in
   an anchor, which is invalid and breaks keyboard navigation.
   Community tile styles live in master.css under COMMUNITIES MOSAIC.
   ------------------------------------------------------------------ */
.listings-section {
    padding: 4.5rem 0;
    background: linear-gradient(180deg, #f6f9f7 0%, #ffffff 60%);
}

.section-subtitle {
    font-size: 1.1rem;
    color: #6a7a72;
    margin-bottom: 2.75rem;
    font-weight: 300;
}

.featured-listings-grid {
    margin-bottom: 2.5rem;
}

/* The card is an <a>. UIkit's a:hover underline is (0,1,1), so a plain
   text-decoration:none would lose: cover every state explicitly. */
a.featured-card,
a.featured-card:hover,
a.featured-card:focus,
a.featured-card:active,
a.featured-card:visited {
    text-decoration: none;
    color: inherit;
}

/* Breakpoints match the UIkit ones this replaced (uk-child-width-1-2@s at
   640, 1-3@m at 960). Grid items stretch by default, so a two-line address on
   one listing no longer leaves its neighbours short. */
.featured-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1.75rem;
}

@media (min-width: 640px) { .featured-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 960px) { .featured-grid { grid-template-columns: repeat(3, 1fr); } }

.featured-card {
    display: flex;
    flex-direction: column;
    background: #fff;
    border: 1px solid #e8ece9;
    border-radius: 16px;
    overflow: hidden;
    box-shadow: 0 1px 2px rgba(10, 47, 34, .04), 0 8px 24px rgba(10, 47, 34, .06);
    transition: transform .35s cubic-bezier(.2, .7, .3, 1),
                box-shadow .35s ease,
                border-color .35s ease;
}

.featured-card:hover {
    transform: translateY(-6px);
    border-color: #d5e4db;
    box-shadow: 0 2px 4px rgba(10, 47, 34, .06), 0 18px 40px rgba(10, 47, 34, .14);
}

.featured-card:focus-visible {
    outline: 3px solid #007e3f;
    outline-offset: 3px;
}

/* 3:2, the ratio the MLS delivers in: 640x426 for LargePhoto, and 296x197 for
   anything still cached from before that switch. A taller box would crop the
   photo and then upscale the remainder harder, which is where these get mushy. */
.featured-card-media {
    position: relative;
    aspect-ratio: 3 / 2;
    overflow: hidden;
    background: #eef1ef;
}

.featured-card-media img {
    width: 100%;
    height: 100%;
    display: block;
    object-fit: cover;
    transition: transform .6s cubic-bezier(.2, .7, .3, 1);
}

.featured-card:hover .featured-card-media img {
    transform: scale(1.07);
}

/* Scrim, so the price stays legible over a bright photo. */
.featured-card-media::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: linear-gradient(to top,
        rgba(6, 26, 18, .80) 0%,
        rgba(6, 26, 18, .34) 30%,
        rgba(6, 26, 18, 0) 58%);
}

.featured-card-media--empty {
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(135deg, #f4f7f5 0%, #e4ebe7 100%);
    color: #a6b3ac;
}

.featured-card-media--empty i, .featured-card-media--empty svg { font-size: 2.25rem; }

/* ---------------------------------------------------------------------------
   Loading a photo on demand.

   Photos are cached when a listing is first DISPLAYED, so a card can render
   before its photo exists anywhere. Rather than an empty grey box, the slot
   shows a sweeping skeleton until media/js/photo-loader.js fills it in.
   --------------------------------------------------------------------------- */

.featured-card-media.is-loading {
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(135deg, #f4f7f5 0%, #e4ebe7 100%);
    color: #b7c3bc;
}

.featured-card-media.is-loading i,
.featured-card-media.is-loading svg { font-size: 2.25rem; }

/* The sweep. A separate layer from ::after, which is already the price scrim.
   Deliberately NO z-index: both pseudo elements are positioned and sit at
   z-index auto, so tree order decides, and ::after paints last. Lifting this
   to z-index 1 puts the bright sweep OVER the scrim and the white price
   washes out every time the shimmer passes under it. */
.featured-card-media.is-loading::before {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(100deg,
        rgba(255, 255, 255, 0) 20%,
        rgba(255, 255, 255, .68) 50%,
        rgba(255, 255, 255, 0) 80%);
    background-size: 220% 100%;
    animation: cpr-photo-shimmer 1.35s ease-in-out infinite;
}

@keyframes cpr-photo-shimmer {
    from { background-position: 180% 0; }
    to   { background-position: -60% 0; }
}

/* Fade the photo in once it has actually decoded, so it never flashes. */
.featured-photo-in {
    opacity: 0;
    transition: opacity .45s ease;
}

.featured-photo-in.is-visible { opacity: 1; }

/* Respect a reduced-motion preference: keep the state readable, drop the
   sweep and the fade rather than animating anything. */
@media (prefers-reduced-motion: reduce) {
    .featured-card-media.is-loading::before { animation: none; opacity: .5; }
    .featured-photo-in { transition: none; opacity: 1; }
}

.featured-tag {
    position: absolute;
    top: 14px;
    left: 14px;
    z-index: 2;
    padding: .32rem .72rem;
    border-radius: 999px;
    background: rgba(255, 255, 255, .93);
    color: #00522a;
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
}

.featured-price {
    position: absolute;
    left: 18px;
    bottom: 14px;
    z-index: 2;
    color: #fff;
    font-size: 1.7rem;
    font-weight: 700;
    letter-spacing: -.02em;
    line-height: 1.1;
    text-shadow: 0 1px 14px rgba(0, 0, 0, .45);
}

.featured-card-body {
    flex: 1 1 auto;
    padding: 1.15rem 1.25rem .9rem;
}

.featured-address {
    margin: 0;
    font-size: 1.05rem;
    font-weight: 600;
    line-height: 1.35;
    color: #1d2b24;
}

.featured-locality {
    margin: .25rem 0 0;
    font-size: .9rem;
    color: #6a7a72;
}

.featured-stats {
    display: flex;
    margin-top: 1.05rem;
    padding-top: .9rem;
    border-top: 1px solid #eef1ef;
}

/* Three equal cells that must survive the narrowest card, which is the
   3-column grid at ~960px, not mobile. A 12,345 sqft listing overflowed the
   row at .88rem; sized down, and left to wrap rather than nowrap so a freak
   value breaks a line instead of breaking the card. */
/* 1 1 auto, not 1 1 0: equal thirds starve the sqft cell (it is the widest
   label by far) and wrap it onto a second line while the bed cell sits half
   empty. Sizing to content and sharing the slack keeps one clean line. */
.featured-stat {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .32rem;
    padding: 0 .15rem;
    font-size: .82rem;
    line-height: 1.3;
    text-align: center;
    color: #55665e;
}

.featured-stat + .featured-stat { border-left: 1px solid #eef1ef; }
.featured-stat i, .featured-stat svg { font-size: .8rem; color: #007e3f; flex: none; }
.featured-stat-text { min-width: 0; }
.featured-stat strong { font-weight: 700; color: #1d2b24; }

.featured-card-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: .1rem 1.25rem 1.05rem;
}

.featured-mls {
    font-size: .72rem;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: #9aa8a1;
}

.featured-cta {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    font-size: .85rem;
    font-weight: 600;
    color: #007e3f;
}

.featured-cta i { transition: transform .25s ease; }
.featured-card:hover .featured-cta i { transform: translateX(4px); }

@media (prefers-reduced-motion: reduce) {
    .featured-card,
    .featured-card-media img,
    .featured-cta i { transition: none; }
    .featured-card:hover { transform: none; }
    .featured-card:hover .featured-card-media img { transform: none; }
    .featured-card:hover .featured-cta i { transform: none; }
}

.loading-placeholder {
    text-align: center;
    padding: 3rem 0;
    color: #666;
}

.loading-placeholder i {
    font-size: 2rem;
    margin-bottom: 1rem;
    color: #007e3f;
}

.placeholder-content {
    text-align: center;
    padding: 3rem 0;
    color: #666;
}

.placeholder-icon {
    font-size: 3rem;
    margin-bottom: 1rem;
    color: #007e3f;
}

.placeholder-title {
    font-size: 1.5rem;
    font-weight: 600;
    margin-bottom: 0.5rem;
    color: #333;
}

.placeholder-text {
    font-size: 1rem;
    color: #666;
    max-width: 400px;
    margin: 0 auto;
}

/* Responsive Design */
@media (max-width: 768px) {
    .listings-section { padding: 3rem 0; }
    .section-subtitle { margin-bottom: 2rem; }
    .featured-price { font-size: 1.5rem; }
}

@media (max-width: 480px) {
    .listings-section { padding: 2.5rem 0; }
    .featured-card-body { padding: 1rem 1rem .85rem; }
    .featured-card-foot { padding: .1rem 1rem .95rem; }
    .featured-price { font-size: 1.45rem; }
}
