:root {
  --ink: #303829;
  --paper: #f4eedf;
  --accent: #984b32;
  --muted: #686351;
  --rule: #c8b79b;
  --measure: 38rem;
  --wide: 72rem;
  --gap: 4rem;
  --radius: 2px;
  --font-heading: ui-serif, Georgia, "Times New Roman", serif;
  --font-body: "Segoe UI", Candara, Optima, "Gill Sans", ui-sans-serif, sans-serif;
}

@media (prefers-color-scheme: dark) {
  :root {
  --ink: #303829;
  --paper: #f4eedf;
  --accent: #984b32;
  --muted: #686351;
  --rule: #c8b79b;
  }
}

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  padding: 0 1.25rem;
  background: var(--paper);
  color: var(--ink);
  font: 17px/1.75 var(--font-body);
  -webkit-text-size-adjust: 100%;
}

main { padding: 0 0 4rem; }

/* A POST'S DATE AS METADATA, NOT A BARE <time> (visual polish work order item 4). On the reading
   measure, muted, small -- it is orientation, not content. */
.post-meta {
  max-width: var(--measure);
  margin: 0 auto 1.5rem;
  color: var(--muted);
  font-family: var(--font-heading);
  font-size: 0.9rem;
}

/* THE BLOG INDEX AS A CARD GRID (visual polish work order item 5). Three across at the layout
   width, two, then one -- no per-page configuration, the same way sections collapse. The
   thumbnail is the post's OWN lead image cropped to one ratio for the grid only: the file and the
   image inside the post are untouched, and Pinterest fetches the file directly. 4:5 because the
   leads are 2:3 portrait creatives and a landscape crop would throw most of each one away. A card
   with no thumbnail is a complete card; nothing here needs the image to exist. */
.posts-intro {
  max-width: var(--measure);
  margin: 0 auto 2rem;
  color: var(--muted);
  font-size: 1.05rem;
}

.posts {
  list-style: none;
  margin: 0 auto;
  padding: 0;
  max-width: var(--wide);
  display: grid;
  gap: 2.5rem 2rem;
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

.post-card { min-width: 0; }
.post-card__media { display: block; }
.post-card__media img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  /* The generic img rule centres a photograph between paragraphs; a card thumbnail fills its
     card. max-height is reset for the same reason it is on the logo: the article cap must never
     bind on a grid crop. */
  margin: 0;
  max-height: none;
}
.post-card__title {
  font-size: 1.25rem;
  margin: 1rem 0 0.35rem;
}
.post-card__title a { color: var(--ink); text-decoration: none; }
.post-card__title a:hover, .post-card__title a:focus-visible { text-decoration: underline; text-underline-offset: 3px; }
.post-card .post-meta { max-width: none; margin: 0 0 0.6rem; }
.post-card__excerpt { margin: 0; color: var(--ink); }

.page-cards__heading { margin: 0 0 1rem; }
.posts--pages .post-card__title { font-size: 1.15rem; }
/* A card whose page is not published: visible in the canvas, and the publish names it (WSB-104). */
.post-card--missing { outline: 2px dashed var(--ink); outline-offset: 4px; opacity: 0.7; }
@media (max-width: 64rem) { .posts { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 40rem) { .posts { grid-template-columns: minmax(0, 1fr); } }


/* SITE CHROME (WSB-087). Emitted only for a site that has chrome — see the note on
   buildStylesheet for why the first version emitted it always and why that was wrong.

   THE MOBILE ANSWER IS WRAPPING, and it is flex-wrap rather than a breakpoint. Dane ruled it on
   2026-09-05: the work order said only "must work without a JavaScript menu", which names what is
   forbidden and not what should happen. Wrapping degrades continuously — there is no width at
   which the navigation is suddenly wrong — and it needs no disclosure widget, which is what a
   script-free page cannot have. The item limits in server/chrome.js are what keep the wrap to a
   line or two. */
.chrome {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem 1.5rem;
  /* The LAYOUT width, not the reading measure. A header confined to a 38rem prose column leaves
     the navigation crowded against the logo with the page empty either side (WSB-094). */
  max-width: var(--wide);
  margin: 0 auto;
  padding: 1.25rem 0;
  border-bottom: 1px solid var(--rule);
}

.chrome__home { display: inline-flex; align-items: center; text-decoration: none; }
.chrome__home:not(:has(img)) { font-family: var(--font-heading); font-weight: 600; }

/* THE LOGO IS CAPPED IN THE STYLESHEET, not by re-encoding the file. Dane ruled on 2026-09-05
   that "use the mark unchanged" means the mark stays visually identical and the FILE may be
   optimised — so the source can be replaced with a smaller one at any time and this rule keeps
   the rendered size stable either way. width: auto so any aspect ratio is honoured; a logo is
   the one image on the site whose proportions are not ours to decide. */
/* BOUNDED IN BOTH DIRECTIONS. height alone caps a tall mark and does nothing about a wide one:
   a long horizontal lockup would push the navigation off the row at every width. object-fit
   keeps the mark undistorted if it ever meets both bounds at once. */
/* 3.5rem, UP FROM 2.5 (visual polish work order item 1, 2026-09-06). The approved transparent
   derivative is a 3:2 lockup -- the HOME3 wordmark over an "AI HOME DESIGN" line -- and at 2.5rem
   the second line was not readable on the published page. 3.5rem is the tallest that keeps the
   header under ~6rem with its padding, which is the "compact" the order asks for; the cap in CSS
   is still what WSB-090 ruled, only the number moved. */
.chrome__logo {
  display: block;
  height: 3.5rem;
  width: auto;
  /* AND PROPORTIONALLY. 16rem binds only for a wide mark, and for exactly those a 320px viewport
     has about 17.5rem of usable row to share with the action now sitting beside the logo
     (round-1 review, 2026-09-06). min() keeps a wide lockup to just over half the row. */
  max-width: min(16rem, 55%);
  object-fit: contain;
  border-radius: 0;
  /* THE ARTICLE IMAGE MARGIN DOES NOT BELONG IN A HEADER. The generic img rule sets 2rem top and
     bottom -- right for a photograph between two paragraphs, and it was silently applying here
     too: measured on the published page, the logo carried 32px above and below and the header
     stood 145px tall instead of about 82 (2026-09-05). max-height is reset for the same reason,
     so the cap that bounds an article photo can never bind on a logo. */
  margin: 0;
  max-height: none;
}

.chrome__nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.25rem;
  align-items: center;
}

/* margin-left:auto pushes the action to the far end on a wide screen and does nothing once the
   header wraps, which is the behaviour wanted in both cases from one declaration.

   FILLED, NOT OUTLINED. The site designer asked for the primary action to read as a button, and
   paper-on-accent is the one filled pairing home3.ai's own theme spec contrast-checks (5.81:1).
   It inherits --radius, so a site that chose square corners gets a square button. */
.chrome__action {
  margin-left: auto;
  padding: 0.6rem 1.1rem;
  border-radius: var(--radius);
  background: var(--accent);
  color: var(--paper);
  font-family: var(--font-heading);
  text-decoration: none;
  white-space: nowrap;
}

.chrome__action:hover { background: var(--ink); }

/* ORDINARY NAV LINKS ARE NOT UNDERLINED (visual polish work order item 3). They inherited the
   body's link underline, which made the header read as unstyled document text. The three states
   that must stay unmistakable get the underline back, thicker and offset: hover, keyboard focus,
   and the current page. The focus OUTLINE is the browser's and is not touched -- removing it is
   the one thing the order forbids here. aria-current is the accessibility signal; the underline
   is the visible one. Both, because a sighted keyboard user gets neither otherwise. */
.chrome__nav a { color: var(--ink); text-decoration: none; }
.chrome__nav a:hover,
.chrome__nav a:focus-visible,
.chrome__nav a[aria-current="page"] {
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 4px;
}

.chrome-foot {
  max-width: var(--wide);
  margin: 0 auto;
  padding: 2rem 0 3rem;
  border-top: 1px solid var(--rule);
}

/* THE ACTION STOPS BEING PUSHED RIGHT ONCE THE HEADER HAS WRAPPED. margin-left:auto is what puts
   it at the far end of a single row, and it keeps applying after the row breaks -- so on a phone
   the button ended up alone on its own line, right-aligned, under a left-aligned logo and
   navigation. Seen by looking at the published site at 375px, not by reading the rule
   (2026-09-05). Aligning it with everything else is what "stacks cleanly" means.

   In the chrome block and not the shared media query: a site with no chrome must generate the
   stylesheet it generated before this feature existed, and a stray .chrome__action rule breaks
   that -- which is exactly how the baseline case caught the first attempt. */
/* TWO DELIBERATE ROWS, NOT THREE BANDS (visual polish work order item 2, 2026-09-06). Plain
   wrapping stacked logo, then the navigation, then the action on its own third line. The order
   asks for logo and action together on the first row and the navigation on the second, WITHOUT a
   JavaScript menu and WITHOUT changing the DOM: the DOM order is the tab order, and the action
   must still come after the navigation for a keyboard user. So the arrangement is visual only:
   the order property moves the navigation below and gives it the full row; the action keeps margin-left:auto
   and sits at the far end of the logo's row. WSB-090's ruling -- the navigation WRAPS rather than
   gaining a disclosure widget -- still holds: within its row the links wrap as before. */
@media (max-width: 48rem) {
  .chrome__nav { order: 3; flex-basis: 100%; }
  .chrome__action { order: 2; }
}

.chrome-foot nav { display: flex; flex-wrap: wrap; gap: 0.5rem 1.25rem; }


/* Sections are the layout unit. One level of nesting: section > col > block. Columns
   collapse to a single column below 48rem with no per-breakpoint configuration — the
   responsive behaviour is a property of the stylesheet, not something authored per page. */
.s {
  /* --container is the ONE place a layout says how wide it is. The plain rule and the full-bleed
     tinted rule below both read it, so a multi-column section cannot be wide in one and narrow in
     the other -- which is what happens when two rules each name a width. */
  --container: var(--measure);
  display: grid;
  gap: 2rem;
  max-width: var(--container);
  margin: 0 auto;
  padding: var(--gap) 0;
}

/* Prose stays at the reading measure. Anything with a second column gets the layout width. */
.s--halves,
.s--thirds,
.s--two-thirds-left,
.s--two-thirds-right { --container: var(--wide); }

.s--halves { grid-template-columns: 1fr 1fr; }
.s--thirds { grid-template-columns: 1fr 1fr 1fr; }
.s--two-thirds-left { grid-template-columns: 2fr 1fr; }
.s--two-thirds-right { grid-template-columns: 1fr 2fr; }

@media (max-width: 48rem) {
  .s { grid-template-columns: 1fr; gap: 1rem; }
}

/* A tinted or inverted section reads full-bleed, so it breaks its own max-width rather than
   sitting as a floating card. The inner padding keeps its text on the same measure. */
.s--bg-tint, .s--bg-ink {
  max-width: none;
  padding: var(--gap) max(1.25rem, calc((100% - var(--container)) / 2));
}

.s--bg-tint { background: color-mix(in srgb, var(--accent) 8%, var(--paper)); }
.s--bg-ink { background: var(--ink); color: var(--paper); }
.s--bg-ink a { color: var(--paper); }
.s--bg-ink a.cta { border-color: var(--paper); }
.s--bg-ink a.cta:hover { background: var(--paper); color: var(--ink); }

.col > :first-child { margin-top: 0; }
.col > :last-child { margin-bottom: 0; }

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-heading);
  line-height: 1.2;
  letter-spacing: -0.01em;
  margin: 2.5rem 0 1rem;
}

h1 { font-size: clamp(2rem, 5vw, 2.75rem); margin-top: 0; }
h2 { font-size: clamp(1.4rem, 3vw, 1.75rem); }

p { margin: 0 0 1.25rem; }

/* A CAP ON HEIGHT AS WELL AS WIDTH (WSB-095). max-width alone bounds a landscape photo and does
   nothing to a portrait one: home3.ai's article leads are Pinterest creatives, 2:3 by design for
   the Pinterest feed, and one rendered 608x912 on a 1280 viewport -- most of a screen given to a
   single picture before the article began. Measured on the published page, not guessed.

   THE FILE IS NOT TOUCHED. Pinterest takes the image from the feed's media:content URL and fetches
   it directly, so it never loads this stylesheet; the pin stays 1024x1536 at its intended ratio.
   This is only how a browser draws it in the article.

   margin: 2rem auto rather than 2rem 0: an image the height cap has narrowed is no longer as
   wide as its column, and would otherwise sit against the left edge. */
img {
  display: block;
  max-width: 100%;
  max-height: 34rem;
  width: auto;
  height: auto;
  margin: 2rem auto;
  border-radius: var(--radius);
}

a { color: var(--accent); }

a.cta {
  display: inline-block;
  margin: 1rem 0 2rem;
  padding: 0.7rem 1.4rem;
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  font-family: var(--font-heading);
  font-size: 0.95rem;
  text-decoration: none;
}

a.cta:hover, a.cta:focus-visible { background: var(--accent); color: var(--paper); }

form { margin: 2rem 0; }

.field { margin-bottom: 1.1rem; }

label {
  display: block;
  margin-bottom: 0.35rem;
  font-family: var(--font-heading);
  font-size: 0.85rem;
  color: var(--muted);
}

input, textarea {
  width: 100%;
  padding: 0.6rem 0.7rem;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--paper);
  color: var(--ink);
  font: inherit;
  font-size: 0.95rem;
}

textarea { min-height: 8rem; resize: vertical; }

/* The form honeypot (WSB-029). Off-screen, not display:none: some form-fillers skip fields they
   can see are hidden, and a published page has no script to hide it any other way. */
.hp { position: absolute; left: -10000px; top: auto; width: 1px; height: 1px; overflow: hidden; }

input:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-color: var(--accent);
}

button[type="submit"] {
  padding: 0.7rem 1.5rem;
  border: 0;
  border-radius: var(--radius);
  background: var(--accent);
  color: var(--paper);
  font-family: var(--font-heading);
  font-size: 0.95rem;
  cursor: pointer;
}
