/*
Theme Name: DP Portfolio
Theme URI: https://www.darrenpellegrino.com
Author: Darren Pellegrino
Description: Block theme for darrenpellegrino.com. Two-colour fine-art photography portfolio with WooCommerce print sales. Archivo Black and Archivo, self-hosted.
Version: 6.12.0
Requires at least: 6.5
Tested up to: 6.8
Requires PHP: 7.4
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: dp-portfolio
Tags: portfolio, photography, block-theme, full-site-editing, e-commerce
*/

/* ------------------------------------------------------------------
   Nearly everything lives in theme.json. This file carries only what
   theme.json cannot express.
   ------------------------------------------------------------------ */


/* ==================================================================
   TUNABLE VALUES
   ==================================================================
   Override these from Appearance / Editor / Styles / Additional CSS
   without editing this file:

       :root { --dp-masonry-gap: 8px; }
   ================================================================== */

:root {
  --dp-masonry-gap: 2px;
  --dp-masonry-row-gap: 1px;
  --dp-filmstrip-height: clamp(280px, 55vh, 560px);
  --dp-filmstrip-gap: 0px;
  --dp-filmstrip-hero-height: 450px;
}


/* ==================================================================
   NATIVE GALLERY — MASONRY STYLE
   ==================================================================
   Core WordPress has no masonry layout. This adds one, registered as
   a block style in functions.php so it appears in the Gallery block's
   Styles panel as "Masonry".

   Measurements taken from the live Squarespace site at 1280px:
   4 columns, 2px column gap, 1px row gap, edge to edge.
   ================================================================== */

/* Every selector below carries .has-nested-images deliberately. Core
   applies its own layout through that class, and a rule without it
   loses on specificity — which silently pinned column-count to 1.

   The figure rules also repeat core's :not(#individual-image) hack.
   WordPress uses it to inject ID-level specificity into a class
   selector; without matching it, core keeps its calculated width and
   images render about a third of their column. */

.wp-block-gallery.is-style-masonry.has-nested-images {
  display: block;
  column-gap: var(--dp-masonry-gap);
  column-count: 1;
}

@media (min-width: 640px)  { .wp-block-gallery.is-style-masonry.has-nested-images { column-count: 2; } }
@media (min-width: 1000px) { .wp-block-gallery.is-style-masonry.has-nested-images { column-count: 3; } }
@media (min-width: 1200px) { .wp-block-gallery.is-style-masonry.has-nested-images { column-count: 4; } }

/* Respect the block's own Columns slider on wide screens. Core writes
   a columns-N class; these map it onto column-count so the editor
   control actually does something. Narrow screens keep the
   breakpoints above, because six columns on a phone is unreadable. */

@media (min-width: 1200px) {
  .wp-block-gallery.is-style-masonry.has-nested-images.columns-1 { column-count: 1; }
  .wp-block-gallery.is-style-masonry.has-nested-images.columns-2 { column-count: 2; }
  .wp-block-gallery.is-style-masonry.has-nested-images.columns-3 { column-count: 3; }
  .wp-block-gallery.is-style-masonry.has-nested-images.columns-4 { column-count: 4; }
  .wp-block-gallery.is-style-masonry.has-nested-images.columns-5 { column-count: 5; }
  .wp-block-gallery.is-style-masonry.has-nested-images.columns-6 { column-count: 6; }
  .wp-block-gallery.is-style-masonry.has-nested-images.columns-7 { column-count: 7; }
  .wp-block-gallery.is-style-masonry.has-nested-images.columns-8 { column-count: 8; }
}

.wp-block-gallery.is-style-masonry.has-nested-images figure.wp-block-image:not(#individual-image) {
  width: 100%;
  max-width: 100%;
  flex-basis: auto;
  flex-grow: 0;
  break-inside: avoid;
  -webkit-column-break-inside: avoid;
  page-break-inside: avoid;
  display: block;
  margin: 0 0 var(--dp-masonry-row-gap);
}

.wp-block-gallery.is-style-masonry.has-nested-images figure.wp-block-image:not(#individual-image) img {
  display: block;
  width: 100%;
  height: auto;
  object-fit: unset;
}

/* Masonry captions take their typography from theme.json's caption
   element. Only the colour is stated, for the same reason as the
   filmstrip: core makes gallery captions white. */

.wp-block-gallery.is-style-masonry.has-nested-images
  figure.wp-block-image:not(#individual-image) figcaption {
  font-family: inherit;
  font-size: inherit;
  line-height: inherit;
  letter-spacing: inherit;
  color: inherit;
  /* Weight stated rather than inherited, and synthesis off.

     Font smoothing is deliberately NOT set here. Forcing `antialiased`
     switches macOS from subpixel to grayscale rendering, which makes
     text look both heavier and softer — the exact symptom this was
     meant to cure. Left alone, captions render like every other
     paragraph on the page. */
  font-weight: 400;
  font-synthesis-weight: none;
  font-synthesis: none;
  /* THE actual cause of captions looking bolder and blurrier than the
     essay beside them. Core sets will-change:transform on gallery
     captions — it animates them as overlays — which pins the element
     to its own GPU layer. macOS then renders that layer's text with
     grayscale instead of subpixel antialiasing: heavier strokes, softer
     edges, identical computed styles. Releasing the layer fixes it. */
  will-change: auto;
  transform: none;
  backface-visibility: visible;
  background: none;
  position: static;
}


/* ==================================================================
   FILMSTRIP  (group-based, not a Gallery block)
   ==================================================================
   Each frame is a Group holding an Image block and a Paragraph block.
   The description is therefore a real paragraph — it inherits the
   page's text styling directly and none of core's gallery-caption CSS
   touches it.

   That matters: as a figcaption inside a Gallery block, core styled
   the text as an overlay (white, absolutely positioned, on its own
   compositing layer), which rendered heavier and softer than the essay
   beside it no matter what was overridden.

   Squarespace ran these reels at 437px tall on a 1280px screen; the
   clamp tracks viewport height so it behaves on any display.
   ================================================================== */

.dp-filmstrip {
  display: flex;
  flex-wrap: nowrap;
  align-items: flex-start;
  gap: var(--dp-filmstrip-gap);
  overflow-x: auto;
  overflow-y: visible;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
  padding-bottom: 0.5rem;
}

.dp-filmstrip > .wp-block-group {
  flex: 0 0 auto;
  width: auto;
  max-width: none;
  margin: 0;
  scroll-snap-align: center;
}

.dp-filmstrip > .wp-block-group > figure.wp-block-image {
  margin: 0;
  width: auto;
}

.dp-filmstrip img {
  display: block;
  height: var(--dp-filmstrip-height);
  width: auto;
  max-width: none;
}

/* The description. width:0 with min-width:100% keeps its text from
   driving the frame's intrinsic width — without it a long paragraph
   made the frame thousands of pixels wide. */

.dp-filmstrip .dp-caption {
  width: 0;
  min-width: 100%;
  margin: 0;
  padding: 0.6rem 0 0;
  text-align: left;
}

/* One description visible at a time, following the scroll. Without
   JavaScript every description simply stays visible.

   No transition here on purpose: a fade left the outgoing description
   on screen while the next appeared, so scrolling quickly showed
   several at once. The script switches visibility instead, which is
   instant. */

.dp-filmstrip.dp-filmstrip-ready > .wp-block-group {
  cursor: pointer;
}

/* On a phone a sideways strip is awkward; stack instead. */

/* The homepage hero is the same reel mechanism at Squarespace's own
   height — 450px on a 1280px screen — and carries no descriptions. */

.dp-filmstrip-hero img {
  height: var(--dp-filmstrip-hero-height);
}

@media (max-width: 600px) {
  .dp-filmstrip {
    display: block;
    overflow-x: visible;
  }
  .dp-filmstrip > .wp-block-group {
    width: 100%;
    margin: 0 0 var(--dp-masonry-row-gap);
  }
  .dp-filmstrip img {
    width: 100%;
    height: auto;
  }

  /* Indent the descriptions to the page's own text margin.

     The photographs run edge to edge on a phone, and the caption
     sits in the same full-width frame — so without this the writing
     starts hard against the screen edge while every other paragraph
     on the page is inset. Same value the root padding uses, so the
     descriptions line up with the essay above them.

     Horizontal only: the space above each description is set on the
     shared .dp-caption rule and stays there. */

  .dp-filmstrip .dp-caption {
    padding-left: var(--wp--preset--spacing--50, 1.5rem);
    padding-right: var(--wp--preset--spacing--50, 1.5rem);
  }
}


/* --- arrows --------------------------------------------------------
   44x44 buttons inset 15px from each edge, vertically centred on the
   frames — the measurements Squarespace used. */

.dp-filmstrip-wrap {
  position: relative;
  max-width: none;
}

.dp-filmstrip-btn {
  position: absolute;
  top: calc(var(--dp-filmstrip-height) / 2);
  transform: translateY(-50%);
  width: 44px;
  height: 44px;
  padding: 0;
  border: none;
  border-radius: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 2;
  background: var(--wp--preset--color--base);
  color: var(--wp--preset--color--contrast);
  opacity: 0.9;
}

.dp-filmstrip-btn:hover { opacity: 1; }
.dp-filmstrip-btn:disabled { opacity: 0.25; cursor: default; }

.dp-filmstrip-btn:focus-visible {
  outline: 2px solid var(--wp--preset--color--contrast);
  outline-offset: 2px;
}

.dp-filmstrip-btn svg { width: 28px; height: 28px; display: block; }

.dp-filmstrip-prev { left: 15px; }
.dp-filmstrip-next { right: 15px; }

@media (max-width: 600px) {
  .dp-filmstrip-btn { display: none; }
}


/* ==================================================================
   IMPORTED SQUARESPACE GALLERIES
   ==================================================================
   Pages not yet converted to native Gallery blocks still carry
   Squarespace's markup and class names but none of its CSS. These
   rules lay those out until conversion, and can be deleted once every
   gallery page has been converted.
   ================================================================== */

.entry-content .gallery-masonry,
.entry-content .gallery-reel {
  position: relative;
  width: 100vw;
  max-width: none;
  left: 50%;
  right: auto;
  margin-left: -50vw;
  margin-right: 0;
  transform: none;
  padding: 0;
}

.gallery-masonry-wrapper {
  column-count: 1;
  column-gap: var(--dp-masonry-gap);
  width: 100%;
  margin: 0;
  padding: 0;
}

@media (min-width: 640px)  { .gallery-masonry-wrapper { column-count: 2; } }
@media (min-width: 1000px) { .gallery-masonry-wrapper { column-count: 3; } }
@media (min-width: 1200px) { .gallery-masonry-wrapper { column-count: 4; } }

.gallery-masonry-item {
  break-inside: avoid;
  -webkit-column-break-inside: avoid;
  page-break-inside: avoid;
  display: block;
  width: 100%;
  margin: 0 0 var(--dp-masonry-row-gap);
  padding: 0;
}

/* Squarespace wrapped each image in a paragraph tag; strip its spacing. */
.gallery-masonry-item-wrapper,
.gallery-masonry-item-wrapper p,
.gallery-reel-item-wrapper,
.gallery-reel-item-wrapper p {
  margin: 0;
  padding: 0;
  line-height: 0;
}

.gallery-masonry-item img {
  display: block;
  width: 100%;
  height: auto;
}

/* Reel: horizontal filmstrip at uniform height, as the photo stories
   had on Squarespace. */

.gallery-reel-wrapper,
.gallery-reel-list {
  display: flex;
  flex-wrap: nowrap;
  gap: 0;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
}

.gallery-reel-item {
  flex: 0 0 auto;
  height: clamp(280px, 52vh, 520px);
  margin: 0;
  padding: 0;
  position: static;
  scroll-snap-align: center;
}

.gallery-reel-item img {
  display: block;
  height: 100%;
  width: auto;
  max-width: none;
  object-fit: cover;
}

/* TEMPORARY. These are Squarespace's own caption elements on the story
   pages not yet converted to native Gallery blocks. The editor cannot
   reach them — they are not WordPress captions — so the typography is
   stated here to stop them defaulting to something unrelated.

   Delete this whole IMPORTED SQUARESPACE GALLERIES section once every
   story page has been converted. */

.gallery-caption,
.gallery-caption-content {
  font: inherit;
  color: inherit;
  padding-top: 0.6rem;
}

/* Squarespace controls that no longer function. */

.gallery-lightbox,
.gallery-reel-control,
.gallery-reel-control-btn,
.gallery-masonry-control-btn,
.sqs-video-icon {
  display: none !important;
}

/* Squarespace's carousel script parked frames at -9999px; without the
   script they must be restored or the reel renders empty. Scoped to
   reels only — an earlier version targeted every fe-block on the page
   and flattened the grid on About, Books and Contact. */

.gallery-reel [class*="fe-block"],
.gallery-reel [class*="sqs-block"] {
  position: static !important;
  transform: none !important;
}


/* ==================================================================
   FOOTER
   ==================================================================
   Holds the bottom of the viewport on short pages. The margin-top:auto
   only takes effect when content is shorter than the viewport; on long
   gallery pages it resolves to 0 and nothing moves.

   No alignment default here on purpose — centre individual blocks from
   the editor toolbar where you want it.
   ================================================================== */

.wp-site-blocks {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.wp-site-blocks > footer {
  margin-top: auto;
}


/* ==================================================================
   NAVIGATION SUBMENUS
   ==================================================================
   WordPress gives dropdown panels a narrow default width, so long
   labels wrap. "Where The Dunes Meet The Sea" was breaking onto four
   lines. Sizing the panel to its content keeps every item on one row.
   ================================================================== */

.wp-block-navigation__submenu-container {
  width: auto;
  min-width: max-content;
}

.wp-block-navigation__submenu-container .wp-block-navigation-item__content {
  white-space: nowrap;
}

/* On mobile the menu is a full-screen overlay where wrapping is
   correct — a narrow screen cannot fit a 440px row. */

@media (max-width: 600px) {
  .wp-block-navigation__submenu-container {
    min-width: 0;
  }
  .wp-block-navigation__submenu-container .wp-block-navigation-item__content {
    white-space: normal;
  }
}


/* ==================================================================
   ODDS AND ENDS
   ================================================================== */

/* The eyebrow above photo-story titles carries its own typography in
   the block markup now, so it can be changed from the editor like any
   other paragraph. Nothing to declare here. */


.wp-block-site-logo img {
  display: block;
}

/* Shop grid.

   No aspect-ratio or object-fit here on purpose. Cropping is the
   Product Image block's own decision (Styles > Dimensions > Aspect
   ratio), and an earlier square-crop rule in this file was quietly
   beating that setting: the template said "auto", every photograph
   still rendered square. Whole frames, portrait and landscape, are
   what the block is asking for.

   Letting images keep their own proportions makes the tiles uneven,
   so the price no longer lands on the same line across a row. That
   part cannot come from a Styles panel - nothing there can say "sit
   at the bottom of whichever tile is tallest" - so it is set here.
   The tile becomes a flex column and the price takes the slack above
   it, carrying the button with it. Prices and buttons share a
   baseline whatever the photograph's shape or the title's length.

   What this costs: a top margin set on the Price block in the editor
   will not apply, because auto replaces it. Every other control on
   these blocks still works, spacing below the price included. */

.wc-block-product {
  display: flex;
  flex-direction: column;
}

.wc-block-product .wp-block-woocommerce-product-price {
  margin-top: auto;
}

/* Whole photographs, one height.

   The Product Image block's Aspect ratio setting decides the shape of
   the box - that stays in the editor, where it belongs. This rule
   only changes how the photograph sits inside it: contain instead of
   cover, so the frame is fitted rather than filled and nothing is
   trimmed off the edges.

   Equal heights follow from the box, not from here. An image fitted
   into a box reaches the box's full height only if the box is
   wider-proportioned than the image; a 3:2 landscape in a square box
   runs out of width first and comes up short. The widest photographs
   in the shop are 3:2, so a 3:2 box (or wider, like 16:9) puts every
   frame on the same height. Square and 4:3 will not.

   What this costs: if the block offers a Scale control (Cover /
   Contain / Fill), it stops having an effect - contain is fixed here.
   Aspect ratio, sizing and spacing all still work. */

.wc-block-product .wc-block-components-product-image img {
  object-fit: contain;
}

/* Centre the mobile menu, the way Squarespace did.

   Core stacks the overlay items hard left. The alignment does not come
   from a plain align-items declaration - it is driven by a custom
   property core sets from the block's justification, which is why
   overriding align-items directly does nothing. Setting the property
   is what actually moves them.

   Scoped to .is-menu-open, which only exists while the overlay is
   showing. The navigation is set to overlay on mobile only, so the
   desktop bar is untouched.

   This does not disable anything: the block's justification control
   still governs the desktop bar, which is the only place it was ever
   visible. */

.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__container,
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__submenu-container {
  --navigation-layout-justification-setting: center;
  --navigation-layout-align: center;
  text-align: center;
}


/* Centre the overlay on the screen, not just the text.

   The earlier rule centred each item inside the menu's own box, but
   that box sat top-left and shrank to fit its content — so with the
   submenus collapsed the whole menu drifted left. Centring the
   container and giving the list its full width puts the menu in the
   middle of the screen both ways. */

@media (max-width: 600px) {
  .wp-block-navigation__responsive-container.is-menu-open {
    align-items: center;
    justify-content: center;
  }

  .wp-block-navigation__responsive-container.is-menu-open
    .wp-block-navigation__responsive-container-content {
    width: 100%;
    align-items: center;
    justify-content: center;
  }

  .wp-block-navigation__responsive-container.is-menu-open
    .wp-block-navigation__container {
    width: 100%;
  }

  /* A chevron beside the items that open.

     Core ships this icon and then hides it: with open-on-click it
     renders the arrow as a sibling of the toggle button rather than
     inside it, and its own stylesheet suppresses the stray. Nothing
     then tells anyone that Work and Stories expand. Showing it costs
     no markup — the SVG is already in the page.

     Rotated a quarter turn so it points right while closed, and back
     to its own orientation when open, which reads as the menu
     unfolding. The rotation follows aria-expanded, so core's button
     still drives it.

     The list item is a column by default, which dropped the arrow
     onto its own line under the label. Row plus wrap keeps label and
     arrow together while the submenu still takes a full-width line of
     its own beneath them. */

  .wp-block-navigation__responsive-container.is-menu-open
    .wp-block-navigation-item.has-child {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 0.4em;
  }

  .wp-block-navigation__responsive-container.is-menu-open
    .wp-block-navigation-item.has-child
    > .wp-block-navigation__submenu-container {
    flex-basis: 100%;
  }

  .wp-block-navigation__responsive-container.is-menu-open
    .wp-block-navigation-item.has-child
    > .wp-block-navigation__submenu-icon {
    display: inline-flex;
    transform: rotate(-90deg);
    transition: transform 0.2s ease;
  }

  .wp-block-navigation__responsive-container.is-menu-open
    .wp-block-navigation-item.has-child:has(> button[aria-expanded="true"])
    > .wp-block-navigation__submenu-icon {
    transform: rotate(0deg);
  }

  /* Menu-sized type in the overlay.

     The Navigation block carries one font size and it has to suit the
     desktop bar, where 15px is right. Fifteen pixels on a full-screen
     phone menu is not - Squarespace ran its mobile menu two to three
     times the size of its nav bar.

     Set on the link and button elements rather than the list items:
     the list item is only a box, and core sizes the text on the
     element inside it.

     What this costs: the Navigation block's font size no longer shows
     in the overlay - change it and the desktop bar moves while the
     menu stays 25px. Everything else on the block still applies, the
     typeface and colour included. Change these two numbers to resize
     the menu. */

  .wp-block-navigation__responsive-container.is-menu-open
    .wp-block-navigation__container > li > .wp-block-navigation-item__content {
    font-size: 25px;
  }

  .wp-block-navigation__responsive-container.is-menu-open
    .wp-block-navigation__submenu-container .wp-block-navigation-item__content {
    font-size: 16px;
  }
}


/* Navigation sits last in the header markup so the hamburger lands to
   the right of the cart on a phone. On a desktop the menu belongs in
   front of the icons instead — same markup, opposite order, which no
   block setting can express because a block has one position, not one
   per screen size.

   601px is where core stops collapsing the menu into the overlay, so
   the flip happens exactly when the hamburger becomes a menu bar. */

@media (min-width: 601px) {
  header nav.wp-block-navigation {
    order: -1;
  }
}


/* Keep submenus shut in the overlay until they are tapped.

   The block is set to open submenus on click, and core honours that:
   the toggle button is there and reports aria-expanded="false". Its
   overlay stylesheet then displays the submenu anyway, so Work and
   Stories arrived pre-opened and the menu ran nine hundred pixels
   tall.

   Keying off aria-expanded rather than a class means core's own
   button still drives it — flip the attribute and the submenu
   reappears, which is exactly what the toggle does. Nothing here
   fights the block's setting; turn "open submenus on click" back off
   and this rule stops matching, because the button disappears with
   it. */

@media (max-width: 600px) {
  .wp-block-navigation__responsive-container.is-menu-open
    .wp-block-navigation-item.has-child:has(> button[aria-expanded="false"])
    > .wp-block-navigation__submenu-container {
    display: none;
  }
}


/* The Foto icon, inside the Social Icons block.

   Core's Social Icons ships a fixed set of services with no way to add
   one, and a Navigation block will not accept an Image block, so an
   icon for Foto cannot be inserted the ordinary way. What it will
   accept is the generic "Link" service - a chain glyph - and that
   gives us a real social icon with the right markup, size, circle,
   spacing and hover. Only the picture is wrong.

   So the chain is swapped for the Foto mark. Not as a background
   image: these icons are white on black, and the file is a black
   glyph. Used as a mask the file contributes only its shape, and the
   colour comes from currentColor - so it inherits whatever the block
   is set to, exactly like the icons beside it, and follows any colour
   change made in the editor.

   Applies to any social link given the dp-foto class in Advanced >
   Additional CSS class(es). Nothing else on the block is touched, and
   removing the class restores the chain.

   The path is root-relative so it survives the move to the real
   domain. If the file is ever re-uploaded under a new name, this is
   the one line that needs updating. */

.wp-block-social-link.dp-foto .wp-block-social-link-anchor svg {
  display: none;
}

.wp-block-social-link.dp-foto .wp-block-social-link-anchor::before {
  content: "";
  display: block;
  width: 1em;
  height: 1em;
  background-color: currentColor;
  -webkit-mask: url("/wp-content/uploads/2026/08/Foto.png") center / contain no-repeat;
  mask: url("/wp-content/uploads/2026/08/Foto.png") center / contain no-repeat;
}


/* Keep focus visible — the theme removes underlines from links. */

a:focus-visible,
button:focus-visible,
.wp-block-button__link:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}


/* ==================================================================
   CONTACT FORM
   ==================================================================
   Fluent Forms ships its own look: rounded corners, grey borders,
   system fonts and a blue submit button. None of that belongs on a
   two-colour site, so the form is restyled to match everything else —
   square corners, the site's typeface, a black button.

   Selectors are scoped to .fluentform so nothing here touches the
   WooCommerce checkout or comment forms.
   ================================================================== */

.fluentform .ff-el-form-control {
  font-family: inherit;
  font-size: inherit;
  line-height: inherit;
  color: var(--wp--preset--color--contrast);
  background-color: var(--wp--preset--color--base) !important;
  border: 1px solid var(--wp--preset--color--contrast) !important;
  border-radius: 0;
  padding: 0.7rem 0.9rem;
  box-shadow: none;
}

/* iOS zooms the whole page in when you tap a field whose text is
   under 16px, and never zooms back out — the visitor is left dragging
   a magnified page around to reach the send button. The body size is
   15px, which the fields inherit, so this lifts them the one pixel
   that stops it. Phone widths only; nothing changes on a desktop.

   This is a browser workaround, not a design choice: it overrides the
   inherited body size on these fields below 600px. Changing body type
   in Global Styles still governs everywhere else, and every other
   control on the form is untouched. */

@media (max-width: 600px) {
  .fluentform .ff-el-form-control {
    font-size: 16px;
  }
}

.fluentform .ff-el-form-control:focus {
  border-color: var(--wp--preset--color--contrast);
  outline: 2px solid var(--wp--preset--color--contrast);
  outline-offset: 1px;
  box-shadow: none;
}

.fluentform textarea.ff-el-form-control {
  min-height: 100px;   /* Squarespace ran the message box at 100px */
  resize: vertical;
}

/* Labels: the site's own small-caps treatment rather than Fluent's. */

.fluentform .ff-el-input--label label {
  font-family: inherit;
  font-size: var(--wp--preset--font-size--small);
  font-weight: 500;
  color: var(--wp--preset--color--contrast);
  margin-bottom: 0.35rem;
}

.fluentform .ff-el-is-required.asterisk-right label:after {
  color: var(--wp--preset--color--contrast);
}

/* Submit: the theme's button, not Fluent's blue. */

.fluentform .ff-btn-submit,
.fluentform button[type="submit"] {
  background-color: var(--wp--preset--color--contrast) !important;
  background-image: none !important;
  color: var(--wp--preset--color--base) !important;
  font-family: var(--wp--preset--font-family--display, 'Archivo Black', 'Arial Black', sans-serif);
  font-size: var(--wp--preset--font-size--small);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  border: 1px solid var(--wp--preset--color--contrast);
  border-radius: 0;
  padding: 0.9rem 1.6rem;
  box-shadow: none;
  transition: background 160ms ease, color 160ms ease;
}

.fluentform .ff-btn-submit:hover,
.fluentform button[type="submit"]:hover {
  background-color: var(--wp--preset--color--base) !important;
  color: var(--wp--preset--color--contrast) !important;
}

.fluentform .ff-btn-submit:focus-visible,
.fluentform button[type="submit"]:focus-visible {
  outline: 2px solid var(--wp--preset--color--contrast);
  outline-offset: 3px;
}

/* Validation messages in the site's own red-free palette. */

.fluentform .error.text-danger,
.fluentform .ff-el-is-error .text-danger {
  font-family: inherit;
  font-size: var(--wp--preset--font-size--fine);
}


/* ==================================================================
   NEWSLETTER SIGNUP (placeholder)
   ==================================================================
   The signup on the homepage is deliberately inert until a mail
   service is chosen — the fields are disabled so nobody types an
   address into something that goes nowhere.

   Styling matches the contact form. When the real form replaces this,
   these rules can go with it.
   ================================================================== */

.dp-newsletter {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  align-items: flex-start;
  margin: 1rem 0;
}

.dp-newsletter input {
  width: 100%;
  max-width: 284px;   /* Squarespace ran these at 284px */
  font: inherit;
  color: inherit;
  background: var(--wp--preset--color--base);
  border: 1px solid var(--wp--preset--color--contrast);
  border-radius: 0;
  padding: 0.7rem 0.9rem;
}

.dp-newsletter button {
  font-family: var(--wp--preset--font-family--display, 'Archivo Black', 'Arial Black', sans-serif);
  font-size: var(--wp--preset--font-size--small);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  background: var(--wp--preset--color--contrast);
  color: var(--wp--preset--color--base);
  border: 1px solid var(--wp--preset--color--contrast);
  border-radius: 0;
  padding: 0.9rem 1.6rem;
}

/* Disabled state: visibly inactive rather than merely unresponsive. */

.dp-newsletter input:disabled,
.dp-newsletter button:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.dp-newsletter__note {
  font-size: var(--wp--preset--font-size--fine);
  font-style: italic;
  opacity: 0.7;
  margin: 0;
}
