/* ============================================================
   Form & Framework — base block-supporting styles.

   Minimal CSS that blocks rely on (.section, .light-background,
   .navmenu, ff-tiles fallback templates). Replaces Yummy's
   main.css. Reads --fnf-* variables from _root.css; doesn't
   define a parallel variable system.
   ============================================================ */

/* ─── Sections ─────────────────────────────────────────────────────────
   Every block renders as <section class="section ...">. Padding comes
   from --fnf-space-section so the theme picker can tune it; per-block
   --pad-* modifiers can still override via !important.                */
.section {
  padding-block: var(--fnf-space-section, 4rem);
  background-color: var(--fnf-color-bg);
  color: var(--fnf-color-text);
}

/* ─── Section background slots ─────────────────────────────────────────
   Unified theme-aware bg classes used by every section block's
   "Background" picker. Six slots that map to the theme contract:
   light/dark are page-bg/text; warm/cool are surface/surface-alt;
   primary/accent are brand colors with their contrast pair.            */
.fnf-section--bg-light   { background-color: var(--fnf-color-bg);          color: var(--fnf-color-text); }
.fnf-section--bg-dark    { background-color: var(--fnf-color-text);        color: var(--fnf-color-bg); }
.fnf-section--bg-warm    { background-color: var(--fnf-color-surface);     color: var(--fnf-color-text); }
.fnf-section--bg-cool    { background-color: var(--fnf-color-surface-alt); color: var(--fnf-color-text); }
.fnf-section--bg-primary { background-color: var(--fnf-color-primary);     color: var(--fnf-color-primary-contrast, #fff); }
.fnf-section--bg-accent  { background-color: var(--fnf-color-accent);      color: var(--fnf-color-accent-contrast,  #fff); }
.fnf-section--bg-dark    h1, .fnf-section--bg-dark    h2, .fnf-section--bg-dark    h3,
.fnf-section--bg-dark    h4, .fnf-section--bg-dark    h5, .fnf-section--bg-dark    h6,
.fnf-section--bg-primary h1, .fnf-section--bg-primary h2, .fnf-section--bg-primary h3,
.fnf-section--bg-primary h4, .fnf-section--bg-primary h5, .fnf-section--bg-primary h6,
.fnf-section--bg-accent  h1, .fnf-section--bg-accent  h2, .fnf-section--bg-accent  h3,
.fnf-section--bg-accent  h4, .fnf-section--bg-accent  h5, .fnf-section--bg-accent  h6 { color: inherit; }

/* Theme-aware muted text on colored sections. Bootstrap's .text-muted /
   .text-body-secondary pin a fixed dark gray (with !important) that ignores
   the section's auto-contrast — so on a dark/primary/accent background a
   subtitle stayed dark-gray while its heading went white, i.e. illegible.
   On those sections, derive muted from the section's OWN foreground color
   (inherit) dimmed via opacity — the same trick the header/footer taglines
   use. Light/warm/cool sections keep Bootstrap's muted, which reads fine on a
   light background. Higher specificity + !important beats Bootstrap's rule. */
.fnf-section--bg-dark    .text-muted, .fnf-section--bg-dark    .text-body-secondary,
.fnf-section--bg-primary .text-muted, .fnf-section--bg-primary .text-body-secondary,
.fnf-section--bg-accent  .text-muted, .fnf-section--bg-accent  .text-body-secondary {
  color: inherit !important;
  opacity: 0.78;
}
/* Hero subtitle has the same problem via a DIFFERENT mechanism:
   .fnf-hero__subtitle hard-codes color:var(--fnf-color-text-muted) (gray), and
   the hero block's own contrast override keys off `.fnf-hero--bg-*` — but the
   assembler emits the generic `.fnf-section--bg-*` theme class on hero sections,
   so that override never fires and the subtitle stayed gray on a colored hero
   (the "Team" hero band). The title escapes it only because it's an <h1> caught
   by the heading-inherit rule above. Flip the subtitle to the band's contrast
   color here, at runtime (retroactive — block CSS would need a re-assemble). */
.fnf-section--bg-dark    .fnf-hero__subtitle,
.fnf-section--bg-primary .fnf-hero__subtitle,
.fnf-section--bg-accent  .fnf-hero__subtitle {
  color: inherit !important;
  opacity: 0.9;
}

/* A solid .btn-primary on a primary/accent brand band is the same (primary) or
   a clashing (accent) color as the band itself — on a primary section it's
   literally the same fill, so the button disappears and only its label shows.
   Invert it to the band's contrast color: a white CTA on the colored band.
   Bootstrap 5.3 buttons are built on these --bs-btn-* vars, so overriding them
   on a more specific selector re-skins the button cleanly. (Dark sections keep
   the brand-colored button — it reads fine against a dark background.) */
.fnf-section--bg-primary .btn-primary {
  --bs-btn-bg:                  var(--fnf-color-primary-contrast, #fff);
  --bs-btn-border-color:        var(--fnf-color-primary-contrast, #fff);
  --bs-btn-color:               var(--fnf-color-primary);
  --bs-btn-hover-bg:            var(--fnf-color-primary-contrast, #fff);
  --bs-btn-hover-border-color:  var(--fnf-color-primary-contrast, #fff);
  --bs-btn-hover-color:         var(--fnf-color-primary);
  --bs-btn-active-bg:           var(--fnf-color-primary-contrast, #fff);
  --bs-btn-active-border-color: var(--fnf-color-primary-contrast, #fff);
  --bs-btn-active-color:        var(--fnf-color-primary);
}
.fnf-section--bg-accent .btn-primary {
  --bs-btn-bg:                  var(--fnf-color-accent-contrast, #fff);
  --bs-btn-border-color:        var(--fnf-color-accent-contrast, #fff);
  --bs-btn-color:               var(--fnf-color-accent);
  --bs-btn-hover-bg:            var(--fnf-color-accent-contrast, #fff);
  --bs-btn-hover-border-color:  var(--fnf-color-accent-contrast, #fff);
  --bs-btn-hover-color:         var(--fnf-color-accent);
  --bs-btn-active-bg:           var(--fnf-color-accent-contrast, #fff);
  --bs-btn-active-border-color: var(--fnf-color-accent-contrast, #fff);
  --bs-btn-active-color:        var(--fnf-color-accent);
}
.fnf-section--bg-primary .btn-primary:hover,
.fnf-section--bg-accent  .btn-primary:hover { opacity: 0.9; }

/* ── Brand-colored utilities on colored bands (the general guard) ───────────
   Closes the recurring "theme color on a same-theme background" bug class
   (muted text + the primary button above are the first two cases). Anything
   Bootstrap colors with the brand "primary" / "info" — text, icons, outline
   buttons, links — collides on a dark/primary/accent band (on a primary band
   it's literally the same color → invisible). Make those derive from the
   band's contrast color instead. SEMANTIC status colors (success/danger/
   warning) are intentional signals and are deliberately left untouched. */
.fnf-section--bg-dark    .text-primary, .fnf-section--bg-dark    .text-info,
.fnf-section--bg-primary .text-primary, .fnf-section--bg-primary .text-info,
.fnf-section--bg-accent  .text-primary, .fnf-section--bg-accent  .text-info {
  color: inherit !important;   /* e.g. contact-block icons go white on a band */
}
/* Outline-primary on a primary band is a purple outline on purple → invisible.
   Flip its border + label to the band's contrast color (and fill on hover). */
.fnf-section--bg-primary .btn-outline-primary {
  --bs-btn-color:              var(--fnf-color-primary-contrast, #fff);
  --bs-btn-border-color:       var(--fnf-color-primary-contrast, #fff);
  --bs-btn-hover-bg:           var(--fnf-color-primary-contrast, #fff);
  --bs-btn-hover-border-color: var(--fnf-color-primary-contrast, #fff);
  --bs-btn-hover-color:        var(--fnf-color-primary);
}
.fnf-section--bg-dark    .link-primary,
.fnf-section--bg-primary .link-primary,
.fnf-section--bg-accent  .link-primary {
  color: inherit !important;
  text-decoration: underline;
}

/* Tile CARDS on a colored band ───────────────────────────────────────────────
   A gallery tile (testimonial, feature, team, card, etc.) carries its OWN light
   background regardless of the section band — the Tile background option mixes
   the slot color with white, so every card fill is a light tint. But the card
   inherits the band's text color, which on a dark/primary/accent band is the
   light contrast (white). Result: body/quote text rendered white on a cream
   card → washed out (only headings escaped, because they set their own color).
   Reset card text to the normal body color so it reads on the card's light fill.
   Headings keep their explicit colors; .text-muted inside resolves via `inherit`
   (the guard above) to this dark color at reduced opacity — also now legible. */
.fnf-section--bg-dark    .icon-box, .fnf-section--bg-dark    .testimonial-item,
.fnf-section--bg-dark    .team-member, .fnf-section--bg-dark    .event-item,
.fnf-section--bg-dark    .tile-item, .fnf-section--bg-dark    .card,
.fnf-section--bg-primary .icon-box, .fnf-section--bg-primary .testimonial-item,
.fnf-section--bg-primary .team-member, .fnf-section--bg-primary .event-item,
.fnf-section--bg-primary .tile-item, .fnf-section--bg-primary .card,
.fnf-section--bg-accent  .icon-box, .fnf-section--bg-accent  .testimonial-item,
.fnf-section--bg-accent  .team-member, .fnf-section--bg-accent  .event-item,
.fnf-section--bg-accent  .tile-item, .fnf-section--bg-accent  .card {
  color: var(--fnf-color-text);
}

/* Legacy aliases — kept so older composition JSON keeps rendering. */
.light-background    { background-color: var(--fnf-color-bg);          color: var(--fnf-color-text); }
.dark-background     { background-color: var(--fnf-color-text);        color: var(--fnf-color-bg); }
.dark-background h1, .dark-background h2, .dark-background h3,
.dark-background h4, .dark-background h5, .dark-background h6 { color: inherit; }
.bg-body-secondary   { background-color: var(--fnf-color-surface-alt); color: var(--fnf-color-text); }

/* ─── Inline text color + size ─────────────────────────────────────────
   Applied by the WYSIWYG color/size pickers via wrapper spans. Kept
   theme-aware (var-based) so changing the palette later updates
   colored text in place. Sizes are em-relative so they scale with
   their surrounding context. */
.fnf-text--primary { color: var(--fnf-color-primary); }
.fnf-text--accent  { color: var(--fnf-color-accent); }
.fnf-text--light   { color: var(--fnf-color-bg); }
.fnf-text--dark    { color: var(--fnf-color-text); }
.fnf-text--warm    { color: var(--fnf-color-surface); }
.fnf-text--cool    { color: var(--fnf-color-surface-alt); }

/* ─── Event-link CTA disabled state ────────────────────────────────────
   ff-cta.js applies .ff-cta--upcoming-disabled to a button when it's
   waiting for the next event in its series to start. The button still
   shows so visitors know "this will be live soon" — but it's not
   clickable. The pencil overlay (in edit mode) keeps pointer-events
   so authors can still re-configure it. */
.ff-cta--upcoming-disabled {
  opacity: 0.55;
  cursor: not-allowed;
  pointer-events: none;
}
.ff-cta--upcoming-disabled > * {
  pointer-events: auto;
}

/* ─── Content block CTA buttons ────────────────────────────────────────
   Variants emit a .fnf-content__ctas wrapper unconditionally so the
   {{#if}} blocks can stay flat. Only apply margin/spacing when the
   wrapper actually has a button child — otherwise an opted-out
   block would get phantom whitespace below the text. */
.fnf-content__ctas:has(.btn) {
  margin-top: 1.5rem;
}

/* ─── ff-form: checkbox row spacing ────────────────────────────────────
   Bootstrap's .form-check uses padding-left:1.5em + a negatively-
   margined input, which can render with a visible gap between the
   checkbox and its label depending on font metrics. Switch the row to
   an explicit flex layout with a fixed gap so "Add me to your mailing
   list" sits next to its checkbox, not floating off to the right. */
.ff-form .form-check {
  padding-left: 0;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-height: auto;
}
.ff-form .form-check-input {
  margin: 0;
  flex: 0 0 auto;
}
.ff-form .form-check-label {
  margin: 0;
  cursor: pointer;
}

/* ─── Email-signup form (contact block, email-signup variant) ──────────
   Tiny flex layout for a one-field mailing-list form. Inline puts the
   input and button on one row; stacked puts the button below. */
.fnf-signup-form--inline {
  display: flex;
  gap: 0.5rem;
  align-items: stretch;
  flex-wrap: wrap;
  justify-content: center;
}
.fnf-signup-form--inline > .form-control { flex: 1 1 18rem; min-width: 0; }
.fnf-signup-form--inline > .btn          { flex: 0 0 auto; }
.fnf-signup-form--inline > .fnf-signup-form__success { flex: 1 1 100%; text-align: center; }
.fnf-signup-form--stacked {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  max-width: 26rem;
  margin-inline: auto;
}

/* ─── Tile shape (aspect ratio for tile photos) ────────────────────────
   When the gallery block's "Tile shape" option is set to anything other
   than "free", ff-tiles.js wraps each tile column in a tile-shape--<X>
   class. The rules below constrain the photo's aspect ratio so all
   tiles in the row render at the same height regardless of the source
   image's natural dimensions. object-fit: cover crops the photo to
   fill without stretching. Targets the various shapes the templates
   produce (img inside .card-img-top / .member-img / .img-fluid, plus
   .event-item which uses background-image). */
.tile-shape--ratio-1x1 .card-img-top img,
.tile-shape--ratio-1x1 .member-img img,
.tile-shape--ratio-1x1 .ff-tile-photo img,
.tile-shape--ratio-1x1 img.img-fluid {
  aspect-ratio: 1 / 1; object-fit: cover; width: 100%;
}
.tile-shape--ratio-4x3 .card-img-top img,
.tile-shape--ratio-4x3 .member-img img,
.tile-shape--ratio-4x3 .ff-tile-photo img,
.tile-shape--ratio-4x3 img.img-fluid {
  aspect-ratio: 4 / 3; object-fit: cover; width: 100%;
}
.tile-shape--ratio-3x4 .card-img-top img,
.tile-shape--ratio-3x4 .member-img img,
.tile-shape--ratio-3x4 .ff-tile-photo img,
.tile-shape--ratio-3x4 img.img-fluid {
  aspect-ratio: 3 / 4; object-fit: cover; width: 100%;
}
/* event-item uses a background-image rather than an <img>, so apply
   the aspect ratio to the box itself. */
.tile-shape--ratio-1x1 .event-item { aspect-ratio: 1 / 1; min-height: 0; }
.tile-shape--ratio-4x3 .event-item { aspect-ratio: 4 / 3; min-height: 0; }
.tile-shape--ratio-3x4 .event-item { aspect-ratio: 3 / 4; min-height: 0; }

/* ─── Photo shape (cross-block) ─────────────────────────────────────────
   The shape options live in two places: applied as wrapper classes on
   gallery tile columns (.fnf-photo-shape--<X>) AND as wrapper classes on
   .fnf-photo-frame elements in hero/content. The selectors below cover
   both surfaces so the same vocabulary works everywhere.

   Non-rectangle shapes force a 1:1 aspect on the photo box so circle
   doesn't render as a stretched pill and the hex/blob/leaf masks land
   on a square canvas. The wrapper's overflow:hidden (or clip-path)
   crops the actual image inside.

   Targets the various IMG containers each tile-template emits
   (.card-img-top, .member-img, .ff-tile-photo, img.img-fluid) plus
   .event-item (background-image), mirroring the aspect-ratio rules
   above. */
.fnf-photo-shape--circle .card-img-top img,
.fnf-photo-shape--circle .member-img img,
.fnf-photo-shape--circle .ff-tile-photo img,
.fnf-photo-shape--circle img.img-fluid,
.fnf-photo-frame.fnf-photo-shape--circle {
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  object-fit: cover;
  width: 100%;
  overflow: hidden;
}
.fnf-photo-shape--circle .event-item {
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  min-height: 0;
}

/* Blob — asymmetric border-radius gives an organic, hand-drawn outline
   without needing clip-path or an SVG mask. The %-/% syntax sets
   horizontal and vertical radii independently per corner, so opposite
   corners can bulge differently. */
.fnf-photo-shape--blob .card-img-top img,
.fnf-photo-shape--blob .member-img img,
.fnf-photo-shape--blob .ff-tile-photo img,
.fnf-photo-shape--blob img.img-fluid,
.fnf-photo-frame.fnf-photo-shape--blob {
  aspect-ratio: 1 / 1;
  border-radius: 60% 40% 30% 70% / 60% 30% 70% 40%;
  object-fit: cover;
  width: 100%;
  overflow: hidden;
}
.fnf-photo-shape--blob .event-item {
  aspect-ratio: 1 / 1;
  border-radius: 60% 40% 30% 70% / 60% 30% 70% 40%;
  min-height: 0;
}

/* Hexagon — clip-path polygon. Six points placed on a unit square; the
   center of each edge cuts in so the corners chamfer into a regular
   hex. clip-path doesn't need overflow:hidden because it crops the
   element directly. */
.fnf-photo-shape--hex .card-img-top img,
.fnf-photo-shape--hex .member-img img,
.fnf-photo-shape--hex .ff-tile-photo img,
.fnf-photo-shape--hex img.img-fluid,
.fnf-photo-frame.fnf-photo-shape--hex {
  aspect-ratio: 1 / 1;
  clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
  object-fit: cover;
  width: 100%;
}
.fnf-photo-shape--hex .event-item {
  aspect-ratio: 1 / 1;
  clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
  min-height: 0;
}

/* Leaf — two diagonal corners rounded, the other two square. Reads as
   a stylized leaf / tab shape. Same border-radius trick as blob. */
.fnf-photo-shape--leaf .card-img-top img,
.fnf-photo-shape--leaf .member-img img,
.fnf-photo-shape--leaf .ff-tile-photo img,
.fnf-photo-shape--leaf img.img-fluid,
.fnf-photo-frame.fnf-photo-shape--leaf {
  aspect-ratio: 1 / 1;
  border-radius: 0 50% 0 50%;
  object-fit: cover;
  width: 100%;
  overflow: hidden;
}
.fnf-photo-shape--leaf .event-item {
  aspect-ratio: 1 / 1;
  border-radius: 0 50% 0 50%;
  min-height: 0;
}

/* ─── Photo frame (cross-block) ─────────────────────────────────────────
   Variant templates wrap a photo <img data-ff-photo> inside
   <div class="fnf-photo-frame" data-aspect="..."> so the frame owns the
   box (max-width, aspect-ratio, border-radius, overflow) and the img
   fills the frame at 100% × 100%. Wrapper bounds and img bounds stay
   in lockstep so caption strips + edit overlays line up with what the
   user sees.

   Block options drive this:
     photoAspect → data-aspect on the frame
     photoSize   → max-width inline style on the frame
     photoFit    → data-ff-fit on the inner <img> (photomanager reads it)
     photoShape  → CSS class on the frame (rounded / circle / etc.)        */
.fnf-photo-frame {
  display: block;
  position: relative;
  width: 100%;
  overflow: hidden;
}
.fnf-photo-frame > img {
  display: block;
  width: 100%;
  height: auto;          /* default — img drives frame height (auto aspect) */
  object-fit: cover;
}
.fnf-photo-frame[data-aspect="landscape"]     { aspect-ratio: 4 / 3; }
.fnf-photo-frame[data-aspect="portrait"]      { aspect-ratio: 3 / 4; }
.fnf-photo-frame[data-aspect="square"]        { aspect-ratio: 1 / 1; }
.fnf-photo-frame[data-aspect="wide"]          { aspect-ratio: 16 / 9; }
.fnf-photo-frame[data-aspect="tall"]          { aspect-ratio: 9 / 16; }
/* When the frame has an aspect lock (via data-aspect or a photo-shape
   class that sets aspect-ratio), the img must FILL the frame so
   object-fit:cover + object-position (focalY) can crop. Without this
   the img keeps its natural height, overflows the aspect-locked frame,
   gets clipped, and the Reposition focal point has no visible effect. */
.fnf-photo-frame[data-aspect="landscape"] > img,
.fnf-photo-frame[data-aspect="portrait"] > img,
.fnf-photo-frame[data-aspect="square"] > img,
.fnf-photo-frame[data-aspect="wide"] > img,
.fnf-photo-frame[data-aspect="tall"] > img,
/* Shape classes force a 1:1 box too, so their img must fill it as well —
   otherwise the circle/blob/hex/leaf crop only appears when Photo aspect is
   also set to a fixed value (it defaults to Auto). */
.fnf-photo-frame.fnf-photo-shape--circle > img,
.fnf-photo-frame.fnf-photo-shape--blob > img,
.fnf-photo-frame.fnf-photo-shape--hex > img,
.fnf-photo-frame.fnf-photo-shape--leaf > img {
  height: 100%;
}

.fnf-text--size-xsmall  { font-size: 0.65em; }
.fnf-text--size-small   { font-size: 0.85em; }
.fnf-text--size-large   { font-size: 1.25em; }
.fnf-text--size-xlarge  { font-size: 1.5em; }
.fnf-text--size-xxlarge { font-size: 2em; }

/* Per-paragraph alignment from the WYSIWYG alignment buttons. Applied
   on the block-level ancestor of the selection — usually a real block
   tag (p, h1-h6, li, blockquote, td/th), but sometimes a wrapping
   <span> when the editable root IS the block (e.g. <p data-ff="..."> —
   only the innerHTML is persisted, so attributes on the wrapper itself
   don't survive a save). display:block makes the span behave as a
   block container so text-align takes effect. */
.fnf-text--align-left,
.fnf-text--align-center,
.fnf-text--align-right,
.fnf-text--align-justify { display: block; }
.fnf-text--align-left    { text-align: left; }
.fnf-text--align-center  { text-align: center; }
.fnf-text--align-right   { text-align: right; }
.fnf-text--align-justify { text-align: justify; }

/* Per-span font picker. Theme-aware via the same --fnf-font-* vars the
   _root.css contract defines, so flipping the theme's font choices
   updates inline-formatted text in place. */
.fnf-font--display { font-family: var(--fnf-font-display); }
.fnf-font--heading { font-family: var(--fnf-font-heading); }
.fnf-font--body    { font-family: var(--fnf-font-body); }
.fnf-font--accent  { font-family: var(--fnf-font-accent); }
.fnf-font--brand   { font-family: var(--fnf-font-brand); }
.fnf-font--mono    { font-family: var(--fnf-font-mono); }

/* ─── Header (used by both: editor's default fallback AND the static
       template/*.html pages like calendar.html / blog.html / post.html
       that haven't been migrated to be composition-driven yet) ──────── */
.header {
  background: var(--fnf-color-bg);
  border-bottom: 1px solid var(--fnf-color-border, #dee2e6);
  z-index: 1020;
  padding: 12px 0;
}
/* Block-rendered headers (header/styles.css) don't want this default
   border — the per-block "Show bottom border" toggle controls it via
   .fnf-header--bordered. Reset here so the toggle actually toggles. */
.fnf-header { border-bottom: none; }
/* Logo + site-name INHERIT the header band's color (set by .fnf-header--bg-*)
   instead of pinning the dark heading color — otherwise the title rendered
   black on a primary/dark/accent header band while the tagline (color:inherit)
   correctly went light. The header lives in its own .fnf-header--bg-* namespace,
   so the .fnf-section--bg-* colored-band guard above never reached it. This
   matches the block's own `.fnf-header .sitename { color: inherit }`. */
.header .logo {
  color: inherit;
  text-decoration: none;
}
.header .sitename {
  font-family: var(--fnf-font-brand);
  color: inherit;
  font-size: 1.25rem;
  font-weight: var(--fnf-font-weight-brand, 600);
  margin: 0;
}

/* Optional sub-line under site-name in header brand and footer brand column.
   Hidden when empty so sites that don't set a tagline don't show a blank
   space. In edit mode (body.ff-role-editor / ff-role-template added by
   ff-editable.js, but not while ff-preview is on) the empty slot is
   restored to its natural display + given a clickable minimum size so
   the user can populate it. */
[data-ff="site-tagline"]:empty { display: none; }
body.ff-role-editor:not(.ff-preview) [data-ff="site-tagline"]:empty,
body.ff-role-template:not(.ff-preview) [data-ff="site-tagline"]:empty {
  display: revert;
  min-width: 8em;
  min-height: 1em;
}
/* Tagline inherits the parent's color so it works on light headers
   (theme text color) and photo-banner overlays (auto-white) alike,
   then dims slightly via opacity for visual hierarchy under site-name. */
.fnf-header__tagline {
  color: inherit;
  opacity: 0.75;
  line-height: 1.2;
  margin-top: 0.15rem;
}
.fnf-footer__tagline {
  color: inherit;
  opacity: 0.85;
  line-height: 1.3;
}

/* Main wrapper — passthrough; gives static pages a hook if they ever
   need page-level layout adjustments. */
.main { padding-top: 0; }

/* Footer for static template/*.html pages. Composition footers get
   their own block CSS once footer blocks ship. */
.footer {
  background: var(--fnf-color-surface-alt, #f4f6f8);
  padding: 2rem 0;
  margin-top: 3rem;
  font-size: 0.9rem;
  color: var(--fnf-color-text-muted);
}

/* ─── Navmenu — inline, no popup ───────────────────────────────────────
   Just enough to flex the links horizontally with sane spacing. Header
   variants override colors / sizing per their own modifier classes.   */
.navmenu { padding: 0; }
.navmenu ul {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
  align-items: center;
}
.navmenu li { position: relative; }
.navmenu a {
  color: inherit;
  text-decoration: none;
  padding: 0;
  transition: opacity 0.15s, color 0.15s;
}
.navmenu a:hover { opacity: 0.8; }
.navmenu .active { font-weight: 600; }

/* Mobile toggle (hamburger) — visibility controlled per-variant by
   Bootstrap's d-md-none / d-lg-none utilities. */
.mobile-nav-toggle { font-size: 1.5rem; cursor: pointer; }

/* ─── Sub-page dropdowns ──────────────────────────────────────────────
   When a nav item has children (sub-pages or post-children), ff-nav.js
   wraps it as <li class="dropdown"><a>… <i.toggle-dropdown></i></a><ul>…</ul></li>.
   Desktop: the inner <ul> hides by default and pops on hover.
   Mobile: clicking the chevron toggles .dropdown-active on the <ul>. */
.navmenu .toggle-dropdown {
  font-size: 0.7em;
  margin-left: 4px;
  cursor: pointer;
  transition: transform 0.15s;
}
.navmenu .dropdown { position: relative; }
.navmenu .dropdown > ul {
  position: absolute;
  top: 100%;
  left: 0;
  display: none;
  flex-direction: column;
  gap: 0;
  background: var(--fnf-color-bg, #fff);
  border: 1px solid var(--fnf-color-border, #dee2e6);
  border-radius: var(--fnf-radius-sm, 4px);
  box-shadow: var(--fnf-shadow-md, 0 4px 12px rgba(0,0,0,0.12));
  padding: 0.4rem 0;
  min-width: 200px;
  margin: 0;
  z-index: 100;
}
.navmenu .dropdown:hover > ul,
.navmenu .dropdown:focus-within > ul,
.navmenu .dropdown > ul.dropdown-active {
  display: flex;
}
.navmenu .dropdown > ul > li { width: 100%; }
.navmenu .dropdown > ul > li > a {
  display: block;
  padding: 0.4rem 1rem;
  white-space: nowrap;
  color: var(--fnf-color-text, inherit);
}
.navmenu .dropdown > ul > li > a:hover {
  background: var(--fnf-color-surface-alt, #f4f6f8);
}
/* Second-level dropdowns flyout to the side (multi-level menu pattern) */
.navmenu .dropdown .dropdown > ul {
  top: -0.4rem;
  left: 100%;
}

/* On narrow viewports the absolute-positioned popup overflows; collapse
   inline + indented and rely on the click-toggle to expand. */
@media (max-width: 1199px) {
  .navmenu .dropdown > ul {
    position: static;
    box-shadow: none;
    border: none;
    padding: 0 0 0 1rem;
    min-width: 0;
    background: transparent;
  }
  .navmenu .dropdown:hover > ul,
  .navmenu .dropdown:focus-within > ul {
    display: none; /* hover-open is for desktop only */
  }
  .navmenu .dropdown > ul.dropdown-active { display: flex; }
  .navmenu .dropdown .dropdown > ul { left: auto; top: auto; }
}

/* ─── Mobile nav: hamburger drop-down ─────────────────────────────────
   Below the md breakpoint every header variant renders a
   .mobile-nav-toggle (d-md-none) and ff-nav.js toggles
   body.mobile-nav-active on tap. The header block's own CSS deliberately
   keeps the nav inline (counteracting Yummy's popup), which left the
   hamburger with nothing to open. These rules collapse the link list
   behind the hamburger and drop it down as a panel when tapped. The
   #navmenu id-specificity intentionally outranks the header block's
   inlined "keep inline" rules (which are class-only). */
@media (max-width: 767.98px) {
  .fnf-header { position: relative; }

  .fnf-header #navmenu > ul {
    position: absolute !important;
    top: 100% !important;
    left: 0 !important;
    right: 0 !important;
    display: none !important;
    flex-direction: column !important;
    flex-wrap: nowrap !important;
    align-items: stretch !important;
    gap: 0 !important;
    margin: 0 !important;
    padding: 6px 0 !important;
    background: var(--fnf-color-bg, #fff) !important;
    border-top: 1px solid var(--fnf-color-border, #dee2e6) !important;
    box-shadow: 0 10px 22px rgba(0, 0, 0, 0.16) !important;
    border-radius: 0 0 var(--fnf-radius-sm, 6px) var(--fnf-radius-sm, 6px) !important;
    z-index: 1050 !important;
  }
  body.mobile-nav-active .fnf-header #navmenu > ul { display: flex !important; }

  /* Full-width, readable rows regardless of the header's theme colors. */
  .fnf-header #navmenu > ul > li { width: 100%; }
  .fnf-header #navmenu > ul > li > a {
    display: block !important;
    padding: 12px 20px !important;
    color: var(--fnf-color-text, #212529) !important;
    font-size: 1rem !important;
    opacity: 1 !important;
  }
  .fnf-header #navmenu > ul > li > a:hover {
    background: var(--fnf-color-surface-alt, #f4f6f8) !important;
  }

  /* Hamburger stays above the panel and tappable. */
  .fnf-header .mobile-nav-toggle { position: relative; z-index: 1051; }
}

/* ─── Tile templates ──────────────────────────────────────────────────
   ff-tiles.js falls back to these named templates when no <template>
   tag is present. Ports of Yummy's classes into the --fnf-* vocabulary;
   noticeably trimmed (no chefs/menu/events page-specific styling).    */

/* Generic tile (catch-all when template name doesn't match a fallback) */
.tile-item {
  padding: 1rem;
  border: 1px solid var(--fnf-color-border, #dee2e6);
  border-radius: var(--fnf-radius-md);
  background: var(--fnf-color-bg);
}

/* Testimonial */
.testimonial-item {
  background: var(--fnf-color-surface);
  padding: 2rem;
  border-radius: var(--fnf-radius-md);
  box-shadow: var(--fnf-shadow-sm);
  text-align: center;
  height: 100%;
}
.testimonial-item .quote-icon-left,
.testimonial-item .quote-icon-right {
  color: var(--fnf-color-accent);
  font-size: 1.5rem;
  display: inline-block;
  line-height: 0;
  position: relative;
}
.testimonial-item .quote-icon-left  { left: -5px; }
/* bi-quote only ships an opening glyph; flip it for the closer. */
.testimonial-item .quote-icon-right {
  right: -5px;
  top: 10px;
  transform: scale(-1, -1);
}
.testimonial-item h3 {
  font-family: var(--fnf-font-heading);
  font-size: 1.1rem;
  margin: 1rem 0 0;
  color: var(--fnf-color-heading);
}
.testimonial-item h4 {
  font-size: 0.9rem;
  color: var(--fnf-color-text-muted);
  margin: 0 0 0.5rem;
  font-weight: normal;
}
.testimonial-item .stars i { color: #ffc107; font-size: 0.85rem; }
/* Size lock — high specificity (0,3,1) so the gallery's tile-shape--ratio-*
   and fnf-photo-shape--* wrappers (which target img.img-fluid at 0,2,1
   with aspect-ratio + width:100%) can't stretch the avatar across the
   testimonial card. Width/height/aspect-ratio/fit/margin live here. */
.testimonial-item img.testimonial-img.img-fluid {
  width: 80px;
  height: 80px;
  aspect-ratio: auto;
  object-fit: cover;
  margin: 0 auto 0.75rem;
  display: block;
}
/* Default avatar shape — lower specificity (0,2,0) so the gallery's
   Photo shape option (fnf-photo-shape--blob / --leaf / --hex / etc.,
   each 0,2,1 on img.img-fluid) wins and the testimonial avatar
   actually reshapes. Without an override, defaults to a circle. */
.testimonial-item .testimonial-img {
  border-radius: 50%;
}

/* Team member */
.team-member {
  display: flex;
  flex-direction: column;
  background: var(--fnf-color-surface);
  border-radius: var(--fnf-radius-md);
  overflow: hidden;
  box-shadow: var(--fnf-shadow-sm);
  width: 100%;
}
.team-member .member-img { position: relative; }
.team-member .member-img img { width: 100%; display: block; }
.team-member .member-img .social {
  position: absolute;
  inset: auto 0 0 0;
  padding: 0.5rem;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  gap: 0.75rem;
  justify-content: center;
  opacity: 0;
  transition: opacity 0.2s;
}
.team-member:hover .member-img .social { opacity: 1; }
.team-member .member-img .social a { color: #fff; text-decoration: none; }
.team-member .member-info { padding: 1rem; text-align: center; }
.team-member .member-info h4 {
  font-family: var(--fnf-font-heading);
  font-size: 1.1rem;
  margin: 0 0 0.25rem;
  color: var(--fnf-color-heading);
}
.team-member .member-info span {
  color: var(--fnf-color-text-muted);
  font-size: 0.875rem;
}
.team-member .member-info p { margin: 0.5rem 0 0; font-size: 0.9rem; }

/* Event card (full-bleed photo + text overlay) */
.event-item {
  background-size: cover;
  background-position: center;
  border-radius: var(--fnf-radius-md);
  overflow: hidden;
  padding: 1.5rem;
  min-height: 320px;
  color: #fff;
  position: relative;
  height: 100%;
}
.event-item::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, transparent 30%, rgba(0, 0, 0, 0.7) 100%);
}
.event-item h3,
.event-item .price,
.event-item .description { position: relative; z-index: 1; color: #fff; }
.event-item h3 {
  font-family: var(--fnf-font-heading);
  font-size: 1.4rem;
  margin: 0 0 0.5rem;
}
.event-item .price {
  display: inline-block;
  background: var(--fnf-color-accent);
  color: var(--fnf-color-accent-contrast);
  padding: 0.25rem 0.75rem;
  border-radius: var(--fnf-radius-sm);
  font-weight: 600;
  margin-bottom: 0.75rem;
}
.event-item .description { font-size: 0.9rem; }

/* Menu / product card */
.menu-item .card-body { padding: 1rem; }
.menu-item .card-title {
  font-family: var(--fnf-font-heading);
  font-size: 1.1rem;
  margin: 0 0 0.5rem;
  color: var(--fnf-color-heading);
}
.menu-item .ingredients {
  color: var(--fnf-color-text-muted);
  font-size: 0.875rem;
  margin: 0 0 0.5rem;
}
.menu-item .price {
  color: var(--fnf-color-accent);
  font-weight: 600;
  margin: 0;
}

/* Feature / icon box */
.icon-box {
  background: var(--fnf-color-surface);
  padding: 2.25rem 1.75rem 2rem;
  border-radius: var(--fnf-radius-md);
  text-align: center;
  height: 100%;
  box-shadow: var(--fnf-shadow-sm);
  display: flex;
  flex-direction: column;
  align-items: center;
}
.icon-box i.bi {
  font-size: 2.5rem;
  color: var(--fnf-color-accent);
  margin-bottom: 1rem;
  display: inline-block;
}
/* Direct-child only. Earlier the rule was `.icon-box img` which capped EVERY
   img inside an icon-box to 80px — including the <img class="img-fluid">
   nested in <div class="card-img-top"> when the feature-card tile renders a
   real photo. That silently overrode the per-tile photoAspect option (1:1 /
   4:3 / 3:4) and made photos look like a thin strip. The 80px cap is meant
   only for the small-icon case where an SVG/icon-img sits directly inside
   icon-box; nested photos in card-img-top take their aspect from the
   .tile-shape--ratio-* wrapper instead. */
.icon-box > img { max-height: 80px; margin: 0 auto 1rem; display: block; }
.icon-box h4 {
  font-family: var(--fnf-font-heading);
  font-size: 1.2rem;
  margin: 0 0 0.5rem;
  color: var(--fnf-color-heading);
}
.icon-box p { color: var(--fnf-color-text-muted); margin: 0; }

/* Section title (used by content block's section-title variant) */
.section-title { text-align: center; margin-bottom: 2rem; }
.section-title h2 {
  font-family: var(--fnf-font-heading);
  color: var(--fnf-color-heading);
  font-size: clamp(1.75rem, 3vw, 2.25rem);
  margin: 0 0 0.5rem;
}
.section-title p {
  color: var(--fnf-color-text-muted);
  margin: 0 auto;
  max-width: 42rem;
}

/* ─── Stylized bullet list ───────────────────────────────────────────
   Used in two places:
     1. Tiles — ff-tiles.js emits <ul.fnf-tile-bullets><li> with an
        explicit <span.fnf-tile-bullets__icon> wrapper for the marker.
     2. Rich-text content blocks — when the block has
        .fnf-content--stylized-bullets, any <ul> the user typed in the
        rich-text body gets the same treatment via ::before.
   The actual marker (circle/check/dot/arrow) is set by one of the
   .fnf-bullets-style--* modifiers below. .check-circle is the default. */
.fnf-tile-bullets {
  list-style: none;
  padding: 0;
  margin: 0.75rem 0 0;
  text-align: left;
}
.fnf-tile-bullets li {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  margin-bottom: 0.4rem;
  line-height: 1.4;
}
.fnf-tile-bullets li:last-child { margin-bottom: 0; }
.fnf-tile-bullets__icon {
  flex: 0 0 1.25rem;
  width: 1.25rem;
  height: 1.25rem;
  margin-top: 0.15rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.95rem;
  line-height: 1;
  color: var(--fnf-color-accent, #d4a437);
}
.fnf-tile-bullets__icon .bi { line-height: 1; }
.fnf-tile-bullets__text {
  flex: 1;
  color: var(--fnf-color-text, inherit);
  font-size: 0.95rem;
}

/* Rich-text <ul> inside opted-in content blocks: hide native bullets and
   reserve space on the left for the ::before marker. */
.fnf-content--stylized-bullets [data-ff-rich] ul,
.fnf-content--stylized-bullets .fnf-content__text ul {
  list-style: none;
  padding-left: 0;
  /* Items always read left-to-right; the whole list shrinks to its
     content width and centers as a unit inside a centered section
     (text-only variant) while staying flush-left in a left-aligned
     block. */
  display: inline-block;
  text-align: left;
}
.fnf-content--stylized-bullets [data-ff-rich] ul > li,
.fnf-content--stylized-bullets .fnf-content__text ul > li {
  position: relative;
  padding-left: 1.75rem;
  margin-bottom: 0.4rem;
  line-height: 1.4;
}
.fnf-content--stylized-bullets [data-ff-rich] ul > li::before,
.fnf-content--stylized-bullets .fnf-content__text ul > li::before {
  font-family: "bootstrap-icons";
  position: absolute;
  left: 0;
  top: 0.2rem;
  width: 1.25rem;
  height: 1.25rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  color: var(--fnf-color-accent, #d4a437);
  font-size: 0.95rem;
}

/* ── Bullet-style modifiers ─────────────────────────────────────────── */

/* 1. Check in accent circle (default). Tile marker gets the filled
      circle background; rich-text ::before mirrors it. */
.fnf-bullets-style--check-circle .fnf-tile-bullets__icon {
  background: var(--fnf-color-accent, #d4a437);
  color: #fff;
  border-radius: 50%;
  font-size: 0.7rem;
}
.fnf-bullets-style--check-circle.fnf-content--stylized-bullets [data-ff-rich] ul > li::before,
.fnf-bullets-style--check-circle.fnf-content--stylized-bullets .fnf-content__text ul > li::before {
  content: "\f633";          /* bi-check-lg */
  background: var(--fnf-color-accent, #d4a437);
  color: #fff;
  border-radius: 50%;
  font-size: 0.7rem;
}

/* 2. Bare check — accent-colored check, no circle background. */
.fnf-bullets-style--check .fnf-tile-bullets__icon {
  /* tile icon (<i class="bi-check-lg">) inherits accent color from base */
  font-size: 1.1rem;
}
.fnf-bullets-style--check.fnf-content--stylized-bullets [data-ff-rich] ul > li::before,
.fnf-bullets-style--check.fnf-content--stylized-bullets .fnf-content__text ul > li::before {
  content: "\f633";          /* bi-check-lg */
  font-size: 1.1rem;
}

/* 3. Accent dot — solid filled disc; hide the check icon if rendered. */
.fnf-bullets-style--dot .fnf-tile-bullets__icon .bi { display: none; }
.fnf-bullets-style--dot .fnf-tile-bullets__icon {
  position: relative;
}
.fnf-bullets-style--dot .fnf-tile-bullets__icon::before {
  content: "";
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 50%;
  background: var(--fnf-color-accent, #d4a437);
  display: block;
}
.fnf-bullets-style--dot.fnf-content--stylized-bullets [data-ff-rich] ul > li::before,
.fnf-bullets-style--dot.fnf-content--stylized-bullets .fnf-content__text ul > li::before {
  content: "";
  font-family: inherit;
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 50%;
  background: var(--fnf-color-accent, #d4a437);
  top: 0.55rem;
  left: 0.35rem;
}

/* 4. Arrow / chevron — accent chevron-right, no circle. */
.fnf-bullets-style--arrow .fnf-tile-bullets__icon .bi { display: none; }
.fnf-bullets-style--arrow .fnf-tile-bullets__icon::before {
  content: "\f285";          /* bi-chevron-right */
  font-family: "bootstrap-icons";
  font-size: 1rem;
  font-weight: bold;
  line-height: 1;
  color: var(--fnf-color-accent, #d4a437);
}
.fnf-bullets-style--arrow.fnf-content--stylized-bullets [data-ff-rich] ul > li::before,
.fnf-bullets-style--arrow.fnf-content--stylized-bullets .fnf-content__text ul > li::before {
  content: "\f285";          /* bi-chevron-right */
  font-weight: bold;
  font-size: 1rem;
}

/* ─── Per-tile CTA button(s) ─────────────────────────────────────────
   ff-tiles.js renders up to 3 .fnf-tile-button inside a .fnf-tile-buttons
   wrapper at the bottom of any tile that has button(s). The block-level
   .fnf-button-style--* modifier on the gallery section picks the
   visual treatment (filled-primary / filled-accent / outline /
   outline-light / text). All variants pick up colors from the theme
   CSS vars so they shift with the site's palette. */
.fnf-tile-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 1rem;
}
.fnf-tile-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  padding: 0.5rem 1.1rem;
  font-size: 0.95rem;
  font-weight: 500;
  line-height: 1.2;
  text-decoration: none;
  border: 1px solid transparent;
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
  background: transparent;
  color: inherit;
}
.fnf-tile-button:hover { transform: translateY(-1px); }
/* Center-aligned tile bodies (product-item, feature-card, center): center
   the button row so it sits under the centered text rather than hugging
   the left edge. */
.text-center .fnf-tile-buttons,
.icon-box .fnf-tile-buttons {
  justify-content: center;
}
/* Feature cards (.icon-box, a flex-column at height:100%) always float
   their button row to the bottom so buttons align across same-row cards
   even when bullet counts differ. The bullets list's bottom margin
   guarantees a visible gap above the buttons even when content fills
   the card. */
.icon-box > .fnf-tile-buttons {
  margin-top: auto;
}

/* ─── Bottom-align option (gallery "Line buttons up at the bottom") ───
   .fnf-tiles--pin-buttons on the gallery section makes each card a
   flex-column and pushes its .fnf-tile-buttons row to the bottom, so the
   buttons line up across a row of unequal-height tiles. Default ON. */
.fnf-tiles--pin-buttons .card-body {
  display: flex;
  flex-direction: column;
}
.fnf-tiles--pin-buttons .tile-item {
  display: flex;
  flex-direction: column;
  height: 100%;
}
.fnf-tiles--pin-buttons .card-body > .fnf-tile-buttons,
.fnf-tiles--pin-buttons .tile-item > .fnf-tile-buttons,
.fnf-tiles--pin-buttons .icon-box > .fnf-tile-buttons {
  margin-top: auto;
}
.icon-box > .fnf-tile-bullets {
  margin-bottom: 1.25rem;
}
/* Constrain text-block width inside an icon-box so cards with long
   bullets/body wrap earlier and visually match cards with short text.
   Without this, a tile with 140-char bullets pushes text edge-to-edge
   while a sibling tile with 40-char bullets sits comfortably inset —
   the row reads as inconsistent. The flex container's align-items:center
   centers the now-narrower blocks. */
.icon-box > .fnf-tile-bullets,
.icon-box > p {
  max-width: 20rem;
  width: 100%;
}

/* 1. Filled — brand primary */
.fnf-button-style--primary .fnf-tile-button {
  background: var(--fnf-color-primary, #1e293b);
  color: var(--fnf-color-on-primary, #fff);
  border-color: var(--fnf-color-primary, #1e293b);
}
.fnf-button-style--primary .fnf-tile-button:hover {
  filter: brightness(1.1);
}

/* 2. Filled — brand accent */
.fnf-button-style--accent .fnf-tile-button {
  background: var(--fnf-color-accent, #d4a437);
  color: var(--fnf-color-on-accent, #fff);
  border-color: var(--fnf-color-accent, #d4a437);
}
.fnf-button-style--accent .fnf-tile-button:hover {
  filter: brightness(1.1);
}

/* 3. Outline */
.fnf-button-style--outline .fnf-tile-button {
  background: transparent;
  color: var(--fnf-color-primary, #1e293b);
  border-color: var(--fnf-color-primary, #1e293b);
}
.fnf-button-style--outline .fnf-tile-button:hover {
  background: var(--fnf-color-primary, #1e293b);
  color: var(--fnf-color-on-primary, #fff);
}

/* 4. Outline (light) — for tiles on dark backgrounds */
.fnf-button-style--outline-light .fnf-tile-button {
  background: transparent;
  color: #fff;
  border-color: rgba(255, 255, 255, 0.7);
}
.fnf-button-style--outline-light .fnf-tile-button:hover {
  background: #fff;
  color: var(--fnf-color-primary, #1e293b);
  border-color: #fff;
}

/* 5. Text link with arrow — appends a bi-arrow-right via ::after */
.fnf-button-style--text .fnf-tile-button {
  background: transparent;
  border-color: transparent;
  color: var(--fnf-color-accent, #d4a437);
  padding-left: 0;
  padding-right: 0;
  border-radius: 0;
}
.fnf-button-style--text .fnf-tile-button::after {
  content: "\f135";          /* bi-arrow-right-short */
  font-family: "bootstrap-icons";
  font-size: 1.1em;
  line-height: 1;
  margin-left: 0.25rem;
  transition: transform 0.15s ease;
}
.fnf-button-style--text .fnf-tile-button:hover {
  filter: brightness(0.9);
}
.fnf-button-style--text .fnf-tile-button:hover::after {
  transform: translateX(3px);
}

/* ─── Highlighted tile ──────────────────────────────────────────────
   Per-tile flag set via metadata.highlight; ff-tiles.js adds
   .ff-tile-wrap--highlight to the column wrap. Block-level toggles on
   the gallery section choose which treatments apply
   (.fnf-highlight--outline / --scale / --glow). The wrap is positioned
   relative so .fnf-tile-highlight-ribbon (rendered when a label is
   set) can anchor to the corner. */
.ff-tile-wrap--highlight { position: relative; }

.fnf-highlight--outline .ff-tile-wrap--highlight > div > .card,
.fnf-highlight--outline .ff-tile-wrap--highlight > .card,
.fnf-highlight--outline .ff-tile-wrap--highlight > div > .team-member,
.fnf-highlight--outline .ff-tile-wrap--highlight > div > .icon-box,
.fnf-highlight--outline .ff-tile-wrap--highlight > div > .testimonial-item,
.fnf-highlight--outline .ff-tile-wrap--highlight > div > .event-item,
.fnf-highlight--outline .ff-tile-wrap--highlight > div > .tile-item {
  border: 2px solid var(--fnf-color-accent, #d4a437);
  border-radius: 0.75rem;
}

.fnf-highlight--scale .ff-tile-wrap--highlight {
  transform: scale(1.04);
  transform-origin: center center;
  z-index: 2;
}

.fnf-highlight--glow .ff-tile-wrap--highlight > div > .card,
.fnf-highlight--glow .ff-tile-wrap--highlight > .card,
.fnf-highlight--glow .ff-tile-wrap--highlight > div > .team-member,
.fnf-highlight--glow .ff-tile-wrap--highlight > div > .icon-box,
.fnf-highlight--glow .ff-tile-wrap--highlight > div > .testimonial-item,
.fnf-highlight--glow .ff-tile-wrap--highlight > div > .event-item,
.fnf-highlight--glow .ff-tile-wrap--highlight > div > .tile-item {
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.18), 0 0 0 1px rgba(0, 0, 0, 0.02);
}

/* Corner ribbon — accent-colored badge top-right, visible only when
   the tile has a highlightLabel string. */
.fnf-tile-highlight-ribbon {
  position: absolute;
  top: 0;
  right: 0;
  background: var(--fnf-color-accent, #d4a437);
  color: #fff;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  padding: 0.35rem 0.75rem;
  border-top-right-radius: 0.5rem;
  border-bottom-left-radius: 0.5rem;
  z-index: 3;
  pointer-events: none;
}

/* ─── Horizontal card (gallery tile-template: card-horizontal) ─── */
.fnf-card-horizontal {
  overflow: hidden;
  border-radius: 0.75rem;
}
.fnf-card-horizontal > .row { min-height: 100%; }
.fnf-card-horizontal__media {
  min-height: 160px;
  overflow: hidden;
  background: #f3f4f6;
}
.fnf-card-horizontal__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.fnf-card-horizontal__body { display: flex; }
.fnf-card-horizontal__body .card-body { width: 100%; padding: 1.25rem; }
.fnf-card-horizontal__title {
  font-family: var(--fnf-font-heading);
  color: var(--fnf-color-heading);
  margin-bottom: 0.35rem;
}
.fnf-card-horizontal__subtitle { margin-bottom: 0.5rem; }
.fnf-card-horizontal__body-text { margin-bottom: 0.5rem; }
/* On phones, stack media above body so the photo doesn't get squished. */
@media (max-width: 767.98px) {
  .fnf-card-horizontal__media { min-height: 200px; }
}

/* ============================================================
   Photo shapes via SVG clip-path (ff-shapes.js injects the <clipPath>
   defs). Curated set: organic blobs, puffy stars, speech bubbles
   (tail left/right/down x rounded/sharp), clouds, thought bubbles.
   Authored in a square viewBox, so the photo box is forced 1:1 and the
   img fills it (object-fit:cover) before the clip-path cuts the shape.
   Two contexts: content block (class on .fnf-photo-frame) and gallery
   tiles (class on the tile wrapper -> clip the inner tile photo img only,
   NOT the whole card). Regenerate paths via editor/shapes/gen_shapes.js.
   ============================================================ */
.fnf-photo-frame[class*="fnf-photo-shape--organic-"],
.fnf-photo-frame[class*="fnf-photo-shape--star-"],
.fnf-photo-frame[class*="fnf-photo-shape--bubble-"],
.fnf-photo-frame[class*="fnf-photo-shape--cloud-"],
.fnf-photo-frame[class*="fnf-photo-shape--thought-"] {
  aspect-ratio: 1 / 1;
}
.fnf-photo-frame[class*="fnf-photo-shape--organic-"] > img,
.fnf-photo-frame[class*="fnf-photo-shape--star-"] > img,
.fnf-photo-frame[class*="fnf-photo-shape--bubble-"] > img,
.fnf-photo-frame[class*="fnf-photo-shape--cloud-"] > img,
.fnf-photo-frame[class*="fnf-photo-shape--thought-"] > img {
  height: 100%;
  object-fit: cover;
}
[class*="fnf-photo-shape--organic-"].ff-tile-photo img,
[class*="fnf-photo-shape--organic-"].card-img-top img,
[class*="fnf-photo-shape--organic-"].member-img img,
[class*="fnf-photo-shape--organic-"]img.img-fluid,
[class*="fnf-photo-shape--star-"].ff-tile-photo img,
[class*="fnf-photo-shape--star-"].card-img-top img,
[class*="fnf-photo-shape--star-"].member-img img,
[class*="fnf-photo-shape--star-"]img.img-fluid,
[class*="fnf-photo-shape--bubble-"].ff-tile-photo img,
[class*="fnf-photo-shape--bubble-"].card-img-top img,
[class*="fnf-photo-shape--bubble-"].member-img img,
[class*="fnf-photo-shape--bubble-"]img.img-fluid,
[class*="fnf-photo-shape--cloud-"].ff-tile-photo img,
[class*="fnf-photo-shape--cloud-"].card-img-top img,
[class*="fnf-photo-shape--cloud-"].member-img img,
[class*="fnf-photo-shape--cloud-"]img.img-fluid,
[class*="fnf-photo-shape--thought-"].ff-tile-photo img,
[class*="fnf-photo-shape--thought-"].card-img-top img,
[class*="fnf-photo-shape--thought-"].member-img img,
[class*="fnf-photo-shape--thought-"]img.img-fluid {
  aspect-ratio: 1 / 1;
  object-fit: cover;
  width: 100%;
  height: auto;
}
.fnf-photo-frame.fnf-photo-shape--organic-1,
.fnf-photo-shape--organic-1 .ff-tile-photo img,
.fnf-photo-shape--organic-1 .card-img-top img,
.fnf-photo-shape--organic-1 .member-img img,
.fnf-photo-shape--organic-1 img.img-fluid {
  clip-path: url(#fnf-shape-organic-1);
}
.fnf-photo-frame.fnf-photo-shape--organic-2,
.fnf-photo-shape--organic-2 .ff-tile-photo img,
.fnf-photo-shape--organic-2 .card-img-top img,
.fnf-photo-shape--organic-2 .member-img img,
.fnf-photo-shape--organic-2 img.img-fluid {
  clip-path: url(#fnf-shape-organic-2);
}
.fnf-photo-frame.fnf-photo-shape--organic-3,
.fnf-photo-shape--organic-3 .ff-tile-photo img,
.fnf-photo-shape--organic-3 .card-img-top img,
.fnf-photo-shape--organic-3 .member-img img,
.fnf-photo-shape--organic-3 img.img-fluid {
  clip-path: url(#fnf-shape-organic-3);
}
.fnf-photo-frame.fnf-photo-shape--organic-4,
.fnf-photo-shape--organic-4 .ff-tile-photo img,
.fnf-photo-shape--organic-4 .card-img-top img,
.fnf-photo-shape--organic-4 .member-img img,
.fnf-photo-shape--organic-4 img.img-fluid {
  clip-path: url(#fnf-shape-organic-4);
}
.fnf-photo-frame.fnf-photo-shape--star-1,
.fnf-photo-shape--star-1 .ff-tile-photo img,
.fnf-photo-shape--star-1 .card-img-top img,
.fnf-photo-shape--star-1 .member-img img,
.fnf-photo-shape--star-1 img.img-fluid {
  clip-path: url(#fnf-shape-star-1);
}
.fnf-photo-frame.fnf-photo-shape--star-2,
.fnf-photo-shape--star-2 .ff-tile-photo img,
.fnf-photo-shape--star-2 .card-img-top img,
.fnf-photo-shape--star-2 .member-img img,
.fnf-photo-shape--star-2 img.img-fluid {
  clip-path: url(#fnf-shape-star-2);
}
.fnf-photo-frame.fnf-photo-shape--star-3,
.fnf-photo-shape--star-3 .ff-tile-photo img,
.fnf-photo-shape--star-3 .card-img-top img,
.fnf-photo-shape--star-3 .member-img img,
.fnf-photo-shape--star-3 img.img-fluid {
  clip-path: url(#fnf-shape-star-3);
}
.fnf-photo-frame.fnf-photo-shape--star-4,
.fnf-photo-shape--star-4 .ff-tile-photo img,
.fnf-photo-shape--star-4 .card-img-top img,
.fnf-photo-shape--star-4 .member-img img,
.fnf-photo-shape--star-4 img.img-fluid {
  clip-path: url(#fnf-shape-star-4);
}
.fnf-photo-frame.fnf-photo-shape--bubble-left-round,
.fnf-photo-shape--bubble-left-round .ff-tile-photo img,
.fnf-photo-shape--bubble-left-round .card-img-top img,
.fnf-photo-shape--bubble-left-round .member-img img,
.fnf-photo-shape--bubble-left-round img.img-fluid {
  clip-path: url(#fnf-shape-bubble-left-round);
}
.fnf-photo-frame.fnf-photo-shape--bubble-right-round,
.fnf-photo-shape--bubble-right-round .ff-tile-photo img,
.fnf-photo-shape--bubble-right-round .card-img-top img,
.fnf-photo-shape--bubble-right-round .member-img img,
.fnf-photo-shape--bubble-right-round img.img-fluid {
  clip-path: url(#fnf-shape-bubble-right-round);
}
.fnf-photo-frame.fnf-photo-shape--bubble-down-round,
.fnf-photo-shape--bubble-down-round .ff-tile-photo img,
.fnf-photo-shape--bubble-down-round .card-img-top img,
.fnf-photo-shape--bubble-down-round .member-img img,
.fnf-photo-shape--bubble-down-round img.img-fluid {
  clip-path: url(#fnf-shape-bubble-down-round);
}
.fnf-photo-frame.fnf-photo-shape--bubble-left-sharp,
.fnf-photo-shape--bubble-left-sharp .ff-tile-photo img,
.fnf-photo-shape--bubble-left-sharp .card-img-top img,
.fnf-photo-shape--bubble-left-sharp .member-img img,
.fnf-photo-shape--bubble-left-sharp img.img-fluid {
  clip-path: url(#fnf-shape-bubble-left-sharp);
}
.fnf-photo-frame.fnf-photo-shape--bubble-right-sharp,
.fnf-photo-shape--bubble-right-sharp .ff-tile-photo img,
.fnf-photo-shape--bubble-right-sharp .card-img-top img,
.fnf-photo-shape--bubble-right-sharp .member-img img,
.fnf-photo-shape--bubble-right-sharp img.img-fluid {
  clip-path: url(#fnf-shape-bubble-right-sharp);
}
.fnf-photo-frame.fnf-photo-shape--bubble-down-sharp,
.fnf-photo-shape--bubble-down-sharp .ff-tile-photo img,
.fnf-photo-shape--bubble-down-sharp .card-img-top img,
.fnf-photo-shape--bubble-down-sharp .member-img img,
.fnf-photo-shape--bubble-down-sharp img.img-fluid {
  clip-path: url(#fnf-shape-bubble-down-sharp);
}
.fnf-photo-frame.fnf-photo-shape--cloud-puffy,
.fnf-photo-shape--cloud-puffy .ff-tile-photo img,
.fnf-photo-shape--cloud-puffy .card-img-top img,
.fnf-photo-shape--cloud-puffy .member-img img,
.fnf-photo-shape--cloud-puffy img.img-fluid {
  clip-path: url(#fnf-shape-cloud-puffy);
}
.fnf-photo-frame.fnf-photo-shape--cloud-wide,
.fnf-photo-shape--cloud-wide .ff-tile-photo img,
.fnf-photo-shape--cloud-wide .card-img-top img,
.fnf-photo-shape--cloud-wide .member-img img,
.fnf-photo-shape--cloud-wide img.img-fluid {
  clip-path: url(#fnf-shape-cloud-wide);
}
.fnf-photo-frame.fnf-photo-shape--cloud-chunky,
.fnf-photo-shape--cloud-chunky .ff-tile-photo img,
.fnf-photo-shape--cloud-chunky .card-img-top img,
.fnf-photo-shape--cloud-chunky .member-img img,
.fnf-photo-shape--cloud-chunky img.img-fluid {
  clip-path: url(#fnf-shape-cloud-chunky);
}
.fnf-photo-frame.fnf-photo-shape--thought-puffy,
.fnf-photo-shape--thought-puffy .ff-tile-photo img,
.fnf-photo-shape--thought-puffy .card-img-top img,
.fnf-photo-shape--thought-puffy .member-img img,
.fnf-photo-shape--thought-puffy img.img-fluid {
  clip-path: url(#fnf-shape-thought-puffy);
}
.fnf-photo-frame.fnf-photo-shape--thought-wide,
.fnf-photo-shape--thought-wide .ff-tile-photo img,
.fnf-photo-shape--thought-wide .card-img-top img,
.fnf-photo-shape--thought-wide .member-img img,
.fnf-photo-shape--thought-wide img.img-fluid {
  clip-path: url(#fnf-shape-thought-wide);
}
.fnf-photo-frame.fnf-photo-shape--thought-chunky,
.fnf-photo-shape--thought-chunky .ff-tile-photo img,
.fnf-photo-shape--thought-chunky .card-img-top img,
.fnf-photo-shape--thought-chunky .member-img img,
.fnf-photo-shape--thought-chunky img.img-fluid {
  clip-path: url(#fnf-shape-thought-chunky);
}
