/*
 * ==========================================================================
 * PROPERTY FAVOURITES
 * ==========================================================================
 *
 * The hearts were <span aria-disabled> until now, so property-pages.css styles
 * .hzp-fav as inert text. They are <button> elements now, which arrive with a
 * user-agent border, background and font of their own, so the first block here
 * takes those off and leaves the existing .hzp-fav geometry -- the 32px circle
 * and the 21px stroked glyph -- untouched and still the only thing deciding how
 * the heart is laid out.
 *
 * A fifth file rather than rules added to property-pages.css or property.css:
 * both were open in other sessions while this was written. Loaded after them,
 * so their --hzp-* tokens are in scope here.
 *
 * Every selector below names either a <button>.hzp-fav, the .hzp-fav--on
 * modifier, or a .hzfav-* class, none of which existed before this file. A page
 * that has no heart on it renders exactly as it did.
 */

/* ------------------------------------------------------------- the contract */

/*
 * --hzfav-saved is the colour of a saved favourite on this channel. It is
 * declared on :root so it is in scope for every element on every property
 * page: this file is linked from components/layouts/footer/styles.blade.php,
 * which the shop layout includes in <head> unconditionally.
 *
 * The shared name is the point of it. The "Save this search" control on the
 * search page reads the same variable from property-pages.css, so the two
 * saved states on this channel are one declaration and cannot drift apart.
 * That file carries #e11d48 as its var() fallback and this declares the same
 * value, so the two agree whether or not this declaration is reached.
 *
 * WHY THIS RED
 *
 * A filled red heart is the convention for "saved", and the convention's red
 * is a crimson rather than a signal red. #e11d48 sits at hue 347deg -- pinker,
 * and eleven degrees off the #d92228 at hue 358deg that this project already
 * spends on the demo notices on the project pages. Keeping those two apart
 * matters more than reusing a value: #d92228 is this project's warning red,
 * and a heart drawn in the warning red says "problem" where it means "kept".
 *
 * Contrast, measured rather than assumed. #e11d48 is 4.70:1 against white,
 * which is what sits behind every heart on this channel -- the card body, the
 * 94%-white disc on the home page cards and the favourites tiles, and the
 * solid white circle on the gallery. That clears the 3:1 WCAG 1.4.11 asks of
 * a non-text graphic, and clears 4.5:1 too, which is the threshold that
 * would apply if it were ever put on running text.
 *
 * --hzfav-saved-strong is the hover, at 6.28:1. --hzfav-saved-wash is the
 * hover backing on the search card, standing in for the purple wash the
 * unsaved heart uses. Both are local to this file; the contract is one name.
 *
 * Colour is not the carrier of the state and is not being asked to be: the
 * glyph goes from outline to filled, and the accessible name changes with it.
 */
:root {
    --hzfav-saved: #f40051;
    --hzfav-saved-strong: #d60047;
    --hzfav-saved-wash: #fff0f5;
}

/* --------------------------------------------------------------- the control */

button.hzp-fav {
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
}

button.hzp-fav:hover {
    color: var(--hzp-accent, #0745D9);
    background: var(--hzp-accent-wash, #EEF3FF);
}

button.hzp-fav:focus-visible {
    outline: 2px solid var(--hzp-accent, #0745D9);
    outline-offset: 2px;
}

/*
 * The saved state, and the first thing that distinguishes it: the glyph fills.
 *
 * Colour alone would carry it for most readers but not for all, so the fill is
 * the signal and the colour follows it. One class and one red across this
 * channel rather than one per component -- this reaches the search card's
 * .hzp-fav, the gallery's .hzpg__tool, the home card's .hz-lcard__fav and the
 * detail bar's .hzd-bar__act, because the script sets .hzp-fav--on on every
 * [data-hzfav] whatever its own class is.
 *
 * It was the brand purple until now, which is the colour this channel uses for
 * "active" everywhere else. A heart is the one control where that reading is
 * wrong: a filled purple heart is a house style, a filled red one is
 * understood without being learned.
 *
 * (0,1,1), which is not enough on its own for four different surfaces with
 * hover and neutral rules of their own. The section at the foot of this file
 * corrects each of them and says why.
 */
button.hzp-fav--on {
    color: var(--hzfav-saved, #e11d48);
}

button.hzp-fav--on svg {
    fill: currentColor;
}

/*
 * The listing page's heart is a .hzpg__tool, which property-pages.css already
 * styles as a bordered 36px circle and already has a <button> form, because the
 * Share control beside it was one. So it needs no reset -- only the same
 * "saved" modifier the card hearts take, which is one class name across both so
 * the script has one thing to toggle. The two rules above it that name
 * button.hzp-fav do not reach here; these carry the fill and the border.
 *
 * The border takes the red as well as the glyph. This is a 36px circular icon
 * button sitting on a photograph, and a red ring around a filled red heart
 * reads as one saved control; a red glyph inside a purple ring would read as
 * two states disagreeing. It is not the "bordered and red all over" shape that
 * means destructive, because that shape needs a text label, and this has none.
 *
 * The white background and the neutral 1px border are property-pages.css's and
 * stay as they are when unsaved -- they are what makes any glyph legible over
 * a photograph.
 */
button.hzpg__tool[data-hzfav] svg {
    transition: fill 120ms ease;
}

.hzp-detail button.hzpg__tool.hzp-fav--on {
    border-color: var(--hzfav-saved, #e11d48);
    color: var(--hzfav-saved, #e11d48);
}

/*
 * .hzp-detail button.hzpg__tool:hover in property-pages.css is (0,3,1), the
 * same as the rule above, and would win or lose on file order alone. Written
 * out at (0,4,1) so a saved heart deepens under the pointer instead of
 * flickering back to the unsaved purple if that file is ever reordered.
 */
.hzp-detail button.hzpg__tool.hzp-fav--on:hover {
    border-color: var(--hzfav-saved-strong, #be123c);
    color: var(--hzfav-saved-strong, #be123c);
}

.hzp-detail button.hzpg__tool.hzp-fav--on svg {
    fill: currentColor;
}

@media (prefers-reduced-motion: reduce) {
    button.hzpg__tool[data-hzfav] svg {
        transition: none;
    }
}

/* ------------------------------------------------------- the favourites grid */

/*
 * /account/favorites is a shortlist, and a shortlist is read across rather than
 * down: the reader already knows what each of these is and wants them all in
 * view at once to compare. So a favourite is a compact tile here -- photograph,
 * title, price -- rather than the full search card, which spends most of its
 * height on a description and a set of actions that the reader has already had.
 *
 * The geometry is the car channel's, measured off its own Favorites page rather
 * than guessed: an auto-filled 220px minimum track with a 14px gutter, dropping
 * to a 150px minimum below 768px, which is what keeps it two-up on a phone
 * instead of collapsing to a single column. The palette and the type are not
 * shared -- see .hzfav-tile__price and .hzfav-tile__title below.
 */
.hzfav-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 14px;
    margin: 0;
    padding: 0;
    list-style: none;
}

@media (max-width: 767.98px) {
    .hzfav-grid {
        grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    }
}

/*
 * position: relative because the remove control is positioned against it, and
 * overflow: hidden so the photograph takes the tile's corner radius without
 * needing one of its own. The radius is this channel's --hzac-radius, not the
 * car channel's 8px.
 */
.hzfav-tile {
    position: relative;
    display: grid;
    align-content: start;
    overflow: hidden;
    border: 1px solid var(--hzac-line, #e7e9ee);
    border-radius: var(--hzac-radius, 10px);
    background: #ffffff;
    transition: border-color 140ms ease;
}

.hzfav-tile:hover {
    border-color: var(--hzac-line-strong, #d6dae1);
}

/*
 * The whole tile is the link. `.acct a` already sets colour and decoration to
 * inherit at a specificity this cannot reach, and inheriting is what is wanted,
 * so only the layout is set here.
 */
.hzfav-tile__link {
    display: grid;
    align-content: start;
    min-width: 0;
}

/*
 * A fixed band rather than an aspect ratio, which is what the car channel does
 * and is the right call for a grid whose track width changes: every tile in a
 * row lines up on the same two horizontals however wide the column happens to
 * be, and object-fit absorbs the difference in the photographs.
 */
.hzfav-tile__media {
    display: block;
    width: 100%;
    height: 132px;
    background: var(--hzac-fill, #f4f5f7);
    object-fit: cover;
}

.hzfav-tile__body {
    display: grid;
    gap: 3px;
    min-width: 0;
    padding: 12px 13px;
}

/*
 * One line, then an ellipsis. A shortlist is scanned, and a title that wraps to
 * three lines on one tile and one on the next destroys the horizontal rhythm
 * that makes it scannable. The full title is a click away and is also the
 * accessible name of the remove button beside it.
 */
.hzfav-tile__title {
    overflow: hidden;
    color: var(--hzac-ink, #12141a);
    font-size: 13.5px;
    font-weight: 600;
    line-height: 1.45;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/*
 * This channel's purple, and this channel's price idiom: the figure carries the
 * weight and the currency and the rent period follow it a size down, which is
 * how a price is set on a property card and on a listing page here.
 */
.hzfav-tile__price {
    color: var(--hzac-primary, #0745D9);
    font-size: 13.5px;
    font-weight: 700;
    line-height: 1.45;
    white-space: nowrap;
}

.hzfav-tile__price small {
    margin-inline-start: 4px;
    font-size: 12px;
    font-weight: 600;
}

/* ------------------------------------------------------ removing from here */

/*
 * The car channel's tiles have no remove control at all -- no button, no glyph,
 * nothing on hover; the tile is one anchor and the only way to unsave is to go
 * back to the car itself. Copying that would take away something this page
 * already does, so it is not copied.
 *
 * Instead the heart is kept, filled and in the saved red because everything on
 * this page is saved by definition, and held at zero opacity so
 * that a tile at rest is the car tile exactly. It appears on hover, on
 * focus-within -- which is what puts it in reach of a keyboard, since tabbing
 * to it is what reveals it -- and unconditionally wherever hover is not a thing
 * the pointer can do.
 */
.hzfav-tile__remove {
    position: absolute;
    top: 8px;
    inset-inline-end: 8px;
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.94);
    box-shadow: 0 1px 3px rgba(18, 20, 26, 0.24);
    /* Server-rendered red rather than waiting for the script: every tile on
       this page is a saved favourite before any JavaScript runs. The
       94%-white disc and the shadow above it are what keep it legible over
       the photograph and are unchanged. */
    color: var(--hzfav-saved, #e11d48);
    font: inherit;
    opacity: 0;
    cursor: pointer;
    transition: opacity 140ms ease, background-color 140ms ease;
    -webkit-appearance: none;
    appearance: none;
}

.hzfav-tile__remove svg {
    width: 17px;
    height: 17px;
    fill: currentColor;
    stroke: currentColor;
    stroke-width: 1.4;
    stroke-linejoin: round;
}

.hzfav-tile:hover .hzfav-tile__remove,
.hzfav-tile:focus-within .hzfav-tile__remove {
    opacity: 1;
}

.hzfav-tile__remove:hover {
    background: #ffffff;
    color: var(--hzfav-saved-strong, #be123c);
}

.hzfav-tile__remove:focus-visible {
    opacity: 1;
    outline: 2px solid var(--hzac-primary, #0745D9);
    outline-offset: 2px;
}

@media (hover: none) {
    .hzfav-tile__remove {
        opacity: 1;
    }
}

@media (prefers-reduced-motion: reduce) {
    .hzfav-tile,
    .hzfav-tile__remove {
        transition: none;
    }
}

/* ------------------------------------------- a favourite that has gone away */

/*
 * Saved here, then unpublished on this channel. It keeps its place on the grid
 * rather than being dropped, because it is still in the customer's list and
 * only they get to decide to drop it -- and because a list that quietly shrinks
 * is the same lie as a stale cache. The tile says what happened in the space
 * the photograph would have taken, keeps the title it was saved under, and puts
 * a plain, always-visible Remove where the price would be. The dashed border is
 * the one thing that marks it out at a glance in a row of live tiles.
 */
.hzfav-tile--gone {
    border-style: dashed;
    border-color: var(--hzac-line-strong, #d6dae1);
}

.hzfav-tile__gone {
    display: grid;
    place-content: center;
    justify-items: center;
    gap: 6px;
    padding: 12px;
    background: var(--hzac-fill-soft, #fafbfc);
    color: var(--hzac-muted, #6b7280);
    text-align: center;
}

.hzfav-tile__gone svg {
    width: 20px;
    height: 20px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.hzfav-tile__gone-text {
    font-size: 12px;
    line-height: 1.4;
}

.hzfav-tile--gone .hzfav-tile__title {
    color: var(--hzac-muted, #6b7280);
}

.hzfav-tile__drop {
    justify-self: start;
    padding: 0;
    border: 0;
    background: none;
    color: var(--hzac-primary, #0745D9);
    font: inherit;
    font-size: 12.5px;
    font-weight: 600;
    text-align: start;
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
}

.hzfav-tile__drop:hover {
    color: var(--hzac-primary-dark, #0638B0);
}

.hzfav-tile__drop:focus-visible {
    outline: 2px solid var(--hzac-primary, #0745D9);
    outline-offset: 2px;
}

/* ------------------------------------------------ the home page's own heart */

/*
 * The home page's listing cards carry .hz-lcard__fav, which property.css styles
 * as an inert 29px disc -- it was a <span aria-disabled> with a title saying
 * saving was not available, which stopped being true once the rest of this
 * channel could save. It is a <button> now, so it needs the same three things
 * taken off it that .hzp-fav did, and the cursor put back the right way round;
 * property.css sets cursor: not-allowed at (0,1,0) and this reaches it at
 * (0,1,1). The disc, its shadow and the glyph inside it are left exactly as
 * property.css draws them.
 *
 * There is no saved-state colour rule here on purpose: button.hzp-fav--on
 * above already carries it, and it asks only for the modifier the script sets.
 * "On" is one class and one red across this channel rather than one per card.
 * The saved hover is a different matter and is at the foot of this file, since
 * button.hz-lcard__fav:hover below outranks that blanket rule.
 */
button.hz-lcard__fav {
    padding: 0;
    border: 0;
    font: inherit;
    cursor: pointer;
    transition: color 140ms ease, background-color 140ms ease;
    -webkit-appearance: none;
    appearance: none;
}

button.hz-lcard__fav:hover {
    background: #ffffff;
    color: var(--hagzi-primary, #0745D9);
}

button.hz-lcard__fav:focus-visible {
    outline: 2px solid var(--hagzi-primary, #0745D9);
    outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
    button.hz-lcard__fav {
        transition: none;
    }
}

/* ------------------------------------------ saved state, per control surface */

/*
 * button.hzp-fav--on near the top of this file sets the saved colour for every
 * heart on the channel at (0,1,1). What it cannot do alone is survive the
 * hover and neutral rules that sit on the individual controls -- two of them
 * in this file, one in a template another session owns. Each rule below names
 * the surface it corrects and why it is written at the specificity it is.
 *
 * Nothing here touches an unsaved heart: every selector carries .hzp-fav--on,
 * which only the script's saved state puts on the element.
 */

/*
 * Search results card.
 *
 * button.hzp-fav:hover at the top of this file paints the unsaved hover, a
 * purple glyph on the purple wash, and at (0,2,1) it outranks the saved-state
 * rule -- so a saved heart went purple the moment it was pointed at. It
 * deepens now instead, and the wash follows the glyph rather than contradicting
 * it.
 */
button.hzp-fav.hzp-fav--on:hover {
    background: var(--hzfav-saved-wash, #fff1f2);
    color: var(--hzfav-saved-strong, #be123c);
}

/*
 * Home page card rows.
 *
 * The same collision: button.hz-lcard__fav:hover above is (0,2,1) and was
 * repainting a saved heart in --hagzi-primary under the pointer. Only the
 * colour and the backing that hover already changed are set here; the 29px
 * 94%-white disc and its shadow belong to property.css and are what make the
 * glyph legible over a photograph, so they are left where they are.
 */
button.hz-lcard__fav.hzp-fav--on:hover {
    background: #ffffff;
    color: var(--hzfav-saved-strong, #be123c);
}

/*
 * Listing detail, the action bar under the gallery.
 *
 * OVERRIDE OF A DECLARATION THIS SESSION DOES NOT OWN.
 *
 * resources/themes/property/views/products/view.blade.php pushes an inline
 * <style> onto the styles stack containing
 *
 *     .hzd-bar__act.hzp-fav--on { color: var(--hagzi-primary, #0745D9); }
 *
 * at (0,2,0), with a matching svg fill rule. The stack is emitted at line 145
 * of the shop layout and this stylesheet is linked at line 154, so document
 * order alone settles it today -- but that template is open in another session
 * and a block moved earlier or later would silently take the colour back. The
 * element in this selector makes it (0,2,1) and independent of where theirs
 * lands. Their `fill: currentColor` is correct and is left to do its job.
 */
button.hzd-bar__act.hzp-fav--on {
    color: var(--hzfav-saved, #e11d48);
}

/* Their .hzd-bar__act:hover recolours to --hzp-ink. This keeps the red and
   leaves their tint background alone. */
button.hzd-bar__act.hzp-fav--on:hover {
    color: var(--hzfav-saved-strong, #be123c);
}

/*
 * The Remove link on a tile whose listing is no longer published.
 *
 * Held OFF the saved red deliberately. It is a 12.5px underlined text link
 * reading "Remove", not a heart, and it carries [data-hzfav] -- so the script
 * gives it .hzp-fav--on along with everything else, and the blanket rule would
 * have turned the one piece of running text in this file red. Red text beside
 * a dashed "no longer published" tile reads as an error about the tile rather
 * than as affection for it. It keeps the channel's link purple; the heart red
 * is for hearts.
 *
 * (0,2,1) to clear the blanket rule, plus a hover variant, because that
 * specificity would otherwise also swallow .hzfav-tile__drop:hover at (0,2,0).
 */
button.hzfav-tile__drop.hzp-fav--on {
    color: var(--hzac-primary, #0745D9);
}

button.hzfav-tile__drop.hzp-fav--on:hover {
    color: var(--hzac-primary-dark, #0638B0);
}

/* ----------------------------------------------- animated listing-card heart */

/*
 * Search, seller and homepage cards get the animated heart treatment. The
 * detail-page gallery/action controls and the Remove control on /favorites
 * deliberately retain their established geometry.
 */
button.hzp-fav.hzp-like,
button.hz-lcard__fav.hzp-like {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    min-width: 34px;
    height: 34px;
    padding: 0;
    overflow: visible;
    border: 1px solid #e0e3e9;
    border-radius: 999px;
    background: #ffffff;
    color: #171a21;
    box-shadow: 0 2px 7px rgba(16, 20, 28, 0.1);
    line-height: 1;
    transition:
        border-color 150ms ease,
        box-shadow 150ms ease,
        transform 150ms ease;
}

button.hzp-fav.hzp-like {
    position: relative;
}

button.hz-lcard__fav.hzp-like {
    width: 32px;
    min-width: 32px;
    height: 32px;
}

button.hzp-fav.hzp-like:hover,
button.hz-lcard__fav.hzp-like:hover,
button.hzp-fav.hzp-like.hzp-fav--on:hover,
button.hz-lcard__fav.hzp-like.hzp-fav--on:hover {
    border-color: #cfd4dd;
    background: #ffffff;
    color: #171a21;
    box-shadow: 0 4px 12px rgba(16, 20, 28, 0.14);
}

button.hzp-like:active {
    transform: translateY(1px);
}

.hzp-like__icon {
    position: relative;
    display: grid;
    flex: none;
    width: 22px;
    height: 22px;
    place-items: center;
    color: #4b5260;
    transform-origin: center;
}

button.hzp-like .hzp-like__icon svg {
    width: 22px;
    height: 22px;
    overflow: visible;
    fill: transparent;
    stroke: currentColor;
    stroke-width: 1.7;
    stroke-linecap: round;
    stroke-linejoin: round;
}

button.hzp-like .hzp-like__icon svg path {
    fill: transparent;
    transition:
        fill 150ms cubic-bezier(0.22, 1, 0.36, 1),
        stroke 150ms cubic-bezier(0.22, 1, 0.36, 1);
}

button.hzp-like:hover .hzp-like__icon {
    color: var(--hzfav-saved, #f40051);
}

button.hzp-like.hzp-fav--on {
    background: #ffffff;
    color: #171a21;
}

button.hzp-like.hzp-fav--on .hzp-like__icon,
button.hzp-like.hzp-fav--on:hover .hzp-like__icon,
button.hzp-like.hzp-savesearch--on .hzp-like__icon,
button.hzp-like.hzp-savesearch--on:hover .hzp-like__icon {
    color: var(--hzfav-saved, #f40051);
}

button.hzp-like.hzp-fav--on .hzp-like__icon svg path,
button.hzp-like.hzp-savesearch--on .hzp-like__icon svg path {
    fill: currentColor;
}

.hzp-like__particles {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 0;
    height: 0;
    color: var(--hzfav-saved, #f40051);
    pointer-events: none;
}

.hzp-like__particles i {
    position: absolute;
    top: -1.5px;
    left: -1.5px;
    width: 3px;
    height: 3px;
    border-radius: 50%;
    background: currentColor;
    opacity: 0;
}

button.hzp-like--burst .hzp-like__icon {
    animation: hzfav-like-pop 350ms cubic-bezier(0.34, 1.96, 0.64, 1);
}

button.hzp-like--burst .hzp-like__particles i {
    animation: hzfav-like-burst var(--hzfav-pdur, 600ms) ease-out var(--hzfav-pdelay, 0ms) forwards;
}

@keyframes hzfav-like-pop {
    0% { transform: scale(1); }
    30% { transform: scale(0.82); }
    100% { transform: scale(1); }
}

@keyframes hzfav-like-burst {
    0% {
        opacity: 0;
        transform: translate(0, 0) scale(0.4);
    }
    20% {
        opacity: 1;
        transform: translate(
            var(--hzfav-px-quarter),
            var(--hzfav-py-quarter)
        ) scale(var(--hzfav-psize, 1));
    }
    100% {
        opacity: 0;
        transform: translate(var(--hzfav-px), var(--hzfav-py)) scale(var(--hzfav-pend, 0.6));
    }
}

@media (max-width: 640px) {
    button.hzp-fav.hzp-like,
    button.hz-lcard__fav.hzp-like {
        width: 32px;
        min-width: 32px;
        height: 32px;
    }
}

@media (prefers-reduced-motion: reduce) {
    button.hzp-fav.hzp-like,
    button.hz-lcard__fav.hzp-like,
    button.hzp-like .hzp-like__icon svg path,
    button.hzp-like--burst .hzp-like__icon,
    button.hzp-like--burst .hzp-like__particles i {
        transition: none;
        animation: none;
    }
}
