/*!
Theme Name: OpenHouse
Theme URI: https://openhouse.homeanddecor.com
Author: Pyper Publishing
Author URI: https://homeanddecor.com
Description: OpenHouse columnists theme for the Home&Decor ecosystem.
Version: 0.1.14
Tested up to: 7.0
Requires PHP: 8.3
License: GNU General Public License v2 or later
License URI: LICENSE
Text Domain: openhouse

This theme, like WordPress, is licensed under the GPL.
Use it to make something cool, have fun, and share what you've learned.

OpenHouse is based on Underscores https://underscores.me/, (C) 2012-2020 Automattic, Inc.
Underscores is distributed under the terms of the GNU GPL v2 or later.

Normalizing styles have been helped along thanks to the fine work of
Nicolas Gallagher and Jonathan Neal https://necolas.github.io/normalize.css/
*/

/*--------------------------------------------------------------
>>> TABLE OF CONTENTS:
----------------------------------------------------------------
# Generic
	- Normalize
	- Box sizing
# Base
	- Typography
	- Elements
	- Links
	- Forms
## Layouts
# Components
	- Navigation
	- Posts and pages
	- Comments
	- Widgets
	- Media
	- Captions
	- Galleries
# Utilities
	- Accessibility
	- Alignments

--------------------------------------------------------------*/

/*--------------------------------------------------------------
# Generic
--------------------------------------------------------------*/

/* Normalize
--------------------------------------------- */

/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */

/* Document
	========================================================================== */

/**
 * 1. Correct the line height in all browsers.
 * 2. Prevent adjustments of font size after orientation changes in iOS.
 */
html {
	line-height: 1.15;
	-webkit-text-size-adjust: 100%;
}

/* Sections
	========================================================================== */

/**
 * Remove the margin in all browsers.
 */
body {
	margin: 0;
}

/**
 * Render the `main` element consistently in IE.
 */
main {
	display: block;
}

/**
 * Correct the font size and margin on `h1` elements within `section` and
 * `article` contexts in Chrome, Firefox, and Safari.
 */
h1 {
	font-size: 2em;
	margin: 0.67em 0;
}

/* Grouping content
	========================================================================== */

/**
 * 1. Add the correct box sizing in Firefox.
 * 2. Show the overflow in Edge and IE.
 */
hr {
	box-sizing: content-box;
	height: 0;
	overflow: visible;
}

/**
 * 1. Correct the inheritance and scaling of font size in all browsers.
 * 2. Correct the odd `em` font sizing in all browsers.
 */
pre {
	font-family: monospace, monospace;
	font-size: 1em;
}

/* Text-level semantics
	========================================================================== */

/**
 * Remove the gray background on active links in IE 10.
 */
a {
	background-color: transparent;
}

/**
 * 1. Remove the bottom border in Chrome 57-
 * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
 */
abbr[title] {
	border-bottom: none;
	text-decoration: underline;
	text-decoration: underline dotted;
}

/**
 * Add the correct font weight in Chrome, Edge, and Safari.
 */
b,
strong {
	font-weight: bolder;
}

/**
 * 1. Correct the inheritance and scaling of font size in all browsers.
 * 2. Correct the odd `em` font sizing in all browsers.
 */
code,
kbd,
samp {
	font-family: monospace, monospace;
	font-size: 1em;
}

/**
 * Add the correct font size in all browsers.
 */
small {
	font-size: 80%;
}

/**
 * Prevent `sub` and `sup` elements from affecting the line height in
 * all browsers.
 */
sub,
sup {
	font-size: 75%;
	line-height: 0;
	position: relative;
	vertical-align: baseline;
}

sub {
	bottom: -0.25em;
}

sup {
	top: -0.5em;
}

/* Embedded content
	========================================================================== */

/**
 * Remove the border on images inside links in IE 10.
 */
img {
	border-style: none;
}

/* Forms
	========================================================================== */

/**
 * 1. Change the font styles in all browsers.
 * 2. Remove the margin in Firefox and Safari.
 */
button,
input,
optgroup,
select,
textarea {
	font-family: inherit;
	font-size: 100%;
	line-height: 1.15;
	margin: 0;
}

/**
 * Show the overflow in IE.
 * 1. Show the overflow in Edge.
 */
button,
input {
	overflow: visible;
}

/**
 * Remove the inheritance of text transform in Edge, Firefox, and IE.
 * 1. Remove the inheritance of text transform in Firefox.
 */
button,
select {
	text-transform: none;
}

/**
 * Correct the inability to style clickable types in iOS and Safari.
 */
button,
[type="button"],
[type="reset"],
[type="submit"] {
	-webkit-appearance: button;
}

/**
 * Remove the inner border and padding in Firefox.
 */
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
	border-style: none;
	padding: 0;
}

/**
 * Restore the focus styles unset by the previous rule.
 */
button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
	outline: 1px dotted ButtonText;
}

/**
 * Correct the padding in Firefox.
 */
fieldset {
	padding: 0.35em 0.75em 0.625em;
}

/**
 * 1. Correct the text wrapping in Edge and IE.
 * 2. Correct the color inheritance from `fieldset` elements in IE.
 * 3. Remove the padding so developers are not caught out when they zero out
 *		`fieldset` elements in all browsers.
 */
legend {
	box-sizing: border-box;
	color: inherit;
	display: table;
	max-width: 100%;
	padding: 0;
	white-space: normal;
}

/**
 * Add the correct vertical alignment in Chrome, Firefox, and Opera.
 */
progress {
	vertical-align: baseline;
}

/**
 * Remove the default vertical scrollbar in IE 10+.
 */
textarea {
	overflow: auto;
}

/**
 * 1. Add the correct box sizing in IE 10.
 * 2. Remove the padding in IE 10.
 */
[type="checkbox"],
[type="radio"] {
	box-sizing: border-box;
	padding: 0;
}

/**
 * Correct the cursor style of increment and decrement buttons in Chrome.
 */
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
	height: auto;
}

/**
 * 1. Correct the odd appearance in Chrome and Safari.
 * 2. Correct the outline style in Safari.
 */
[type="search"] {
	-webkit-appearance: textfield;
	outline-offset: -2px;
}

/**
 * Remove the inner padding in Chrome and Safari on macOS.
 */
[type="search"]::-webkit-search-decoration {
	-webkit-appearance: none;
}

/**
 * 1. Correct the inability to style clickable types in iOS and Safari.
 * 2. Change font properties to `inherit` in Safari.
 */
::-webkit-file-upload-button {
	-webkit-appearance: button;
	font: inherit;
}

/* Interactive
	========================================================================== */

/*
 * Add the correct display in Edge, IE 10+, and Firefox.
 */
details {
	display: block;
}

/*
 * Add the correct display in all browsers.
 */
summary {
	display: list-item;
}

/* Misc
	========================================================================== */

/**
 * Add the correct display in IE 10+.
 */
template {
	display: none;
}

/**
 * Add the correct display in IE 10.
 */
[hidden] {
	display: none;
}

/* Box sizing
--------------------------------------------- */

/* Inherit box-sizing to more easily change it's value on a component level.
@link http://css-tricks.com/inheriting-box-sizing-probably-slightly-better-best-practice/ */
*,
*::before,
*::after {
	box-sizing: inherit;
}

html {
	box-sizing: border-box;
}

/*--------------------------------------------------------------
# Base
--------------------------------------------------------------*/

/* Typography
--------------------------------------------- */
body,
button,
input,
select,
optgroup,
textarea {
	color: #404040;
	font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
	font-size: 1rem;
	line-height: 1.5;
}

h1,
h2,
h3,
h4,
h5,
h6 {
	clear: both;
}

p {
	margin-bottom: 1.5em;
}

dfn,
cite,
em,
i {
	font-style: italic;
}

blockquote {
	margin: 0 1.5em;
}

address {
	margin: 0 0 1.5em;
}

pre {
	background: #eee;
	font-family: "Courier 10 Pitch", courier, monospace;
	line-height: 1.6;
	margin-bottom: 1.6em;
	max-width: 100%;
	overflow: auto;
	padding: 1.6em;
}

code,
kbd,
tt,
var {
	font-family: monaco, consolas, "Andale Mono", "DejaVu Sans Mono", monospace;
}

abbr,
acronym {
	border-bottom: 1px dotted #666;
	cursor: help;
}

mark,
ins {
	background: #fff9c0;
	text-decoration: none;
}

big {
	font-size: 125%;
}

/* Elements
--------------------------------------------- */
body {
	background: #fff;
}

hr {
	background-color: #ccc;
	border: 0;
	height: 1px;
	margin-bottom: 1.5em;
}

ul,
ol {
	margin: 0 0 1.5em 3em;
}

ul {
	list-style: disc;
}

ol {
	list-style: decimal;
}

li > ul,
li > ol {
	margin-bottom: 0;
	margin-left: 1.5em;
}

dt {
	font-weight: 700;
}

dd {
	margin: 0 1.5em 1.5em;
}

/* Make sure embeds and iframes fit their containers. */
embed,
iframe,
object {
	max-width: 100%;
}

img {
	height: auto;
	max-width: 100%;
}

figure {
	margin: 1em 0;
}

table {
	margin: 0 0 1.5em;
	width: 100%;
}

/* Links — removed; owned by the design system
---------------------------------------------
   The _s color defaults (royalblue / visited purple / midnightblue) and the
   thin-dotted focus outline are removed: a:visited/a:hover at (0,1,1) beat
   every single-class design rule and painted all accents purple on visited
   links. tokens.css `a { color: inherit }` and the
   :where(a,button):focus-visible brand ring govern links instead. */

/* Forms
--------------------------------------------- */
button,
input[type="button"],
input[type="reset"],
input[type="submit"] {
	border: 1px solid;
	border-color: #ccc #ccc #bbb;
	border-radius: 3px;
	background: #e6e6e6;
	color: rgba(0, 0, 0, 0.8);
	line-height: 1;
	padding: 0.6em 1em 0.4em;
}

button:hover,
input[type="button"]:hover,
input[type="reset"]:hover,
input[type="submit"]:hover {
	border-color: #ccc #bbb #aaa;
}

button:active,
button:focus,
input[type="button"]:active,
input[type="button"]:focus,
input[type="reset"]:active,
input[type="reset"]:focus,
input[type="submit"]:active,
input[type="submit"]:focus {
	border-color: #aaa #bbb #bbb;
}

input[type="text"],
input[type="email"],
input[type="url"],
input[type="password"],
input[type="search"],
input[type="number"],
input[type="tel"],
input[type="range"],
input[type="date"],
input[type="month"],
input[type="week"],
input[type="time"],
input[type="datetime"],
input[type="datetime-local"],
input[type="color"],
textarea {
	color: #666;
	border: 1px solid #ccc;
	border-radius: 3px;
	padding: 3px;
}

input[type="text"]:focus,
input[type="email"]:focus,
input[type="url"]:focus,
input[type="password"]:focus,
input[type="search"]:focus,
input[type="number"]:focus,
input[type="tel"]:focus,
input[type="range"]:focus,
input[type="date"]:focus,
input[type="month"]:focus,
input[type="week"]:focus,
input[type="time"]:focus,
input[type="datetime"]:focus,
input[type="datetime-local"]:focus,
input[type="color"]:focus,
textarea:focus {
	color: #111;
}

select {
	border: 1px solid #ccc;
}

textarea {
	width: 100%;
}

/*--------------------------------------------------------------
# Layouts
--------------------------------------------------------------*/

/*--------------------------------------------------------------
# Components
--------------------------------------------------------------*/

/* Navigation
--------------------------------------------- */
.main-navigation {
	display: block;
	width: 100%;
}

.main-navigation ul {
	display: none;
	list-style: none;
	margin: 0;
	padding-left: 0;
}

.main-navigation ul ul {
	box-shadow: 0 3px 3px rgba(0, 0, 0, 0.2);
	float: left;
	position: absolute;
	top: 100%;
	left: -999em;
	z-index: 99999;
}

.main-navigation ul ul ul {
	left: -999em;
	top: 0;
}

.main-navigation ul ul li:hover > ul,
.main-navigation ul ul li.focus > ul {
	display: block;
	left: auto;
}

.main-navigation ul ul a {
	width: 200px;
}

.main-navigation ul li:hover > ul,
.main-navigation ul li.focus > ul {
	left: auto;
}

.main-navigation li {
	position: relative;
}

.main-navigation a {
	display: block;
	text-decoration: none;
}

/* Small menu. */
.menu-toggle,
.main-navigation.toggled ul {
	display: block;
}

@media screen and (min-width: 37.5em) {

	.menu-toggle {
		display: none;
	}

	.main-navigation ul {
		display: flex;
	}
}

.site-main .comment-navigation,
.site-main
.posts-navigation,
.site-main
.post-navigation {
	margin: 0 0 1.5em;
}

.comment-navigation .nav-links,
.posts-navigation .nav-links,
.post-navigation .nav-links {
	display: flex;
}

.comment-navigation .nav-previous,
.posts-navigation .nav-previous,
.post-navigation .nav-previous {
	flex: 1 0 50%;
}

.comment-navigation .nav-next,
.posts-navigation .nav-next,
.post-navigation .nav-next {
	text-align: end;
	flex: 1 0 50%;
}

/* Posts and pages
--------------------------------------------- */
.sticky {
	display: block;
}

.post,
.page {
	margin: 0 0 1.5em;
}

.updated:not(.published) {
	display: none;
}

.page-content,
.entry-content,
.entry-summary {
	margin: 1.5em 0 0;
}

.page-links {
	clear: both;
	margin: 0 0 1.5em;
}

/* Comments
--------------------------------------------- */
.comment-content a {
	word-wrap: break-word;
}

.bypostauthor {
	display: block;
}

/* Widgets
--------------------------------------------- */
.widget {
	margin: 0 0 1.5em;
}

.widget select {
	max-width: 100%;
}

/* Media
--------------------------------------------- */
.page-content .wp-smiley,
.entry-content .wp-smiley,
.comment-content .wp-smiley {
	border: none;
	margin-bottom: 0;
	margin-top: 0;
	padding: 0;
}

/* Make sure logo link wraps around logo image. */
.custom-logo-link {
	display: inline-block;
}

/* Captions
--------------------------------------------- */
.wp-caption {
	margin-bottom: 1.5em;
	max-width: 100%;
}

.wp-caption img[class*="wp-image-"] {
	display: block;
	margin-left: auto;
	margin-right: auto;
}

.wp-caption .wp-caption-text {
	margin: 0.8075em 0;
}

.wp-caption-text {
	text-align: center;
}

/* Galleries
--------------------------------------------- */
.gallery {
	margin-bottom: 1.5em;
	display: grid;
	grid-gap: 1.5em;
}

.gallery-item {
	display: inline-block;
	text-align: center;
	width: 100%;
}

.gallery-columns-2 {
	grid-template-columns: repeat(2, 1fr);
}

.gallery-columns-3 {
	grid-template-columns: repeat(3, 1fr);
}

.gallery-columns-4 {
	grid-template-columns: repeat(4, 1fr);
}

.gallery-columns-5 {
	grid-template-columns: repeat(5, 1fr);
}

.gallery-columns-6 {
	grid-template-columns: repeat(6, 1fr);
}

.gallery-columns-7 {
	grid-template-columns: repeat(7, 1fr);
}

.gallery-columns-8 {
	grid-template-columns: repeat(8, 1fr);
}

.gallery-columns-9 {
	grid-template-columns: repeat(9, 1fr);
}

.gallery-caption {
	display: block;
}

/*--------------------------------------------------------------
# Utilities
--------------------------------------------------------------*/

/* Accessibility
--------------------------------------------- */

/* Text meant only for screen readers. */
.screen-reader-text {
	border: 0;
	clip: rect(1px, 1px, 1px, 1px);
	clip-path: inset(50%);
	height: 1px;
	margin: -1px;
	overflow: hidden;
	padding: 0;
	position: absolute !important;
	width: 1px;
	word-wrap: normal !important;
}

.screen-reader-text:focus {
	background-color: #f1f1f1;
	border-radius: 3px;
	box-shadow: 0 0 2px 2px rgba(0, 0, 0, 0.6);
	clip: auto !important;
	clip-path: none;
	color: #21759b;
	display: block;
	font-size: 0.875rem;
	font-weight: 700;
	height: auto;
	left: 5px;
	line-height: normal;
	padding: 15px 23px 14px;
	text-decoration: none;
	top: 5px;
	width: auto;
	z-index: 100000;
}

/* Do not show the outline on the skip link target. */
#primary[tabindex="-1"]:focus {
	outline: 0;
}

/* Alignments
--------------------------------------------- */
.alignleft {

	/*rtl:ignore*/
	float: left;

	/*rtl:ignore*/
	margin-right: 1.5em;
	margin-bottom: 1.5em;
}

.alignright {

	/*rtl:ignore*/
	float: right;

	/*rtl:ignore*/
	margin-left: 1.5em;
	margin-bottom: 1.5em;
}

.aligncenter {
	clear: both;
	display: block;
	margin-left: auto;
	margin-right: auto;
	margin-bottom: 1.5em;
}

/* OpenHouse — featured-image fill
--------------------------------------------- */
/*
 * Featured images dropped into a fixed-ratio / fixed-height photo slot
 * (the profile portrait, post cards). The four design sheets style the empty
 * `.oh-photo` tonal placeholders; this project-owned rule covers the REAL
 * <img> so it fills the slot edge-to-edge (height-driven portrait + ratio
 * cards both use object-fit: cover). Lives here, never in the locked v37
 * design sheets.
 */
.oh-photo-fill {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	z-index: 0;
}

/* OpenHouse — theme-card spotlight lift restoration (D29)
--------------------------------------------- */
/*
 * MOTION.md §6 specifies a -8px lift on the hovered/keyboard-focused theme
 * card, but the v37 entrance rule `.oh-theme-grid .oh-theme-card.oh-reveal
 * .is-in` (components.css, specificity 0,4,0) pins `transform: translateY(0)`
 * after reveal, masking the lift in every state — a cascade accident, not a
 * design choice (user ruling, D29). These higher-specificity project-owned
 * rules re-assert the intended lift; the locked sheets stay untouched.
 * `.oh-reveal-instant` (frozen clock, §10) still wins via !important.
 */
@media (hover: hover) {
	.oh-theme-grid .oh-theme-card.oh-reveal.is-in:hover {
		transform: translateY(-8px);
	}
}

.oh-theme-grid .oh-theme-card.oh-reveal.is-in:has(.oh-card-link:focus-visible) {
	transform: translateY(-8px);
}

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

	.oh-theme-grid .oh-theme-card.oh-reveal.is-in:hover,
	.oh-theme-grid .oh-theme-card.oh-reveal.is-in:has(.oh-card-link:focus-visible) {
		transform: none;
	}
}

/* OpenHouse — footer form status line (feature 13, MailerLite NQYATA)
--------------------------------------------- */
/*
 * Base: ~0.78 rem, .oh-label letter-spacing, var(--oh-text-2) — unobtrusive.
 * Success lifts to var(--oh-text) (full white) — positive confirmation.
 * Error: no non-neutral accent token exists in the design system (--oh-accent
 * is white, same as --oh-text). Error state is differentiated typographically
 * instead: uppercase + letter-spacing matches .oh-label, signalling "alert"
 * via form language rather than hue. This is the stated design choice (D14 +
 * CLAUDE.md § tokens). No new colors are introduced.
 */
.oh-form-status {
	font-size: 0.78rem;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	font-weight: 500;
	color: var(--oh-text-2);
	margin-top: var(--oh-s3);
}

.oh-form-status.is-success {
	color: var(--oh-text);
	text-transform: none;
	letter-spacing: 0;
	font-weight: 400;
}

.oh-form-status.is-error {
	color: var(--oh-text-2);
}

/* OpenHouse — mobile profile hero order (fix pass, 2026-06-12)
--------------------------------------------- */
/*
 * User ruling: on the stacked (≤900px) profile hero the PORTRAIT leads,
 * then name / theme / bio / No. — overriding the v37 natural source order
 * (screens.css PREHANDOFF Task 2 comment). Desktop two-column grid is
 * untouched; the locked sheets stay untouched (the .oh-photo-fill
 * precedent). Source order in the template is unchanged, so the DOM and
 * heading sequence stay as built — this is presentation-only.
 */
@media (max-width: 900px) {

	.oh-profile-hero .oh-profile-portrait {
		order: -1;
	}
}

/* OpenHouse — profile portrait column restoration (fix pass 2, 2026-06-12)
--------------------------------------------- */
/*
 * FIELDS.md §6 computes the portrait slot width AS the hero grid's 0.95fr
 * column (≈3/4 against the 78vh height clamp on desktop). But an fr
 * track's implied minimum is its item's min-content, and the display-xl
 * name's longest word inflates the LEFT track past its 1.05fr share —
 * squeezing the portrait (measured 396×702 ≈ 1:1.77 @1280×900 against
 * the intended ≈522×702 ≈ 3:4). min-width: 0 releases the floor so the
 * tracks resolve by pure ratio, exactly as the design's geometry table
 * assumes. Locked sheets untouched.
 *
 * FIX 1 (2026-06-22): the name must NEVER break mid-word. D35 added
 * `overflow-wrap: break-word` here as a "guard," but break-word splits
 * INSIDE a word that doesn't fit — "Desboyaux" rendered "DESBOYA/UX" at
 * the display-xl clamp. Editorial rule: wrap a multi-word name ONLY at
 * spaces; a single word wider than the column shrinks via the clamp() or
 * minorly overflows — it never hyphenates/splits. `min-width:0` above
 * keeps the portrait geometry correct independently of name wrapping.
 */
.oh-profile-left {
	min-width: 0;
}

.oh-profile-name {
	overflow-wrap: normal;
	word-break: normal;
	hyphens: none;
}

/*
 * Item 3 (D64): cap the hero-name clamp so the longest real surname fits its
 * column. FIX 1 (above) stopped the mid-word SPLIT, but "Desboyaux" as one
 * unbreakable word at the locked `clamp(3.2rem, 9vw, 8rem)` (screens.css) is
 * simply wider than the ~394–578px hero text column at every desktop width
 * (rendered-DOM @901/1024/1280/1440: it overflowed +67 → +150px). The word's
 * rendered width is ~5.685× the font-size (measured, constant across widths),
 * and the binding case is the NARROWEST column (901px → 7.69vw is the exact-fit
 * ceiling), so the coefficient is tuned to 7.5vw (~10px clearance @901) and the
 * max to 6.25rem (~9.5px clearance @1440, just under the 101.7px hard ceiling).
 * The user ACCEPTED a modestly smaller desktop name to keep the full surname
 * intact (D64 Item 3). The floor (3.2rem) is unchanged → @390 is identical.
 * `.oh-profile-hero .oh-profile-name` (0,2,0) beats the locked screens.css
 * `.oh-profile-name` (0,1,0) regardless of order — the FIX 1 / D29 / D35
 * mechanism; the locked sheet stays untouched. No D60.
 */
.oh-profile-hero .oh-profile-name {
	font-size: clamp(3.2rem, 7.5vw, 6.25rem);
}

/*
 * Listing-profile name override (D75-follow): the slot-5 listing profile's name
 * is "Home&Decor" — uppercased to "HOME&DECOR", a single UNBREAKABLE 10-char
 * token whose rendered width is ~6.75x the font-size (measured), wider than the
 * D64 binding case "DESBOYAUX" (~5.685x). At the global clamp above it overflowed
 * its hero column into the portrait (rendered DOM: +62px @901, +97 @1440, +11
 * @390). Scoped to THIS profile (body.postid-35) so the GLOBAL clamp — tuned for
 * the real columnists in D64 Item 3 — is UNTOUCHED (Dianna's "DESBOYAUX" keeps
 * its size; only this provisional listing profile shrinks). Same mechanism as D64
 * (a re-tuned clamp, NO word-break), tuned empirically for ratio 6.75 against
 * the MEASURED hero columns (~394px @901 two-col, ~577px capped @>=1280, ~335px
 * @390 / ~305px @360 single-col): floor 2.7rem (fits @360), 6.2vw (binding @901
 * two-col), max 5.15rem (fits the ~571px capped column) — ~13-40px clearance at
 * every tested width (360/390/901/1024/1280/1440/1920). body.postid-35 (0,2,1)
 * beats the D64 `.oh-profile-hero .oh-profile-name` (0,2,0) + the locked (0,1,0);
 * no locked edit. If this slot becomes a real columnist with a normal name,
 * delete this rule (the global clamp resumes).
 */
body.postid-35 .oh-profile-name {
	font-size: clamp(2.7rem, 6.2vw, 5.15rem);
}

/* OpenHouse — footer form input keyboard focus ring (fix pass, UI-04)
--------------------------------------------- */
/*
 * components.css (locked) removes the input outline on :focus and signals
 * focus by border-color alone — hard to spot when tabbing. :focus-visible
 * re-asserts a ring for KEYBOARD focus only; pointer clicks keep the
 * design's quiet border shift. style.css loads BEFORE the locked sheets,
 * so the bare `.oh-form input:focus-visible` (0,2,1) would tie with the
 * locked `outline: none` and lose on order — the `.oh-keepreading`
 * ancestor lifts this to (0,3,1), the same higher-specificity-from-here
 * mechanism as the D29 lift restoration. Locked sheets untouched.
 */
.oh-keepreading .oh-form input:focus-visible {
	outline: 2px solid var(--oh-text);
	outline-offset: 2px;
}

/* OpenHouse — open-post hero scale-settle, real-photo path (fix pass, UI-02)
--------------------------------------------- */
/*
 * screens.css (locked) settles the hero with a ::before that duplicates the
 * BACKGROUND paint (background: inherit) — visible on the tonal empty-state
 * hero, but transparent when the hero holds a real <img.oh-photo-fill> (the
 * div carries no background), so the photo arrived without the settle.
 * These rules mirror the exact locked literals (scale 1.04 -> 1, 1300ms,
 * --oh-ease-fluid — MOTION §4) on the img. The two paths are mutually
 * exclusive (the tonal hero has no img; the photo hero's ::before paints
 * nothing), so the zooms cannot visually stack. Scoped to .oh-post-hero:
 * card .oh-photo-fill imgs (home/profile/related) are untouched. Frozen
 * clock (§10) and reduced-motion resolve to the final state, no movement.
 */
.oh-post-hero.oh-reveal .oh-photo-fill {
	transform: scale(1.04);
	transition: transform 1300ms var(--oh-ease-fluid);
	will-change: transform;
}

.oh-post-hero.oh-reveal.is-in .oh-photo-fill {
	transform: scale(1);
}

.oh-post-hero.oh-reveal.oh-reveal-instant .oh-photo-fill {
	transform: none !important;
	transition: none !important;
}

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

	.oh-post-hero.oh-reveal .oh-photo-fill,
	.oh-post-hero.oh-reveal.is-in .oh-photo-fill {
		transform: none;
		transition: none;
	}
}

/* OpenHouse — chip avatar img cover (fix pass, UI-06)
--------------------------------------------- */
/*
 * The templates put .oh-chip-avatar ON the <img> itself
 * (get_the_post_thumbnail attr class), so the locked 30x30 box applies
 * directly — but an img defaults to object-fit: fill and would squish a
 * non-square portrait into the circle. cover crops instead; display:block
 * drops the inline baseline gap. (The audit's `.oh-chip-avatar img`
 * selector assumed a wrapper; adapted to the real markup.)
 */
img.oh-chip-avatar {
	object-fit: cover;
	display: block;
}

/* OpenHouse — dispatch share control (feature 16; restyled D49)
--------------------------------------------- */
/*
 * Quiet, type-led share affordance composed INTO the byline meta row as the
 * last flow child of `.oh-post-meta`. No box, no fill, radius 0 — type + an
 * inline-SVG share glyph on the dark ground, in the site's tracked-affordance
 * vocabulary (the `.oh-enter` / `.oh-page-arrow` idiom: an uppercase
 * letter-spaced label beside a glyph that lifts on hover). Neutral only:
 * var(--oh-text-2) resting -> var(--oh-text) on hover/focus/confirmed (the
 * token system has no non-neutral accent — D14/D31; white is the only accent).
 *
 * The glyph is an INLINE SVG (currentColor, 1px hairline stroke) — never a
 * Unicode text glyph: the WP front-end emoji script (twemoji) rewrites
 * emoji-presentation characters into a remote s.w.org <img> that cannot inherit
 * currentColor and breaks the neutral color (the D48 bug). An inline SVG is
 * categorically immune. The ↗ it replaces also read as "external link", not
 * "share"; the share-node mark reads unambiguously as share.
 *
 * Confirmed state is "no check" (D50): share.js only toggles .is-copied + the
 * label text now (its old `arr.textContent = ✓` swap is removed), and this
 * sheet hides the glyph on .is-copied — the confirmation is purely typographic.
 * `.arr` stays as share.js's binding hook. CSS lives here only, never in the
 * locked v37 sheets (D29).
 */
.oh-share {
	/* FULL reset of the _s base <button> (style.css:540 paints a #e6e6e6,
	   1px-bordered, 3px-rounded, padded PILL — the box users saw when a stale
	   cached stylesheet lacked this rule, D50). The prior reset covered
	   background/border/padding but NOT border-radius or the native button
	   appearance, so any leaked fill rendered as a rounded box and the focus
	   ring inherited 3px corners. appearance:none kills native chrome;
	   border-radius:0 holds the site's radius-0 law (and squares the ring). */
	-webkit-appearance: none;
	appearance: none;
	background: none;
	border: 0;
	border-radius: 0;
	margin: 0;
	padding: 0;
	font: inherit;
	cursor: pointer;
	color: var(--oh-text-2);
	display: inline-flex;
	align-items: center;
	gap: var(--oh-s2);
	transition: color 200ms var(--oh-ease);
}

/* Glyph wrapper. `.arr` is share.js's binding hook (kept). It holds only the
   inline SVG now — the confirmed state shows no glyph (see .is-copied below). */
.oh-share .arr {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	line-height: 1;
}

.oh-share .arr svg {
	display: block;
	width: 14px;
	height: 14px;
	/* color transition is owned by .oh-share and cascades to currentColor; the
	   glyph only animates its own transform (the hover lift). */
	transition: transform 300ms var(--oh-ease);
}

@media (hover: hover) {

	.oh-share:hover {
		color: var(--oh-text);
	}

	.oh-share:hover .arr svg {
		transform: translateY(-2px);
	}
}

.oh-share:focus-visible {
	outline: 2px solid var(--oh-text);
	outline-offset: 3px;
}

/* Confirmed (copied/shared): NO check glyph (the old text ✓ read heavy/ugly,
   and was a Unicode glyph — D48 risk). The confirmation is purely typographic:
   the share mark is hidden, the label lifts var(--oh-text-2) -> var(--oh-text)
   and drops to mixed-case (the .oh-form-status.is-success idiom; no accent hue,
   D14/D31), so "Copied" reads as confirmation, not one more uppercase meta
   label. Color + text only; no movement (MOTION §9). */
.oh-share.is-copied {
	color: var(--oh-text);
}

.oh-share.is-copied .arr {
	display: none;
}

.oh-share.is-copied .oh-share-label {
	text-transform: none;
	letter-spacing: 0;
}

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

	.oh-share,
	.oh-share .arr svg {
		transition: none;
	}

	.oh-share:hover .arr svg {
		transform: none;
	}
}

/* ============================================================
   404 — Home&Decor-hub-consistent not-found (D53)
   Replaces the _s 404 inner body. Composition mirrors the hub's
   Framer 404 (large "404" numeral + message + "Go back") in this
   site's vocabulary: serif numeral, neutral palette, radius 0,
   on the base ground between nav and footer. Project-owned;
   the four locked sheets are untouched (D29).
   ============================================================ */
.oh-404 {
	display: flex;
	align-items: center;
	min-height: clamp(420px, 64vh, 720px);
	padding: var(--oh-s9) 0;
}

.oh-404-inner {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: clamp(var(--oh-s6), 6vw, var(--oh-s10));
}

.oh-404-numeral {
	margin: 0;
	font-family: var(--oh-font-serif);
	font-weight: 500;
	font-size: clamp(7rem, 22vw, 15rem);
	line-height: 0.86;
	letter-spacing: -0.02em;
	color: var(--oh-text);
}

.oh-404-body {
	flex: 1 1 280px;
	max-width: 44ch;
}

.oh-404-title {
	margin: 0;
	font-family: var(--oh-font-display);
	font-weight: 500;
	font-size: clamp(1.4rem, 3vw, 2.1rem);
	line-height: 1.18;
	letter-spacing: -0.01em;
	color: var(--oh-text);
}

.oh-404-note {
	margin: var(--oh-s4) 0 0;
	font-family: var(--oh-font-body);
	font-size: 1rem;
	line-height: 1.6;
	color: var(--oh-text-2);
}

.oh-404-back {
	display: inline-flex;
	align-items: center;
	gap: var(--oh-s2);
	margin-top: var(--oh-s6);
	padding: var(--oh-s3) var(--oh-s5);
	border: 1px solid var(--oh-text);
	border-radius: 0;
	font-family: var(--oh-font-display);
	font-size: 0.78rem;
	font-weight: 500;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--oh-text);
	text-decoration: none;
	transition: background-color 200ms var(--oh-ease), color 200ms var(--oh-ease);
}

.oh-404-back:hover,
.oh-404-back:focus-visible {
	background-color: var(--oh-text);
	color: var(--oh-bg);
}

.oh-404-back .arr {
	transition: transform 300ms var(--oh-ease);
}

.oh-404-back:hover .arr,
.oh-404-back:focus-visible .arr {
	transform: translateX(-3px);
}

@media (max-width: 640px) {

	.oh-404-numeral {
		font-size: clamp(5.5rem, 30vw, 9rem);
	}
}

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

	.oh-404-back,
	.oh-404-back .arr {
		transition: none;
	}

	.oh-404-back:hover .arr,
	.oh-404-back:focus-visible .arr {
		transform: none;
	}
}

/* ============================================================
   Profile archive empty-state — "Columns coming soon." (D56)
   Visual restyle of the STRUCT-02/D38 empty-state (copy unchanged).
   It inherited .oh-body + .oh-muted (Inter 1rem, left, --oh-text-2),
   reading as a cramped afterthought under the section head. Restyle
   it to OCCUPY the empty card area with intent: centered, larger
   serif, generous vertical air, a quiet hairline above (echoing the
   .oh-secthead-eyebrow idiom). Higher specificity (.oh-archive scope)
   to win over the tokens.css single-class rules regardless of cascade
   order. Project-owned; the four locked sheets are untouched (D29).
   Neutral tier only (--oh-text-2 / --oh-line). No motion added — the
   inherited .oh-reveal fade keeps its existing reduced-motion guard.
   ============================================================ */
.oh-archive .oh-archive-empty {
	margin: 0;
	padding-block: clamp(var(--oh-s8), 12vh, var(--oh-s10));
	font-family: var(--oh-font-serif);
	font-size: clamp(1.6rem, 3vw, 2.4rem);
	line-height: 1.3;
	font-weight: 400;
	text-align: center;
	color: var(--oh-text-2);
}

.oh-archive .oh-archive-empty::before {
	content: "";
	display: block;
	width: 40px;
	height: 1px;
	margin: 0 auto var(--oh-s5);
	background: var(--oh-line);
}

/* ============================================================
   PROFILE BREADCRUMB → HERO RHYTHM (F1)
   ============================================================
   The new profile back-breadcrumb (single-oh_columnist.php) reuses the
   locked .oh-breadcrumb rule (css/screens.css), whose 48px bottom padding
   would stack on .oh-profile-hero's 48px top padding → a doubled ~96px gap.
   Absorb the hero's top padding so the breadcrumb→hero rhythm matches the
   post page's breadcrumb→header. Higher-specificity longhand (0,2,0 beats
   the locked 0,1,0); the locked sheet stays untouched (D29). Project-owned. */
.oh-breadcrumb + .oh-profile-hero { padding-block-start: 0; }

/* ------------------------------------------------------------
   BREADCRUMB NAME OVERFLOW GUARD (N1 — closing quickscan 2026-06-19)
   ------------------------------------------------------------
   The breadcrumb is a flex / flex-wrap row (locked .oh-breadcrumb,
   screens.css). A free-text crumb that is a single unbreakable token
   wider than the viewport (a no-space columnist name, or a long post
   title) overflowed the page at mobile before Muriel's content. Set on
   the CONTAINER so it is inherited by EVERY crumb — the trailing
   <span aria-current> AND the owner <a> link (on single.php the
   columnist name renders as a link, not a span). Verified rendered-DOM
   @390: `overflow-wrap: break-word` is INEFFECTIVE here (it does not
   reduce a flex item's min-content size → docScrollWidth stayed 949 on
   the profile / 795 on the post); `anywhere` IS sizing-aware → the item
   shrinks and the word wraps → no overflow (docScrollWidth 375). Real
   spaced names wrap at spaces, unchanged. Project-owned (locked sheet
   untouched, D29). */
.oh-breadcrumb { overflow-wrap: anywhere; }

/* ============================================================
   FEED EMPTY-STATE — "Dispatches coming soon." (F3)
   ============================================================
   Mirrors the D56 profile recipe (.oh-archive .oh-archive-empty);
   keep the two visually in sync. Separate hook so F3 stays droppable.
   The feed is a 2-col grid, so the lone <p> spans both columns.
   Project-owned; the four locked sheets are untouched (D29). Neutral
   tier only (--oh-text-2 / --oh-line); no box/fill/radius. No motion
   added — the inherited .oh-reveal fade keeps its reduced-motion guard. */
.oh-feed .oh-feed-empty {
	grid-column: 1 / -1;
	margin: 0;
	padding-block: clamp(var(--oh-s8), 12vh, var(--oh-s10));
	font-family: var(--oh-font-serif);
	font-size: clamp(1.6rem, 3vw, 2.4rem);
	line-height: 1.3;
	font-weight: 400;
	text-align: center;
	color: var(--oh-text-2);
}

.oh-feed .oh-feed-empty::before {
	content: "";
	display: block;
	width: 40px;
	height: 1px;
	margin: 0 auto var(--oh-s5);
	background: var(--oh-line);
}

/* ============================================================
   COLUMNIST-RAIL CONTINUOUS CAROUSEL — snap suspend (F2 rewrite)
   ============================================================
   The mobile rail (.oh-theme-grid, locked css/screens.css) carries
   `scroll-snap-type: x mandatory`, which owns the scroll position and
   re-snaps any sub-card scrollLeft write to a card edge on the same frame —
   making a continuous smooth drift impossible while snap governs the
   scroller (root cause of the two rejected attempts). js/home-rail.js adds
   `.is-drifting` to the rail only while auto-motion is running and removes it
   the instant the user interacts; this rule suspends snap during that window
   so the rAF drift is smooth, then native snap returns for manual browsing.

   D60 + user-authorized (this session): this is an additive, state-scoped
   override placed in project-owned style.css, NOT an edit to the locked sheet.
   Specificity (0,2,0) beats the locked `.oh-theme-grid` snap rule (0,1,0)
   regardless of source order, so co-locating it in screens.css would buy
   nothing and break the byte-identical lock. The locked sheets stay untouched;
   removing this rule + home-rail.js reverts the rail to its pristine state. */
.oh-theme-grid.is-drifting {
	scroll-snap-type: none;
}

/* ============================================================
   HOME THEME-GRID — 5/10 display: 5 EQUAL tiles, inverted-pyramid / quincunx
   (FIX B, post-D64; replaces the earlier 3+2 unequal layout)
   ============================================================
   At launch the grid renders 5 tiles (OPENHOUSE_VISIBLE_COLUMNS, functions.php);
   front-page.php adds `.is-five` when EXACTLY 5 tiles render. The locked
   screens.css grid is `repeat(5, 1fr)` (one row of five at >=1001px).

   The earlier D64 3+2 made row-2 tiles WIDER (span 3) than row-1 (span 2),
   reading as a false "featured" hierarchy. FIX B replaces it with FIVE
   EQUAL-SIZE tiles in an inverted pyramid:

       [ 1 ]  [ 2 ]  [ 3 ]
          [ 4 ]  [ 5 ]

   Mechanism: a 6-col base, every tile `span 2` (so all five are EQUAL width)
   with `aspect-ratio: 4/5` (so all five are EQUAL height, matching the
   full-bleed photo crop). Row 1 = tiles 1/2/3 at cols 1-2 / 3-4 / 5-6. Row 2 =
   tiles 4/5 each `span 2` but offset ONE column — cols 2-3 and 4-5 — so tile 4
   centres in the 1|2 gap and tile 5 in the 2|3 gap (with equal columns + a
   uniform gap, each row-2 tile's centre lands exactly on a top-row gap centre).
   Vertical gap between rows = the locked grid gap (var(--oh-s4)).

   Additive + state-scoped — NO locked-sheet edit: `.oh-theme-grid.is-five`
   (0,2,0) beats the locked `.oh-theme-grid` (0,1,0); the per-tile placement
   (0,3,0) beats the locked `.oh-theme-card` min-height (0,1,0). Desktop-only
   (>=1001px) so it NEVER touches the <=1000px mobile rail (grid-auto-flow:column
   + the F2 carousel). The sr-only <h2> is position:absolute (out of grid flow),
   so the five tiles are the only grid items; `:nth-of-type` counts the <article>
   tiles reliably past the heading. When the rendered count is not 5 (e.g. the
   one-value flip to 10) `.is-five` is absent and the locked repeat(5,1fr) grid
   returns — zero rework. */
@media (min-width: 1001px) {
	.oh-theme-grid.is-five {
		grid-template-columns: repeat(6, 1fr);
	}
	/* all five tiles EQUAL: span 2 (equal width) + 4:5 (equal height) */
	.oh-theme-grid.is-five .oh-theme-card {
		aspect-ratio: 4 / 5;
		min-height: 0;
	}
	/* row 1 — tiles 1/2/3 across the top (cols 1-2 / 3-4 / 5-6) */
	.oh-theme-grid.is-five .oh-theme-card:nth-of-type(1) { grid-row: 1; grid-column: 1 / span 2; }
	.oh-theme-grid.is-five .oh-theme-card:nth-of-type(2) { grid-row: 1; grid-column: 3 / span 2; }
	.oh-theme-grid.is-five .oh-theme-card:nth-of-type(3) { grid-row: 1; grid-column: 5 / span 2; }
	/* row 2 — tiles 4/5 offset one col so each centres in a top-row gap
	   (4 -> cols 2-3 under the 1|2 gap; 5 -> cols 4-5 under the 2|3 gap) */
	.oh-theme-grid.is-five .oh-theme-card:nth-of-type(4) { grid-row: 2; grid-column: 2 / span 2; }
	.oh-theme-grid.is-five .oh-theme-card:nth-of-type(5) { grid-row: 2; grid-column: 4 / span 2; }
}

/* ============================================================
   HOME THEME-CARD — mobile signature-block alignment (Phase A, post-D78)
   ============================================================
   On the <=1000px horizontal rail every tile is a flex column that BOTTOM-pins
   .oh-theme-body (components.css: margin-top:auto), so the "Signed by" block
   sits at the card foot. The theme NAME already reserves two lines
   (components.css `.oh-theme-name { min-height: 2.1em }`) so its height is
   uniform across tiles — but the AUTHOR name does NOT reserve anything. A
   two-line author (e.g. "Todd Lagrow & John Z. Lagrow", which wraps at the
   210px rail-card width) makes that one tile's signature block a line taller,
   and because the block is bottom-pinned its "Signed by" label + name are
   pushed UP ~21px versus the one-line tiles (measured @360/@390: the Lagrow
   tile's label sat at 161 vs 182 on the other four — it read as "floating
   higher").

   Fix = mirror the existing name idiom on the author: reserve a two-line slot
   so every tile's signature block is the SAME height and the "Signed by" label
   + name share one baseline regardless of how the name wraps. 210px is the
   rail-card floor (screens.css `grid-auto-columns: clamp(210px, ...)`), so the
   longest current name tops out at exactly two lines — two is the complete
   reservation, no clipping (the already-two-line Lagrow tile renders fine at
   263px today and is itself unchanged; the four one-line tiles rise to meet it).

   Scope: <=1000px ONLY. The desktop grid (>1000px) is wide enough that every
   author fits on one line and all five are already aligned (verified
   @1024/@1280) — leave it byte-untouched. Specificity 0,3,0 (`.oh-theme-grid
   .oh-theme-card .oh-theme-author`) clears the locked `.oh-theme-author` (0,1,0),
   and `min-height` is a brand-new property on that selector besides. Additive,
   project-owned style.css — NO locked-sheet edit. Does not touch the D65/D75
   name clamps (different elements/scopes). */
@media (max-width: 1000px) {
	.oh-theme-grid .oh-theme-card .oh-theme-author {
		min-height: 2.2em; /* two lines at the author's line-height 1.1 (1.2rem font) */
	}
}

/* ============================================================
   HOME THEME-CARD — full-bleed portrait tiles (D64 Item 1)
   ============================================================
   The home theme-card moves from a glow-only "column spine" to a full-bleed
   columnist portrait with the glow floating ON TOP. Target z-stack inside
   .oh-theme-card: <img> photo 0 < fixed scrim 1 < radial glow ::before 2 <
   content (.oh-theme-index/.oh-theme-body) 3 < .oh-card-link 4. Levels 2/3/4
   are the three AUTHORIZED components.css z-index re-stacks (D60/D64 — the only
   locked edit in the plan); levels 0/1 are these additive card-scoped rules.

   Both the <img> and the scrim are DIRECT children of .oh-theme-card, so the
   locked `.oh-theme-card > *` rule (now `position: relative; z-index: 3`) also
   matches them — these rules MUST re-assert BOTH position:absolute AND the
   z-index, at specificity 0,2,0 (two classes), to beat that 0,1,0 `> *`
   regardless of source order. The width/height/object-fit come from the base
   .oh-photo-fill (untouched by `> *`).

   HARD CONSTRAINT: the photo is an <img> (front-page.php the_post_thumbnail),
   NEVER a CSS background-image — home-rail.js freezeTone() freezes only
   backgroundColor, so a background photo would break the F2 carousel seam; an
   <img> deep-clones cleanly via cloneNode(true) (D64 ruling 1). Crop = the
   already-generated oh-inline 4:5 (D43), no Regenerate.

   The spotlight (hover/focus lift + glow .56->1 + sibling dim .44 + reduced-
   motion transform-none) references opacity/transform/::before, NEVER z-index,
   so it is behaviour-identical. has_post_thumbnail() guards the markup, so a
   photo-less tile renders BYTE-IDENTICAL to before — none of these rules apply
   without .has-photo / the .oh-photo-fill img / the scrim span. */
.oh-theme-card .oh-photo-fill {
	position: absolute;
	inset: 0;
	z-index: 0;
}
/* Fixed bottom-up scrim — IDENTICAL on every photo tile regardless of the
   photo's lightness (user ruling: consistency over per-photo tuning, D64). z1,
   above the photo + below the glow; darkens the lower band where the name +
   signature sit so the forced-light text stays legible over any portrait. */
.oh-theme-card .oh-tile-scrim {
	position: absolute;
	inset: 0;
	z-index: 1;
	pointer-events: none;
	background: linear-gradient(
		to top,
		rgba(0, 0, 0, 0.72),
		rgba(0, 0, 0, 0.30) 42%,
		transparent 75%
	);
}
/* Force the card text to the light tiers over the scrim (photo tiles only). The
   resting index/by use --oh-text-3 (40% white, tuned for the flat dark surface)
   — too faint over a portrait; lift them to --oh-text-2. Name/author are
   asserted at --oh-text. Specificity 0,3,0 beats the base 0,1,0. */
.oh-theme-card.has-photo .oh-theme-index,
.oh-theme-card.has-photo .oh-theme-by {
	color: var(--oh-text-2);
}
.oh-theme-card.has-photo .oh-theme-name,
.oh-theme-card.has-photo .oh-theme-author {
	color: var(--oh-text);
}

/* ============================================================
   HOME THEME-CARD — dispatch/columnist number to the TOP-LEFT corner
   (FIX A, post-D64; global — all tiles, photo and photo-less)
   ============================================================
   The locked components.css anchors `.oh-theme-index` mid-tile (column flow,
   margin-top: var(--oh-s11)); with the full-bleed photo it floated unanchored
   over the image. FIX A pins it to the TOP-LEFT corner as a magazine-index mark,
   inset by var(--oh-s5) (== the card's own top/side padding, so it lines up with
   the body text's left edge — consistent rhythm). The index is a direct child
   of .oh-theme-card, so the locked `.oh-theme-card > *` (position:relative;
   z-index:3) matches it — this rule (0,2,0) re-asserts position:absolute + the
   inset + margin:0 (overriding the locked margin-top:s11 0,1,0) and keeps z3
   (content layer, above the photo z0 / scrim z1 / glow z2, below the link z4).
   Pulling the index out of the flex column leaves `.oh-theme-body`
   (margin-top:auto) as the only in-flow child, so the name + signature stay
   bottom-anchored. Global (no media query) — also applies on the mobile rail;
   the locked <=1000px `.oh-theme-index { margin-top:0 }` (0,3,0) only zeroes the
   margin (agrees) and never touches position/top/left. NO locked edit. */
.oh-theme-card .oh-theme-index {
	position: absolute;
	top: var(--oh-s5);
	left: var(--oh-s5);
	margin: 0;
	z-index: 3;
}
/* On a photo tile the corner mark sits over the BARE top of the image (the scrim
   is bottom-up — little cover up there), so lift it to full --oh-text + a
   black-alpha text-shadow (the .oh-portrait-meta idiom) to read over a light OR
   dark photo top. (Overrides the D64 has-photo index color --oh-text-2; same
   0,3,0 specificity, wins on source order.) */
.oh-theme-card.has-photo .oh-theme-index {
	color: var(--oh-text);
	text-shadow: 0 1px 3px rgba(0, 0, 0, 0.55), 0 0 12px rgba(0, 0, 0, 0.4);
}

/* ============================================================
   LISTING PROFILE — the .oh-listing-* authorial component
   (INSIDE THE MARKET; listing-profile pattern, this session)
   ============================================================
   INSIDE THE MARKET (the slot-5 listing profile) publishes a RECURRING post
   shape, not a one-off: running editorial text (often with a "Listing
   Highlights" spec block) -> an end-of-post photo carousel of the property ->
   an external listing button. These three named classes give that shape ONE
   authorial identity so the profile's future posts wear it without re-authoring.

   Carried by PROCEDURE + the named classes, NOT theme branching: the markup is
   authored into the post body (RUNBOOK §3a "listing dispatch"), styled here, and
   progressively enhanced by js/listing-carousel.js (the nav arrows). There is NO
   "if profile == X" auto-detect anywhere — the profile is provisional. All three
   live inside the 680px .oh-article column, inherit the existing tokens (radius 0,
   neutral palette, --oh-ease), and add NOTHING to any other surface.

   D60 regime: project-owned style.css ONLY (no locked-sheet edit). Selectors that
   target a generic element are scoped under .oh-article so they out-specify the
   locked screens.css `.oh-article p` (0,1,1) despite style.css loading first
   (the D56 specificity-over-source-order doctrine). New CSS + the new
   listing-carousel.js => OPENHOUSE_VERSION 0.1.11 -> 0.1.12 (D50).

   ---- 1. Listing Highlights spec sheet (<ul class="oh-listing-specs">) ----
   A magazine spec sheet: hairline-ruled key/value rows. Body (sans) font against
   the serif prose = a deliberate "data block" contrast (the site's label idiom). */
.oh-article .oh-listing-specs {
	list-style: none;
	margin: var(--oh-s7) 0;
	padding: 0;
	border-top: 1px solid var(--oh-line);
}
.oh-article .oh-listing-specs li {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	gap: var(--oh-s5);
	padding: var(--oh-s3) 0;
	border-bottom: 1px solid var(--oh-line);
}
.oh-article .oh-listing-specs .oh-spec-k {
	flex: none;
	font-family: var(--oh-font-body);
	font-size: 0.72rem;
	font-weight: 500;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--oh-text-2);
}
.oh-article .oh-listing-specs .oh-spec-v {
	font-family: var(--oh-font-body);
	font-size: 0.95rem;
	text-align: right;
	color: var(--oh-text);
}

/* ---- 2. End-of-post property carousel (.oh-listing-carousel) ----
   A pure-CSS scroll-snap track (native swipe / trackpad / drag); js/listing-
   carousel.js adds a restrained nav row (plate counter + inline-SVG prev/next
   chevrons, the site's .oh-page-arrow language). The track owns its own
   horizontal scroll, so the page never overflows the column. */
.oh-article .oh-listing-carousel {
	margin: var(--oh-s8) 0 var(--oh-s6);
}
.oh-article .oh-listing-track {
	display: flex;
	gap: var(--oh-s3);
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	scroll-behavior: smooth;
	-webkit-overflow-scrolling: touch;
	scrollbar-width: none; /* Firefox — the nav row is the affordance */
}
.oh-article .oh-listing-track::-webkit-scrollbar { display: none; } /* WebKit */
.oh-article .oh-listing-slide {
	flex: 0 0 100%;
	scroll-snap-align: start;
	margin: 0;
	aspect-ratio: 3 / 2;
	overflow: hidden;
	background: var(--oh-surface); /* neutral floor while the photo loads */
}
.oh-article .oh-listing-slide img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}
/* nav row (JS-built): plate counter on the left, chevrons on the right */
.oh-article .oh-listing-nav {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--oh-s4);
	margin-top: var(--oh-s4);
}
.oh-article .oh-listing-count {
	font-family: var(--oh-font-mono);
	font-size: 0.72rem;
	letter-spacing: 0.12em;
	color: var(--oh-text-3);
}
.oh-article .oh-listing-arrows { display: inline-flex; gap: var(--oh-s5); }
.oh-article .oh-listing-arrow {
	background: none;
	border: 0;
	padding: 0;
	font: inherit;
	color: var(--oh-text-2);
	cursor: pointer;
	display: inline-flex;
	align-items: center;
	transition: color 200ms var(--oh-ease);
}
.oh-article .oh-listing-arrow svg { display: block; transition: transform 300ms var(--oh-ease); }
.oh-article .oh-listing-arrow:hover { color: var(--oh-text); }
.oh-article .oh-listing-arrow.prev:hover svg { transform: translateX(-4px); }
.oh-article .oh-listing-arrow.next:hover svg { transform: translateX(4px); }
.oh-article .oh-listing-arrow[disabled] { color: var(--oh-text-3); opacity: 0.45; pointer-events: none; }

/* ---- 3. External listing button (.oh-listing-cta) ----
   A sober hairline button (radius 0, no fill); the arrow nudges up-right on hover
   to signal it leaves the site (target=_blank). Centered as the article's closing
   beat. The row is a <p>, so it MUST be scoped under .oh-article to beat the
   locked `.oh-article p` margin/font (0,1,1). */
.oh-article .oh-listing-cta-row { text-align: center; margin: var(--oh-s7) 0 0; }
.oh-article .oh-listing-cta {
	display: inline-flex;
	align-items: center;
	gap: var(--oh-s3);
	padding: var(--oh-s3) var(--oh-s6);
	border: 1px solid var(--oh-line);
	font-family: var(--oh-font-body);
	font-size: 0.72rem;
	font-weight: 500;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--oh-text-2);
	transition: color 200ms var(--oh-ease), border-color 200ms var(--oh-ease);
}
.oh-article .oh-listing-cta:hover { color: var(--oh-text); border-color: var(--oh-text); }
.oh-article .oh-listing-cta .arr { display: inline-flex; transition: transform 300ms var(--oh-ease); }
.oh-article .oh-listing-cta:hover .arr { transform: translate(3px, -3px); }

/* Reduced motion: kill the slide-smooth + every nudge; final state, no movement
   (MOTION §10 / the components.css C5 idiom). */
@media (prefers-reduced-motion: reduce) {
	.oh-article .oh-listing-track { scroll-behavior: auto; }
	.oh-article .oh-listing-arrow svg,
	.oh-article .oh-listing-cta .arr { transition: none; }
	.oh-article .oh-listing-arrow.prev:hover svg,
	.oh-article .oh-listing-arrow.next:hover svg,
	.oh-article .oh-listing-cta:hover .arr { transform: none; }
}

/* Mobile: a touch less top air; slides are 100% of the track (itself the
   full-width-minus-gutter column), so nothing overflows the page. */
@media (max-width: 768px) {
	.oh-article .oh-listing-carousel { margin-top: var(--oh-s7); }
	.oh-article .oh-listing-specs li { gap: var(--oh-s4); }
}
