/* ============================================================
   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; }

/* 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 {
  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; }
.header .logo {
  color: var(--fnf-color-heading);
  text-decoration: none;
}
.header .sitename {
  font-family: var(--fnf-font-brand);
  color: var(--fnf-color-heading);
  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 ───────────────────────────────────────────
   ff-tiles.js renders an .fnf-tile-button at the bottom of any tile
   whose metadata.buttonLabel is set. 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-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  margin-top: 1rem;
  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): the
   button's inline-flex default left-aligns when wrapped by text-center,
   so reset to block + auto margins to actually center it. */
.text-center > .fnf-tile-button,
.icon-box > .fnf-tile-button {
  display: inline-flex;
  margin-left: auto;
  margin-right: auto;
}
/* In an icon-box (flex-column, height:100%), float the button 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 button even when content fills the card. */
.icon-box > .fnf-tile-button {
  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; }
}
