/*
Theme Name: Houzez Child — Properseas
Theme URI: https://properseas.com/
Description: Houzez child theme for properseas.com. Home for template overrides and custom code. Created 2026-07-17 (WP-D, defect D2: author email override).
Author: Properseas
Template: houzez
Version: 1.0.0
*/

/* Child-theme CSS additions go below, each with a dated comment block. */

/*
 * 2026-07-21 · archive-flip fix cycle 1 (visual-critic blocker, wp-engineer):
 * Taxonomy-archive intro copy (.taxonomy-description) ran the full 1286px
 * container at 15px type (~150-170 chars/line at 1440px) — read as an SEO blob.
 * Cap the measure at ~72ch, bump type to 16px/27px, and open a ~40px gap before
 * the "N Properties / Sort by" bar. Scoped to taxonomy-archive body classes
 * (tax-property_type / tax-property_city) so the other .taxonomy-description
 * usage (archive-property.php) is untouched. At 390px the container is already
 * narrower than 72ch, so mobile keeps its full width (no shrink).
 */
.tax-property_type .taxonomy-description,
.tax-property_city .taxonomy-description {
    max-width: 72ch;
    margin-bottom: 40px;
}
.tax-property_type .taxonomy-description p,
.tax-property_city .taxonomy-description p {
    font-size: 16px;
    line-height: 27px;
}

/*
 * 2026-07-27 · newsletter 403 release, fix cycle 1 (visual-critic FAIL P1-P4, wp-engineer).
 *
 * Until this release the footer newsletter form 403'd before WordPress ran, so its feedback
 * panel had never actually appeared on the dark footer — it had only ever been seen on the
 * white /contact/ page. This release is what puts it on #202A30, so it is styled here for
 * both contexts.
 *
 * P1 — the panel was stock Bootstrap: .alert-success #d1e7dd fill / #a3cfbb border /
 * #0a3622 text, and .alert-danger's red equivalent. There is no green (or that red) in the
 * palette: Elementor kit 7 is Primary #1E264C, Secondary #3B4B95, Text #C7C7C7,
 * Accent #FFFFFF, footer surface #202A30.
 * The error state is restyled alongside the success state deliberately: the server-side
 * validation added in this same release makes rejection messages reachable in the footer
 * for the first time, so shipping one without the other would just move the problem.
 *
 * Base rules below are the LIGHT-surface treatment (/contact/, widget 0bcb0ae). The dark
 * override further down is scoped to the newsletter widget, which only ever renders in the
 * footer.
 */
.houzez-ele-form-js .ele-form-messages .alert,
.houzez-ele-form-js .error-container .properseas-form-error {
    display: block;
    margin: 0;
    padding: 12px 16px;
    border: 1px solid transparent;
    border-radius: 4px;
    font-size: 14px;
    line-height: 1.5;
    /* Houzez adds .alert-dismissible but renders no close button, so the space Bootstrap
       reserves for one is dead. */
    padding-right: 16px;
}

.houzez-ele-form-js .ele-form-messages .alert-success {
    background-color: #F1F3F8;
    border-color: rgba(30, 38, 76, 0.22);
    color: #1E264C;
}

.houzez-ele-form-js .ele-form-messages .alert-danger,
.houzez-ele-form-js .error-container .properseas-form-error {
    background-color: #FBF2F2;
    border-color: rgba(140, 42, 42, 0.28);
    color: #8C2A2A;
}

/* Spacing: replace Houzez's literal <br/> spacer with real margin, and drop the 16px of
   dead space Bootstrap's .alert leaves below the panel.
   The gap is carried by the panel itself, not by its container: jQuery Validate hides
   spent messages with display:none rather than removing them, so a container-level margin
   would leave a permanent dead gap once a field has errored even once. */
.houzez-ele-form-js > br {
    display: none;
}

.houzez-ele-form-js .ele-form-messages .alert,
.houzez-ele-form-js .error-container .properseas-form-error {
    margin-top: 12px;
}

/*
 * P2 — the panel overhung the input by 3px on the left and the button by 4px on the right.
 * Cause: the newsletter widget styles .elementor-form-fields-wrapper as a white pill with
 * `padding: 3px 4px 5px 3px` (post-20101.css, element 15ce116). The message containers are
 * siblings OUTSIDE that wrapper, so they run the full form width while the controls sit
 * inset by exactly that padding. Match the wrapper's horizontal padding to line them up.
 * If that widget's wrapper padding is ever changed in Elementor, these two values must
 * change with it.
 */
.elementor-element-15ce116 .ele-form-messages,
.elementor-element-15ce116 .error-container {
    padding-left: 3px;
    padding-right: 4px;
}

/* P1 (dark) — the newsletter form only ever renders in the #202A30 footer. */
.elementor-element-15ce116 .ele-form-messages .alert-success {
    background-color: rgba(255, 255, 255, 0.10);
    border-color: rgba(255, 255, 255, 0.30);
    color: #FFFFFF;
}

.elementor-element-15ce116 .ele-form-messages .alert-danger,
.elementor-element-15ce116 .error-container .properseas-form-error {
    background-color: rgba(255, 255, 255, 0.10);
    border-color: rgba(255, 203, 61, 0.55);
    color: #FFFFFF;
}

/*
 * P3 — below 1025px the form's two columns carry `elementor-md-100`, so the field and the
 * submit button stack; the widget sets the field-group row gap to 0, which put the input's
 * bottom edge exactly on the button's top edge (both 10274.1 at 390px) and let the 4px
 * :invalid halo collide with the button border. Open an 8px gap while stacked only — the
 * side-by-side desktop layout is untouched.
 */
@media (max-width: 1024px) {
    .elementor-element-15ce116 .elementor-form-fields-wrapper > .elementor-field-group {
        margin-bottom: 8px;
    }

    .elementor-element-15ce116 .elementor-form-fields-wrapper > .elementor-field-group:last-child {
        margin-bottom: 0;
    }
}

/*
 * 2026-07-28 · footer legal block (wp-engineer).
 *
 * NO LEGAL COPY IS QUOTED IN THIS FILE, AND NONE MAY BE ADDED.
 * A child-theme stylesheet is excluded from the LiteSpeed combiner, so it ships as its own
 * public asset on every page including the 404, and hcdn pins it for a year. That makes every
 * comment in here published text: a quoted sentence is as public as the sentence itself, and
 * it cannot be corrected or purged as quickly. This block quoted the footer's row 1 while that
 * row was being replaced, which briefly published a superseded licence-identification sentence
 * in an asset — caught by qa-auditor at the edge, 2026-07-28. Rows are referred to by NUMBER
 * from here on, so this file can never contradict the copy it styles.
 * The copy itself lives in Elementor post 20101 and in
 * docs/rollback/2026-07-28-legal-footer/README.md.
 *
 * The block is three rows in the footer bottom bar (Elementor fts_builder 20101, container
 * f7aecc6), stacked in reading order:
 *
 *   row 1  identity and licence sentence  -> heading widget, .ps-legal-identity
 *   row 2  the four required links        -> icon-list widget, .ps-legal-links
 *   row 3  copyright line                 -> heading widget 65d6e30 (unchanged by this block)
 *
 * The container was switched from a single justified row to a centred column so the three
 * rows stack. Two consequences worth recording:
 *   - the link row leaves the bottom-right corner, where the fixed .back-to-top-wrap
 *     (42x42, z-index 99) sat directly on top of the last link in row 2 at 1440px —
 *     visual-critic's standing finding. Centring the links moves them clear of it rather
 *     than adding three more link targets underneath it.
 *   - everything below is layout and separator work only.
 *
 * Separators are generated here, not stored as text nodes in Elementor, so a middot can
 * never end up inside link text, inside a translated string, or in the accessible name of
 * a link. The `content: "..." / ""` pair supplies empty alternative text where the browser
 * supports it, so assistive technology reads four link labels rather than interpolating the
 * word "middle dot" between them. Browsers that do not understand the alt-text syntax keep
 * the preceding declaration and still render the middot.
 *
 * U+00B7 is written as the CSS escape \00B7 deliberately: this stylesheet is served without
 * an explicit charset, and an escape cannot be mangled by a re-encoding in transit the way
 * a literal two-byte c2 b7 can.
 */
/* Row 1's width is NOT capped here. An earlier version of this block carried
   `.ps-legal-identity { max-width: 72ch }`, which never applied: Elementor's
   `.elementor.elementor .e-con > .elementor-widget { max-width: 100% }` out-specifies a
   single class 4-to-1, so the computed value was `100%` at every width. The tidy one-line
   result at 1440/1920 comes from the flex parent's shrink-to-fit, not from a cap. The dead
   rule is removed rather than given specificity to win with, because making it bite now would
   re-wrap a line visual-critic has already passed. (Present-but-inert CSS, found 2026-07-28 —
   the second time this site has produced one. Check computed values, not rules.)

   `text-wrap: balance` is deliberately NOT inside a media query: row 1 sets on one line at
   1440/1920 where it is a no-op, two lines at 768, three at 390 and four at 320, and every
   one of those wants balancing. Scoping it to mobile left 768 ragged. */
.ps-legal-identity .elementor-heading-title {
    margin: 0;
    text-wrap: balance;
}

.ps-legal-links .elementor-icon-list-items.elementor-inline-items {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: center;
    /* Horizontal rhythm is carried by the separator's own margins so that the gap either
       side of each middot is identical; the row gap only applies once the list wraps. */
    column-gap: 0;
    row-gap: 4px;
    margin: 0;
    padding: 0;
}

.ps-legal-links .elementor-icon-list-items.elementor-inline-items .elementor-icon-list-item {
    display: inline-flex;
    align-items: baseline;
    margin: 0;
    padding: 0;
}

/* Elementor emits an empty ::after on every inline list item for its optional divider
   rule. We supply our own separator, so retire it inside this widget only. */
.ps-legal-links .elementor-icon-list-items.elementor-inline-items .elementor-icon-list-item::after {
    content: none;
}

.ps-legal-links .elementor-icon-list-items.elementor-inline-items .elementor-icon-list-item > a {
    /* The widget carries .elementor-list-item-link-full_width, which stretches the anchor
       and would push the separator onto its own line. */
    width: auto;
    padding: 0;
}

.ps-legal-links .elementor-icon-list-items.elementor-inline-items .elementor-icon-list-item + .elementor-icon-list-item::before {
    content: "\00B7";
    content: "\00B7" / "";
    /* rgba(188,188,188,.75) over the #1D262B bar resolves to ~5.1:1 — comfortably past AA
       even though a decorative separator is not held to a text ratio. */
    color: rgba(188, 188, 188, 0.75);
    margin: 0 0.7em;
    /* Keeps the dot from breaking away from the link it belongs to. Note this does NOT stop a
       dot leading a wrapped line — a ::before is welded to the link that FOLLOWS it, so it
       wraps with it. That is why the separators are dropped entirely below 768px instead. */
    white-space: nowrap;
}

/* Hover and focus for row 2.
   The visible text is the inner `.elementor-icon-list-text` span, which Elementor colours
   #BCBCBC from the widget's own setting. The theme's `a:hover` recolours the ANCHOR, which is
   #1E264C and never seen — so hovering these four links changed nothing at all while the 11
   sibling footer links go #FFFFFF -> #FFCB3D. Measured, not assumed: anchor and span resolve
   to different colours. The fix therefore targets the span.
   Specificity: Elementor's rule is
   `.elementor-20101 .elementor-element.elementor-element-eac3a76 .elementor-icon-list-text`
   = four classes. The `:hover` / `:focus-visible` pseudo-class counts as a class, so the
   selectors below are four classes plus an element and win by one element. Verified computed.
   #FFCB3D on the #1D262B bar is 10.4:1. */
.ps-legal-links .elementor-icon-list-item > a .elementor-icon-list-text {
    transition: color 0.3s;
}

.ps-legal-links .elementor-icon-list-item > a:hover .elementor-icon-list-text,
.ps-legal-links .elementor-icon-list-item > a:focus-visible .elementor-icon-list-text {
    color: #FFCB3D;
}

/* Keyboard focus was invisible: outline-style none, box-shadow none, even under
   :focus-visible. The sibling footer links measure the same, so this is a theme-wide gap
   rather than something these four links introduced — but an invisible focus ring on the
   only route to the statutory complaints book is not something to reproduce for consistency.
   Flagged for visual-critic: this is deliberately BETTER than the siblings, not matched to
   them. Sweeping the rest of the footer is a separate change set. */
.ps-legal-links .elementor-icon-list-item > a:focus-visible {
    outline: 2px solid #FFCB3D;
    outline-offset: 3px;
    border-radius: 2px;
}

/* Mobile: the sentence wraps to three or four lines and the link row wraps to two, so give
   the block more leading and keep it off the screen edges — the bottom bar has no horizontal
   padding at this breakpoint.
   `text-wrap: balance` evens row 1's three lines out; without it the closing licence number
   is left as an orphan on its own line at 390px. It is a progressive enhancement and is
   ignored by browsers that do not support it. It is also the only tool available here: the
   copy is owner-approved and byte-fixed, so a non-breaking space is not an option. */
@media (max-width: 767px) {
    .ps-legal-identity,
    .ps-legal-links {
        padding-left: 20px;
        padding-right: 20px;
    }

    .ps-legal-identity .elementor-heading-title {
        line-height: 1.7;
    }

    /* Row 2 wraps below 768px — two lines at 390px, four at 320px — and a `::before`
       separator wraps with the link it precedes, so every wrapped line opened with a stray
       middot: "a bulleted list whose first bullet fell off". It also pushed each wrapped line
       12.5px right of true centre, so row 2 no longer lined up with row 1 above it or row 3
       below it. `white-space: nowrap` cannot fix this — it prevents the dot separating from
       its link, which is the opposite problem.
       Once the rows stack, the separators have no work to do: line breaks already separate
       the links. So they are dropped and replaced with real spacing. */
    .ps-legal-links .elementor-icon-list-items.elementor-inline-items .elementor-icon-list-item + .elementor-icon-list-item::before {
        content: none;
    }

    .ps-legal-links .elementor-icon-list-items.elementor-inline-items {
        column-gap: 22px;
        row-gap: 10px;
    }
}

/*
 * The four in-content links on /legal/.
 *
 * They inherited the theme default — #1E264C, no underline, weight 400 — against #222222 body
 * text. That is 14.62:1 against the white surface but **1.09:1 against the text around them**,
 * so they were not identifiable as links at all, and nothing changed on hover. This is the
 * first page on the site to exercise that default: both sibling legal pages contain zero
 * in-content links.
 *
 * Underlined rather than recoloured. To distinguish links by COLOUR alone WCAG wants 3:1
 * against the surrounding text, and no colour that clears 3:1 against #222222 also stays
 * legible on white — so the underline does the identifying work and the colour is free to be
 * the readable one. Hover then has two signals, colour and thickness.
 *
 * Scoped to `.page-content-wrap`, the Houzez wrapper for classic page content. Measured: it is
 * present on exactly the three legal pages and on none of /about/, /contact/, /blog/ or
 * /agents/, which are Elementor-built. The two siblings have no in-content links today, so
 * this changes nothing on them now and guarantees all three match the moment they do. Any
 * future classic page inherits the fix rather than the unusable default.
 */
.page-content-wrap a {
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 2px;
    transition: color 0.3s;
}

.page-content-wrap a:hover,
.page-content-wrap a:focus-visible {
    /* #3B4B95 is Elementor kit 7's Secondary. 8.06:1 on white. */
    color: #3B4B95;
    text-decoration-thickness: 2px;
}

.page-content-wrap a:focus-visible {
    outline: 2px solid #3B4B95;
    outline-offset: 2px;
    border-radius: 2px;
}

/*
 * Property detail pages, below Bootstrap's `lg` breakpoint, carry a SECOND fixed overlay:
 * Houzez's `.mobile-property-contact` agent bar (`d-block d-lg-none`, so visible under
 * 992px), 71px tall at 390px and 768px and 96px at 320px, pinned to the bottom of the
 * viewport. It also pushes `.back-to-top-wrap` up on top of it — measured, the button's top
 * edge sits a consistent 122px above the viewport bottom on these pages at 320, 390 and
 * 768px, against 57px elsewhere.
 *
 * Two consequences, both of which this rule fixes:
 *   - the button clipped the last link in row 2 by 2px at 390px;
 *   - the agent bar sat over row 3 at 320px. That one is pre-existing rather than new —
 *     before this release the whole of row 2 was underneath it on these pages — but a legal
 *     block that is permanently obscured on the site's most-visited page type is not doing
 *     its job, so it is fixed here rather than logged and left.
 *
 * 130px clears the measured 122px on every one of those widths with slack. Scoped to
 * `body.single-property` so no other page type pays for it. The extra specificity (three
 * classes plus an element) is what beats Elementor's own generated padding rule for this
 * container, which is three classes; nothing here depends on the footer's post ID.
 */
@media (max-width: 991px) {
    body.single-property .elementor-element.elementor-element-c3da54d {
        --padding-bottom: 130px;
        padding-bottom: 130px;
    }
}

/* NOTE — the keep-out that stops the theme's fixed .back-to-top-wrap landing on the link row
   is deliberately NOT here. It is bottom padding on container c3da54d — 78px at <=1024px,
   62px at <=767px — set in Elementor itself, because Elementor's own generated padding rule
   for that container out-specifies any selector this file could write.
   See replay-elementor-post-20101-legal-footer.php. Recorded here so the two halves of that
   decision are never read in isolation. */
