/*
Theme Name: Topsail Tanner
Author: Tanner Gray
Description: Lightweight custom block theme for TopsailTanner.com. Built on native WordPress block templates with no page builder dependency.
Requires at least: 6.7
Tested up to: 7.0.4
Requires PHP: 8.2
Version: 0.7.0
License: Proprietary
License URI: https://topsailtanner.com
Text Domain: topsail-tanner
*/

/*
 * Design tokens live in theme.json. This file carries only what global
 * styles cannot express: component structure, the accessibility
 * baselines the Master Build Brief requires, and the brand's
 * application rules.
 *
 * Palette is locked by docs/brand/Topsail_Tanner_Brand_Direction.md:
 * Deep Navy #1B2A41, Warm Sand #E8DFCB, Seafoam #5F9EA0,
 * Charcoal #2B2B2B. No other brand hue may appear. Gold is prohibited.
 *
 * Seafoam measures ~2.9:1 on white, below the AA threshold for text, so
 * it is used here only for underlines, borders, focus rings and other
 * non-text accents on light surfaces. Text links are Navy. This is the
 * brand's own application rule, not a substitution for it.
 */

/* ---------------------------------------------------------------
 * Focus visibility
 *
 * The brief requires visible focus states throughout. :focus-visible
 * keeps the indicator off mouse clicks while guaranteeing it for
 * keyboard users. Seafoam carries it — a non-text use, so its contrast
 * ratio is judged as a graphical object (3:1), which it clears.
 * --------------------------------------------------------------- */

:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
	outline: 3px solid var(--wp--preset--color--seafoam);
	outline-offset: 2px;
}

/* On navy surfaces the seafoam ring loses separation, so the focus
   indicator inverts to white. */
.tt-on-navy :where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
	outline-color: var(--wp--preset--color--base);
}

/* ---------------------------------------------------------------
 * Reduced motion
 *
 * Global backstop. Components that animate also check the query
 * themselves so they can drop the behaviour, not merely its duration.
 * --------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {

	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
}

/* ---------------------------------------------------------------
 * Screen-reader-only text
 *
 * Block themes do not ship this, and several components need a label
 * that is announced but not shown — a submenu toggle, or the warning
 * that a link opens in a new tab.
 * --------------------------------------------------------------- */

.screen-reader-text {
	position: absolute !important;
	overflow: hidden;
	clip-path: inset(50%);
	inline-size: 1px;
	block-size: 1px;
	margin: -1px;
	padding: 0;
	border: 0;
	white-space: nowrap;
	word-wrap: normal;
}

.screen-reader-text:focus {
	z-index: 100000;
	top: 0.5rem;
	left: 0.5rem;
	display: block;
	clip-path: none;
	inline-size: auto;
	block-size: auto;
	padding: 0.75rem 1.25rem;
	background-color: var(--wp--preset--color--base);
	color: var(--wp--preset--color--navy);
	font-size: 0.875rem;
	text-decoration: none;
}

/* ---------------------------------------------------------------
 * Typography rules the token layer cannot express
 * --------------------------------------------------------------- */

/* 16px body floor. The reference site sets 14px; that is below the
   readability floor this project committed to. */
body {
	font-size: max(1rem, var(--wp--preset--font-size--medium));
	text-underline-offset: 0.18em;
}

/* Playfair at display sizes benefits from slightly tighter tracking;
   at small sizes it does not. */
h1,
.tt-display {
	letter-spacing: -0.01em;
}

/* The small uppercase register used for eyebrows and interface labels. */
.tt-eyebrow {
	font-family: var(--wp--preset--font-family--body);
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--wp--preset--color--navy);
	margin: 0 0 0.75rem;
}

.tt-on-navy .tt-eyebrow {
	color: var(--wp--preset--color--sand);
}

/* ---------------------------------------------------------------
 * Links
 *
 * Navy text with a seafoam underline: the interactive accent is present
 * without carrying the contrast burden.
 * --------------------------------------------------------------- */

.wp-block-post-content a:where(:not(.wp-element-button)),
.tt-prose a:where(:not(.wp-element-button)) {
	color: var(--wp--preset--color--navy);
	text-decoration-color: var(--wp--preset--color--seafoam);
	text-decoration-thickness: 2px;
}

/* On a navy band the same link inverts. Declared before the hover rules
   so specificity runs in ascending order down the file. */
.tt-on-navy a:where(:not(.wp-element-button)) {
	color: var(--wp--preset--color--base);
	text-decoration-color: var(--wp--preset--color--seafoam);
}

.wp-block-post-content a:where(:not(.wp-element-button)):hover,
.tt-prose a:where(:not(.wp-element-button)):hover {
	text-decoration-color: var(--wp--preset--color--navy);
}

/* ---------------------------------------------------------------
 * Buttons
 *
 * Square corners, uppercase micro-type, 44px minimum target. The solid
 * variant is navy; the outline variant inverts. On navy surfaces the
 * outline variant switches to white so it stays visible.
 * --------------------------------------------------------------- */

.wp-element-button,
.wp-block-button__link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: 44px;
	transition: background-color 150ms ease, color 150ms ease, border-color 150ms ease;
}

.wp-block-button.is-style-outline > .wp-block-button__link,
.tt-button--outline {
	background-color: transparent;
	color: var(--wp--preset--color--navy);
	border: 1px solid var(--wp--preset--color--navy);
}

.wp-block-button.is-style-outline > .wp-block-button__link:hover,
.tt-button--outline:hover {
	background-color: var(--wp--preset--color--navy);
	color: var(--wp--preset--color--base);
}

.tt-on-navy .wp-block-button.is-style-outline > .wp-block-button__link,
.tt-on-navy .tt-button--outline {
	color: var(--wp--preset--color--base);
	border-color: var(--wp--preset--color--base);
}

.tt-on-navy .wp-block-button.is-style-outline > .wp-block-button__link:hover,
.tt-on-navy .tt-button--outline:hover {
	background-color: var(--wp--preset--color--base);
	color: var(--wp--preset--color--navy);
}

/* ---------------------------------------------------------------
 * Section rhythm
 *
 * The reference's pacing is a sequence of boxed rooms rather than
 * full-bleed vistas, so sections are content-height with generous but
 * not vast padding.
 * --------------------------------------------------------------- */

.tt-section {
	padding-block: var(--wp--preset--spacing--70);
}

.tt-section--tight {
	padding-block: var(--wp--preset--spacing--50);
}

.tt-section--sand {
	background-color: var(--wp--preset--color--sand);
}

.tt-section--navy,
.tt-on-navy {
	background-color: var(--wp--preset--color--navy);
	color: var(--wp--preset--color--base);
}

.tt-on-navy :is(h1, h2, h3, h4) {
	color: var(--wp--preset--color--base);
}

/* A centred section heading with its optional eyebrow above. */
.tt-section__head {
	text-align: center;
	margin-bottom: var(--wp--preset--spacing--50);
}

.tt-section__head > * {
	margin-inline: auto;
}

.tt-section__head p {
	max-width: 46rem;
}

/* The homepage's own main has no padding of its own, so each section
   controls its own vertical rhythm and full-width bands reach the
   edges of the viewport. It also begins directly beneath the header
   (2 October 2026): the theme's block gap put 1.5rem of white between
   the header and the first section on every page — the hero video on
   the homepage, the navy banner elsewhere — which read as a stray
   stripe. */
.tt-main {
	margin-block-start: 0;
	padding-block: 0;
}

/* Content that is not built from full-width bands still needs vertical
   rhythm of its own, because this main has none. The Tour Request page
   is the one that matters: it is a form, not a sequence of sections,
   and without this it would sit flush against the banner above it. */
.tt-main > .wp-block-post-content > * {
	margin-block: var(--wp--preset--spacing--60);
}

/* A band controls its own rhythm through its section padding. */
.tt-main > .wp-block-post-content > .alignfull,
.tt-main > .wp-block-post-content > .alignwide {
	margin-block: 0;
}

/* The welcome strip: heading, brand line, actions, centred. */
.tt-section--welcome {
	text-align: center;
}

/* The heading is seven words. Balanced, a phone shows it as three
   even lines rather than two full ones and an orphan; a desktop is
   unaffected because it fits on one. */
.tt-section--welcome h1 {
	text-wrap: balance;
}

/* Below 390px the display size's fluid floor (1.9rem) no longer fits
   "Mainland Communities" on one line, and the heading fell to four
   lines with "Real" and "Estate" parted. A step down to 1.75rem at
   that width alone keeps it to the approved three: "Topsail Island &",
   "Mainland Communities", "Real Estate". Nothing else uses the size. */
@media (max-width: 389px) {

	.tt-section--welcome h1 {
		font-size: 1.75rem;
	}
}

.tt-section--welcome .wp-block-buttons,
.tt-section--welcome .tt-cta-wrap {
	justify-content: center;
}

.tt-lede {
	max-inline-size: 44rem;
	margin-inline: auto;
	color: var(--wp--preset--color--charcoal);
	text-wrap: balance;
}

.tt-section--center {
	text-align: center;
}

.tt-section--center .wp-block-buttons,
.tt-section--center .tt-cta-wrap {
	justify-content: center;
}

.tt-section--center p {
	max-inline-size: 44rem;
	margin-inline: auto;
}

/* Sections that pair words with a photograph. */
.tt-split {
	align-items: center;
	gap: var(--wp--preset--spacing--60);
}

.tt-split .wp-block-column > *:first-child {
	margin-block-start: 0;
}

/* The four experience cards. */
.tt-cards {
	gap: var(--wp--preset--spacing--40);
}

.tt-cards > .wp-block-column {
	padding: var(--wp--preset--spacing--40);
	background-color: var(--wp--preset--color--base);
	border: 1px solid rgb(27 42 65 / 12%);
}

.tt-cards h3 {
	margin-block-start: 0;
	font-size: var(--wp--preset--font-size--large);
}

.tt-cards p {
	margin-block-end: 0;
}

/* A media slot with no approved photograph renders nothing at all
   outside a local environment, which would otherwise leave its column
   standing empty and the words beside it stranded at 62% width. An empty
   column removes itself, so the section reads as a single measure of
   prose until the photograph arrives. */
.tt-split > .wp-block-column:empty {
	display: none;
}

@media (max-width: 781px) {

	.tt-split {
		gap: var(--wp--preset--spacing--50);
	}
}

/* ---------------------------------------------------------------
 * Interior pages
 *
 * One system across Buying, Selling, Investing, About and Contact, so
 * the five read as one site rather than as five documents that happen
 * to share a header. Every piece below is a modifier on the section
 * rhythm the homepage already uses — there is no separate interior
 * design, and adding one would be the surest way for the two halves of
 * the site to drift apart.
 *
 * The order a page is built from: navy banner (breadcrumb + H1) →
 * intro → alternating white and sand sections, some paired with a
 * photograph → supporting cards where the content is a checklist →
 * disclosure where one is required → the closing Contact me band.
 * --------------------------------------------------------------- */

/* The opening band. It follows the navy banner directly, so it carries
   less top padding than a mid-page section would: the banner has
   already supplied the space above it. */
.tt-section--intro {
	padding-block-start: var(--wp--preset--spacing--50);
}

.tt-section--intro .tt-lede {
	margin-block-start: 0;
}

/* An intro that sits beside a portrait is a column, not a centred
   strip, so its measure runs to the column edge rather than being
   pulled back to the middle. */
.tt-section--split .tt-lede {
	margin-inline: 0;
}

/* ---------------------------------------------------------------
 * Supporting information cards
 *
 * An approved checklist, set as cards. The wording is the approved list
 * unchanged: each item's leading phrase is a <strong>, and promoting it
 * to its own line is what turns a bullet into a card title. Nothing was
 * rewritten to fit the shape.
 * --------------------------------------------------------------- */

.tt-card-list-frame {
	margin-block: 0;
}

.tt-card-list {
	display: grid;
	gap: var(--wp--preset--spacing--40);
	grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
	margin: 0;
	padding: 0;
	list-style: none;
}

.tt-card-list > li {
	padding: var(--wp--preset--spacing--40);
	background-color: var(--wp--preset--color--base);
	border: 1px solid rgb(27 42 65 / 12%);
	line-height: 1.6;
}

.tt-card-list > li > strong {
	display: block;
	margin-block-end: 0.4rem;
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--large);
	font-weight: 600;
	line-height: 1.25;
	color: var(--wp--preset--color--navy);
}

/* ---------------------------------------------------------------
 * Identity and contact detail cards
 *
 * The approved identity block on About, and the identity plus the phone
 * and email on Contact. Set as cards because on those two pages they
 * are the content rather than a footnote to it.
 * --------------------------------------------------------------- */

/* The identity is the live Brokerage Identity block — an <address> —
   since 16 September 2026. On About it closes the professional
   background section since 21 September 2026, whose paragraphs are
   prose rather than cards, so only the address takes the card. */
.tt-section--identity > address,
.tt-section--details > p,
.tt-section--details > address,
.tt-section--details > ul {
	box-sizing: border-box;
	padding: var(--wp--preset--spacing--40);
	background-color: var(--wp--preset--color--base);
	border: 1px solid rgb(27 42 65 / 12%);
	line-height: 1.8;
}

.tt-section--details > ul {
	line-height: 1.6;
}

.tt-section--details .tt-contact-info__row:last-child {
	margin-block-end: 0;
}

/* ---------------------------------------------------------------
 * The Seller's Guide
 *
 * A guide step is a long read rather than a landing page, so the bands
 * are tighter than the interior pages' and alternate less. The reader is
 * working through one argument; a page that changes colour every two
 * paragraphs makes that harder, not easier.
 * --------------------------------------------------------------- */

.tt-section--guide {
	padding-block: var(--wp--preset--spacing--50);
}

/* Long-form prose wants a little more air between paragraphs than a
   landing page does. */
.tt-section--guide p {
	line-height: 1.7;
}

/* The quiet band that closes a step: the general-information note and
   where the facts came from. Set back from the argument above it. */
.tt-section--guide-close {
	border-block-start: 1px solid rgb(27 42 65 / 12%);
}

.tt-section--guide-close h2 {
	font-size: var(--wp--preset--font-size--large);
}

.tt-section--guide > h2:first-child {
	margin-block-start: 0;
}

/* Sources are links out to official material, deliberately not
   reproduced here. Set as a plain list so they read as a citation
   rather than as further reading being promoted. */
.tt-sources {
	max-inline-size: 46rem;
	margin-block: 0;
	padding-inline-start: 1.1rem;
	font-size: 0.9375rem;
	line-height: 1.6;
}

.tt-sources li {
	margin-block-end: 0.25rem;
}

/* Each citation is its own link on its own line rather than a link
   inside a sentence, so the 44px target rule applies to it like any
   other control. The padding buys the height; the text does not move.
   Both classes are named so this outranks the general link rules above
   rather than quietly losing to them. */
.wp-block-list.tt-sources a {
	display: inline-flex;
	align-items: center;
	min-block-size: 44px;
	padding-block: 0.5rem;
}

/* The way into the guide from the Selling page. A link, not a button —
   there is one prominent call to action on this site and this is not
   it. */
.tt-guide-entry {
	margin-block-start: var(--wp--preset--spacing--40);
	font-weight: 500;
}

.tt-guide-entry__link {
	color: var(--wp--preset--color--navy);
	text-decoration: underline;
	text-decoration-color: var(--wp--preset--color--seafoam);
	text-decoration-thickness: 2px;
	text-underline-offset: 0.2em;
}

.tt-guide-entry__link:hover {
	text-decoration-color: currentcolor;
}

/* The step selector sits flush under the banner, so it reads as part of
   the guide's furniture rather than as the first thing in the body. The
   pager closes the step and needs the space the selector does not. */
.tt-main > .wp-block-post-content > .tt-guide-pager {
	margin-block: 0 var(--wp--preset--spacing--60);
}

/* ---------------------------------------------------------------
 * Header
 *
 * Sticky and solid navy rather than transparent over the hero.
 *
 * The reference fades a transparent header into a solid one on scroll.
 * That is deferred here for two reasons that will both resolve: the
 * approved video and poster have not been delivered, so there is
 * nothing whose brightness could be measured to prove the nav stays
 * legible over it; and the logo files carry baked-in backgrounds, so
 * the mark cannot sit over media at all yet. A solid bar is legible
 * against anything, needs no JavaScript, and cannot shift the layout.
 * Recorded as a deviation in the design blueprint, to be revisited when
 * the footage and transparent assets arrive.
 * --------------------------------------------------------------- */

.tt-header {
	position: sticky;
	top: 0;
	z-index: 50;
}

.tt-header__inner {
	gap: var(--wp--preset--spacing--40);
}

/* The identity must not be squeezed out by the menu: it keeps its size
   and the menu gives way — collapsing below 1216px, where the full row
   would otherwise fold to two lines beside the two marks (T-82). */
.tt-header__inner > .tt-mark {
	flex: 0 0 auto;
}

.tt-header__inner > .tt-nav-root {
	flex: 0 1 auto;
	inline-size: auto;
}

@media (max-width: 1215px) {

	.tt-header__inner > .tt-nav-root {
		flex: 0 0 auto;
	}
}

/* On a phone the menu button sits on the row with the two marks again
   (2 October 2026, T-86): the stacked firm mark is narrow enough that
   all three fit from 360px, with a tighter gap because the firm file's
   own transparent border already separates it from the button. */
@media (max-width: 599px) {

	.tt-header .tt-header__inner {
		column-gap: 0.5rem;
	}
}

/* Below 360px the three no longer fit side by side, so the two marks
   keep a row of their own and the menu button takes a compact row
   beneath them, as T-82 set out. */
@media (max-width: 359px) {

	.tt-header .tt-header__inner {
		flex-wrap: wrap;
		row-gap: 0.5rem;
	}

	.tt-header__inner > .tt-mark,
	.tt-header__inner > .tt-nav-root {
		flex: 1 0 100%;
	}
}

/* ---------------------------------------------------------------
 * Footer
 * --------------------------------------------------------------- */

.tt-footer__columns {
	gap: var(--wp--preset--spacing--50);
}

.tt-footer__areas {
	opacity: 0.85;
	line-height: 1.7;
}

/* The legal strip. Brokerage disclosure, fair-housing wording and IDX
   attribution join this band when the broker-in-charge and FBS supply
   them; none is drafted here. The quieting opacity sits on the
   compliance text, not on the strip, because the brokerage's white
   mark lives here too and a brand mark is shown at its own colour,
   never dimmed. */
.tt-footer__legal {
	border-top: 1px solid rgb(232 223 203 / 25%);
}

/* The membership and fair-housing marks, side by side, between the
   brokerage mark and the compliance text (2 October 2026). */
.tt-footer__affiliations {
	gap: 0.75rem;
	margin-block: 0.75rem 0;
}

/* The GUILD seal joins them (2 October 2026). It is gold with its
   lettering cut through, so it sits on the navy as it is, at the tiles'
   height, with no tile of its own. */
.tt-footer__affiliations .tt-brand-mark--clhms-guild .tt-brand-mark__image {
	inline-size: 4.5rem;
	margin-block-end: 0;
}

/* The compliance line: brokerage disclosure, Equal Housing
   Opportunity statement, and the links to the four compliance pages.
   Each part is drawn only when it exists, so this has to look
   deliberate with one of them present and with all three.

   On navy, so the 44px floor and the focus ring both matter here as
   much as anywhere — a compliance link nobody can reach by keyboard
   is the kind of detail that makes the rest of the page a claim. */
.tt-compliance {
	margin-block-start: 0.75rem;
}

/* The quieting opacity the legal strip used to carry as a whole now
   sits on the compliance text alone, because the brokerage's white
   mark shares the strip and a brand mark is shown at its own colour. */
.tt-footer__legal .tt-compliance {
	opacity: 0.85;
}

.tt-compliance__disclosure,
.tt-compliance__housing {
	margin-block: 0.35rem 0;
	font-size: 0.8125rem;
	line-height: 1.5;
}

/* The wording is entered as plain text in settings; a line break typed
   there is kept as a line break here (2 October 2026). */
.tt-compliance__disclosure {
	white-space: pre-line;
}

.tt-compliance__links {
	display: flex;
	flex-wrap: wrap;
	gap: 0 1.5rem;
	margin-block: 0.5rem 0;
	padding: 0;
	list-style: none;
}

.tt-compliance__item {
	margin: 0;
}

/* stylelint-disable-next-line no-descending-specificity -- scoped to the
   footer compliance list, and deliberately later than the global link
   rules it is narrowing. */
.tt-compliance__links a {
	display: inline-flex;
	align-items: center;
	min-block-size: 44px;
	font-size: 0.8125rem;
	letter-spacing: 0.04em;
	text-transform: uppercase;
}

@media (max-width: 781px) {

	.tt-footer__columns {
		gap: var(--wp--preset--spacing--50);
	}
}

/* The compact footer, 2 October 2026 (T-87). The footer was as tall as
   its longest column — seventeen site links at 44px each, about 750px —
   with the other three columns empty beneath their first few lines. The
   links now flow down two columns, in the same order, each still a 44px
   target; from 782px the four columns are a grid sized by what they
   hold, so the email address no longer breaks mid-word; and the legal
   strip sets the brokerage mark beside the compliance links instead of
   above them. Nothing was removed and the reading order is unchanged. */
.tt-footer .tt-nav--compact {
	display: block;
	column-count: 2;
	column-gap: var(--wp--preset--spacing--40);
}

.tt-footer .tt-nav--compact .tt-nav__item {
	break-inside: avoid;
}

/* Second pass, the same day: every column is brought toward the height
   of "Areas served". With a mouse or trackpad the site links stand 30px
   apart rather than 44px — a touch screen keeps the 44px target — the
   agent mark steps from 5.5rem to 4.5rem here, and the block gaps
   beneath the headings tighten. */
@media (min-width: 1024px) and (hover: hover) and (pointer: fine) {

	.tt-footer .tt-nav--compact .tt-nav__link {
		min-block-size: 30px;
	}
}

.tt-footer .tt-brand-mark--tanner-cream .tt-brand-mark__image {
	block-size: 4.5rem;
	margin-block-end: 0;
}

.tt-footer .tt-identity,
.tt-footer .tt-contact-info,
.tt-footer .tt-footer__areas,
.tt-footer .tt-footer__columns nav {
	margin-block-start: 0.75rem;
}

@media (min-width: 782px) {

	.tt-footer .tt-footer__columns {
		display: grid;
		grid-template-columns: repeat(2, minmax(0, 1fr));
		align-items: start;
	}

	.tt-footer .tt-footer__legal {
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		justify-content: space-between;
		gap: 0.5rem var(--wp--preset--spacing--50);
	}

	/* WordPress centres a constrained group's children with auto margins
	   marked important; the strip is a row here, so they are answered in
	   kind. */
	.tt-footer .tt-footer__legal > * {
		flex: 0 1 auto;
		max-inline-size: none;
		margin-block: 0;
		margin-inline: 0 !important;
	}

	.tt-footer .tt-footer__legal .tt-compliance__links {
		margin-block-start: 0;
	}

	/* The mark's box is given its width, because a percentage-sized image
	   inside an auto-sized flex item would collapse to nothing. */
	.tt-footer .tt-footer__legal .tt-brand-mark--bhgre-white {
		flex: 0 0 auto;
		inline-size: 14rem;
	}

	.tt-footer .tt-footer__legal .tt-brand-mark__image--brokerage {
		inline-size: 100%;
	}
}

/* Two by two on a tablet; four across from 1024px, where the email
   address sets the width of its own column. */
@media (min-width: 1024px) {

	.tt-footer .tt-footer__columns {
		grid-template-columns: minmax(0, 1.6fr) max-content minmax(0, 0.9fr) minmax(0, 1.5fr);
	}
}

/* ---------------------------------------------------------------
 * Media frames
 *
 * Every media slot reserves its aspect ratio so nothing shifts while an
 * image loads. This is the CLS guarantee, expressed once.
 * --------------------------------------------------------------- */

.tt-frame {
	position: relative;
	overflow: hidden;
	background-color: var(--wp--preset--color--sand);
}

/* An approved photograph ships as a <picture> — WebP with a JPEG
   fallback — and the image inside it is what fills the frame. The
   picture element itself generates no box, so the frame's ratio and
   clip apply to the image exactly as they do to a bare one. The image
   is matched through :where() so it ranks no higher than a bare
   child and the tile's own image rules still apply on top. */
.tt-frame > picture {
	display: contents;
}

.tt-frame > img,
.tt-frame :where(picture > img),
.tt-frame > video {
	display: block;
	inline-size: 100%;
	block-size: 100%;
	object-fit: cover;
}

.tt-frame--portrait {
	aspect-ratio: 2 / 3;
}

.tt-frame--tall {
	aspect-ratio: 2 / 3;
}

.tt-frame--landscape {
	aspect-ratio: 3 / 2;
}

.tt-frame--card {
	aspect-ratio: 9 / 8;
}

.tt-frame--tile {
	aspect-ratio: 9 / 17;
}

.tt-frame--wide {
	aspect-ratio: 21 / 9;
}

/* ---------------------------------------------------------------
 * Local-only media placeholder
 *
 * Shown when approved media has not been delivered. It renders only in
 * a local environment — the PHP guard refuses to emit it anywhere else,
 * so this styling can never reach a visitor. It is deliberately plain
 * and clearly labelled: it must never be mistaken for a photograph of
 * Topsail Island.
 * --------------------------------------------------------------- */

.tt-placeholder-media {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 0.5rem;
	padding: 1.5rem;
	text-align: center;
	background-color: var(--wp--preset--color--sand);
	border: 2px dashed var(--wp--preset--color--seafoam);
	color: var(--wp--preset--color--charcoal);
	block-size: 100%;
}

.tt-placeholder-media__label {
	font-family: var(--wp--preset--font-family--body);
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.12em;
	text-transform: uppercase;
}

.tt-placeholder-media__detail {
	font-size: 0.8125rem;
	max-inline-size: 24rem;
	margin: 0;
}

/* ---------------------------------------------------------------
 * Small print and disclosures
 *
 * A disclosure has to be subordinate to the content it qualifies and
 * legible at the same time, and the obvious way to do the first breaks
 * the second: shrinking it below the project's 16px floor would trade a
 * stated accessibility commitment for a visual effect. So it stays at
 * body size and earns its subordinate position another way — set apart
 * by a hairline, held to a narrower measure, and quieter in tone than
 * the copy above it. It reads as a footnote without being hard to read.
 * --------------------------------------------------------------- */

.tt-disclosure {
	max-inline-size: 46rem;
	margin-block-start: var(--wp--preset--spacing--40);
	padding-block-start: var(--wp--preset--spacing--30);
	border-block-start: 1px solid rgb(27 42 65 / 20%);
	font-size: 1rem;
	line-height: 1.5;
	color: var(--wp--preset--color--charcoal);

	/* Charcoal held back rather than a second grey introduced: the
	   palette is locked, and a muted tone is not a licence to add a hue.
	   Measures 6.5:1 on white and 5.6:1 on sand. */
	opacity: 0.75;
}

/* ---------------------------------------------------------------
 * Editor-only affordances
 *
 * Placeholder surfaces shown inside the block editor so an author can
 * see where a component will render. Never output on the front end.
 * --------------------------------------------------------------- */

.tt-editor-placeholder {
	padding: 1rem;
	border: 1px dashed var(--wp--preset--color--seafoam);
	background-color: var(--wp--preset--color--sand);
	color: var(--wp--preset--color--charcoal);
	font-family: var(--wp--preset--font-family--body);
	font-size: 0.875rem;
}

/**
 * Photographic tiles.
 *
 * Shared by the pathway tiles and the area tiles, which differ only in
 * their crop and how many sit in a row.
 *
 * The label sits over a navy scrim rather than directly on the
 * photograph. A scrim is what makes the contrast ratio a property of
 * the design instead of a property of whichever picture is uploaded —
 * white on navy at 65% clears AA against any frame beneath it.
 */

.tt-tiles {
	display: grid;
	gap: 1.25rem;
	grid-template-columns: repeat(2, minmax(0, 1fr));
}

.tt-tile {
	position: relative;
	display: block;
	overflow: hidden;
	text-decoration: none;
	color: #fff;
	background-color: var( --wp--preset--color--navy, #1b2a41 );
}

/* The lettering is white in every state the link can be in, said with
   two simple selectors' worth of weight. A tile is an anchor inside
   the post content, and the prose rule that colours such anchors navy
   (`.wp-block-post-content a:where(...)`, class plus element) outranks
   the single class above — so on the photographs the names came out
   navy on navy scrim, and only the hover rules ever changed them. Held
   at `.tt-tile:is(...)` the white wins at rest, after a visit, under
   the pointer, with keyboard focus and while pressed, and no anchor
   rule of one class and one element can take it back. */
.tt-tile:is(:link, :visited, :hover, :focus-visible, :active) {
	color: #fff;
}

.tt-tile__media {
	display: block;
	inline-size: 100%;
}

.tt-tile__media img {
	transition: transform 300ms ease;
}

.tt-tile__scrim {
	position: absolute;
	inset: 0;
	background: linear-gradient(
		180deg,
		rgb(27 42 65 / 25%) 0%,
		rgb(27 42 65 / 45%) 55%,
		rgb(27 42 65 / 78%) 100%
	);
	transition: opacity 300ms ease;
}

.tt-tile__label {
	position: absolute;
	inset-block-end: 0;
	inset-inline: 0;
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
	padding: 1.25rem;
	font-family: var( --wp--preset--font-family--display, Georgia, serif );
	font-size: clamp( 1.1rem, 0.95rem + 0.6vw, 1.45rem );
	font-weight: 600;
	line-height: 1.15;
	text-wrap: balance;
}

.tt-tile__eyebrow {
	font-family: var( --wp--preset--font-family--body, system-ui, sans-serif );
	font-size: 0.6875rem;
	font-weight: 600;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	opacity: 0.9;
}

.tt-tile__name {
	display: block;
}

/* The county, under the name. Body face and a smaller size, so the two
   read as a name and a fact about it rather than as two headings. */
.tt-tile__meta {
	font-family: var( --wp--preset--font-family--body, system-ui, sans-serif );
	font-size: 0.6875rem;
	font-weight: 500;
	line-height: 1.35;
	letter-spacing: 0.02em;
	opacity: 0.88;
}

/* ---------------------------------------------------------------
 * The tile with no photograph
 *
 * An area tile is a link to a page about a real place. Its picture has
 * not been taken yet, and the media guard will not invent one — but the
 * link, the name and the county are worth having without it, so the
 * tile keeps its shape on the navy field instead of disappearing.
 *
 * The label is positioned rather than absolute here, because there is
 * no image beneath it to sit over. The tile is a flex column that pushes
 * it to the bottom, so lettering sits in the same place whether the
 * photograph has arrived or not, and adding one later moves nothing.
 * --------------------------------------------------------------- */

.tt-tile--text {
	display: flex;
	flex-direction: column;
	justify-content: flex-end;
	aspect-ratio: 9 / 17;
	border: 1px solid rgb(232 223 203 / 28%);
	transition: background-color 150ms ease;
}

/* Hover is a border accent rather than a darker fill. The palette is
   locked to four hues and a fifth, darker navy is not one of them —
   seafoam on a border is a role the brand explicitly allows. */
.tt-tile--text:hover {
	border-color: var( --wp--preset--color--seafoam, #5f9ea0 );
}

.tt-tile--text .tt-tile__label {
	position: static;
	inline-size: 100%;
}

/* Hover lifts the photograph very slightly and deepens the scrim. The
   clip on the tile means nothing around it moves. */
.tt-tile:hover .tt-tile__media img {
	transform: scale(1.04);
}

.tt-tile:hover .tt-tile__scrim {
	opacity: 0.88;
}

.tt-tile:focus-visible {
	outline: 3px solid var( --wp--preset--color--seafoam, #5f9ea0 );
	outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {

	.tt-tile:hover .tt-tile__media img {
		transform: none;
	}
}

/* ---------------------------------------------------------------
 * Counts
 *
 * The grid is written for however many tiles actually resolve, so a
 * missing pathway leaves a deliberate row rather than a gap.
 * --------------------------------------------------------------- */

/* The area tiles go to three across a little earlier than everything
   else. They are 9:17, so two of them across a 768px tablet come out
   647px tall each — technically fine, and a wall of two enormous
   portraits in practice. Three across at the same width is 453px, which
   is a tile rather than a poster. The ratio is the approved one and is
   not what changes here; only how many share the row. */
@media (min-width: 700px) {

	.tt-tiles--areas {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

@media (min-width: 782px) {

	.tt-tiles--pathways {
		grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
	}
}

/* Six across from 1000px rather than 1100. Between those two widths the
   three-column rule was producing 580px-tall tiles at 1024 — one of the
   widths this design is checked at — where six across gives 270px. The
   row is the reference's treatment for these tiles and the one the 9:17
   ratio exists for; three across is the fallback for narrower screens,
   not a second desktop layout. */
@media (min-width: 1000px) {

	.tt-tiles--areas.tt-tiles--count-4 {
		grid-template-columns: repeat(4, minmax(0, 1fr));
	}

	.tt-tiles--areas.tt-tiles--count-5,
	.tt-tiles--areas.tt-tiles--count-6 {
		grid-template-columns: repeat(6, minmax(0, 1fr));
	}

	/* Six across is a narrow tile, and the label has three lines to fit
	   into it: the group, the name and the county. At the shared display
	   size the longest of them filled well over half the tile. The
	   lettering steps down here so the photograph stays the larger part
	   of the tile, which is the whole point of a photographic tile. */
	.tt-tiles--areas.tt-tiles--count-5 .tt-tile__label,
	.tt-tiles--areas.tt-tiles--count-6 .tt-tile__label {
		padding: 1rem;
		font-size: clamp( 0.95rem, 0.7rem + 0.55vw, 1.2rem );
	}
}

@media (max-width: 599px) {

	.tt-tiles {
		gap: 1rem;
	}

	.tt-tiles--pathways {
		grid-template-columns: minmax(0, 1fr);
	}

	.tt-tile__label {
		padding: 1rem;
	}
}

/* ---------------------------------------------------------------
 * Area pages
 *
 * The AREAS landing page is an interior page with a tile band in it, so
 * it keeps the interior rhythm unchanged. The six community pages are
 * long reads, so they borrow the guides' quieter band spacing and their
 * closing hairline instead — a reader who has worked through a guide
 * step should recognise the shape of an area page without being told.
 * --------------------------------------------------------------- */

.tt-section--area {
	padding-block: var(--wp--preset--spacing--60);
}

.tt-section--area p {
	line-height: 1.7;
}

.tt-section--area > h2:first-child {
	margin-block-start: 0;
}

/* ---------------------------------------------------------------
 * Related-area links
 *
 * The band that closes a community page. Grouped rather than flat,
 * because the grouping is the useful part: a reader who has just
 * finished one island town is being offered the other two island towns
 * and, separately, three mainland communities.
 *
 * Each link is a two-line block — the name, then the county and whether
 * it is an incorporated town — so the distinction the whole milestone
 * turns on is visible at the moment somebody chooses where to go next.
 * --------------------------------------------------------------- */

.tt-area-links {
	margin-block: 0;
}

.tt-area-links__heading {
	margin-block: 0 var(--wp--preset--spacing--40);
	font-size: var(--wp--preset--font-size--large);
}

.tt-area-links__groups {
	display: grid;
	gap: var(--wp--preset--spacing--40);
	grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}

.tt-area-links__group {
	padding: var(--wp--preset--spacing--40);
	background-color: var(--wp--preset--color--base);
	border: 1px solid rgb(27 42 65 / 12%);
}

.tt-area-links__label {
	margin: 0 0 0.5rem;
	font-family: var(--wp--preset--font-family--body);
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--wp--preset--color--navy);
}

.tt-area-links__list {
	margin: 0;
	padding: 0;
	list-style: none;
}

.tt-area-links__item {
	margin: 0;
}

/* Each entry is its own control on its own line, so the 44px target
   rule applies to it as it would to any other. The padding buys the
   height; the text does not move. */
.tt-area-links__link {
	display: flex;
	flex-direction: column;
	gap: 0.1rem;
	min-block-size: 44px;
	justify-content: center;
	padding-block: 0.45rem;
	text-decoration: none;
}

.tt-area-links__name {
	font-family: var(--wp--preset--font-family--display);
	font-size: 1.0625rem;
	font-weight: 600;
	line-height: 1.25;
	color: var(--wp--preset--color--navy);
	text-decoration: underline;
	text-decoration-color: var(--wp--preset--color--seafoam);
	text-decoration-thickness: 2px;
	text-underline-offset: 0.18em;
}

.tt-area-links__meta {
	font-size: 0.8125rem;
	line-height: 1.4;
	color: var(--wp--preset--color--charcoal);
	opacity: 0.8;
}

.tt-area-links__link:hover .tt-area-links__name {
	text-decoration-color: currentcolor;
}

/* ---------------------------------------------------------------
 * Pathway links
 *
 * The row of ordinary links that closes the AREAS landing page —
 * Buying, Selling, Investing — for a reader who has not settled on a
 * place yet. Each is its own control on a line of controls, so the
 * 44px target rule applies to it exactly as it does to a citation in
 * the sources list. The padding buys the height; the text does not
 * move.
 * --------------------------------------------------------------- */

.tt-pathways {
	margin-block: 0;

	/* The separators between the links are text nodes, so the paragraph
	   stays a normal line box rather than becoming a flex container —
	   turning it into one would make each middle dot an anonymous flex
	   item and put the spacing at the mercy of collapsed whitespace. */
	line-height: 1.4;
}

.tt-pathways__link {
	display: inline-flex;
	align-items: center;
	min-block-size: 44px;
	padding-inline-end: 0.35rem;
	vertical-align: middle;
}

/* ---------------------------------------------------------------
 * Outbound links
 *
 * An ordinary link out to another site — the YouTube channel from the
 * Videos page. Deliberately not the CONTACT ME treatment: this is
 * content navigation, and the one prominent call to action on this site
 * is the contact band. It is a target because it is a control, so it
 * takes the same 44px minimum as a citation or a related-area link.
 * --------------------------------------------------------------- */

.tt-outbound {
	margin-block: var(--wp--preset--spacing--30) 0;
}

.tt-outbound__link {
	display: inline-flex;
	align-items: center;
	min-block-size: 44px;
	font-weight: 500;
	color: var(--wp--preset--color--navy);
	text-decoration: underline;
	text-decoration-color: var(--wp--preset--color--seafoam);
	text-decoration-thickness: 2px;
	text-underline-offset: 0.2em;
}

.tt-outbound__link:hover {
	text-decoration-color: currentcolor;
}

/**
 * Video cards, the featured video, and the player overlay.
 *
 * Shared by the Videos page and the homepage rail, so the two read as
 * one component rather than as two designs that happen to show videos.
 *
 * Palette is locked: Deep Navy, Warm Sand, Seafoam, Charcoal. Seafoam
 * appears here only as a border, an underline or a focus ring — never
 * as text on a light surface, where it would fail contrast.
 */

/* ---------------------------------------------------------------
 * The frame
 *
 * 16:9, reserved before anything loads. The poster, the placeholder
 * and the player all occupy exactly this box, which is what makes
 * pressing play shift nothing.
 * --------------------------------------------------------------- */

.tt-frame--video {
	position: relative;
	display: block;
	overflow: hidden;
	aspect-ratio: 16 / 9;
	background-color: var(--wp--preset--color--navy);
}

/* The poster ships as a <picture> so the WebP can be offered with a
   JPEG fallback, which puts an extra element between the frame and the
   image. Without a width on it the picture takes the file's intrinsic
   1280px and drags the whole card — and then the document — out past
   the viewport. Both elements are sized, so neither can do it. */
.tt-video__facade .tt-frame--video :is(picture, img) {
	display: block;
	inline-size: 100%;
	max-inline-size: 100%;
	block-size: 100%;
	object-fit: cover;
}

/* ---------------------------------------------------------------
 * The facade
 *
 * A link first: with no script it goes to the video on YouTube. The
 * whole card face is the target, so the play control is decorative and
 * the accessible name lives in the visually hidden text.
 * --------------------------------------------------------------- */

.tt-video {
	display: flex;
	flex-direction: column;
	margin: 0;
}

.tt-video__facade {
	position: relative;
	display: block;
	text-decoration: none;
	color: var(--wp--preset--color--base);
}

.tt-video__scrim {
	position: absolute;
	inset: 0;
	background: linear-gradient(
		180deg,
		rgb(27 42 65 / 5%) 0%,
		rgb(27 42 65 / 12%) 60%,
		rgb(27 42 65 / 45%) 100%
	);
	transition: opacity 150ms ease;
}

/* The play triangle, drawn rather than loaded. A borders-only triangle
   inside a disc — no image request, and it scales with the card. */
.tt-video__play {
	position: absolute;
	inset-block-start: 50%;
	inset-inline-start: 50%;
	display: flex;
	align-items: center;
	justify-content: center;
	inline-size: 4rem;
	block-size: 4rem;
	transform: translate(-50%, -50%);
	background-color: rgb(27 42 65 / 82%);
	border: 2px solid var(--wp--preset--color--base);
	border-radius: 50%;
	transition: background-color 150ms ease, transform 150ms ease;
}

.tt-video__play::after {
	content: "";
	inline-size: 0;
	block-size: 0;
	margin-inline-start: 0.35rem;
	border-block-start: 0.7rem solid transparent;
	border-block-end: 0.7rem solid transparent;
	border-inline-start: 1.15rem solid var(--wp--preset--color--base);
}

.tt-video__facade:hover .tt-video__play {
	background-color: var(--wp--preset--color--navy);
	transform: translate(-50%, -50%) scale(1.06);
}

.tt-video__facade:focus-visible {
	outline: 3px solid var(--wp--preset--color--seafoam);
	outline-offset: 3px;
}

/* The runtime, over the poster. Navy at 88% behind white clears AA
   against any frame beneath it. */
.tt-video__runtime {
	position: absolute;
	inset-block-end: 0.6rem;
	inset-inline-end: 0.6rem;
	padding: 0.15rem 0.45rem;
	background-color: rgb(27 42 65 / 88%);
	color: var(--wp--preset--color--base);
	font-family: var(--wp--preset--font-family--body);
	font-size: 0.75rem;
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	letter-spacing: 0.02em;
}

/* ---------------------------------------------------------------
 * The card body
 * --------------------------------------------------------------- */

.tt-video__body {
	padding-block-start: 0.85rem;
}

.tt-video__title {
	margin: 0;
	font-size: clamp( 1.05rem, 0.95rem + 0.35vw, 1.25rem );
	line-height: 1.3;
	color: var(--wp--preset--color--navy);
	text-wrap: balance;
}

.tt-video__summary {
	margin-block: 0.5rem 0;
	font-size: 0.9375rem;
	line-height: 1.6;
	color: var(--wp--preset--color--charcoal);
}

/* ---------------------------------------------------------------
 * The grid
 * --------------------------------------------------------------- */

.tt-videos {
	display: grid;
	gap: var(--wp--preset--spacing--50);
	grid-template-columns: minmax(0, 1fr);
}

.tt-video-group + .tt-video-group {
	margin-block-start: var(--wp--preset--spacing--60);
}

.tt-video-group__head {
	margin-block-end: var(--wp--preset--spacing--40);
}

.tt-video-group__heading {
	margin: 0;
	font-size: clamp( 1.4rem, 1.2rem + 0.6vw, 1.8rem );
}

.tt-video-group__blurb {
	max-inline-size: 46rem;
	margin-block: 0.5rem 0;
	color: var(--wp--preset--color--charcoal);
}

@media (min-width: 600px) {

	.tt-videos {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (min-width: 1000px) {

	.tt-videos {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}

	/* Two cards look deliberate at half width rather than stranded
	   across a three-column grid. */
	.tt-videos--count-2 {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

/* ---------------------------------------------------------------
 * The featured video
 * --------------------------------------------------------------- */

.tt-video-featured {
	display: grid;
	gap: var(--wp--preset--spacing--50);
	align-items: center;
	grid-template-columns: minmax(0, 1fr);
}

.tt-video-featured__title {
	margin-block: 0 0.5rem;
	font-size: clamp( 1.5rem, 1.2rem + 1.1vw, 2.2rem );
	line-height: 1.2;
	text-wrap: balance;
}

.tt-video-featured__summary {
	max-inline-size: 34rem;
	margin: 0;
	line-height: 1.7;
	color: var(--wp--preset--color--charcoal);
}

@media (min-width: 900px) {

	.tt-video-featured {
		grid-template-columns: minmax(0, 1.45fr) minmax(0, 1fr);
		gap: var(--wp--preset--spacing--60);
	}
}

/* ---------------------------------------------------------------
 * The player overlay
 *
 * A native dialog, so the focus trap, Escape and the inert background
 * are the browser's job rather than this file's.
 * --------------------------------------------------------------- */

.tt-video-dialog {
	inline-size: min(96vw, 68rem);
	max-inline-size: none;
	padding: 0;
	background: transparent;
	border: 0;
}

.tt-video-dialog::backdrop {
	background-color: rgb(27 42 65 / 88%);
}

.tt-video-dialog__shell {
	position: relative;
}

.tt-video-dialog__frame {
	position: relative;
	overflow: hidden;
	aspect-ratio: 16 / 9;
	background-color: #000;
}

.tt-video-dialog__frame iframe {
	position: absolute;
	inset: 0;
	inline-size: 100%;
	block-size: 100%;
	border: 0;
}

.tt-video-dialog__close {
	position: absolute;
	inset-block-end: calc(100% + 0.5rem);
	inset-inline-end: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	inline-size: 44px;
	min-block-size: 44px;
	padding: 0;
	background: none;
	border: 1px solid rgb(255 255 255 / 55%);
	color: var(--wp--preset--color--base);
	cursor: pointer;
}

.tt-video-dialog__close:hover {
	background-color: var(--wp--preset--color--base);
	color: var(--wp--preset--color--navy);
}

.tt-video-dialog__close:focus-visible {
	outline: 3px solid var(--wp--preset--color--seafoam);
	outline-offset: 2px;
}

.tt-video-dialog__cross {
	position: relative;
	display: block;
	inline-size: 16px;
	block-size: 16px;
}

.tt-video-dialog__cross::before,
.tt-video-dialog__cross::after {
	content: "";
	position: absolute;
	inset-block-start: 50%;
	inset-inline-start: 0;
	inline-size: 100%;
	block-size: 2px;
	background-color: currentcolor;
}

.tt-video-dialog__cross::before {
	transform: rotate(45deg);
}

.tt-video-dialog__cross::after {
	transform: rotate(-45deg);
}

@media (prefers-reduced-motion: reduce) {

	.tt-video__facade:hover .tt-video__play {
		transform: translate(-50%, -50%);
	}
}

/* ---------------------------------------------------------------
 * Property search
 *
 * The Flexmls search form, wearing this design system. Everything is
 * scoped inside .tt-idx-search, which is markup the Core plugin owns.
 * The vendor's own files are never edited and its markup is never
 * rewritten — what happens below is a stylesheet reaching the classes
 * it renders, which is the supported way to restyle it.
 *
 * Some of its values arrive as inline styles carrying !important and
 * cannot be reached from here at all: the background, the field text,
 * the submit colours and the Advanced link are handed to it as widget
 * settings instead. See Idx\SearchBand::shortcode(). What is left for
 * CSS is geometry, spacing, borders, focus and responsive behaviour.
 *
 * Two constraints run through all of it. Targets are at least 44px,
 * above the reference's 40px. And seafoam never carries text on a light
 * surface — about 2.9:1 there — so it appears as borders and focus
 * rings only.
 *
 * The vendor's class names are snake_case and are not ours to rename.
 * --------------------------------------------------------------- */

/* stylelint-disable selector-class-pattern */

.tt-idx-search {
	inline-size: 100%;
}

/* The vendor puts an inline max-width on its own container — 760px by
   default, which left the band narrower than the column it sits in.
   SearchBand::shortcode() now hands it the real width through the
   widget setting that governs it; what is left here is the 3px margin
   it carries, which on top of a 100% width is 6px of overflow inside
   the wrapper. */
.tt-idx-search .flexmls_connect__search,
.tt-idx-search .flexmls_connect__search_new {
	box-sizing: border-box;
	max-inline-size: 100%;
	inline-size: 100%;
	margin: 0;
	font-family: var(--wp--preset--font-family--body, Inter, sans-serif) !important;
}

/* The vendor's container carries its own padding on top of a 100% width.
   Without border-box that is 19px of horizontal overflow at 390px — the
   exact failure this project checks phones for, and invisible on a
   desktop because the page has room to absorb it.

   The descending-specificity rule is switched off for the reset rules
   below: they are deliberately broad and deliberately late, because
   they exist to contain markup this project did not write and cannot
   reorder. */
/* stylelint-disable no-descending-specificity */
.tt-idx-search *,
.tt-idx-search *::before,
.tt-idx-search *::after {
	box-sizing: border-box;
}
/* stylelint-enable no-descending-specificity */

/* The vendor's own title slot. On the band it is the identity area at
   the left of the row, filled through the widget's `title` setting so
   that it needs no markup of ours to be first in the form.

   The full page carries its own heading above the form and asks the
   widget for no title, so there the slot is closed outright. It has
   to be said in so many words: the vendor prints whitespace inside
   that div even when the title is blank, so :empty never matches it
   and the slot would otherwise claim a column of the grid. */
.tt-idx-search--page .flexmls_connect__search_new_title {
	display: none;
}

.tt-idx-search--band .flexmls_connect__search_new_title {
	align-self: end;
	margin: 0;
	padding: 0 0 0.6rem;
	color: var(--wp--preset--color--navy, #1b2a41);

	/* The vendor writes Arial into the element's own style attribute. */
	font-family: var(--wp--preset--font-family--heading, "Playfair Display", serif) !important;
	font-size: 1.25rem;
	line-height: 1.15;
}

/* A backstop for any other placement of this block: a title slot with
   nothing at all in it contributes a box worth of margin and nothing
   else. */
.tt-idx-search .flexmls_connect__search_new_title:empty {
	display: none;
}

/* Above a listing page's body: the listing agent and firm, from the feed
   (7 October 2026, Hive 18.4). Body size, so it is as legible as the
   listing's own lines. Above a results page: the display limits applied
   to the request, in the small-label register. */
.tt-main > .wp-block-post-content > .tt-idx-listing-agent {
	margin: 0 0 1rem;
	font-size: 1rem;
	line-height: 1.5;
}

.tt-main > .wp-block-post-content > .tt-idx-limits {
	margin: 0 0 1rem;
	font-size: 0.875rem;
	line-height: 1.5;
	color: var(--wp--preset--color--navy, #1b2a41);
}

/* The band's starting area, stated beneath the form (7 October 2026):
   the six communities an untouched search returns, and where to change
   them. Small-label size, full navy for contrast on the sand. */
.tt-idx-search--band .tt-idx-search__area {
	margin: 0.6rem 0 0;
	color: var(--wp--preset--color--navy, #1b2a41);
	font-family: var(--wp--preset--font-family--body);
	font-size: 0.875rem;
	line-height: 1.5;
}

.tt-idx-search--band .tt-idx-search__area a {
	color: inherit;
	text-decoration: underline;
	text-decoration-color: var(--wp--preset--color--seafoam, #6aa5a9);
	text-underline-offset: 0.2em;
}

/* One grid, one baseline. Flex was what this band used to be, and flex
   is why it broke: every field carried its own basis, every basis
   fought the vendor's 760px cap, and the row wrapped wherever it ran
   out of room rather than where the design says it should. A grid
   states the columns outright, so the band lies down flat at full width
   and folds at breakpoints that were chosen rather than stumbled into.

   Single column is the base case, because that is what a phone gets.
   Every wider arrangement is added by a query below. */
.tt-idx-search form {
	display: grid;
	align-items: end;
	gap: 0.75rem 1rem;
	grid-template-columns: minmax(0, 1fr);
	margin: 0;
}

/* The vendor parks a hidden input and an empty div among the fields.
   In a flex row they were invisible; in a grid they each claim a
   column, which is what pushed the submit onto a second row. */
.tt-idx-search form > input[type="hidden"],
.tt-idx-search form > .query {
	display: none;
}

.tt-idx-search .flexmls_connect__search_field,
.tt-idx-search .flexmls_connect__search_new_field_group {
	display: flex;
	flex-direction: column;
	gap: 0.35rem;

	/* The vendor carries a 16px bottom margin on every field. In a row
	   aligned to its own bottom edge that margin is exactly how far each
	   control ends up above the line it is supposed to sit on. */
	margin: 0;
	min-inline-size: 0;
}

/* The wrapper the vendor puts around the min/max rows draws nothing of
   its own, so it steps out of the layout entirely and lets beds, baths
   and price become columns of the band in their own right. Without this
   the three of them share one narrow column and stack — which is most
   of what "clunky and stacked" was. */
.tt-idx-search .flexmls_connect__search_new_min_max {
	display: contents;
}

.tt-idx-search .flexmls_connect__search_new_label,
.tt-idx-search .flexmls_connect__search_field > label,
.tt-idx-search .tt-idx-types__label,
.tt-idx-search legend {
	padding: 0;
	color: var(--wp--preset--color--navy, #1b2a41);
	font-family: var(--wp--preset--font-family--body, Inter, sans-serif);
	font-size: 0.8125rem;
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
}

/* Underlines, not boxes. The reference band draws every ordinary
   field as a transparent well with a single rule beneath it, and that
   is the treatment here — approved 24 August 2026, after the
   horizontal structure was signed off.

   Two things it must not cost. The 44px target survives because a
   target is a height, not a set of four sides, and box-sizing keeps
   the used height at 44px whether the border is on one edge or all of
   them. And the shared baseline survives because the baseline is the
   bottom edge of the box, which is exactly where the rule now sits.

   Horizontal padding goes to nothing so the field text starts on the
   same line as the label above it and the underline runs the full
   width of the column, which is what makes the row read as a set of
   ruled fields rather than a row of floating words.

   The rule is a UI component boundary rather than text, so it is
   held to 3:1. Navy at 65% over sand measures about 4.18:1, and
   4.63:1 over the white the full page uses. */
.tt-idx-search input[type="text"],
.tt-idx-search input[type="number"],
.tt-idx-search select:not(.select2-hidden-accessible),
.tt-idx-search .tt-idx-types__toggle,
.tt-idx-search .select2-container .select2-selection {
	box-sizing: border-box;
	inline-size: 100%;
	min-block-size: 44px;
	padding: 0.5rem 0;
	border: 0;
	border-block-end: 1px solid rgb(27 42 65 / 65%);
	border-radius: 0;
	background: transparent;
	box-shadow: none;
	color: var(--wp--preset--color--charcoal, #2b2b2b);
	font-family: var(--wp--preset--font-family--body, Inter, sans-serif);
	font-size: 1rem;
}

/* select2 draws its own inner list with padding of its own, so the
   shared control padding above stacks on top of it and leaves the
   location field taller than everything beside it. */
.tt-idx-search .select2-container .select2-selection {
	display: flex;
	align-items: center;
	padding-block: 0;
}

.tt-idx-search .select2-container .select2-selection__rendered {
	margin: 0;
	padding-inline: 0;
}

/* A chosen location is a chip, and select2 draws its chips in its
   own pale blue with rounded corners. Against a transparent field on
   sand that is the one piece of another product’s design still
   showing, so it is given the brand: square, navy-ruled, and legible
   on either surface the band sits on. */
.tt-idx-search .select2-container .select2-selection__choice {
	margin-block: 0;
	padding: 0.15rem 0.4rem;
	border: 1px solid rgb(27 42 65 / 45%);
	border-radius: 0;
	background: var(--wp--preset--color--base, #fff);
	color: var(--wp--preset--color--charcoal, #2b2b2b);
	font-size: 0.875rem;
}

/* The disclosure button is one of the fields, so it is shaped here
   with them rather than down in the disclosure section: the chevron
   sits at the far end of the same underline the other controls
   carry. */
.tt-idx-search .tt-idx-types__toggle {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 0.5rem;
	text-align: start;
	cursor: pointer;
}

/* Hover and focus deepen the rule rather than thicken or move it. A
   border that grows on focus moves everything after it in the row by
   a pixel, and on a seven-column band that is a visible twitch. The
   focus ring itself is an outline, which is painted outside the box
   and reserves no space at all. */
.tt-idx-search input[type="text"]:hover,
.tt-idx-search input[type="number"]:hover,
.tt-idx-search select:not(.select2-hidden-accessible):hover,
.tt-idx-search .tt-idx-types__toggle:hover,
.tt-idx-search input[type="text"]:focus,
.tt-idx-search input[type="number"]:focus,
.tt-idx-search select:not(.select2-hidden-accessible):focus,
.tt-idx-search .tt-idx-types__toggle:focus,
.tt-idx-search .select2-container .select2-selection:hover,
.tt-idx-search .select2-container .select2-selection:focus-within {
	border-block-end-color: var(--wp--preset--color--navy, #1b2a41);
}

/* Min and Max are the only thing telling one input of a pair from the
   other, so the placeholder is doing real work and has to be read
   rather than merely glimpsed. The browser default lands around 3.4:1
   on sand; this is the same #555 the vendor uses for its own inactive
   text, and it measures about 5.6:1 there and 7.4:1 on the white of
   the full page. */
.tt-idx-search ::placeholder {
	color: #555;
	opacity: 1;
}

.tt-idx-search .flexmls_connect__min_max_wrapper {
	display: flex;
	align-items: center;
	gap: 0.4rem;
}

/* Both halves of a range share the column evenly, and neither is
   allowed to claim its intrinsic width — an input's default size is
   twenty characters, which is wider than a beds column ever gets. */
.tt-idx-search .flexmls_connect__min_max_wrapper input {
	flex: 1 1 0;
	min-inline-size: 0;
}

.tt-idx-search .flexmls_connect__search_new_to {
	flex: 0 0 auto;
	color: var(--wp--preset--color--charcoal, #2b2b2b);
	font-size: 0.75rem;
}

.tt-idx-search fieldset {
	margin: 0;

	/* A fieldset's min-width is min-content by default, which is enough
	   on its own to push a narrow column sideways. */
	min-inline-size: 0;
	padding: 0;
	border: 0;
}

.tt-idx-search .flexmls_connect__checkbox_wrapper {
	display: inline-flex;
	align-items: center;
	margin-inline-end: 1rem;
}

.tt-idx-search .flexmls_connect__checkbox_wrapper label {
	display: inline-flex;
	align-items: center;
	gap: 0.45rem;
	min-block-size: 44px;
	color: var(--wp--preset--color--charcoal, #2b2b2b);
	font-size: 0.9375rem;
	font-weight: 400;
	letter-spacing: 0;
	text-transform: none;
	cursor: pointer;
}

.tt-idx-search input[type="checkbox"] {
	inline-size: 20px;
	block-size: 20px;
	margin: 0;
	accent-color: var(--wp--preset--color--navy, #1b2a41);
}

/* ---------------------------------------------------------------
 * Property Type, as a disclosure
 *
 * Seven checkboxes are a block, not a field, and a block that tall
 * cannot share a row with anything. blocks/idx-search/view.js folds
 * them behind a button; everything below dresses what it builds.
 *
 * The collapsed state is never applied by CSS alone. If that script
 * fails to load, the vendor's fieldset has to still be a working
 * control rather than a hidden one, so the rule that gives it a full
 * row of its own is written against its un-enhanced position — a
 * direct child of the form — and stops applying by itself the moment
 * the script moves it into a panel.
 * --------------------------------------------------------------- */

.tt-idx-search form > .flexmls_connect__search_new_property_type {

	/* block, not the column the other fields get: the checkbox wrappers
	   are inline, so across a full row they flow onto one line instead of
	   stacking into the 429px tower that started all this. */
	display: block;
	grid-column: 1 / -1;
}

.tt-idx-types {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: 0.35rem;
	min-inline-size: 0;
}

.tt-idx-types__value {
	overflow: hidden;
	white-space: nowrap;
	text-overflow: ellipsis;
}

.tt-idx-types__arrow {
	flex: 0 0 auto;
	inline-size: 0;
	block-size: 0;
	border-block-start: 6px solid var(--wp--preset--color--navy, #1b2a41);
	border-inline: 5px solid transparent;
}

.tt-idx-types__toggle[aria-expanded="true"] .tt-idx-types__arrow {
	transform: rotate(180deg);
}

.tt-idx-types__panel {
	z-index: 20;
	max-block-size: min(60vh, 26rem);
	padding: 0.5rem 1rem 1rem;
	overflow-y: auto;
	border: 1px solid rgb(27 42 65 / 35%);
	background: var(--wp--preset--color--base, #fff);
}

/* The attribute is what closes the panel, so it has to outrank the
   display the panel is given above. */
.tt-idx-types__panel[hidden] {
	display: none;
}

/* One per line inside the panel: it is a list of choices there, not a
   row of chips. */
.tt-idx-types__panel .flexmls_connect__checkbox_wrapper {
	display: flex;
	margin-inline-end: 0;
}

.tt-idx-types__panel .flexmls_connect__search_new_subtypes {
	margin-block-start: 0.75rem;
	padding-block-start: 0.75rem;
	border-block-start: 1px solid rgb(27 42 65 / 20%);
}

/* The submit and the Advanced link, at the end of the row. Colour comes
   from the widget settings; this is the shape. Advanced is a real link
   to the vendor's full search form — it is never drawn when there is
   nowhere for it to go. */
.tt-idx-search .flexmls_connect__search_new_links {
	display: flex;
	align-items: flex-end;
	gap: 1rem;
	margin: 0;
	padding: 0;
	min-inline-size: 0;
}

/* The vendor floats its field groups at 45% under the horizontal field
   order, which the full page still uses. Grid items ignore the float,
   but not the width — it is why the sort control and the submit came
   out at a little under half the column they were given. The element
   in the selector is there to outrank the vendor's own two classes
   rather than to depend on which stylesheet happens to load last. */
.tt-idx-search form .flexmls_connect__search_new_field_group,
.tt-idx-search form .flexmls_connect__search_new_links {
	float: none;
	inline-size: auto;
}

/* The element selector is not decoration. The vendor styles this
   button as input[type=submit].flexmls_connect__search_new_submit,
   which outranks a rule written with classes alone — its 22px Arial
   and its half-em margin both survived a two-class override, and the
   margin is what lifted the submit off the row's baseline. */
.tt-idx-search input[type="submit"].flexmls_connect__search_new_submit {
	inline-size: auto;
	margin: 0;
	min-block-size: 44px;
	padding: 0.6rem 1.5rem;
	border: 0;
	border-radius: 0 !important;
	font-family: var(--wp--preset--font-family--body, Inter, sans-serif);
	font-size: 0.875rem;
	font-weight: 500;
	letter-spacing: 0.06em;
	white-space: nowrap;
	text-transform: uppercase;
	cursor: pointer;
}

.tt-idx-search .flexmls_connect__search_new_links a {
	display: inline-flex;
	align-items: center;
	min-block-size: 44px;
	border-block-end: 2px solid var(--wp--preset--color--seafoam, #5f9ea0);
	font-family: var(--wp--preset--font-family--body, Inter, sans-serif);
	font-size: 0.875rem;
	font-weight: 500;
	letter-spacing: 0.06em;
	white-space: nowrap;
	text-decoration: none;
	text-transform: uppercase;
}

/* Focus has to be visible on every control, including the ones the
   vendor styles inline. Seafoam is legitimate here: a ring, not text. */
.tt-idx-search :focus-visible {
	outline: 3px solid var(--wp--preset--color--seafoam, #5f9ea0);
	outline-offset: 2px;
}

/* select2 builds a small search input inside the location field and
   gives keyboard focus to that, so the ring would be drawn around a
   few pixels in the middle of the field rather than around the field
   itself. It is moved out to the field, and the inner ring is turned
   off so there is one indicator rather than two.

   Both of these change colour and outline only. An outline is
   painted outside the border box and reserves no space, so nothing
   in the row moves when a field is picked up. */
.tt-idx-search .select2-container .select2-selection:focus-within {
	outline: 3px solid var(--wp--preset--color--seafoam, #5f9ea0);
	outline-offset: 2px;
}

.tt-idx-search .select2-search__field:focus-visible {
	outline: none;
}

/* Nothing may overflow its column. A search form that pushes the page
   sideways on a phone is the failure this project checks for at 375px,
   and the vendor's inline widths are wide enough to cause it. */
/* stylelint-disable no-descending-specificity */
.tt-idx-search,
.tt-idx-search * {
	max-inline-size: 100%;
}
/* stylelint-enable no-descending-specificity */

/* Phones. Full-width controls, one per line, and a submit that is a
   target rather than a word. */
@media (width <= 767px) {

	.tt-idx-search .flexmls_connect__search_new_links {
		display: grid;
		gap: 0.75rem;
	}

	.tt-idx-search input[type="submit"].flexmls_connect__search_new_submit {
		inline-size: 100%;
	}

	.tt-idx-search .flexmls_connect__search_new_links a {
		justify-content: center;
	}
}

/* Everywhere above a phone the panel leaves the flow and hangs under
   its button, so opening it cannot move the row underneath. */
@media (width >= 768px) {

	.tt-idx-types__panel {
		position: absolute;
		inset-block-start: 100%;
		inset-inline-start: 0;
		min-inline-size: 17rem;
		margin-block-start: 0.25rem;
		box-shadow: 0 6px 20px rgb(27 42 65 / 18%);
	}
}

/* Tablet: two columns, deliberately paired. Beds sits beside baths
   because they are read together; price and the submit take rows of
   their own because neither survives half a tablet. */
@media (width >= 768px) and (width <= 1023px) {

	.tt-idx-search--band form {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}

	.tt-idx-search--band .flexmls_connect__search_new_title,
	.tt-idx-search--band [data-connect-field="Price"],
	.tt-idx-search--band .flexmls_connect__search_new_links {
		grid-column: 1 / -1;
	}

	.tt-idx-search--band .flexmls_connect__search_new_title {
		padding-block-end: 0;
	}
}

/* Small laptops. Six columns will not stay readable here, so the band
   folds into two balanced rows of four: identity, type, beds and baths
   across the first; the price range and the submit, each two columns
   wide, across the second. */
@media (width >= 1024px) and (width <= 1199px) {

	.tt-idx-search--band form {
		grid-template-columns: repeat(4, minmax(0, 1fr));
	}

	/* Without the type control the identity takes the type's column,
	   so the first row stays full: identity (two columns), beds, baths. */
	.tt-idx-search--band form:has(.flexmls_connect__search_new_property_type > input[type="hidden"][name="PropertyType"]) .flexmls_connect__search_new_title {
		grid-column: span 2;
	}

	.tt-idx-search--band [data-connect-field="Price"],
	.tt-idx-search--band .flexmls_connect__search_new_links {
		grid-column: span 2;
	}
}

/* The desktop band: identity, type, beds, baths, price, submit, in one
   row, in that order. The order is the vendor's own DOM order — the
   widget is asked for its vertical field arrangement and its rows in
   this sequence — so what is read by a screen reader and what is
   reached by the Tab key are the same order that is seen.

   Six columns since 16 September 2026, when the location field left
   the band by the vendor's own setting; the width it had is shared
   between type and price, which are the two controls with the most to
   show. */
@media (width >= 1200px) {

	.tt-idx-search--band form {
		grid-template-columns:
			minmax(5.5rem, 0.6fr)
			minmax(9rem, 1.2fr)
			minmax(7rem, 0.95fr)
			minmax(7rem, 0.95fr)
			minmax(10rem, 1.5fr)
			auto;
	}

	/* Held to the residential type (7 October 2026) the band has no
	   type control, so five columns: identity, beds, baths, price,
	   submit. The width the type column had goes to the price range. */
	.tt-idx-search--band form:has(.flexmls_connect__search_new_property_type > input[type="hidden"][name="PropertyType"]) {
		grid-template-columns:
			minmax(5.5rem, 0.7fr)
			minmax(7rem, 1fr)
			minmax(7rem, 1fr)
			minmax(12rem, 2.2fr)
			auto;
	}
}

/* The vendor still prints the "Property Type" fieldset and its legend
   when the type is held to one and its control is off; only its hidden
   input is wanted, so the box takes no room. The input stays in the
   form and is submitted. */
.tt-idx-search--band .flexmls_connect__search_new_property_type:not(:has(input[name="PropertyType[]"])) {
	display: none;
}

.tt-idx-search--page form {
	grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
}

/* ---------------------------------------------------------------
 * Property search — results and listing detail
 *
 * These pages are rendered entirely by the vendor inside the
 * /search-homes/ page, so there is no wrapper of ours to scope to.
 * The body class the plugin sets is what we have, and it is enough:
 * flexmls_connect__search_results_page and
 * flexmls_connect__listing_details_page.
 *
 * Only two things are changed. Nothing that carries MLS-required
 * content — the disclaimer, the listing office, the update timestamp,
 * the IDX logo text — is touched at all, and nothing is hidden.
 * --------------------------------------------------------------- */

/* Vendor links inside its own pages sit at around 20px, below the
   project's 44px floor. Padding rather than height, so the line the
   link sits in is not stretched apart. */

/* Late and broad on purpose: these scope to vendor pages this file
   cannot reorder. */
/* stylelint-disable no-descending-specificity */
.flexmls_connect__search_results_page main a,
.flexmls_connect__listing_details_page main a {
	padding-block: 0.55rem;
}
/* stylelint-enable no-descending-specificity */

/* Focus stays visible on the vendor's pages too. */
.flexmls_connect__search_results_page main :focus-visible,
.flexmls_connect__listing_details_page main :focus-visible {
	outline: 3px solid var(--wp--preset--color--seafoam, #5f9ea0);
	outline-offset: 2px;
}

/* The required disclaimer and attribution must stay readable. The
   vendor sets these small; this raises them to the project's floor
   without altering a word of them. */
.flexmls_connect__search_results_page .flexmls_connect__disclaimer,
.flexmls_connect__listing_details_page .flexmls_connect__disclaimer {
	color: var(--wp--preset--color--charcoal, #2b2b2b);
	font-size: 0.8125rem;
	line-height: 1.6;
}

/* ---------------------------------------------------------------
 * Featured listings
 *
 * Tanner's own live listings, on the homepage. The heading is decided
 * by how many there are — one is a Featured Listing, several are
 * Featured Properties, none renders nothing — so this file only has to
 * dress what the vendor puts underneath it.
 *
 * The count-and-filters row the widget draws above its results belongs
 * on a search page, not here: this is a short, finished list, not a
 * result set somebody is refining. It is hidden — the row only, never
 * anything carrying MLS-required content.
 *
 * The vendor's snake_case and kebab-case class names are still not ours
 * to rename; the disable from the search section above is still in
 * force here.
 * --------------------------------------------------------------- */

.tt-idx-featured__heading {
	margin-block-end: var(--wp--preset--spacing--40);
	text-align: center;
}

.tt-idx-featured .flexmls-count-and-filters-wrapper,
.tt-idx-featured .flexmls-map-wrapper,
.tt-idx-featured .flexmls-portal-links {
	display: none;
}

/* The compliance label, the last-modified stamp and the IDX logo text
   all stay exactly where the vendor puts them, and readable. */
.tt-idx-featured .flexmls-last-modified-and-idx-wrapper {
	color: var(--wp--preset--color--charcoal, #2b2b2b);
	font-size: 0.8125rem;
}

/* The vendor draws the IDX label as dark text on a mid-grey chip, which
   measured 3.07:1 on the staging audit of 4 October 2026, and the MLS
   number in light grey on white at 2.84:1. Hive asks for a legible
   label and WCAG for 4.5:1, so the chip is navy with white text and the
   number is set in the body colour; nothing the vendor prints changes. */
.tt-main .flexmls-idx-compliance-label {
	color: var(--wp--preset--color--base, #fff);
	background-color: var(--wp--preset--color--navy, #1b2a41);
	font-size: 0.8125rem;
}

/* Weighted above the vendor's own rule for the number, which names
   four classes. */
.tt-main .flexmls-listing-details .mls-id,
.tt-main .flexmls-listing-details.flexmls-v2-widget .more-information-toggle .mls-id {
	color: var(--wp--preset--color--charcoal, #2b2b2b);
}

/* The Contact agent form opens in the vendor's own overlay, which sits
   at the end of the body rather than inside the page's main region, so
   these rules name the overlay itself. Three things in it were found on
   5 October 2026 and none is the vendor's wording or data:

   The Send button takes the plugin's configured color, navy here, as
   its background, and the vendor sets no text color on it, so the label
   stayed the browser's black: 1.45:1. The button that opens the form is
   white on the same navy, and this now matches it.

   Send had no focus outline of its own.

   The message box used the browser's monospace default beside four
   fields in the body face. */

/* stylelint-disable selector-id-pattern -- the
   overlay's ids are the vendor's names, not this theme's. */
#flexmls_connect__colorbox input.flexmls-btn.flexmls-primary-color-background {
	color: var(--wp--preset--color--base, #fff);
}

#flexmls_connect__colorbox input.flexmls-btn.flexmls-primary-color-background:focus-visible {
	outline: 2px solid var(--wp--preset--color--seafoam, #6aa5a9);
	outline-offset: 2px;
}

#flexmls_connect__colorbox .flexmls_connect__contact_form textarea {
	font-family: inherit;
}

/* The line that says who receives the message. The vendor prints its
   Contact Disclaimer setting here, above Send, in a small element of
   its own; this makes it readable and lets it wrap. */
#flexmls_connect__colorbox .flexmls_connect__contact_form .flexmls-small-text {
	display: block;
	padding: 0.25rem 0.5rem 0.75rem;
	font-size: 0.8125rem;
	line-height: 1.45;
	color: var(--wp--preset--color--charcoal, #2b2b2b);
}

/* At 480px and below the vendor turns the overlay's close control into
   a 44px button showing a "×" and also un-hides its word "close" at
   24px, which does not fit: it read "×clos", cut off at the edge. The
   word is set to no size, so the vendor's own "×" is what shows. The
   button keeps its 44px target and its accessible name. The vendor's
   rule is marked important, so this one has to be as well. */
@media (max-width: 480px) {

	#flexmls_connect__colorbox #flexmls_connect__cboxClose {
		font-size: 0 !important; /* stylelint-disable-line declaration-no-important */
	}

	/* On phones the fields sit 5px inside the heading's edge (the
	   vendor's cell padding); the heading and the message line take
	   the same inset so the column lines up. */
	#flexmls_connect__colorbox .flexmls_connect__contact_form h3,
	#flexmls_connect__colorbox .flexmls_connect__contact_form #flexmls_connect__showing_error {
		margin-inline: 5px;
	}
}

/* Above 480px the vendor's close control is a 25px picture of an "×"
   with its word hidden off screen: too small a target, and nothing
   visible when the picture does not load. This gives it the same 44px
   box and visible "×" the vendor itself uses on phones (6 October
   2026). The accessible name is untouched. */
@media (min-width: 481px) {

	#flexmls_connect__colorbox #flexmls_connect__cboxClose {
		display: flex;
		align-items: center;
		justify-content: center;
		inset-block-start: 0;
		inset-inline-end: 0;
		inline-size: 44px;
		block-size: 44px;
		min-inline-size: 44px;
		min-block-size: 44px;
		text-indent: 0;
		font-size: 0;
		color: #333;
		background: rgb(255 255 255 / 95%);
		border-radius: 0 0 0 4px;
		box-shadow: 0 2px 4px rgb(0 0 0 / 20%);
	}

	#flexmls_connect__colorbox #flexmls_connect__cboxClose::before {
		content: "×";
		display: block;
		font-size: 32px;
		line-height: 1;
	}

	#flexmls_connect__colorbox #flexmls_connect__cboxClose:hover,
	#flexmls_connect__colorbox #flexmls_connect__cboxClose:active {
		color: #000;
		background: rgb(240 240 240 / 95%);
	}

	#flexmls_connect__colorbox #flexmls_connect__cboxClose:focus-visible {
		outline: 2px solid var(--wp--preset--color--seafoam, #6aa5a9);
		outline-offset: -2px;
	}

	/* The heading and the message line sit on the form's own column:
	   the fields are 340px wide and centered in the 500px box, and the
	   vendor lets the heading run from the box's left edge, 80px to
	   their left. The heading also keeps clear of the close control. */
	#flexmls_connect__colorbox .flexmls_connect__contact_form h3,
	#flexmls_connect__colorbox .flexmls_connect__contact_form #flexmls_connect__showing_error {
		box-sizing: border-box;
		inline-size: 340px;
		max-inline-size: 100%;
		margin-inline: auto;
	}

	#flexmls_connect__colorbox .flexmls_connect__contact_form h3 {
		margin-block: 1.75rem 1rem;
		padding-inline-end: 0;
	}
}

/* The site's own status line inside the form, read by screen readers
   while a message is being sent. Not shown. */
#flexmls_connect__colorbox .tt-form-status {
	position: absolute;
	inline-size: 1px;
	block-size: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* The vendor's error line in the form, once something is in it. */
#flexmls_connect__colorbox .flexmls_connect__contact_form #flexmls_connect__showing_error:focus-visible {
	outline: 2px solid var(--wp--preset--color--seafoam, #6aa5a9);
	outline-offset: 2px;
}

/* stylelint-enable selector-id-pattern */

/* The brokerage-name line that stood above the header from 5 to 7
   October 2026 is gone on Tanner's instruction; its rules went with it.
   The header's brokerage mark stays unlinked beside the agent's. */

/* The personal-use notice: this site's own paragraph beneath the MLS
   disclaimer, which is printed above it exactly as the feed supplies
   it. Sized to match the disclaimer, not smaller. */

/* The second selector of each pair outranks the page's own block gap
   (`.tt-main > .wp-block-post-content > *`, 4rem), which on a results
   or listing page, where these lines are the content's last children,
   spread them down the page. The homepage block, which sets its own
   spacing, is the reference. */
.tt-main > .wp-block-post-content > :is(.flexmls_connect__search_results_v2, .flexmls-listing-details):has(~ p.tt-idx-use-notice) {
	margin-block-end: 0;
}

/* Hive's own notice (18.3) and disclosure (Exhibit 4 §9), in the forms
   the rules prescribe, beneath the feed's paragraph. Same size as the
   feed's disclaimer and the notice: not smaller. */
p.tt-idx-hive-notice,
.tt-main > .wp-block-post-content > p.tt-idx-hive-notice {
	margin-block: 1rem 0;
	font-size: 0.8125rem;
	line-height: 1.5;
	color: var(--wp--preset--color--charcoal, #2b2b2b);
}

p.tt-idx-hive-disclosure,
.tt-main > .wp-block-post-content > p.tt-idx-hive-disclosure {
	margin-block: 0.5rem 0;
	font-size: 0.8125rem;
	line-height: 1.5;
	color: var(--wp--preset--color--charcoal, #2b2b2b);
}

p.tt-idx-use-notice,
.tt-main > .wp-block-post-content > p.tt-idx-use-notice {
	margin-block: 1rem 0;
	font-size: 0.8125rem;
	line-height: 1.5;
	color: var(--wp--preset--color--charcoal, #2b2b2b);
}

/* When the listing data on the page was really fetched. The site's own
   line, apart from the feed's disclaimer and from each listing's "Last
   Updated" date. */
p.tt-idx-retrieved,
.tt-main > .wp-block-post-content > p.tt-idx-retrieved {
	margin-block: 0.5rem 0;
	font-size: 0.8125rem;
	line-height: 1.5;
	color: var(--wp--preset--color--charcoal, #2b2b2b);
}

.tt-idx-featured .flexmls-listing {
	border: 1px solid rgb(27 42 65 / 20%);
	border-radius: 0;
}

.tt-idx-featured .flexmls-address {
	font-family: var(--wp--preset--font-family--heading, "Playfair Display", serif);
}

.tt-idx-featured .flexmls-price {
	color: var(--wp--preset--color--navy, #1b2a41);
	font-weight: 600;
}

/* The vendor's own branding link — "Search powered by FBS Products" —
   sits at 20px. It is required attribution and is neither hidden nor
   shrunk; it is given a target big enough to hit on a phone. */
.tt-idx-featured .fbs-branding a {
	display: inline-flex;
	align-items: center;
	min-block-size: 44px;
}

.tt-idx-featured :focus-visible {
	outline: 3px solid var(--wp--preset--color--seafoam, #5f9ea0);
	outline-offset: 2px;
}

/* Late and broad on purpose, like the search reset above: this contains
   markup this project did not write and cannot reorder. */
/* stylelint-disable no-descending-specificity */
.tt-idx-featured,
.tt-idx-featured * {
	box-sizing: border-box;
	max-inline-size: 100%;
}
/* stylelint-enable no-descending-specificity */

/* ---------------------------------------------------------------
 * Client reviews
 *
 * A list, laid out as a grid. Deliberately not a carousel: nothing here
 * moves by itself, nothing auto-advances, and there is no third-party
 * widget, iframe or tracking script anywhere near it.
 *
 * The grid is the whole interaction. Every review is present in the
 * markup and reachable by scrolling and by tab, which is what makes it
 * work with a keyboard, a screen reader and a narrow phone without any
 * controls to operate.
 * --------------------------------------------------------------- */

.tt-reviews__heading {
	margin-block-end: var(--wp--preset--spacing--40);
	text-align: center;
}

.tt-reviews__list {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
	gap: var(--wp--preset--spacing--40);
	margin: 0;
	padding: 0;
	list-style: none;
}

/* The homepage selection is short and reads better as a single row on a
   wide screen; the full page fills whatever it is given. */
.tt-reviews--rail .tt-reviews__list {
	grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}

.tt-reviews__item {
	display: flex;
	margin: 0;
}

.tt-reviews__figure {
	display: flex;
	flex-direction: column;
	gap: 0.9rem;
	inline-size: 100%;
	margin: 0;
	padding: var(--wp--preset--spacing--40);
	border: 1px solid rgb(27 42 65 / 20%);
	background-color: var(--wp--preset--color--base);
}

/* The quote carries the weight, so it gets the display face. It is never
   truncated or line-clamped — a shortened testimonial is a different
   testimonial. */
.tt-reviews__quote {
	flex: 1 1 auto;
	margin: 0;
	padding: 0;
	border: 0;
	color: var(--wp--preset--color--charcoal);
	font-family: var(--wp--preset--font-family--heading);
	font-size: 1.0625rem;
	line-height: 1.6;
}

.tt-reviews__quote p {
	margin-block: 0 0.75rem;
}

.tt-reviews__quote p:last-child {
	margin-block-end: 0;
}

.tt-reviews__credit {
	display: flex;
	flex-direction: column;
	gap: 0.35rem;
	padding-block-start: 0.9rem;
	border-block-start: 1px solid var(--wp--preset--color--seafoam);
}

.tt-reviews__name {
	color: var(--wp--preset--color--navy);
	font-family: var(--wp--preset--font-family--body);
	font-size: 0.9375rem;
	font-weight: 600;
}

.tt-reviews__meta {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.25rem 0.9rem;
	color: var(--wp--preset--color--charcoal);
	font-family: var(--wp--preset--font-family--body);
	font-size: 0.8125rem;
}

/* Navy rather than a warm yellow: the palette is locked to four colours
   and a gold star would introduce a fifth, which the brand prohibits. */
.tt-reviews__rating {
	color: var(--wp--preset--color--navy);
	font-size: 1rem;
	letter-spacing: 0.08em;
}

/* The link out to the original is a target in its own right, so it gets
   a real one rather than the height of its text. */
.tt-reviews__source {
	display: inline-flex;
	align-items: center;
	min-block-size: 44px;
}

a.tt-reviews__source {
	color: var(--wp--preset--color--navy);
	text-decoration-color: var(--wp--preset--color--seafoam);
	text-decoration-line: underline;
	text-decoration-thickness: 2px;
}

a.tt-reviews__source:hover {
	text-decoration-color: var(--wp--preset--color--navy);
}

.tt-reviews__more {
	margin-block-start: var(--wp--preset--spacing--40);
	text-align: center;
}

/* Late on purpose: it dresses a link inside post content, which is
   declared far earlier and cannot be reordered around it. */
/* stylelint-disable-next-line no-descending-specificity */
.tt-reviews__more a {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-block-size: 44px;
	padding-inline: 1.6rem;
	font-family: var(--wp--preset--font-family--body);
	font-size: 0.875rem;
	font-weight: 500;
	letter-spacing: 0.06em;
	text-decoration: none;
	text-transform: uppercase;
}

.tt-reviews :focus-visible {
	outline: 3px solid var(--wp--preset--color--seafoam);
	outline-offset: 2px;
}

/* Nothing animates. The rule is here so that adding a transition later
   is a deliberate act that has to reckon with reduced motion. */
@media (prefers-reduced-motion: reduce) {

	.tt-reviews * {
		transition: none !important;
		animation: none !important;
	}
}

@media (width <= 781px) {

	.tt-reviews__list {
		grid-template-columns: 1fr;
	}
}

/* One restrained text link out to the rest of the reviews. Deliberately
   not a button: the site has one call to action, and this is a way to go
   and check rather than a second thing being asked of the reader. */
.tt-reviews__external {
	margin-block-start: var(--wp--preset--spacing--40);
	text-align: center;
	font-family: var(--wp--preset--font-family--body);
	font-size: 0.8125rem;
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
}

/* stylelint-disable-next-line no-descending-specificity */
.tt-reviews__external a {
	display: inline-flex;
	align-items: center;
	min-block-size: 44px;
	color: var(--wp--preset--color--navy);
	text-decoration-color: var(--wp--preset--color--seafoam);
	text-decoration-line: underline;
	text-decoration-thickness: 2px;
}

.tt-reviews__external a:hover {
	text-decoration-color: var(--wp--preset--color--navy);
}

/* ---------------------------------------------------------------
 * Contact and social rail
 *
 * A slim column fixed to the right edge of a wide viewport: the phone,
 * the email, then the social profiles, each a plain link on a 44px
 * square with a monochrome glyph. The plugin prints the markup from
 * wp_footer on the public front end only.
 *
 * It exists only where the content column leaves room for it. The
 * column is 73rem (1168px); at a 1320px viewport with a 17px
 * scrollbar that leaves 68px a side, and the rail's 44px plus its
 * 8px inset need 52px. 1280px was measured first and found short:
 * 56px without a scrollbar, 48px with one, so the rail would have sat
 * on the column's edge. Below the breakpoint the rail is display:none,
 * which takes it out of layout, out of the tab order and out of the
 * accessibility tree at once — a zoomed-in desktop drops below the
 * breakpoint the same way a tablet does.
 *
 * Nearly opaque white with a navy glyph, a hairline border and a soft
 * shadow, so it reads the same over white, sand, navy and photographic
 * sections. Hover and active fill navy with a white glyph; visited is
 * the rest state; focus is the site's seafoam ring. No state changes
 * the geometry, and nothing animates except the tooltip's fade, which
 * the reduced-motion backstop above turns off.
 *
 * Layered at 30: above the page, below the sticky header (50), the
 * navigation panels (40–70) and the native video dialog, which sits in
 * the top layer regardless.
 * --------------------------------------------------------------- */

.tt-rail {
	display: none;
}

@media (min-width: 1320px) {

	.tt-rail {
		position: fixed;
		inset-block-start: 50%;
		inset-inline-end: 0.5rem;
		z-index: 30;
		display: block;
		transform: translateY(-50%);
	}

	.tt-rail__panel {
		padding: 0.25rem;
		background-color: rgb(255 255 255 / 96%);
		border: 1px solid rgb(27 42 65 / 18%);
		border-radius: 6px;
		box-shadow: 0 6px 18px rgb(27 42 65 / 14%);
	}

	.tt-rail__group {
		margin: 0;
		padding: 0;
		list-style: none;
	}

	/* The separator: a hairline between the two groups, present only
	   when there are two, because the plugin prints a group only when
	   it has something in it. */
	.tt-rail__group + .tt-rail__group {
		margin-block-start: 0.25rem;
		padding-block-start: 0.25rem;
		border-block-start: 1px solid rgb(27 42 65 / 18%);
	}

	.tt-rail__item {
		margin: 0;
	}

	.tt-rail__link {
		position: relative;
		display: flex;
		align-items: center;
		justify-content: center;
		inline-size: 44px;
		block-size: 44px;
		border-radius: 4px;
		text-decoration: none;
	}

	.tt-rail__link:is(:link, :visited) {
		color: var(--wp--preset--color--navy);
		background-color: transparent;
	}

	.tt-rail__link:is(:hover, :active) {
		color: var(--wp--preset--color--base);
		background-color: var(--wp--preset--color--navy);
	}

	.tt-rail__icon {
		display: block;
		inline-size: 20px;
		block-size: 20px;
		fill: currentcolor;
	}

	/* The label, to the left, on hover and keyboard focus only. It is
	   positioned out of flow, so showing it moves nothing, and it is
	   aria-hidden: the link's own name is the accessible name. */
	.tt-rail__tip {
		position: absolute;
		inset-block-start: 50%;
		inset-inline-end: calc(100% + 0.75rem);
		padding: 0.35rem 0.6rem;
		font-family: var(--wp--preset--font-family--body);
		font-size: 0.8125rem;
		font-weight: 500;
		line-height: 1.2;
		letter-spacing: 0.02em;
		white-space: nowrap;
		color: var(--wp--preset--color--base);
		background-color: var(--wp--preset--color--navy);
		border: 1px solid transparent;
		border-radius: 3px;
		box-shadow: 0 4px 12px rgb(27 42 65 / 22%);
		opacity: 0;
		visibility: hidden;
		transform: translateY(-50%);
		transition: opacity 120ms ease;
		pointer-events: none;
	}

	.tt-rail__link:is(:hover, :focus-visible) .tt-rail__tip {
		opacity: 1;
		visibility: visible;
	}
}

@media (prefers-reduced-motion: reduce) {

	.tt-rail__tip {
		transition: none;
	}
}

/* Forced colours keep the borders and draw the glyph in the system link
   colour; the transparent outline and border become visible there, so
   the hover state and the tooltip's edge survive the loss of the fills. */
@media (forced-colors: active) {

	.tt-rail__link:is(:hover, :active) {
		outline: 2px solid transparent;
	}

	.tt-rail__icon {
		fill: currentcolor;
		forced-color-adjust: auto;
	}
}
