/*
Theme Name: Tattoo Ess
Theme URI: https://tattooess.com
Author: Tattoo Ess
Author URI: https://tattooess.com
Description: Full Site Editing thema voor Tattoo Ess, tattoo- en piercingshop in Schiedam. Pagina's worden opgebouwd met de blok-inserter met eigen patterns (Hero, Diensten, FAQ, Prijstabel, Contact, etc.), plus een "Artiest" custom post type voor het team.
Requires at least: 6.5
Tested up to: 6.6
Requires PHP: 7.4
Version: 0.6.4
License: GNU General Public License v2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: tattoo-ess
Tags: full-site-editing, block-patterns, custom-logo, custom-post-type, one-column, wide-blocks, block-styles, translation-ready
*/

/* =========================================================
   Tattoo Ess — front-end stylesheet
   -------------------------------------------------------------------
   Structure
     1.  Design tokens (semantic aliases over theme.json presets)
     2.  Base / reset
     3.  Accessibility helpers
     4.  Layout primitives (.wrap, .section, .section-head)
     5.  Typography helpers (.eyebrow, .lede)
     6.  Components
           - Header & navigation
           - Hero
           - Buttons
           - Flash-sheet cards (grid + card)
           - Artist profile
           - Instagram gallery
           - Google Reviews widget
           - Style pills / trust chips
           - Pricing table
           - FAQ accordion
           - Contact info + form + map
           - Image placeholders
           - Footer
           - Breadcrumb
     7.  Responsive breakpoints
     8.  Reduced motion

   Colours, fonts and spacing come from theme.json as --wp--preset--*
   custom properties. This file only defines *semantic* aliases and a
   couple of decorative values that have no theme.json equivalent, so
   there is a single source of truth for the palette.

   Fonts are enqueued in functions.php (never @import-ed here).
   ========================================================= */

/* ---------------------------------------------------------
   1. Design tokens — semantic aliases over theme.json presets
   --------------------------------------------------------- */
:root {
  --te-bg:          var(--wp--preset--color--bg);
  --te-bg-alt:      var(--wp--preset--color--bg-alt);
  --te-ink:         var(--wp--preset--color--ink);
  --te-ink-dim:     var(--wp--preset--color--ink-dim);
  --te-crimson:     var(--wp--preset--color--crimson);
  --te-crimson-txt: var(--wp--preset--color--crimson-text);
  --te-gold:        var(--wp--preset--color--gold);

  /* Hairlines have no palette equivalent — derived from ink. */
  --te-line:        rgba(236, 228, 212, 0.16);
  --te-line-strong: rgba(236, 228, 212, 0.32);

  --te-font-display: var(--wp--preset--font-family--display);
  --te-font-body:    var(--wp--preset--font-family--body);
  --te-font-mono:    var(--wp--preset--font-family--mono);

  /* Shared transition + framing values keep components consistent. */
  --te-transition:  0.15s ease;
  --te-frame-pad:   20px;

  /* Site content width — mirrors theme.json's wideSize so .wrap and any
     other full-width container share one source of truth. Falls back to
     1100px if the global isn't present. */
  --te-content-max: var(--wp--style--global--wide-size, 1100px);
}

/* ---------------------------------------------------------
   2. Base / reset
   --------------------------------------------------------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background-color: var(--te-bg);
  background-image:
    radial-gradient(circle at 15% 0%, rgba(156, 43, 43, 0.08), transparent 40%),
    radial-gradient(circle at 85% 100%, rgba(176, 141, 87, 0.06), transparent 45%);
  color: var(--te-ink);
  font-family: var(--te-font-body);
  font-weight: 400;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

img {
  max-width: 100%;
  display: block;
}

a {
  color: inherit;
}

/* ---------------------------------------------------------
   3. Accessibility helpers
   --------------------------------------------------------- */
a:focus-visible,
button:focus-visible {
  outline: 2px solid var(--te-gold);
  outline-offset: 3px;
}

.screen-reader-text {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(1px, 1px, 1px, 1px);
  white-space: nowrap;
}

.skip-link.screen-reader-text:focus {
  position: fixed;
  top: 12px;
  left: 12px;
  z-index: 1000;
  width: auto;
  height: auto;
  clip: auto;
  white-space: normal;
  padding: 12px 20px;
  background: var(--te-crimson);
  color: var(--te-ink);
  font-family: var(--te-font-mono);
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  text-decoration: none;
  outline: 2px solid var(--te-gold);
  outline-offset: 2px;
}

/* ---------------------------------------------------------
   4. Layout primitives
   --------------------------------------------------------- */
.wrap {
  max-width: var(--te-content-max);
  margin: 0 auto;
  padding: 0 28px;
}

/* A .wrap group renders with WordPress's constrained layout, which caps
   its children at the theme.json contentSize (740px) — good for prose,
   but it squeezes the full-width layout components (card grids, column
   sections, chip rows, the reviews widget) into a narrow strip. These
   components manage their own internal width, so let them use the full
   1100px .wrap. Descendant (not direct-child) selectors are used on
   purpose: WordPress sometimes nests block content in an extra
   .wp-block-group__inner-container, which would break a ">" selector.
   These component classes only ever appear inside .wrap, so descendant
   matching is safe, and scoping under .wrap keeps specificity above
   the zero-specificity :where() cap. */
.wrap .flash-grid,
.wrap .hero-grid,
.wrap .two-col,
.wrap .placeholder-strip,
.wrap .profile,
.wrap .trust-row,
.wrap .pill-grid,
.wrap .price-table-scroll,
.wrap #google-reviews {
  max-width: none;
}

.section {
  padding: 56px 0;
  border-bottom: 1px solid var(--te-line);
}

.section:last-of-type {
  border-bottom: none;
}

/* The .section-head group carries the block's own flex layout
   (justify-content: space-between). This rule only adds the theme's
   vertical alignment and spacing so it never fights the block layout. */
.section-head {
  align-items: flex-end;
  margin-bottom: 48px;
}

.section-head h2 {
  margin: 6px 0 0;
  font-size: clamp(1.8rem, 4vw, 2.6rem);
}

.section-head p {
  max-width: 42ch;
  margin: 0;
  color: var(--te-ink-dim);
}

/* ---------------------------------------------------------
   5. Typography helpers
   --------------------------------------------------------- */
.eyebrow {
  font-family: var(--te-font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--te-gold);
}

.lede {
  max-width: 46ch;
  font-size: 1.08rem;
  color: var(--te-ink-dim);
}

/* The style page has more room, so let its description run wider — this
   fills the space that otherwise sat empty on the right. */
.style-intro .lede {
  max-width: 68ch;
}

/* ---------------------------------------------------------
   6. Components
   --------------------------------------------------------- */

/* ---------- Header & navigation ---------- */
/* Sticky header. WordPress wraps the header template part in
   <header class="wp-block-template-part">, and that wrapper — a direct
   child of <body> — is what must be sticky: making the inner .site-header
   sticky fails because its wrapper is only as tall as the header itself, so
   it scrolls away almost immediately. We stick the wrapper and style the
   inner .site-header. */
header.wp-block-template-part {
  position: sticky;
  top: 0;
  z-index: 20;
}

.site-header {
  background: var(--te-bg);
  background: color-mix(in srgb, var(--te-bg) 82%, transparent);
  border-bottom: 1px solid var(--te-line);
  transition: box-shadow 0.3s ease, background 0.3s ease;
}

/* Progressive enhancement: only apply the blur where supported. */
@supports (backdrop-filter: blur(8px)) or (-webkit-backdrop-filter: blur(8px)) {
  .site-header {
    -webkit-backdrop-filter: saturate(140%) blur(10px);
    backdrop-filter: saturate(140%) blur(10px);
  }
}

.site-header.is-scrolled {
  background: color-mix(in srgb, var(--te-bg) 92%, transparent);
  box-shadow: 0 8px 30px -12px rgba(0, 0, 0, 0.55);
}

/* The header .wrap gets flex + space-between from its group block
   layout; this rule adds the header's vertical padding and guarantees the
   logo and (mobile) burger stay vertically centred, independent of
   whether WordPress emits the alignment class. The padding eases down a
   little once scrolled so the bar feels more compact in use. */
.site-header .wrap {
  align-items: center;
  padding-top: 22px;
  padding-bottom: 22px;
  transition: padding 0.3s ease;
}

.site-header.is-scrolled .wrap {
  padding-top: 14px;
  padding-bottom: 14px;
}

/* On phones, the sticky header goes transparent so the logo and burger
   appear to float over the page as it scrolls beneath them — no solid bar,
   border, or shadow. (The mobile overlay menu still has its own opaque
   background when opened.) */
@media (max-width: 781px) {
  .site-header {
    background: transparent;
    border-bottom-color: transparent;
  }

  .site-header.is-scrolled {
    background: transparent;
    box-shadow: none;
  }

  @supports (backdrop-filter: blur(8px)) or (-webkit-backdrop-filter: blur(8px)) {
    .site-header {
      -webkit-backdrop-filter: none;
      backdrop-filter: none;
    }
  }
}

.mark {
  display: inline-flex;
  align-items: center;
  font-family: var(--te-font-display);
  font-weight: 800;
  font-size: 1.5rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--te-ink);
}

.mark span {
  color: var(--te-crimson-txt);
}

.mark img {
  display: block;
  height: 40px;
  width: auto;
}

/* Nav item spacing is set via the navigation block's blockGap (32px)
   in the header pattern; this rule only styles the links. */
.site-nav a {
  display: inline-block;
  padding: 10px 2px 8px;
  font-family: var(--te-font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--te-ink-dim);
  border-bottom: 1px solid transparent;
  transition: color var(--te-transition), border-color var(--te-transition);
}

.site-nav a:hover,
.site-nav a[aria-current="page"] {
  color: var(--te-ink);
  border-color: var(--te-crimson-txt);
}

/* Mobile nav toggle — enforce a 44x44 touch target, centre the glyph in
   it, and keep it in the theme's ink colour (the block renders
   currentColor). */
.wp-block-navigation__responsive-container-open,
.wp-block-navigation__responsive-container-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  color: var(--te-ink);
}

/* Open mobile overlay. The block's overlayBackgroundColor/overlayTextColor
   attributes (set in the header pattern) provide the colours; here we pad
   the menu content so the links aren't flush against the screen edge. The
   padding is on the content wrapper (not the whole container) so the
   close button stays pinned to the top-right. */
.wp-block-navigation__responsive-container.is-menu-open
  .wp-block-navigation__responsive-container-content {
  padding: 8px 28px 40px;
  width: 100%;
}

.wp-block-navigation__responsive-container.is-menu-open
  .wp-block-navigation__container {
  gap: 4px;
}

.wp-block-navigation__responsive-container.is-menu-open
  .wp-block-navigation-item__content {
  padding: 16px 0;
  font-family: var(--te-font-mono);
  font-size: 1rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* ---------- Hero ---------- */
.hero {
  position: relative;
  overflow: hidden;
  padding: 56px 0 84px;
  border-bottom: 1px solid var(--te-line);
}

.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: repeating-linear-gradient(
    135deg,
    transparent 0 38px,
    var(--te-line) 38px 39px
  );
  opacity: 0.35;
  pointer-events: none;
}

.hero .wrap {
  position: relative;
}

.hero-eyebrow {
  margin: 0 0 18px;
  font-family: var(--te-font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--te-gold);
}

.hero h1 {
  margin: 0 0 28px;
  font-size: clamp(3rem, 9vw, 6.5rem);
  line-height: 0.92;
}

.hero h1 em {
  font-style: normal;
  color: var(--te-crimson-txt);
  -webkit-text-stroke: 1px var(--te-line-strong);
}

.hero p.lede {
  margin: 0 0 36px;
}

/* .hero-grid, .two-col and .placeholder-strip are all core/columns
   blocks; the block owns the column widths, gap and responsive
   stacking. No CSS grid is declared for them (see .profile). */

/* ---------- Buttons ---------- */
.btn {
  display: inline-block;
  padding: 14px 26px;
  font-family: var(--te-font-mono);
  font-size: 0.8rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--te-ink);
  border: 1px solid var(--te-line-strong);
  transition: background var(--te-transition), border-color var(--te-transition),
    color var(--te-transition);
}

.btn:hover {
  border-color: var(--te-crimson-txt);
  color: var(--te-crimson-txt);
}

.btn.solid {
  background: var(--te-crimson);
  border-color: var(--te-crimson);
  color: var(--te-ink);
}

.btn.solid:hover {
  background: transparent;
  color: var(--te-crimson-txt);
}

/* ---------- Flash-sheet cards ---------- */
/* Two rendering paths share the .flash-card look:

   1. The [tattoo_ess_service_cards] shortcode outputs
      .flash-grid.flash-grid--cards > .flash-card directly. That modifier
      class is the CSS grid.
   2. The artist Query Loops output a .wp-block-query (.flash-grid) whose
      .wp-block-post-template carries WordPress's native grid layout (set
      in the pattern/template). The grid lives on the post-template, so
      the outer .flash-grid stays a plain block — otherwise the whole
      post-template would become one grid cell and every card would
      collapse into a single column.

   Keeping the two cases on separate selectors (a modifier class vs. the
   block's own layout) avoids any competing grid on one element. */
/* Both card grids (service cards + artist Query Loops) are flex rows of
   cards that wrap and stay centred. Cards scale to fill the row rather
   than sitting at a fixed width: at most 3 per row on large screens, 2 on
   tablets and 1 on phones. The shared sizing lives in a single rule; the
   two grids only differ in their container selector. */
.flash-grid--cards,
.flash-grid .wp-block-post-template {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 46px 32px;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* 3 per row: each card is a third of the row minus its share of the two
   32px gaps between three columns. flex-grow keeps them filling the row. */
.flash-grid--cards > .flash-card,
.flash-grid .wp-block-post-template > li {
  flex: 1 1 calc((100% - 2 * 32px) / 3);
  min-width: 0;
  max-width: calc((100% - 2 * 32px) / 3);
}

.flash-card {
  position: relative;
  padding: 22px 20px 24px;
  color: var(--te-ink);
  text-decoration: none;
  background: var(--te-bg-alt);
  border: 1.5px dashed var(--te-line-strong);
  transform: rotate(var(--tilt, -1.4deg));
  box-shadow: 0 0 0 0 transparent;
  transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
}

/* Alternating tilt for the pinned-flash-sheet look. */
.flash-card:nth-child(2n) { --tilt: 1.6deg; }
.flash-card:nth-child(3n) { --tilt: -2.2deg; }
.flash-card:nth-child(4n) { --tilt: 1deg; }

.flash-card:hover,
.flash-card:focus-within {
  transform: rotate(0deg) translateY(-4px);
  border-style: solid;
  border-color: var(--te-gold);
  box-shadow: 0 14px 26px rgba(0, 0, 0, 0.35);
}

/* Pin / tack — shared decoration also used by portrait & map frames. */
.flash-card::before,
.profile .portrait-frame::before,
.map-frame::before {
  content: "";
  position: absolute;
  top: -9px;
  left: 50%;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--te-crimson);
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.45);
  transform: translateX(-50%);
}

.flash-card .no {
  font-family: var(--te-font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  color: var(--te-gold);
}

.flash-card .portrait {
  width: 100%;
  aspect-ratio: 4 / 5;
  margin: 14px 0 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: var(--te-bg);
  border: 1px solid var(--te-line);
}

/* The featured-image block wraps its <img> in an <a> when linked, so the
   link must fill the frame too — otherwise the image sizes to the (auto)
   link box and no longer covers the 4:5 portrait. */
.flash-card .portrait a {
  display: block;
  width: 100%;
  height: 100%;
}

.flash-card .portrait img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.flash-card h3 {
  margin: 0 0 4px;
  font-size: 1.4rem;
}

.flash-card .blurb {
  margin: 0 0 14px;
  font-size: 0.9rem;
  color: var(--te-ink-dim);
}

/* When .blurb is a core/post-excerpt block (archive cards), flatten the
   inner excerpt paragraph so it matches the plain <p class="blurb">
   used by the service-card shortcode. */
.flash-card .blurb p {
  margin: 0;
}

.flash-card .view-link {
  font-family: var(--te-font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--te-gold);
}

/* Whole-card click target ("stretched link").
   The card is position:relative, so the primary link inside it is
   expanded with an ::after overlay covering the entire card. A click
   anywhere on the card then follows that link — matching how people
   expect cards to behave — while the visible link text stays in place.
   - Service cards (shortcode): the .card-link in .view-link.
   - Artist cards (Query Loop): the post-title link (always present,
     even when an artist has no featured image).
   The overlay's inset:0 resolves against .flash-card, so the link's own
   wrapper must NOT be positioned. The overlay sits above the card's
   other content (including the featured-image link, which points to the
   same destination), so the whole card is a single click target. */
.flash-card .view-link .card-link::after,
.flash-card .wp-block-post-title a::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
}

/* Specialty line — shared by cards and the profile header. */
.specialty {
  margin: 0 0 10px;
  font-family: var(--te-font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--te-crimson-txt);
}

/* ---------- Artist profile page ---------- */
/* .profile is a core/columns block (300px portrait + flexible body);
   the block owns the two-column layout, gap and responsive stacking, so
   no CSS grid is declared here (avoids a second competing layout). */
.profile .portrait-frame {
  position: relative;
  padding: var(--te-frame-pad);
  background: var(--te-bg-alt);
  border: 1.5px dashed var(--te-line-strong);
  transform: rotate(-1.4deg);
  /* Don't stretch to the (taller) body column, and keep the dashed
     frame a stable 4:5 portrait box whether or not a featured image is
     set — post-featured-image renders nothing when empty, so the frame
     itself must hold the shape. */
  align-self: flex-start;
  aspect-ratio: 4 / 5;
}

/* When a featured image IS present it fills the frame; the figure is
   absolutely-sized inside the padded frame so it never dictates height. */
.profile .portrait-frame .portrait,
.profile .portrait-frame .wp-block-post-featured-image {
  width: 100%;
  height: 100%;
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: var(--te-bg);
  border: 1px solid var(--te-line);
}

.profile .portrait-frame .portrait img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.profile-body h1 {
  margin: 0 0 6px;
  font-size: clamp(2.2rem, 5vw, 3.2rem);
}

.profile-body .specialty {
  font-size: 0.82rem;
  letter-spacing: 0.1em;
  margin: 0 0 26px;
}

.profile-body p {
  color: var(--te-ink-dim);
}

.profile-body p strong {
  color: var(--te-ink);
}

.stat-row {
  display: flex;
  gap: 40px;
  margin: 30px 0 34px;
  flex-wrap: wrap;
}

.stat-row div {
  min-width: 110px;
}

.stat-row .label {
  margin-bottom: 6px;
  font-family: var(--te-font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--te-gold);
}

.stat-row .value {
  font-family: var(--te-font-display);
  font-weight: 700;
  font-size: 1.15rem;
  text-transform: uppercase;
}

/* Inline Instagram handle links (artist stats + booking text). */
.ig-link {
  color: var(--te-gold);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: border-color var(--te-transition);
}

.ig-link:hover,
.ig-link:focus-visible {
  border-color: var(--te-gold);
}

/* ---------- Instagram gallery (profile pages) ---------- */
/* Responsive tiles that scale to fill the available width rather than
   sticking to a fixed narrow grid, so the work is clearly visible. */
.ig-gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 12px;
  margin: 22px 0 18px;
}

.ig-tile {
  position: relative;
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  text-decoration: none;
  background: var(--te-bg-alt);
  border: 1px solid var(--te-line);
}

.ig-tile img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.ig-tile::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(156, 43, 43, 0);
  transition: background var(--te-transition);
}

.ig-tile:hover::after,
.ig-tile:focus-visible::after {
  background: rgba(156, 43, 43, 0.35);
}

/* Wider variant used on style pages (studio-wide work): larger tiles,
   captioned with the artist name. */
.ig-gallery--wide {
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}

/* Artist name overlaid on each style-page tile, so the maker is clear
   before clicking through to their page. */
.ig-tile-artiest {
  position: absolute;
  z-index: 1;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 20px 10px 8px;
  font-family: var(--te-font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--te-ink);
  background: linear-gradient(to top, rgba(20, 18, 16, 0.9), transparent);
  pointer-events: none;
}

/* ---------- Combined gallery page ---------- */
/* Style filter tabs above the grid. Clicking one filters the tiles to that
   style; the grid itself is the standard wide gallery. */
.gallery-filter {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 24px;
}

.gallery-tab {
  padding: 9px 16px;
  font-family: var(--te-font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--te-ink-dim);
  background: transparent;
  border: 1px solid var(--te-line-strong);
  cursor: pointer;
  transition: color var(--te-transition), border-color var(--te-transition),
    background var(--te-transition);
}

.gallery-tab:hover,
.gallery-tab:focus-visible {
  color: var(--te-ink);
  border-color: var(--te-ink-dim);
}

.gallery-tab.is-active {
  color: var(--te-bg);
  background: var(--te-gold);
  border-color: var(--te-gold);
}

/* A hidden tile is removed from the grid flow so the layout reflows. */
.gallery-grid .ig-tile[hidden] {
  display: none;
}

.gallery-empty {
  color: var(--te-ink-dim);
}

.ig-follow-btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 12px 20px;
  font-family: var(--te-font-mono);
  font-size: 0.78rem;
  line-height: 1;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--te-ink);
  border: 1px solid var(--te-line-strong);
  transition: border-color var(--te-transition), color var(--te-transition);
}

.ig-follow-btn svg {
  display: block;
  flex-shrink: 0;
  width: 16px;
  height: 16px;
}

/* The handle sits on the flex cross-axis centre next to the icon. The
   line-height:1 and block display keep its box the same height as the
   icon. */
.ig-follow-handle {
  display: block;
  line-height: 1;
}

/* The button markup is emitted on a single line with the handle in a span,
   so wpautop can't split it. This one guard stays as cheap insurance: if a
   future edit reintroduces a newline, a stray <br> would stack the icon and
   text, and hiding it keeps them on one line. */
.ig-follow-btn br {
  display: none;
}

.ig-follow-btn:hover,
.ig-follow-btn:focus-visible {
  border-color: var(--te-crimson-txt);
  color: var(--te-crimson-txt);
}

/* ---------- Google Reviews widget ---------- */
.reviews-summary {
  display: flex;
  align-items: center;
  gap: 22px;
  flex-wrap: wrap;
  margin-bottom: 40px;
  padding-bottom: 32px;
  border-bottom: 1px dashed var(--te-line);
}

.reviews-summary .score {
  font-family: var(--te-font-display);
  font-weight: 800;
  font-size: 3.2rem;
  line-height: 1;
}

.reviews-summary .score-meta {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.reviews-summary .count {
  font-family: var(--te-font-mono);
  font-size: 0.76rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--te-ink-dim);
}

.reviews-summary .g-link {
  margin-left: auto;
  font-family: var(--te-font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--te-gold);
  border-bottom: 1px solid transparent;
}

.reviews-summary .g-link:hover {
  border-color: var(--te-gold);
}

.stars {
  color: var(--te-gold);
  letter-spacing: 2px;
  font-size: 1.1rem;
}

.reviews-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 28px;
}

.review-card {
  padding: 20px 22px;
  background: var(--te-bg-alt);
  border: 1px solid var(--te-line);
}

.review-card .review-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 10px;
}

.review-card .author {
  font-family: var(--te-font-display);
  font-size: 1rem;
  letter-spacing: 0.01em;
  text-transform: uppercase;
}

.review-card .when {
  font-family: var(--te-font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--te-ink-dim);
}

.review-card p.text {
  margin: 0;
  font-size: 0.92rem;
  color: var(--te-ink-dim);
}

.reviews-note {
  margin-top: 28px;
  font-family: var(--te-font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.04em;
  color: var(--te-ink-dim);
  opacity: 0.75;
}

.reviews-loading {
  font-family: var(--te-font-mono);
  font-size: 0.8rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--te-ink-dim);
}

/* ---------- Team teaser CTA ---------- */
/* The "Ontmoet het team" button sits under the centred artist cards, so
   it should centre too. This is enforced in CSS (not just via the block's
   justifyContent) so it holds even when WordPress doesn't emit the
   is-content-justification-center class on already-seeded markup. The
   compound selector outranks core's .wp-block-buttons.is-layout-flex. */
.wrap .wp-block-buttons.team-cta {
  justify-content: center;
}

/* ---------- Style pills ---------- */
.pill-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: 22px 0 0;
}

.style-pill {
  flex: 1 1 auto;
  text-align: center;
  padding: 11px 18px;
  font-family: var(--te-font-mono);
  font-size: 0.76rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--te-ink);
  background: var(--te-bg-alt);
  border: 1px solid var(--te-line-strong);
  transition: border-color var(--te-transition), color var(--te-transition);
}

.style-pill:hover,
.style-pill:focus-visible {
  border-color: var(--te-gold);
  color: var(--te-gold);
}

/* ---------- Trust chips ---------- */
/* Centered full-width row. Scoped under .wrap so the flex + centering
   win against WordPress's per-block .wp-container-xxx layout rule (which
   is a single class and would otherwise tie-and-override on stale-seeded
   markup that lacks the is-content-justification-center class). */
.wrap .trust-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px;
  width: 100%;
  max-width: none;
}

.trust-row {
  margin: 28px 0 8px;
}

.trust-chip {
  padding: 8px 14px;
  font-family: var(--te-font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--te-ink-dim);
  border: 1px solid var(--te-line);
}

/* ---------- Pricing table ---------- */
.price-table-scroll {
  margin-top: 18px;
  overflow-x: auto;
}

.price-table {
  width: 100%;
  min-width: 360px;
  border-collapse: collapse;
}

.price-table th,
.price-table td {
  padding: 14px 16px;
  text-align: left;
  font-size: 0.92rem;
  border-bottom: 1px solid var(--te-line);
}

.price-table th {
  font-family: var(--te-font-mono);
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--te-gold);
}

.price-table td:last-child,
.price-table th:last-child {
  text-align: right;
}

/* ---------- FAQ accordion (native <details>, no JS) ---------- */
.faq-item {
  border-bottom: 1px solid var(--te-line);
}

.faq-item summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 20px 0;
  font-family: var(--te-font-display);
  font-size: 1.02rem;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  list-style: none;
  cursor: pointer;
}

.faq-item summary::-webkit-details-marker {
  display: none;
}

.faq-item summary:focus-visible {
  outline: 2px solid var(--te-gold);
  outline-offset: 4px;
}

.faq-item summary::after {
  content: "+";
  flex: 0 0 auto;
  font-family: var(--te-font-mono);
  font-size: 1.2rem;
  color: var(--te-gold);
}

.faq-item[open] summary::after {
  content: "\2212";
}

.faq-item p {
  max-width: 68ch;
  margin: 0 0 22px;
  color: var(--te-ink-dim);
}

/* ---------- Contact form ---------- */
.contact-form {
  display: grid;
  gap: 18px;
  max-width: 520px;
}

.contact-form label {
  display: block;
  margin-bottom: 8px;
  font-family: var(--te-font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--te-gold);
}

.contact-form input,
.contact-form select,
.contact-form textarea {
  width: 100%;
  padding: 12px 14px;
  font-family: var(--te-font-body);
  font-size: 0.95rem;
  color: var(--te-ink);
  background: var(--te-bg-alt);
  border: 1px solid var(--te-line-strong);
}

.contact-form input:focus,
.contact-form select:focus,
.contact-form textarea:focus {
  outline: 2px solid var(--te-gold);
  outline-offset: 2px;
}

.contact-form textarea {
  min-height: 120px;
  resize: vertical;
}

.form-note {
  max-width: 60ch;
  font-family: var(--te-font-mono);
  font-size: 0.72rem;
  color: var(--te-ink-dim);
  opacity: 0.8;
}

/* ---------- Contact info list ---------- */
.info-list {
  display: grid;
  gap: 18px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.info-list .label {
  margin-bottom: 4px;
  font-family: var(--te-font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--te-gold);
}

.info-list a {
  color: var(--te-ink);
  text-decoration: underline;
  text-decoration-color: var(--te-line-strong);
}

.info-list a:hover {
  text-decoration-color: var(--te-gold);
}

/* ---------- Map frame ---------- */
.map-frame {
  position: relative;
  margin-top: 28px;
  padding: 14px;
  background: var(--te-bg-alt);
  border: 1.5px dashed var(--te-line-strong);
}

.map-frame iframe {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 10;
  border: 0;
  filter: grayscale(0.5) contrast(1.05);
}

/* ---------- Image placeholders ---------- */
/* Frames an <img>; swap the src for a real photo later and the border,
   ratio and object-fit keep working unchanged. */
.img-placeholder {
  display: block;
  overflow: hidden;
  border: 1.5px dashed var(--te-line-strong);
}

.img-placeholder img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Aspect-ratio modifiers for .img-placeholder. Add more here (e.g.
   3/4 portrait, 21/9 wide) if a pattern needs them. */
.img-placeholder.ratio-hero { aspect-ratio: 4 / 3; }
.img-placeholder.ratio-square { aspect-ratio: 1; }

/* .placeholder-strip and .two-col: layout owned by their core/columns
   blocks (see the note near .hero-grid). */

/* ---------- Breadcrumb ---------- */
.breadcrumb {
  padding: 20px 0 0;
  font-family: var(--te-font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--te-ink-dim);
}

.breadcrumb a {
  color: var(--te-gold);
  text-decoration: none;
}

.breadcrumb a:hover {
  text-decoration: underline;
}

/* ---------- Cinematic video feature ---------- */
/* Full-bleed: the video spans the entire viewport width as a cinematic
   band, with the heading overlaid on top for an immersive, film-like
   presentation. */
.video-feature {
  position: relative;
  background: #000;
  overflow: hidden;
}

.video-feature .wp-block-video {
  width: 100%;
  max-width: none;
  margin: 0;
  /* Cinematic band: fills the width and holds a consistent height whether
     or not a video has been added yet (the figure is empty until upload).
     Capped so it never dominates on very wide screens. */
  height: clamp(320px, 68vh, 760px);
  background: #000;
}

.video-feature .wp-block-video video {
  display: block;
  position: relative;
  z-index: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: #000;
}

/* Gradient scrim behind the heading so it stays legible over any footage.
   It only covers the TOP portion of the band (where the text sits) so it
   never overlaps the video's own controls at the bottom. pointer-events:
   none keeps the whole video clickable. */
.video-feature::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 55%;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    rgba(20, 18, 16, 0.75) 0%,
    rgba(20, 18, 16, 0.2) 45%,
    rgba(20, 18, 16, 0) 100%
  );
}

/* Heading overlay, pinned to the top of the band. pointer-events:none on
   the wrapper lets clicks pass through to the video; links/controls inside
   would re-enable it, but this is display-only text. */
.video-overlay {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 100%;
  max-width: var(--te-content-max);
  z-index: 2;
  padding: 48px 28px;
  pointer-events: none;
  text-align: left;
}

/* Keep the overlaid blocks left-aligned and full-width within the overlay.
   WordPress's constrained layout applies `margin: 0 auto !important` to
   centre children; these overrides use !important purely to beat that core
   rule, so the heading stays left even if an older copy of this section was
   saved with the constrained layout. (New inserts use a flow layout and
   don't need this, but it keeps existing content correct.) */
.video-overlay > * {
  max-width: 100% !important;
  margin-left: 0 !important;
  margin-right: 0 !important;
  text-align: left;
}

.video-overlay .eyebrow {
  color: var(--te-gold);
}

.video-overlay h2 {
  margin: 6px 0 0;
  font-size: clamp(1.9rem, 5vw, 3rem);
  color: var(--te-ink);
  text-shadow: 0 2px 24px rgba(0, 0, 0, 0.6);
}

.video-lede {
  margin: 14px 0 0;
  max-width: 46ch;
  font-size: 1.05rem;
  color: var(--te-ink);
  text-shadow: 0 1px 16px rgba(0, 0, 0, 0.7);
}

/* On small screens, ease the overlay vertical padding (keep the sides). */
@media (max-width: 600px) {
  .video-overlay {
    padding: 28px 20px;
  }
}

/* ---------- Footer ---------- */
.site-footer {
  padding: 48px 0;
  border-top: 1px solid var(--te-line);
}

.site-footer .wrap {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 16px;
}

/* .foot-top and .footer-legal get their horizontal flex layout from
   the group block; these rules only set full width (they are column
   children of .site-footer .wrap) and visual styling. */
.site-footer .foot-top {
  width: 100%;
}

.site-footer .foot-mark {
  font-family: var(--te-font-display);
  font-weight: 700;
  font-size: 1rem;
  text-transform: uppercase;
}

.site-footer .foot-meta {
  font-family: var(--te-font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--te-ink-dim);
}

/* WordPress's wpautop can wrap shortcode output in a <p>; in the footer's
   flex rows that would add stray top/bottom margin, so zero it out. */
.foot-top p,
.foot-bottom > p {
  margin: 0;
}

/* Footer bottom row: social icons on the left, legal links on the right.
   A top border separates it from the address row above. */
.foot-bottom {
  width: 100%;
  padding-top: 20px;
  border-top: 1px solid var(--te-line);
}

/* Footer social icon row. Icons only render for channels filled in under
   Customizer → Contactgegevens. */
.foot-socials {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
}

.foot-social {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  color: var(--te-ink-dim);
  border: 1px solid var(--te-line-strong);
  border-radius: 50%;
  transition: color var(--te-transition), border-color var(--te-transition);
}

.foot-social svg {
  display: block;
  width: 20px;
  height: 20px;
}

.foot-social:hover,
.foot-social:focus-visible {
  color: var(--te-gold);
  border-color: var(--te-gold);
}

.footer-legal {
  font-family: var(--te-font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.footer-legal a {
  color: var(--te-ink-dim);
  text-decoration: none;
}

.footer-legal a:hover {
  color: var(--te-gold);
}

/* ---------------------------------------------------------
   7. Responsive breakpoints
   -------------------------------------------------------------------
   Column layouts (.hero-grid, .two-col, .placeholder-strip, .profile)
   are core/columns blocks and stack automatically at 782px, so no
   custom rule is needed for them here.
   --------------------------------------------------------- */

/* Match the core/columns default stacking breakpoint (782px): once the
   profile portrait sits above the body, cap its width so it doesn't
   stretch full-bleed. */
@media (max-width: 781px) {
  .profile .portrait-frame {
    max-width: 260px;
  }
}

@media (max-width: 900px) {
  /* Tablet: 2 cards per row (half the row minus one 32px gap). */
  .flash-grid--cards > .flash-card,
  .flash-grid .wp-block-post-template > li {
    flex-basis: calc((100% - 32px) / 2);
    max-width: calc((100% - 32px) / 2);
  }
}

@media (max-width: 600px) {
  /* Phone: one card per row, centred, capped so it never gets oversized. */
  .flash-grid--cards > .flash-card,
  .flash-grid .wp-block-post-template > li {
    flex-basis: 100%;
    max-width: 340px;
  }
}

/* ---------------------------------------------------------
   8. Motion — scroll reveals & micro-interactions
   --------------------------------------------------------- */

/* Scroll reveal. Elements marked .reveal start hidden (only under the .js
   class, added by the script, so no-JS visitors see everything); when the
   script marks them .is-visible they play a keyframe entrance that fades and
   rises them into place.

   This uses a keyframe ANIMATION rather than a CSS transition on purpose. A
   transition out of a just-applied hidden state gets dropped by some desktop
   browsers — notably Firefox and Edge — which collapse the hide and the show
   into a single style pass, leaving nothing to interpolate, so the element
   simply appears. A keyframe animation always runs from its first frame, so
   the motion plays reliably in every browser, on load and on scroll alike.
   Only opacity and transform animate (both GPU-friendly, no layout cost). */
.js .reveal {
  opacity: 0;
}

.js .reveal.is-visible {
  animation: te-rise 0.8s cubic-bezier(0.16, 0.7, 0.2, 1) both;
}

/* Staggered children: within a revealed grid/row, each item eases in a beat
   after the previous one for a gentle cascade. Gated behind .js so non-JS
   visitors just see the items. */
.js .reveal-stagger.is-visible > * {
  animation: te-rise 0.7s cubic-bezier(0.16, 0.7, 0.2, 1) both;
}

.js .reveal-stagger.is-visible > *:nth-child(1) { animation-delay: 0.06s; }
.js .reveal-stagger.is-visible > *:nth-child(2) { animation-delay: 0.15s; }
.js .reveal-stagger.is-visible > *:nth-child(3) { animation-delay: 0.24s; }
.js .reveal-stagger.is-visible > *:nth-child(4) { animation-delay: 0.33s; }
.js .reveal-stagger.is-visible > *:nth-child(5) { animation-delay: 0.42s; }
.js .reveal-stagger.is-visible > *:nth-child(6) { animation-delay: 0.51s; }
.js .reveal-stagger.is-visible > *:nth-child(7) { animation-delay: 0.60s; }
.js .reveal-stagger.is-visible > *:nth-child(8) { animation-delay: 0.69s; }
.js .reveal-stagger.is-visible > *:nth-child(n + 9) { animation-delay: 0.78s; }

@keyframes te-rise {
  from {
    opacity: 0;
    transform: translateY(24px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* Hero entrance: the eyebrow, heading, intro and buttons fade in and slide
   slightly up in a short staggered sequence on load, rather than just
   appearing. The hidden start-state is gated behind .hero-anim — a class
   motion.js adds only while it's running — so with JavaScript off (or if the
   script fails to load) the text is simply visible, never stuck hidden.
   motion.js then adds .is-in to each line a beat apart, which runs the
   keyframe entrance below. A keyframe animation (not a transition) is used so
   the motion plays reliably in every browser, including desktop Firefox and
   Edge, which can skip a transition triggered from a just-applied state. */
.js .hero .hero-anim {
  opacity: 0;
}

.js .hero .hero-anim.is-in {
  animation: te-rise 0.9s cubic-bezier(0.16, 0.7, 0.2, 1) both;
}

/* Gallery tiles: a slow, subtle image zoom on hover adds life without
   moving the tile itself (the frame stays put; only the photo scales). */
.ig-tile img {
  transition: transform 0.5s cubic-bezier(0.2, 0.7, 0.2, 1);
}

.ig-tile:hover img,
.ig-tile:focus-visible img {
  transform: scale(1.05);
}

/* Style pills & filter tabs: a tiny lift on hover so they feel tactile. */
.style-pill,
.gallery-tab {
  transition: transform var(--te-transition), border-color var(--te-transition),
    color var(--te-transition), background var(--te-transition);
}

.style-pill:hover,
.style-pill:focus-visible,
.gallery-tab:hover,
.gallery-tab:focus-visible {
  transform: translateY(-2px);
}

/* Primary buttons: gentle lift + shadow on hover. */
.btn {
  transition: transform var(--te-transition), background var(--te-transition),
    color var(--te-transition), border-color var(--te-transition),
    box-shadow var(--te-transition);
}

.btn:hover,
.btn:focus-visible {
  transform: translateY(-2px);
  box-shadow: 0 10px 22px rgba(0, 0, 0, 0.3);
}

/* Social icons & inline links already transition colour; add a soft lift to
   the footer social circles so the row feels responsive. */
.foot-social {
  transition: color var(--te-transition), border-color var(--te-transition),
    transform var(--te-transition);
}

.foot-social:hover,
.foot-social:focus-visible {
  transform: translateY(-3px);
}

/* ---------------------------------------------------------
   8b. Desktop pointer polish
   These enhancements are gated to devices with a real pointer
   (hover: hover + pointer: fine), so touch devices don't get
   sticky-hover states. Transform/opacity/colour only.
   --------------------------------------------------------- */
@media (hover: hover) and (pointer: fine) {
  /* Nav links: an underline that wipes in from the left instead of the
     static bottom border simply changing colour. The border stays for the
     current page; the animated line is layered via ::after. */
  .site-nav a {
    position: relative;
    border-color: transparent;
  }

  .site-nav a::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: -1px;
    height: 1px;
    background: var(--te-crimson-txt);
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform 0.28s cubic-bezier(0.2, 0.7, 0.2, 1);
  }

  .site-nav a:hover::after,
  .site-nav a:focus-visible::after,
  .site-nav a[aria-current="page"]::after {
    transform: scaleX(1);
  }

  /* Logo: a tiny nudge on hover so it feels interactive. */
  .mark {
    transition: transform var(--te-transition);
  }

  .mark:hover {
    transform: translateY(-1px);
  }

  /* Service/flash cards: let the whole card lift a touch more on a real
     pointer, and nudge the "view" link forward to imply direction. */
  .flash-card .view-link {
    display: inline-block;
    transition: transform 0.25s cubic-bezier(0.2, 0.7, 0.2, 1),
      color var(--te-transition);
  }

  .flash-card:hover .view-link {
    transform: translateX(4px);
  }

  /* Gallery tiles: the caption slides up a hair on hover, reinforcing the
     image zoom that already runs. */
  .ig-tile-artiest {
    transition: transform 0.35s cubic-bezier(0.2, 0.7, 0.2, 1);
  }

  .ig-tile:hover .ig-tile-artiest,
  .ig-tile:focus-visible .ig-tile-artiest {
    transform: translateY(-2px);
  }

  /* Primary button: a subtle sheen sweep on hover. The pseudo-element is
     clipped to the button and translates across once. */
  .btn {
    position: relative;
    overflow: hidden;
  }

  .btn::after {
    content: "";
    position: absolute;
    top: 0;
    left: -60%;
    width: 40%;
    height: 100%;
    background: linear-gradient(
      100deg,
      transparent,
      rgba(236, 228, 212, 0.18),
      transparent
    );
    transform: skewX(-18deg);
    transition: transform 0.6s ease;
    pointer-events: none;
  }

  .btn:hover::after,
  .btn:focus-visible::after {
    transform: translateX(360%) skewX(-18deg);
  }
}

/* ---------------------------------------------------------
   9. Reduced motion
   --------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

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