/*
Theme Name: Ivy Counting House
Theme URI: https://ivycountinghouse.com/
Author: Root Worldwide, Inc.
Author URI: https://rootww.com/
Description: Bespoke block theme for Ivy Counting House: bookkeeping for owner-led businesses. Brand palette and type scale are locked in theme.json so the identity cannot drift. Self-hosted variable fonts, no external requests.
Version: 1.17.0
Requires at least: 6.6
Tested up to: 7.0
Requires PHP: 8.1
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: ivy
Tags: block-theme, full-site-editing, one-column, custom-colors, custom-menu, editor-style
*/

/* ═══════════════════════════════════════════════════════════
   Nearly everything lives in theme.json. This file covers only
   what theme.json cannot express.
   ═══════════════════════════════════════════════════════════ */

/* ── accessibility ─────────────────────────────────────────── */

.ivy-skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 999;
  padding: 1rem 1.5rem;
  background: var(--wp--preset--color--navy);
  color: var(--wp--preset--color--cream);
  font-size: var(--wp--preset--font-size--x-small);
  letter-spacing: 0.2em;
  text-transform: uppercase;
}
.ivy-skip-link:focus { left: 0; }

/* Visible, on-brand focus ring: never remove focus outlines */
:where(a, button, input, textarea, select, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--wp--preset--color--forest);
  outline-offset: 3px;
}

/* ── the monogram ──────────────────────────────────────────── */

/* Always sized by height: the mark is tall and narrow (120:208), so
   width-based sizing would blow it up vertically out of all proportion. */
.ivy-emblem {
  display: block;
  width: auto;
  color: currentColor;
}
/* Scaled by 220/208 against the old values, because the viewBox now carries
   6 units of padding top and bottom (see ivy_emblem() for why). The artwork
   inside therefore renders at exactly the size it always did:
   2.75rem × 208/220 = 2.6rem of mark, plus clear space that stops the bottom
   ledger rule being clipped off by sub-pixel rounding. */
.ivy-emblem--sm { height: 2.75rem; }
.ivy-emblem--md { height: 4.23rem; }
.ivy-emblem--lg { height: 5.82rem; }

/* ── letterspaced caps (the brand's signature move) ────────── */

.ivy-tracked,
.is-style-ivy-tracked {
  font-family: var(--wp--preset--font-family--serif);
  font-weight: 600;
  letter-spacing: 0.3em;
  /* tracking adds trailing space; indent pulls the block back to optical centre */
  text-indent: 0.3em;
  text-transform: uppercase;
  /* these labels are short, so when one does wrap on a phone the default
     break leaves a stranded last word. No-op on single-line labels. */
  text-wrap: balance;
}
.ivy-tracked--wide { letter-spacing: 0.46em; text-indent: 0.46em; }

/* Small-caps section label.
   This look used to be got by writing the heading as an <h4>, because
   theme.json styles h4 this way. That made the heading level a STYLING choice,
   so every page jumped h1 -> h4 with nothing in between, which is exactly the
   kind of outline screen-reader users navigate by. The class carries the look
   now, and the heading can take its correct level.
   Typed selectors so this beats theme.json's `:root :where(h2)` regardless of
   which stylesheet the browser sees first. */
h2.ivy-label,
h3.ivy-label,
.ivy-label {
  font-family: var(--wp--preset--font-family--serif);
  font-size: var(--wp--preset--font-size--x-small);
  font-weight: 600;
  letter-spacing: 0.3em;
  text-transform: uppercase;
}

@media (max-width: 380px) {
  .ivy-tracked,
  .is-style-ivy-tracked { letter-spacing: 0.22em; text-indent: 0.22em; }
  .ivy-tracked--wide    { letter-spacing: 0.32em; text-indent: 0.32em; }
}

/* The wordmark lockup */
.ivy-wordmark {
  font-family: var(--wp--preset--font-family--display);
  font-weight: 500;
  letter-spacing: 0.055em;
  text-indent: 0.055em;
  line-height: 0.95;
}

/* ── hero: scrim so cream type stays legible over photography ──
   Applied to the Cover block's own overlay layer rather than a
   pseudo-element on a wrapper. A wrapper would have to sit inside the
   constrained layout, which stops `alignfull` from reaching the
   viewport edges: the cover must be the full-bleed element itself. */

.ivy-hero .wp-block-cover__background,
.wp-block-cover.ivy-hero > .wp-block-cover__background,
.is-style-ivy-hero .wp-block-cover__background {
  background: linear-gradient(
    to bottom,
    rgba(13, 27, 42, 0.66) 0%,
    rgba(13, 27, 42, 0.5) 45%,
    rgba(13, 27, 42, 0.76) 100%
  ) !important;
  opacity: 1 !important;
}

/* deeper scrim on small screens, where text overlaps more of the image */
@media (max-width: 781px) {
  .ivy-hero .wp-block-cover__background,
  .wp-block-cover.ivy-hero > .wp-block-cover__background,
  .is-style-ivy-hero .wp-block-cover__background {
    background: linear-gradient(
      to bottom,
      rgba(13, 27, 42, 0.76) 0%,
      rgba(13, 27, 42, 0.66) 45%,
      rgba(13, 27, 42, 0.84) 100%
    ) !important;
  }
}

/* ── self-heal a Cover whose overlay has been stripped ────────
   A Cover block draws its tint with an EMPTY <span class="wp-block-cover__
   background …>. TinyMCE deletes empty inline elements on cleanup, so saving a
   page from the Visual tab silently removes the navy scrim: the block comment
   still says dimRatio:80, the editor still looks right, and the live page shows
   cream text on an untinted photograph. That is a contrast failure, not just a
   colour one. It happened to About on 2026-07-31.

   These rules fire ONLY when the span is genuinely absent, so they never double
   up with a healthy Cover. Restoring the span is still the proper fix; this is
   the net underneath it. */

.wp-block-cover:not(.ivy-hero):not(:has(> .wp-block-cover__background))::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: var(--wp--preset--color--navy);
  opacity: 0.8;
}

/* the hero carries a gradient rather than a flat tint */
.wp-block-cover.ivy-hero:not(:has(> .wp-block-cover__background))::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    rgba(13, 27, 42, 0.66) 0%,
    rgba(13, 27, 42, 0.5) 45%,
    rgba(13, 27, 42, 0.76) 100%
  );
}

/* keep the text above whichever overlay is doing the work */
.wp-block-cover .wp-block-cover__inner-container {
  position: relative;
  z-index: 2;
}

/* ── quiet rule used as a section divider ──────────────────── */

/* Core ships `.wp-block-separator { margin-left:auto; margin-right:auto }`,
   which centred the rule under every page title while the title itself was
   left-aligned. `hr.ivy-rule` (0,1,1) outranks it (0,1,0) — and the longhands
   are needed because a `margin-inline` shorthand lost to core's longhands. */
hr.ivy-rule,
.ivy-rule {
  width: 4.5rem;
  height: 1px;
  border: 0;
  background: currentColor;
  opacity: 0.35;
}
hr.ivy-rule { margin-left: 0; margin-right: 0; }
hr.ivy-rule--center,
.ivy-rule--center { margin-left: auto; margin-right: auto; }

/* ── imagery ───────────────────────────────────────────────── */

/* Images sit flush and calm; no rounded corners anywhere in this identity */
.wp-block-image img,
.wp-block-cover { border-radius: 0 !important; }

/* max-width, NOT width.
   `width: 100%` forced every image to fill its container whatever size was
   chosen in the editor, so the Size dropdown appeared to do nothing: it only
   changes which FILE is served, and the CSS then stretched that file to the
   full column. Picking "Medium 300x200" downloaded a 300px file and blew it up
   to 1152px, which is the same apparent size but blurry.

   With max-width the dropdown works: a smaller size renders at its own size and
   is never upscaled. Nothing on the site changes today, because every image in
   use is already larger than the column it sits in. */
.wp-block-image img {
  display: block;
  max-width: 100%;
  height: auto;
}

/* Portrait-ish crop for side-by-side editorial rows.
   Both the raw class (used in patterns) and the is-style-* class
   WordPress emits when the matching block style is chosen in the
   sidebar: they must stay in sync or the sidebar option does nothing. */
.ivy-figure--tall img,
.wp-block-image.is-style-ivy-tall img {
  aspect-ratio: 4 / 5;
  object-fit: cover;
}

/* SHOW THE WHOLE FRAME. No ratio imposed, nothing cropped: the shape comes
   from the file itself and these declarations only undo a crop.

   House rule, set by Dan: a photograph he has chosen is shown entire. The
   cropping classes above stay for decorative stock, where fitting the layout
   matters more than the composition. Used by Audrey's portrait (2:3, which
   .ivy-figure--tall was cutting) and the About hero (3:2, whose open ledger
   .ivy-figure--wide sliced in half). */
.ivy-figure--whole img {
  aspect-ratio: auto;
  object-fit: fill;
  /* max-width, not width — see the note on .wp-block-image img above. This is
     the rule that has to give way for the editor's Size dropdown to do
     anything to the About hero or Audrey's portrait. */
  max-width: 100%;
  height: auto;
  max-height: none;
}
/* Full-width feature image.
   3:2 is right on a phone, but at the 72rem wide measure it renders ~768px
   tall — 85% of a laptop viewport — so it reads as a wall rather than a
   banner. Desktop gets a wider crop plus a viewport-relative height cap, so
   the image scales with the screen instead of swallowing it. */
.ivy-figure--wide img,
.wp-block-image.is-style-ivy-wide img {
  aspect-ratio: 3 / 2;
  object-fit: cover;
  object-position: center;
}

@media (min-width: 782px) {
  .ivy-figure--wide img,
  .wp-block-image.is-style-ivy-wide img {
    aspect-ratio: 5 / 2;
    /* clamped so it never dominates a short laptop screen, and never
       collapses to a letterbox sliver on a tall one */
    max-height: clamp(19rem, 44vh, 27rem);
  }
}

/* Post lead image.
   Deliberately NOT .ivy-figure--wide: at the 72rem measure the featured image
   read as a banner and opened too big a gap between the headline and the first
   line of text. Held at the 44rem body measure it behaves like part of the
   article. 3:2 is the native ratio of the current image, so nothing is cropped
   at that width and no height cap is needed. */
.ivy-figure--post img {
  aspect-ratio: 3 / 2;
  object-fit: cover;
  object-position: center;
}

/* ── the article column ────────────────────────────────────────
   Held to the theme's own 48rem content measure and CENTRED, because every
   other page on this site is centred: the interior pages fill the 72rem row
   with equal margins either side. Left-aligning this column left a lopsided
   right gutter that read, correctly, as "not like the rest of the site".

   ⚠ Must sit inside a FLOW group, never as a direct child of a constrained
   one. Constrained layout forces `margin-inline: auto !important` on its
   children, which also lands on `hr.ivy-rule` and centres the rule under the
   title. The wrapper absorbs that so the rule stays flush left inside this
   column while the column itself is centred. */

.ivy-article {
  max-width: 48rem;
  margin-left: auto;
  margin-right: auto;
}

/* ── Roman numerals ────────────────────────────────────────────
   A counter rather than `list-style-type: upper-roman`, because ::marker
   still will not take a font-family in every browser and these need the
   display face. Numerals are right-aligned so I/II/III/IV hang against a
   common edge instead of drifting. */

.ivy-numerals {
  list-style: none;
  counter-reset: ivy-numeral;
  padding-left: 0;
  margin: 0;
}
.ivy-numerals > li {
  counter-increment: ivy-numeral;
  position: relative;
  padding-left: 3.4em;
  margin-block: 1.5em;
}
.ivy-numerals > li::before {
  content: counter(ivy-numeral, upper-roman);
  position: absolute;
  left: 0;
  top: 0;
  width: 2.4em;
  text-align: right;
  font-family: var(--wp--preset--font-family--display);
  color: var(--wp--preset--color--forest);
  letter-spacing: 0.06em;
}

@media (max-width: 480px) {
  .ivy-numerals > li { padding-left: 2.5em; }
  .ivy-numerals > li::before { width: 1.8em; }
}

/* ── links inside prose ────────────────────────────────────────
   theme.json sets links to navy with no underline. That is right in the
   header and footer, where position makes the role obvious, but inside a
   paragraph it leaves a link completely indistinguishable from the text
   around it: same colour, no underline, no affordance at all. Colour alone
   would already fail WCAG 1.4.1, and here there is not even a colour
   difference. Buttons keep their own treatment. */

.wp-block-post-content a:not(.wp-element-button) {
  color: var(--wp--preset--color--forest);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
}
.wp-block-post-content a:not(.wp-element-button):hover {
  color: var(--wp--preset--color--navy);
}

/* Previous/next row carries the border, so when a post has no neighbours the
   page ends with a rule under nothing. Collapse the row when it holds no
   links. Browsers without :has() simply ignore this and show the old rule. */
.ivy-postnav:not(:has(a)) { display: none; }

/* ── the email address, kept out of the HTML ───────────────────
   Harvesters crawl HTML source looking for something@something.tld. The
   address is not in the markup at all: the page carries an empty
   <span class="ivy-mail"></span> and the text is assembled here, in the
   stylesheet, which harvesters do not read.

   The @ is written as an escape so the literal pattern does not appear in this
   file either. Screen readers do announce generated content, so this stays
   audible; what it is not is selectable, which is the trade. That is why the
   Contact page and its form are linked immediately before it: anyone who wants
   to click rather than read has a route.

   ⚠ This is a speed bump, not a lock. The only address that cannot be
   harvested is one that is not published, which is why the footer and the
   Contact page now link to the form instead of showing it. */

.ivy-mail::before { content: "contact"; }
.ivy-mail::after  { content: "\0040" "ivycountinghouse" "\002E" "com"; }
.ivy-mail { white-space: nowrap; }

/* ── contact form ──────────────────────────────────────────────
   Fluent Forms ships its own generic input styling: rounded corners, system
   fonts, a blue button. Left alone it reads as something bolted on. These
   rules put it back into the identity. Scoped to .fluentform so nothing else
   on the site is affected, and written against the plugin's own class names.

   If the plugin is ever swapped, this whole block can go. */

.fluentform .ff-el-input--label label {
  font-family: var(--wp--preset--font-family--serif);
  font-size: 0.92rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--wp--preset--color--navy);
}
.fluentform .ff-el-input--label label .ff-el-is-required.asterisk-right:after {
  color: var(--wp--preset--color--forest);
}

.fluentform input[type="text"],
.fluentform input[type="email"],
.fluentform input[type="tel"],
.fluentform textarea {
  width: 100%;
  border: 1px solid rgba(13, 27, 42, 0.24);
  border-radius: 0;              /* nothing on this site is rounded */
  background: var(--wp--preset--color--paper);
  color: var(--wp--preset--color--ink);
  font-family: var(--wp--preset--font-family--serif);
  font-size: 1.05rem;
  line-height: 1.5;
  padding: 0.7rem 0.85rem;
  box-shadow: none;
  transition: border-color 0.15s ease;
}
.fluentform input[type="text"]:focus,
.fluentform input[type="email"]:focus,
.fluentform input[type="tel"]:focus,
.fluentform textarea:focus {
  border-color: var(--wp--preset--color--forest);
  outline: 2px solid var(--wp--preset--color--forest);
  outline-offset: 2px;
}

.fluentform .ff-el-form-control::placeholder { color: rgba(36, 36, 36, 0.45); }

/* The optional-notes hint. Roman rather than italic, and close to body size:
   this is instructions someone has to read, not a decorative aside, and small
   italic serif is the hardest combination to read of the lot. */
.fluentform .ff-el-help-message {
  font-family: var(--wp--preset--font-family--serif);
  font-size: 1.1rem;
  line-height: 1.5;
  font-style: normal;
  color: rgba(36, 36, 36, 0.88);
  margin-bottom: 0.55rem;
}

.fluentform .ff-el-group { margin-bottom: 1.5rem; }

/* validation messages: readable, not shouty */
.fluentform .error.text-danger,
.fluentform .ff-el-is-error .text-danger {
  font-family: var(--wp--preset--font-family--serif);
  font-size: 0.95rem;
  color: #8a2b20;
}

/* button, matching the site's own */
.fluentform .ff-btn-submit,
.fluentform button.ff-btn {
  background: var(--wp--preset--color--navy) !important;
  color: var(--wp--preset--color--cream) !important;
  border: 1px solid var(--wp--preset--color--navy);
  border-radius: 0 !important;
  font-family: var(--wp--preset--font-family--serif);
  font-size: 0.88rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-indent: 0.2em;
  text-transform: uppercase;
  padding: 0.95rem 2.2rem;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.fluentform .ff-btn-submit:hover,
.fluentform button.ff-btn:hover {
  background: var(--wp--preset--color--forest) !important;
  border-color: var(--wp--preset--color--forest);
}

/* the thank-you message after submitting */
.ff-message-success {
  border: 1px solid rgba(41, 70, 59, 0.35);
  background: var(--wp--preset--color--paper);
  color: var(--wp--preset--color--navy);
  padding: 1.25rem 1.4rem;
  border-radius: 0;
}

/* ── inclusion lists ───────────────────────────────────────────
   Used for the "What's included" lists on Services. Discs are too
   heavy for this identity; a short forest rule reads as a ledger
   tick without shouting. */

.ivy-list {
  list-style: none;
  padding-left: 0;
  margin: 0;
}
.ivy-list li {
  position: relative;
  padding-left: 1.6em;
  margin-block: 0.4em;
  line-height: 1.5;
}
.ivy-list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.68em;
  width: 0.7em;
  height: 1px;
  background: var(--wp--preset--color--forest);
  opacity: 0.85;
}
/* on the navy band the forest rule disappears, so lift it to cream */
.has-navy-background-color .ivy-list li::before,
.ivy-footer .ivy-list li::before {
  background: var(--wp--preset--color--cream);
  opacity: 0.5;
}

/* ── FAQ disclosure ────────────────────────────────────────── */

.ivy-faq .wp-block-details {
  border-top: 1px solid rgba(13, 27, 42, 0.16);
  padding-block: 1.35rem;
}
.ivy-faq .wp-block-details:last-of-type {
  border-bottom: 1px solid rgba(13, 27, 42, 0.16);
}
.ivy-faq summary {
  cursor: pointer;
  list-style: none;
  font-family: var(--wp--preset--font-family--display);
  font-size: var(--wp--preset--font-size--large);
  line-height: 1.35;
  padding-right: 2rem;
  position: relative;
}
.ivy-faq summary::-webkit-details-marker { display: none; }
.ivy-faq summary::after {
  content: "+";
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  font-family: var(--wp--preset--font-family--serif);
  font-size: 1.4rem;
  color: var(--wp--preset--color--forest);
  transition: transform 0.25s ease;
}
.ivy-faq details[open] summary::after {
  content: "–";
}

/* ── header ────────────────────────────────────────────────── */

/* Pinned masthead.
 *
 * The sticky element is the template-part WRAPPER, not .ivy-header inside it.
 * Both boxes are exactly the header's height, and a sticky element can only
 * travel inside its own parent -- pinning the inner group would give it zero
 * room and it would scroll straight off the top. The wrapper's parent is
 * .wp-site-blocks, which is the full page height, so that is where the travel
 * lives. Every template renders this part with tagName "header", and the
 * footer part uses "footer", so this selector cannot catch the footer.
 *
 * Sticky also dies if any ancestor scrolls or clips; body, html and
 * .wp-site-blocks are all overflow:visible here, which is why this works
 * without touching the markup.
 */
header.wp-block-template-part {
  position: sticky;
  top: 0;
  z-index: 100;
}

/* Logged-in admins get a fixed toolbar across the top of the viewport, so the
   header has to start below it or it hides underneath. */
.admin-bar header.wp-block-template-part { top: 32px; }
@media screen and (max-width: 782px) {
  .admin-bar header.wp-block-template-part { top: 46px; }
}
/* under 600px WordPress stops fixing the toolbar, so the offset goes away */
@media screen and (max-width: 600px) {
  .admin-bar header.wp-block-template-part { top: 0; }
}

/* Anchor targets have to clear the pinned header instead of landing beneath it. */
html {
  scroll-padding-top: 6rem;
}

.ivy-header {
  border-bottom: 1px solid rgba(13, 27, 42, 0.12);
}
.ivy-header a { text-decoration: none; }

/* Navigation: letterspaced small caps */
.ivy-header .wp-block-navigation {
  font-family: var(--wp--preset--font-family--serif);
  font-size: var(--wp--preset--font-size--x-small);
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
}
.ivy-header .wp-block-navigation a:hover { text-decoration: underline; text-underline-offset: 0.4em; }

/* Mobile overlay menu on brand */
.wp-block-navigation__responsive-container.is-menu-open {
  background-color: var(--wp--preset--color--cream) !important;
  color: var(--wp--preset--color--navy) !important;
  padding-top: 4rem;
}
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item a {
  font-family: var(--wp--preset--font-family--display);
  font-size: 1.6rem;
  letter-spacing: 0.06em;
  text-transform: none;
  font-weight: 400;
}

/* ── footer ────────────────────────────────────────────────── */

.ivy-footer {
  border-top: 1px solid rgba(244, 240, 232, 0.16);
}

/* ── dark sections: force text back to cream ───────────────────
   theme.json sets link and heading colours at ELEMENT level, which
   beats a container's textColor. On the navy footer that rendered
   headings and links navy-on-navy at contrast 1.0: invisible, leaving
   only the cream list bullets showing. Any link or heading dropped onto
   a dark band would hit the same trap, so this covers both.
   Specificity (0,2,0) beats theme.json's `:root :where(...)` (0,1,0),
   so no !important is needed. Buttons are excluded: they carry their
   own deliberate colours. */
.ivy-footer :is(h1, h2, h3, h4, h5, h6),
.ivy-footer a:not(.wp-element-button),
.has-navy-background-color :is(h1, h2, h3, h4, h5, h6),
.has-navy-background-color a:not(.wp-element-button) {
  color: var(--wp--preset--color--cream);
}

.ivy-footer a { text-decoration: none; }
.ivy-footer a:hover { text-decoration: underline; text-underline-offset: 0.35em; }

/* Footer page list: a plain stack, not a bulleted list.
   Core ships it as a <ul> with discs and 40px indent. */
.ivy-footer .wp-block-page-list,
.ivy-footer .wp-block-page-list ul {
  list-style: none;
  padding-left: 0;
  margin: 0;
}
.ivy-footer .wp-block-page-list li { margin: 0; }
.ivy-footer .wp-block-page-list li::marker { content: none; }

/* ── motion ────────────────────────────────────────────────── */

@media (prefers-reduced-motion: no-preference) {
  .ivy-rise {
    animation: ivy-rise 1.05s cubic-bezier(0.22, 0.61, 0.36, 1) both;
  }
  @keyframes ivy-rise {
    from { opacity: 0; transform: translateY(12px); }
    to   { opacity: 1; transform: none; }
  }
}

/* ── print ─────────────────────────────────────────────────── */

/* ── Journal listing: centre the text on the PHOTO ──────────
   The date shares the left column and sits above the photo, so asking the two
   columns to centre against each other lines the text up with the middle of
   the date-plus-photo stack -- half a date block too high (measured at 21px on
   a 1440 viewport). Nudging the text column down by half that block puts its
   centre on the photo's centre.

   A transform rather than margin or padding, so the row does not get taller
   and the rhythm of the list is unchanged. The value is derived from the two
   things that make the gap: the date's line box (0.92rem at the theme's 1.6
   line-height) and the figure's top margin. If either changes in
   templates/index.html, change it here too.

   Only above 782px, which is where core stops laying columns out side by side.
   Once they stack there is nothing to centre against. */
@media (min-width: 782px) {
  .wp-block-post-template .wp-block-columns > .wp-block-column:last-child {
    transform: translateY(calc((0.92rem * 1.6 + var(--wp--preset--spacing--30)) / 2));
  }
}

@media print {
  .ivy-header, .ivy-footer, .wp-block-navigation { display: none; }
  body { background: #fff; color: #000; }
}
