/* ============================================================
   assets/css/fabbro.css
   /intervento-fabbro-h24/ — page-specific sections only.

   Tokens, .container, .btn and the .hero--split hero come from
   global.css; the pricing and coverage sections come from
   prezzi.css. Neither is redefined here (CLAUDE.md §"Section CSS",
   rule 2). Load order: global -> prezzi -> fabbro.

   Sections left in this file:
     1 steps · 2 services · 3 emergency (closing)
     (pricing + coverage now live in prezzi.css)
============================================================ */

/* ---------- shared bits ---------- */

.cta-btn{
  display:inline-flex; align-items:center; justify-content:center;
  text-align:center; gap:10px;
  background:var(--amber-600); color:var(--paper-000);
  font-family:var(--font-display);
  font-size:16px; font-weight:700; text-decoration:none;
  padding:17px 30px; border-radius:999px;
  /* keeps a label like "CHIAMA 0282397097" on one line; the button
     grows to fit rather than breaking the number onto its own row */
  white-space:nowrap;
  box-shadow:0 10px 24px rgba(243,90,0,.28);
  transition:transform .15s ease, box-shadow .15s ease;
}
.cta-btn:hover{
  transform:translateY(-1px);
  box-shadow:0 14px 28px rgba(243,90,0,.34);
}
.cta-btn svg{ flex-shrink:0; }

.cta-btn--secondary{
  background:var(--paper-000); color:var(--green-900);
  border:2px solid var(--green-900); box-shadow:none;
}
.cta-btn--secondary:hover{ background:var(--green-100); box-shadow:none; }

.cta-group{
  display:flex; flex-wrap:wrap; align-items:center;
  justify-content:center; gap:16px;
}

.fb-section-title{
  margin:0 0 18px;
  font-family:var(--font-display);
  font-size:clamp(28px,3vw,38px); font-weight:800;
  color:var(--green-900); letter-spacing:-.01em;
}

/* ============================================================
   1. HERO
   Nothing here. The hero is global.css §7b's .hero--split component,
   used as-is — including the landscape photo ratio and stat-card
   positions, which now live there so this page and the homepage
   can't drift apart.
============================================================ */

/* Left column stays left-aligned; only the buttons wrap as a row. */
.hero.hero--split .cta-group{ justify-content:flex-start; }

/* The number stays on the label's own line — .cta-btn is nowrap, so
   the button widens instead of breaking. It used to be display:block,
   which stacked it under "CHIAMA SUBITO!" and, once the button was
   stretched on a phone, left both lines ragged against the icon. */
.fb-hero-phone{
  font-weight:800; letter-spacing:.01em;
}

/* ============================================================
   2. STEPS — Contattaci / Specifica la zona / Richiedi
============================================================ */
.fb-steps{ background:var(--paper-000); padding:clamp(56px,7vw,84px) 5vw; }
.fb-steps-inner{ max-width:1160px; margin:0 auto; }

.fb-step-grid{
  display:grid; grid-template-columns:repeat(3,1fr); gap:24px;
}
.fb-step{
  background:var(--paper-050);
  border:1px solid var(--line-200);
  border-radius:20px;
  padding:32px 28px 34px;
  text-align:center;
  transition:transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.fb-step:hover{
  transform:translateY(-4px);
  box-shadow:0 18px 36px rgba(14,57,94,.12);
  border-color:transparent;
}
.fb-step-media{
  width:84px; height:84px; margin:0 auto 20px;
  border-radius:20px; background:var(--green-100);
  display:flex; align-items:center; justify-content:center;
}
.fb-step-media img{ width:48px; height:48px; display:block; }

/* Styled like a heading but kept as <p> — these are paragraphs on the
   old page, and the heading hierarchy must stay exactly as it was. */
.fb-step-title{
  margin:0 0 12px;
  font-family:var(--font-display);
  font-size:19px; font-weight:800; color:var(--green-900);
  line-height:1.3;
}
.fb-step p{
  margin:0; font-size:15px; line-height:1.65; color:var(--ink-700);
}

/* ============================================================
   4. SERVICES — 4 icon cards
============================================================ */
.fb-services{ background:var(--paper-000); padding:clamp(60px,7vw,88px) 5vw; }
.fb-services-inner{ max-width:1160px; margin:0 auto; text-align:center; }

.fb-services-rule{
  width:20%; min-width:120px; height:5px; border:0;
  background:var(--green-900); border-radius:3px;
  margin:0 auto 26px;
}
.fb-services h3{
  margin:0 0 10px;
  font-family:var(--font-display);
  font-size:clamp(19px,2.1vw,24px); font-weight:700;
  color:var(--green-900); line-height:1.35;
}
.fb-services-call{
  margin:0 0 44px;
  font-size:17px; font-weight:700; color:var(--amber-600);
}
.fb-services-call a{ color:var(--amber-600); text-decoration:none; }
.fb-services-call a:hover{ text-decoration:underline; }

.fb-service-grid{
  display:grid; grid-template-columns:repeat(4,1fr); gap:24px;
}
.fb-service-card{
  background:var(--paper-050);
  border-radius:24px;
  padding:34px 24px 32px;
  transition:transform .18s ease, box-shadow .18s ease;
}
.fb-service-card:hover{
  transform:translateY(-4px);
  box-shadow:0 20px 40px rgba(14,57,94,.14);
}
.fb-service-media{
  width:96px; height:96px; margin:0 auto 20px;
  border-radius:22px; background:var(--green-100);
  display:flex; align-items:center; justify-content:center;
}
.fb-service-media img{
  width:56px; height:56px; display:block;
  transition:transform .25s ease;
}
.fb-service-card:hover .fb-service-media img{ transform:scale(1.07); }

.fb-service-card h4{
  margin:0;
  font-family:var(--font-display);
  font-size:16px; font-weight:800; letter-spacing:.01em;
  color:var(--green-900); line-height:1.35;
}

/* ============================================================
   6. EMERGENCY — dark closing panel
============================================================ */
.fb-emergency{ background:var(--green-950); padding:clamp(60px,7vw,88px) 5vw; }
.fb-emergency-inner{ max-width:820px; margin:0 auto; text-align:center; }

.fb-emergency h2:where(:not(.h1-look)){
  margin:0 0 24px;
  font-family:var(--font-display);
  font-size:clamp(26px,3.4vw,38px); font-weight:800;
  color:var(--paper-000); letter-spacing:-.01em; line-height:1.15;
}
.fb-emergency p{
  font-size:16.5px; line-height:1.75; color:var(--green-100);
  margin:0 0 18px;
}
.fb-emergency p:last-of-type{ margin-bottom:32px; }

/* The common closing-band shape: no heading at all in the source, just
   a plain <p> label and a call button, single centred column (no photo,
   no taglist) — most city pages, not only Asti. Reuses the base
   .fb-emergency component with no modifier, the same way Roma's does,
   since there is no split or grid to add. The label still needs the
   same big/bold display treatment Torino's, Udine's and Alessandria's
   closing labels already get, despite being a <p> here rather than an
   <h2>/<h3>/<p> playing that role in --split/--twocol — visual weight
   is free under hard rule 9 even though the source never marked this
   one up as a heading, so it isn't promoted to one, only styled to
   match.

   :first-CHILD, not :first-of-type. The hub page, Roma and Biella all
   pair a real <h2>/<h3> with an ordinary body <p> right after it — that
   <p> is still the first <p> among its siblings (:first-of-type would
   match it), but it is the SECOND element in the block, behind the
   heading. :first-child only matches when the <p> has no element before
   it at all, which is true for the label-only pages above and false for
   every page with a real heading — so a normal 16.5px body paragraph
   never gets promoted to this display treatment by accident. Found on
   the apertura-porte page's closing band, which had exactly this
   collision; the hub page had the same bug, silently, until now. */
.fb-emergency-inner > p:first-child{
  margin:0 0 28px;
  font-family:var(--font-display);
  font-size:clamp(1.25rem,1rem + 1.1vw,1.85rem);
  font-weight:800; line-height:1.2;
  color:var(--paper-000);
  letter-spacing:.01em;
  text-wrap:balance;
}
/* .cta-btn is nowrap by design (fabbro.css §1's own comment: the number
   stays on one line, the button widens instead of breaking) — fine
   inside a flex column with room to grow, but this button is a direct
   child of a plain, narrow (max-width:820px, no split) centred block,
   and Asti's "CHIAMA SUBITO 01411706992!" doesn't fit 288px available
   at 320px without wrapping. A real ~37px overflow, not the usual
   sub-pixel residual — confirmed via the 8-width sweep, and worse than
   it looks: an overflowing position:fixed .call-bar (width:100%) reads
   the browser's own widened layout viewport at that point, not the
   device width, so it grows to match and compounds the overflow
   further. Only .fb-emergency-inner's own direct-child button is
   affected — Torino's, Udine's and Alessandria's buttons all sit one
   level deeper, inside .fb-emergency__copy/__areas, so their own
   nowrap behaviour is untouched. */
.fb-emergency-inner > .cta-btn{
  white-space:normal;
  max-width:100%;
}
/* The note above says the --split/--twocol pages' buttons sit one
   level deeper, inside .fb-emergency__copy, "so their own nowrap
   behaviour is untouched". A page has now actually hit that case:
   apertura-porte-blindate-torino's "CHIAMA SUBITO! 01118838241" is an
   11-digit number, the longest in the set, and overflowed 320px by
   2px. Same guard, one level deeper. white-space:normal only wraps
   when a line needs it, so every shorter number in the set renders
   exactly as before — re-checked on fabbro-torino/udine/alessandria
   after the change. */
.fb-emergency__copy .cta-btn{
  white-space:normal;
  max-width:100%;
}

/* Roma's closing band is not a CTA — it is an H2, an H3 and the list of
   zones covered, all set white on the dark fill by inline styles on the
   old page. The colour is why the band exists, so it moves here; the
   inline styles do not survive (CSS rule 3). */
.fb-emergency h3{
  margin:0 0 18px;
  font-family:var(--font-display);
  font-size:clamp(1.05rem,.95rem + .5vw,1.3rem);
  font-weight:700; line-height:1.3;
  color:var(--paper-000); letter-spacing:.01em;
}
/* Torino only: the source's zone-list sub-label is a real <h4>, one
   level below Roma's <h3> above. No .fb-emergency h4 existed, so this
   is new — same small-eyebrow visual language .fb-areas__title and
   .section-kicker already use elsewhere, recoloured to read on the
   dark fill instead of restyled from scratch. */
.fb-emergency h4{
  margin:0 0 10px;
  font-family:var(--font-body); font-weight:700;
  font-size:.82rem; letter-spacing:.06em; text-transform:uppercase;
  color:var(--green-100);
}
/* Zone chips on the dark fill: the light rules and dark ink of the
   default .fb-taglist are invisible here, so both invert. */
.fb-emergency .fb-taglist{ text-align:left; margin-top:4px; }
.fb-emergency .fb-tag{
  color:var(--paper-000);
  border-bottom-color:rgba(255,255,255,.16);
}
.fb-emergency .fb-tag::before{ background:var(--amber-400); }

/* Closing call button under the service cards — Valle d'Aosta.
   The old page ends that block with a call button of its own, centred
   under the last card. .features has no such slot, so one is defined
   here rather than reaching for an inline style (CSS rule 3). */
.features__cta{
  margin:clamp(34px,4vw,52px) 0 0;
  text-align:center;
}

/* 6b. Two-column closing band — Ticino and Valle d'Aosta.

   Both pages carry a standalone photo the city pages do not, wrapped in an
   empty <h4> by the old builder. It used to sit in a band of its own between
   the last service card and the call bar, where a single image in an
   otherwise empty strip read as a stray upload. The owner asked for it
   beside the closing CTA instead, so this modifier turns that band into two
   columns: copy and call button on the left, photo on the right.

   The base .fb-emergency-inner is a centred 820px column, so both the
   width cap and the centring have to be undone here, not just the
   text-align — otherwise the grid is squeezed into 820px in the middle of
   a full-width band and the photo never reaches the right. */
.fb-emergency--split .fb-emergency-inner{
  max-width:min(1100px,100%);
  display:grid;
  grid-template-columns:1fr;
  align-items:center;
  gap:clamp(28px,4vw,56px);
  text-align:center;
}
@media (min-width:860px){
  .fb-emergency--split .fb-emergency-inner{
    /* The photo's track is a SIZED track, not minmax(0,auto). The image is
       lazy and below the fold, so with an auto track the column measured 0px
       until the file arrived and then jumped to 537px as the reader scrolled
       into it — a layout shift, on a page targeting CLS < 0.05. A sized
       track reserves the column whether the image has loaded or not. */
    grid-template-columns:minmax(0,1fr) clamp(280px,40%,537px);
    text-align:left;
  }
}
/* The label keeps the band's white type; the button must not stretch to the
   column width, so the copy side is a column that shrink-wraps its button. */
.fb-emergency__copy{
  display:flex; flex-direction:column; align-items:center;
  gap:clamp(18px,2.2vw,26px);
  /* Same min-width:auto grid-item trap as .fb-tag above, one level up:
     this is itself the grid item sitting in .fb-emergency-inner's
     minmax(0,1fr) track. Without this, its own automatic minimum width
     is driven by its widest child's content instead of the track's
     available space — Torino's H3 label and CHIAMA SUBITO button (both
     long, unwrapped/undersquished content) were winning that tug-of-war
     and forcing the whole column past the viewport at 320px, the same
     failure shape as the taglist fix above but one layer higher. */
  min-width:0;
}
@media (min-width:860px){
  .fb-emergency__copy{ align-items:flex-start; }
}
/* p:last-of-type in the base block adds 32px under the label; inside this
   flex column the gap above already spaces it, so the margin is cleared.
   The label is also scaled up from the base 16.5px: beside a 537px photo
   it read as a caption rather than as the closing line of the page. Only
   the split variant is touched, so every other closing band is unchanged. */
/* :first-of-type, not every p. The band's LABEL is the display-size line;
   Udine's closing column also carries "Alcune delle zone dove operiamo…"
   and a list of towns after it, and those must stay at reading size. On
   every other split page the label is the only <p> here, so scoping this
   changes nothing for them. */
.fb-emergency--split .fb-emergency__copy > p:first-of-type{
  margin:0;
  font-family:var(--font-display);
  font-size:clamp(1.25rem,1rem + 1.1vw,1.85rem);
  font-weight:800; line-height:1.2;
  color:var(--paper-000);
  letter-spacing:.01em;
  text-wrap:balance;
}
/* Any later paragraph in that column is body copy. */
.fb-emergency--split .fb-emergency__copy > p ~ p{
  margin:0;
  font-size:16.5px; line-height:1.75;
  color:var(--green-100);
}

/* Udine's list of towns, inside that same column.

   width:100% is load-bearing again. .fb-emergency__copy is a flex column
   with align-items:flex-start (center below 860px), which stops a child
   stretching — so the grid shrank to ONE 210px track inside a 604px column
   and the 18 towns ran down a single file. The same trap as the media box
   above.

   Two explicit tracks rather than auto-fill: the column is a fixed ~604px
   whatever the viewport does, so auto-fill would always resolve to 2 anyway,
   and stating it keeps the count from drifting if the split ratio is ever
   retuned. Scoped to --split so Roma's wider centred band, which auto-fills
   to 3, is not touched.

   OWNER'S FIX, 22 Sep 2026 — moved inside the >=860px band. This was
   written for Udine's ~604px desktop column and was unconditional, so
   below 860px — where .fb-emergency--split stacks to one column and
   .fb-emergency__copy is the full (narrow) viewport width — it still
   forced 2 fixed tracks. minmax(0,…) only floors a TRACK; the grid
   ITEM sitting in it (and .fb-emergency-inner's own 1fr track above
   it) still defaults to min-width:auto, so the row's min-content
   width won instead of the viewport and the second column ran off the
   right edge. Never visible on Udine's shorter list, but Torino's
   longer one pushed it past the point of being a rounding error — a
   real ~20px overflow at 320px, not the usual decorative-shape false
   positive. Below 860px this now falls back to the general
   .fb-taglist auto-fill rule, which resolves to one column on its
   own in a narrow flex item. Re-verified Udine at 320–1440px after
   the change: unaffected, still 2 columns from 860px up. */
@media (min-width:860px){
  .fb-emergency--split .fb-emergency__copy .fb-taglist{
    width:100%;
    grid-template-columns:repeat(2,minmax(0,1fr));
    column-gap:clamp(16px,2vw,28px);
  }
}
/* Narrower tracks mean the longer names wrap, so the dot aligns to the
   first line instead of the middle of a two-line entry. */
.fb-emergency--split .fb-emergency__copy .fb-tag{ align-items:flex-start; }
.fb-emergency--split .fb-emergency__copy .fb-tag::before{ margin-top:6px; }

/* Alessandria only: a third .fb-emergency shape. Roma is one centred
   column with real headings; Udine/Torino are --split with a photo.
   This page's source closing band is two plain <p> columns side by
   side — a label+button column and a zone-list column — with no
   photo and no heading anywhere in either one. Reuses --split's
   two-column grid idea with no sized photo track, since there is
   nothing to reserve space for; the right column gets its own class
   (.fb-emergency__areas) rather than reusing .fb-emergency__copy
   twice, because the two columns' first paragraphs need different
   treatment (a big label on the left, a small eyebrow on the right)
   and one shared class name would have made that ambiguous to style. */
.fb-emergency--twocol .fb-emergency-inner{
  max-width:min(1100px,100%);
  display:grid;
  grid-template-columns:1fr;
  align-items:start;
  gap:clamp(28px,4vw,56px);
  text-align:center;
}
@media (min-width:860px){
  .fb-emergency--twocol .fb-emergency-inner{
    grid-template-columns:minmax(0,1fr) minmax(0,1.3fr);
    text-align:left;
  }
}
.fb-emergency--twocol .fb-emergency__copy > p:first-of-type{
  margin:0;
  font-family:var(--font-display);
  font-size:clamp(1.25rem,1rem + 1.1vw,1.85rem);
  font-weight:800; line-height:1.2;
  color:var(--paper-000);
  letter-spacing:.01em;
  text-wrap:balance;
}
.fb-emergency__areas{
  display:flex; flex-direction:column; align-items:center;
  gap:clamp(14px,1.8vw,20px);
  min-width:0;
}
@media (min-width:860px){
  .fb-emergency__areas{ align-items:flex-start; }
}
/* Same small-eyebrow visual language as .fb-emergency h4 (Torino) and
   .fb-areas__title (Mantova/Milano) — this line is a <p> in the
   source, not a heading, so it borrows that look via a class instead
   of promoting it to an element hard rule 9 would then have to treat
   as new heading structure. */
.fb-emergency__areas > p:first-of-type{
  margin:0;
  font-family:var(--font-body); font-weight:700;
  font-size:.82rem; letter-spacing:.06em; text-transform:uppercase;
  color:var(--green-100);
}
@media (min-width:860px){
  .fb-emergency__areas .fb-taglist{
    width:100%;
    grid-template-columns:repeat(2,minmax(0,1fr));
    column-gap:clamp(16px,2vw,28px);
  }
}
.fb-emergency__areas .fb-tag{ align-items:flex-start; }
.fb-emergency__areas .fb-tag::before{ margin-top:6px; }

.fb-emergency__media{
  border-radius:var(--radius-l);
  overflow:hidden;
  box-shadow:var(--shadow-pop);
  /* A pale sheet behind the photo, so the frame still reads as a frame
     while the file is missing from the local uploads copy (A14) and the
     <img> renders as nothing at all. */
  background:rgba(255,255,255,.06);
  /* width:100% is load-bearing. margin-inline:auto turns OFF a grid item's
     default stretch, so without an explicit width this box shrink-wrapped
     its content — and its only child is a lazy <img> that renders at zero
     until it loads. The frame measured 0x0 on arrival and snapped to full
     size as the reader scrolled in. With width:100% the box fills its
     track, and the auto margins only do anything in the single-column
     layout below 860px, where the cap actually bites. */
  width:100%;
  max-width:min(537px,100%);
  margin-inline:auto;
}
/* Chieti's closing photo is wrapped in an off-site link (hard rule 8 —
   flagged, not removed), so the anchor has to behave like the <img> it
   replaces. Without this it is an inline box that shrink-wraps, and the
   frame stops matching the picture. Inert on the pages whose photo is a
   bare <img>. */
.fb-emergency__media a:has(img){ display:block; width:100%; }
.fb-emergency__media img{
  display:block;
  width:100%; height:auto;
  /* No aspect-ratio here on purpose. An earlier version hardcoded 537/302,
     Ticino's photo — which would have squashed Valle d'Aosta's 541x333 into
     the wrong shape. With width:100%, height:auto and the width/height
     ATTRIBUTES both present in the markup, the browser derives the ratio
     from the attributes per image, so the height is reserved before the
     lazy file arrives without any per-page value here. */
}

/* Torino only: photo on the left, copy on the right — the mirror of
   every other .fb-emergency--split page — plus a smaller frame with a
   white ground instead of the pale sheet. Owner's call, 22 Sep 2026,
   purely visual (hard rule 9 protects heading level/text, not which
   side a block sits on or its frame colour). `order` swaps which grid
   track each child renders in without touching DOM order, so reading
   order and the underlying markup are unchanged. Scoped to this
   modifier only — Udine keeps its own copy-left/photo-right shape and
   pale sheet untouched. The photo's track stays an explicitly SIZED
   track (not minmax(0,auto)), same reason as the base rule above: it
   reserves the column before the lazy image arrives, so this still
   doesn't cost any CLS. */
@media (min-width:860px){
  .fb-emergency--media-left .fb-emergency-inner{
    grid-template-columns:clamp(220px,32%,420px) minmax(0,1fr);
  }
  .fb-emergency--media-left .fb-emergency__media{ order:1; }
  .fb-emergency--media-left .fb-emergency__copy{ order:2; }
}
.fb-emergency--media-left .fb-emergency__media{
  max-width:min(420px,100%);
  background:var(--paper-000);
}
/* Widened to match .container's own cap (--max-w, global.css) — the same
   width the service cards above this band render at — instead of the base
   component's 1100px. More room for the copy column means fewer comuni
   wrap onto a second line inside their cell. */
.fb-emergency--media-left .fb-emergency-inner{
  max-width:min(var(--max-w),100%);
}
/* The copy column is now the wide flexible track instead of Udine's fixed
   ~604px, so its taglist has room for more than the base 2-column rule
   above. Same per-column width as that already-proven 2-column layout
   (~147-155px) at both steps, just spread over more columns instead of
   fewer — checked against the measured column width at each breakpoint
   before picking these two numbers, not guessed. Source order matters
   here: same specificity (three classes) as the .fb-emergency--split rule
   above, so this only wins because it comes after it in the file. */
@media (min-width:860px){
  .fb-emergency--media-left .fb-emergency__copy .fb-taglist{
    grid-template-columns:repeat(3,minmax(0,1fr));
  }
}
@media (min-width:1150px){
  .fb-emergency--media-left .fb-emergency__copy .fb-taglist{
    grid-template-columns:repeat(4,minmax(0,1fr));
  }
}

/* ============================================================
   7. CITY PAGES  (fabbro-milano, fabbro-roma, ...)
   Nothing here is Milan-specific — every city page reuses it.

   These pages are built almost entirely from global.css
   components: .hero--split for the hero, .tile-strip/.tile for the
   service strip, .about__grid/__media/__content for the text+image
   splits, .features/.feature-card for the service cards, .btn for
   every button, and the sticky .call-bar. Pricing comes from
   prezzi.css. Only the five rules below are genuinely new.
============================================================ */

/* 7b. Alternating background for a second .about block on one page,
   so two text+image sections don't run together. */
.about--tint{ background:var(--green-050); }

/* An .about block whose text column carries a list rather than a
   paragraph needs more than half the row. 62/38 instead of 50/50 —
   enough for three comune columns, while the map still reads at its
   own scale. Only above 900px: below that global.css §9's auto-fit
   is already collapsing the grid, and this must not fight it. */
@media (min-width:900px){
  .about__grid--wide-text{
    grid-template-columns:minmax(0,1.62fr) minmax(0,1fr);
  }
}

/* global.css §9 colours every link inside .about__content green, and
   only exempts .btn--white — which turns a .btn--primary placed there
   into green-on-orange. Put the button's own colour back. */
.about__content a.btn--primary,
.about__content a.btn--primary:hover,
.about__content a.btn--primary:focus-visible{ color:var(--paper-000); }
.about__content a.btn--primary .icon-phone{ color:inherit; }

/* 7b-bis. A paragraph the old page hangs BELOW an .about row rather than
   inside either of its columns — Montesilvano.

   Its source row has three columns: copy left, photo right, and then a
   col-sm-12 carrying one more paragraph across the full width. Dropping
   that paragraph into .about__content would have put it beside the photo
   and after the call button, which reads as an afterthought to the CTA
   rather than as the close of the intro. So it sits outside .about__grid,
   inside the same .container.

   NO max-width: it runs the full container, which is what col-sm-12 means
   on the old page. An earlier version capped it at 78ch to keep the line
   length near the copy column's; that was overruled — the paragraph is the
   full-width close of the section and reads as one. */
.about__tail{
  margin:clamp(28px,3.4vw,44px) 0 0;
}
/* On Montesilvano .about__tail IS the paragraph. On Chieti that full-width
   column holds two things — the services line and the call button — so the
   class goes on a wrapper instead. global.css leaves <p> at margin:0 and
   lets each component space its own children, so that spacing is set here.
   Inert where the tail has no element children. */
.about__tail > * + *{ margin-top:clamp(18px,2.2vw,26px); }

/* 7c. .feature-card__icon is built for a 24px inline SVG; these pages
   put a PNG in it, at the artwork's own 128px so it stays crisp. The
   chip grows to fit rather than the image shrinking to fit the chip. */
.feature-card__icon img{
  width:128px; height:128px; object-fit:contain; display:block;
}
/* Bergamo puts two icons in one card (its page builder left the last
   two cards' artwork stranded in an earlier column). Stack them so the
   chip stays one icon wide instead of doubling the column. */
.feature-card__icon:has(img + img){
  flex-direction:column;
  gap:12px;
}
.feature-card__icon:has(img){
  /* fit-content, not auto: as a block child it would otherwise stretch
     the tint panel across the whole card on a phone */
  width:fit-content; height:auto;
  padding:16px; border-radius:20px;
}

/* Pisa only: the source's "Servizi" heading is a real <h2>, one level
   above every other page's <h3>/"I servizi" here — kept at its own
   level (hard rule 9 protects level and text, not visual weight).
   Unstyled, global.css's h2 is roughly double h3's size and would
   read as an oversized outlier next to every sibling page's section
   title, so this restyles it down to the exact size/weight h3 already
   renders at in this same context. */
.features__head--center h2:where(:not(.h1-look)){
  font-size:clamp(1.15rem,1.05rem + .5vw,1.45rem);
  font-weight:700;
}

/* 7c-bis. One card per row, artwork left and copy right — for the
   long service write-ups, where a three-up grid left each card a
   narrow column of dense text. Reusable on any city page.

   --cols-max is global.css's own grid knob (§"Fluid grids"), so the
   column count changes without redefining the grid.

   The card is a two-item flex row — artwork, then a .feature-card__body
   holding the heading and however many paragraphs the card has. A grid
   was the first attempt and was wrong: the icon's row sized to 160px,
   which pushed the first paragraph that far below the heading. */
.features__grid--rows{
  --cols-max:1;
}
.feature-card__body > :last-child{ margin-bottom:0; }
/* global.css leaves <p> at margin:0 and lets each component space its
   own paragraphs (§FAQ, §region-panel do the same). Feature cards never
   had the rule, so the two-paragraph cards ran together. */
.feature-card__body p + p{ margin-top:var(--space-xs); }

@media (max-width:859px){
  /* Below 860px the card is a stacked column — the icon-left/copy-right
     row below is ≥860px only — so a left-aligned chip sitting over
     left-aligned copy read as two things that happened to land on the
     left, not a deliberate single column. Centering both reads as one
     stack. Scoped here (not a bare rule reset again at ≥860px) so the
     existing row layout is untouched by construction.

     .feature-card__icon is already width:fit-content (7c, so the tint
     chip hugs a single 128px icon instead of stretching); margin-inline
     auto is what centers a fit-content block, and it also centers
     Bergamo's stacked two-icon case (:has(img + img) above) as one unit
     without a separate rule. */
  .features__grid--rows .feature-card{ text-align:center; }
  .features__grid--rows .feature-card__icon{ margin-inline:auto; }
  /* Icon trimmed a little: centred and full-size it read as heavier at
     the top of the card than the same 128px did sitting to the left. */
  .features__grid--rows .feature-card__icon img{ width:104px; height:104px; }
}

@media (min-width:860px){
  .features__grid--rows .feature-card{
    display:flex; align-items:flex-start;
    gap:clamp(28px,3.2vw,48px);
    padding:clamp(28px,3vw,38px) clamp(28px,3vw,38px) clamp(26px,2.8vw,34px);
  }
  .features__grid--rows .feature-card__icon{
    flex:none; margin-bottom:0;
  }
  /* min-width:0 so a long word can't push the column wider */
  .features__grid--rows .feature-card__body{ flex:1 1 auto; min-width:0; }
  /* the heading sits level with the top of the artwork */
  .features__grid--rows .feature-card__body > :first-child{ margin-top:2px; }

  /* Owner's rule, 21 Sep 2026 — moved here from the mobile block on the
     same day, at the owner's correction: an EVEN number of cards goes
     two-up on DESKTOP; an ODD count stays the single full-width row
     layout above, exactly as it already renders — untouched, because
     nothing here matches an odd count and no existing rule is edited.
     Mobile is back to always one stacked column, as it was before this.

     No JS and no per-page class: the standard pure-CSS "quantity query"
     (Heydon Pickering). :first-child:nth-last-child(even) matches an
     element only when it is BOTH the first child AND an even number of
     positions from the last — which happens for the first child only
     when the total sibling count is itself even. :has() lets the GRID
     react to that fact about its children, so the column count is a
     function of how many cards the page happens to have, decided at
     render time, not authored per page.

     min-width:0 on the card stops a long unbroken word (there aren't
     any in this copy, checked) from forcing the column wider than its
     share. */
  .features__grid--rows:has(.feature-card:first-child:nth-last-child(even)){
    grid-template-columns:repeat(2,minmax(0,1fr));
    column-gap:clamp(24px,2.8vw,40px);
  }

  /* The icon-left/copy-right row above doesn't fit a half-width column
     the way it fits the full-width one: at ~600px wide that row was
     fine, but the same 128px icon and 48px gap left the two-up column
     cramped. So the two-up card is NOT the row layout, narrower — it is
     the mobile card's own stacked, centred treatment from the block
     above, reused rather than re-invented, with the icon at the same
     104px. Only .feature-card__body > :first-child's 2px margin-top
     (set for the row layout, to line the heading up with the icon's
     top edge) is left alone here — with everything centred and stacked
     it is not visible either way, so it isn't worth a fourth selector
     to reset it. */
  .features__grid--rows:has(.feature-card:first-child:nth-last-child(even)) .feature-card{
    display:block;
    text-align:center;
    min-width:0;
  }
  .features__grid--rows:has(.feature-card:first-child:nth-last-child(even)) .feature-card__icon{
    margin:0 auto 20px;
  }
  .features__grid--rows:has(.feature-card:first-child:nth-last-child(even)) .feature-card__icon img{
    width:104px; height:104px;
  }

  /* Exactly six cards: same quantity-query technique, narrowed to a count
     of six. :nth-last-child(6) matches the first child only when it is
     also the 6th-from-last, which happens only when there are exactly
     six siblings total. Placed after the even-count rule above so it
     wins on equal specificity via source order; every other even count
     (4, 8, ...) still gets two columns from that rule. The centred,
     stacked card/icon treatment above already matches six along with
     every other even count, so only the column arrangement is
     overridden here.

     The owner's correction, same day: three-up read fine for the first
     three cards, but the last three each carry a third paragraph — at
     three-up that's noticeably too little width per column for the
     extra text, so they drop to two-up instead. One 6-column base grid
     covers both groups: the first three each span 2 of 6 (three-up),
     the last three each span 3 of 6 (two-up) — which leaves the sixth
     card with nothing to sit beside, so it spans the full width alone
     on its own row rather than sitting half-empty next to a gap. */
  .features__grid--rows:has(.feature-card:first-child:nth-last-child(6)){
    grid-template-columns:repeat(6,minmax(0,1fr));
    column-gap:clamp(20px,2.4vw,32px);
  }
  .features__grid--rows:has(.feature-card:first-child:nth-last-child(6)) .feature-card:nth-child(-n+3){
    grid-column:span 2;
  }
  .features__grid--rows:has(.feature-card:first-child:nth-last-child(6)) .feature-card:nth-child(n+4){
    grid-column:span 3;
  }
  .features__grid--rows:has(.feature-card:first-child:nth-last-child(6)) .feature-card:nth-child(6){
    grid-column:span 6;
  }
}

/* 7c-ter. Lucca's third row pairs a real card with a plain coverage-map
   photo, not a fourth card — the source has no icon/heading for it,
   just a bare <img>. .feature-media sits in the same grid as
   .feature-card but skips the icon+body chrome entirely, matching the
   source's own plain treatment rather than inventing a card shell
   around it. */
.features__grid--rows .feature-media{
  display:flex; align-items:center; justify-content:center;
}
.features__grid--rows .feature-media img{
  max-width:100%; height:auto; border-radius:var(--radius-m);
}

/* 7c-ter DELETED — .features__closing is gone.

   It used to stack the closing photo and a call button under the last
   service card, on the light background. The owner rejected that shape on
   21 Sep 2026: the photo belongs INSIDE the closing CTA, as its right-hand
   column, which is exactly the ruling already given for Ticino on 18 Sep
   (F7). Pescara, Chieti, Teramo and Vicenza now all use
   .fb-emergency--split (§6b) like every other page that ends on a picture,
   and the duplicate call button above the photo is removed on the three
   that had one.

   Nothing references .features__closing any more, so it is deleted rather
   than left to rot — the same call made about .fb-shot when Ticino's band
   was dissolved. The only thing that block had which §6b did not is the
   linked-photo rule, which moves there. */

/* 7d. STORY — the long copy blocks as a numbered editorial run.
   Deliberately NOT cards: the page already has four card grids
   (tiles, pricing, services, chips) and a fifth made the whole thing
   read as one long row of boxes. Here the structure comes from a
   numbered marker and a hairline rail instead of borders.

   The numerals are a CSS counter, so they exist only in the render —
   nothing is added to the DOM or to the page's copy. */
.fb-story{ background:var(--paper-050); }
.fb-story__inner{
  max-width:940px;
  counter-reset:fb-story;
}

/* Roma opens its story section with an H2 and two paragraphs that sit
   above the numbered blocks and belong to none of them. Kept outside
   .fb-story__block on purpose: inside, it would take a counter numeral
   and a rail segment it has no business having. */
/* Full width of the inner, not a 68ch column.

   The 68ch cap left the head 605px wide inside a 940px inner while the
   numbered blocks below started 78px further right and ran to 952 — so the
   intro and the blocks shared neither edge, and ~335px sat empty beside the
   intro. The head now spans the section and the blocks are centred under it
   (see .fb-story__block), which gives the two parts one deliberate
   relationship instead of two accidental ones. */
.fb-story__head{
  margin:0 0 clamp(28px,3.5vw,44px);
}
.fb-story__head h2:where(:not(.h1-look)){
  margin:0 0 16px;
  font-family:var(--font-display);
  font-size:clamp(1.55rem,1.2rem + 1.4vw,2.3rem);
  font-weight:800; line-height:1.2;
  color:var(--green-900); letter-spacing:-.01em;
}
.fb-story__head p{
  margin:0 0 16px;
  font-size:16.5px; line-height:1.8;
  color:var(--ink-700); text-align:left;
}
.fb-story__head p:last-child{ margin-bottom:0; }
.fb-story__head strong{ color:var(--green-900); font-weight:700; }
.fb-story__head a{ color:var(--green-700); font-weight:700; }
.fb-story__head a:hover{ color:var(--amber-600); }

/* Centred as a group under the full-width head.

   The cap was 760px, which left ~624px of content — one track short of the
   three columns the keyword run used to get when blocks filled the section.
   880px restores that (about 800px of content, comfortably three 210px
   tracks) while keeping a visible inset inside the 940px section, so the
   blocks still read as centred rather than flush. */
.fb-story__block{
  position:relative;
  counter-increment:fb-story;
  padding:0 0 clamp(36px,4vw,52px) clamp(56px,6vw,78px);
  max-width:880px;
  margin-inline:auto;
}
.fb-story__block:last-child{ padding-bottom:0; }

/* The numeral sits in its own disc at the head of the rail. */
.fb-story__block::before{
  content:counter(fb-story,decimal-leading-zero);
  position:absolute; left:0; top:0;
  width:44px; height:44px; border-radius:50%;
  display:flex; align-items:center; justify-content:center;
  background:var(--paper-000);
  border:1px solid var(--line-200);
  font-family:var(--font-display);
  font-size:.95rem; font-weight:800; letter-spacing:.02em;
  color:var(--amber-600);
}
/* Hairline rail joining one block to the next. */
.fb-story__block::after{
  content:""; position:absolute;
  left:22px; top:56px; bottom:12px; width:1px;
  background:linear-gradient(var(--line-200),transparent);
}
.fb-story__block:last-child::after{ display:none; }

.fb-story__block h3{
  margin:6px 0 16px;
  font-family:var(--font-display);
  font-size:clamp(1.2rem,1.05rem + .6vw,1.6rem);
  font-weight:800; line-height:1.25;
  color:var(--green-900); letter-spacing:-.01em;
}
.fb-story__block p{
  margin:0 0 16px;
  font-size:16.5px; line-height:1.8;
  color:var(--ink-700);
  /* left-aligned on purpose: justified text at this measure opens
     rivers, which is what made the old version look ragged */
  text-align:left;
  max-width:68ch;
}
.fb-story__block p:last-child{ margin-bottom:0; }
.fb-story__block strong{ color:var(--green-900); font-weight:700; }
.fb-story__block a{ color:var(--green-700); font-weight:700; }
.fb-story__block a:hover{ color:var(--amber-600); }
.fb-story__block .fb-taglist{ margin-top:20px; }
/* Three columns for the keyword run, stated rather than left to auto-fill.
   auto-fill resolves from the track floor, so a few pixels lost anywhere in
   the chain silently drops it to two — which is exactly what happened when
   the blocks were first capped. Below 900px it falls back to the auto-fill
   rule above, and below 620px to the explicit two-column phone rule. */
@media (min-width:900px){
  .fb-story__block .fb-taglist{ grid-template-columns:repeat(3,minmax(0,1fr)); }
}

@media (max-width:620px){
  .fb-story__block{ padding-left:0; padding-bottom:34px; }
  .fb-story__block::before{
    position:static; margin-bottom:14px;
    width:38px; height:38px; font-size:.85rem;
  }
  .fb-story__block::after{ display:none; }
}

/* Lets two .features sections sit next to each other without their
   backgrounds merging into one block. */
.features--plain{ background:var(--paper-000); }

/* 7e. Pipe-separated runs rendered as chips — see _taglist.php.
   Each entry gets its own pill with a dot marker; the original "|"
   characters are still in the DOM inside .fb-tag__sep, just not
   painted, so nothing is removed from the copy. */
/* An aligned index, not wrapped pills. Entries vary from "SOS Fabbro"
   to "Installazione Cilindri di Sicurezza", so free-flowing chips gave
   ragged rows with uneven gaps. Equal grid tracks line every entry up
   on both axes; the hairline under each one carries the eye across. */
.fb-taglist{
  display:grid;
  grid-template-columns:repeat(auto-fill,minmax(210px,1fr));
  gap:0 clamp(20px,2.5vw,34px);
  list-style:none; margin:0; padding:0;
}
.fb-tag{
  display:flex; align-items:center; gap:10px;
  padding:10px 2px;
  border-bottom:1px solid var(--line-200);
  font-size:14px; font-weight:600; line-height:1.4;
  color:var(--green-900);
  /* A grid item defaults to min-width:auto (content-based), same as a
     flex item — the minmax(0,…) on the track above only sizes the
     TRACK, not this item sitting in it. Torino's zone list is the
     first taglist long enough to expose it: without this, a couple of
     tags in the narrow single-column mobile layout refused to shrink
     below their own min-content width and pushed the row past the
     viewport. Same fix already used on .feature-card elsewhere. */
  min-width:0;
}
.fb-tag::before{
  content:""; flex-shrink:0;
  width:5px; height:5px; border-radius:50%;
  background:var(--amber-500);
}
/* The separators stay in the DOM for crawlers and copy-paste. */
.fb-tag__sep{
  position:absolute; width:1px; height:1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap;
}

/* The "Fabbro Vicino a Me" index runs to 40 comuni and sits in the
   narrower about column (the map takes the other half), where auto-fill
   only ever found room for two tracks. Pin the count instead: two
   columns everywhere, three once the viewport is wide enough that the
   text column can carry them. minmax(0,1fr) lets a long comune wrap
   rather than push its track wider than the others.
   The 1200px floor is deliberate — below it the about grid is still
   two-up, so a third track would drop to ~130px and break names like
   "Fabbro a Trezzano sul Naviglio" across three lines. */
.fb-taglist--areas{
  grid-template-columns:repeat(2,minmax(0,1fr));
  column-gap:clamp(14px,1.6vw,24px);
}
@media (min-width:1200px){
  .fb-taglist--areas{ grid-template-columns:repeat(3,minmax(0,1fr)); }
}
/* Narrower tracks mean some names wrap, so the dot aligns to the
   first line rather than to the middle of a two-line entry. */
.fb-taglist--areas .fb-tag{ align-items:flex-start; }
.fb-taglist--areas .fb-tag::before{ background:var(--green-700); margin-top:6px; }

/* 7e-sexies. Closing media block.

   Rieti ends on a photo plus one call button. Dropped into the hub's
   .fb-closing-media the two just stacked hard-left in a 1240px block —
   a button floating above a raw photo with 850px of dead space beside
   them. This gives them a shape.

   DOM order is button then image, because that is the order the old
   page has and a crawler should see it unchanged. Visually the photo
   comes first and the button sits under it, which is the order that
   reads properly — column-reverse does that without touching the DOM. */
.fb-final{
  position:relative;
  isolation:isolate;
  overflow:hidden;
  background:
    linear-gradient(160deg,
      var(--green-950) 0%,
      var(--green-900) 60%,
      var(--green-800) 100%);
  padding:clamp(44px,5vw,76px) 5vw;
}
/* Same off-centre amber light as the banner and the services panel. */
.fb-final::before{
  content:"";
  position:absolute; z-index:-1;
  inset:auto auto -45% -12%;
  width:min(620px,70%); aspect-ratio:1;
  border-radius:50%;
  background:radial-gradient(circle,rgba(255,81,0,.26) 0%,rgba(255,81,0,0) 70%);
  pointer-events:none;
}
/* Two columns above 900px: the closing line and its call button on the
   left, the photo on the right. Below that they stack, copy first. */
.fb-final__inner{
  display:grid;
  gap:clamp(26px,3.5vw,54px);
  align-items:center;
  max-width:var(--max-w);
  margin-inline:auto;
}
@media (min-width:900px){
  .fb-final__inner{
    grid-template-columns:minmax(0,.9fr) minmax(0,1.1fr);
  }
}

.fb-final__copy{ text-align:center; }
@media (min-width:900px){
  .fb-final__copy{ text-align:left; }
}
/* Scoped to beat ".fb-final__copy p" below, which is a type+class
   selector and would otherwise zero this margin and tuck the amber rule
   in behind the button. */
.fb-final__copy .fb-final__title{
  /* Bottom margin has to clear the amber rule below the text AND leave
     the button room. */
  margin:0 0 clamp(28px,3.2vw,40px);
  font-family:var(--font-display);
  font-size:clamp(1.5rem,1.1rem + 1.7vw,2.4rem);
  font-weight:800; line-height:1.15;
  color:var(--paper-000);
  letter-spacing:-.01em;
  text-wrap:balance;
}
/* Amber rule, matching the banner and the services title. */
.fb-final__title::after{
  content:"";
  display:block;
  width:56px; height:3px; border-radius:3px;
  margin:18px auto 0;
  background:var(--amber-500);
}
@media (min-width:900px){
  .fb-final__title::after{ margin-inline:0; }
}
.fb-final__copy p{ margin:0; }

/* The photo gets a frame so it reads as a finished element rather than
   a loose asset dropped on a dark field. */
.fb-final__media img{
  display:block;
  width:100%; height:auto;
  border-radius:var(--radius-l);
  border:1px solid rgba(255,255,255,.14);
  box-shadow:0 24px 60px rgba(0,0,0,.38);
}

/* 7e-quater. Full-width heading band.

   Tivoli carries a SECOND <h1> of its own — "FABBRO A TIVOLI" — in a
   full-width coloured row directly under the hero, set white by an
   inline style. The heading is reproduced at its original level (see
   that page's file for why it is not demoted); this band is what
   carries the white text now the inline style is gone.

   A flat block of navy with centred text read as a placeholder, so the
   band is built rather than filled: a diagonal brand gradient, one
   off-centre amber glow to stop the field going dead, and a short rule
   under the heading to tie it to the accent used elsewhere. All of it
   is ::before/::after and gradients — no extra DOM, no added copy. */
.fb-banner{
  position:relative;
  isolation:isolate;
  overflow:hidden;
  padding:clamp(34px,4.6vw,58px) 5vw;
  text-align:center;
  background:
    linear-gradient(118deg,
      var(--green-950) 0%,
      var(--green-900) 52%,
      var(--green-800) 100%);
}
/* Soft amber light, off to one side so the band has a direction. */
.fb-banner::before{
  content:"";
  position:absolute; z-index:-1;
  inset:-60% -10% auto auto;
  width:min(560px,60%); aspect-ratio:1;
  border-radius:50%;
  background:radial-gradient(circle,rgba(255,81,0,.30) 0%,rgba(255,81,0,0) 68%);
  pointer-events:none;
}
/* Hairline top edge, so the band separates from the hero above it. */
.fb-banner::after{
  content:"";
  position:absolute; inset:0 0 auto 0; height:1px;
  background:linear-gradient(90deg,
    transparent, rgba(255,255,255,.18) 30%, rgba(255,255,255,.18) 70%, transparent);
}
/* h1 AND h2: Tivoli's band is still the page's second <h1>, Ticino's was
   demoted to <h2> on the owner's instruction (_PHASE-6-LOG.md A8). The band
   looks the same either way — the level is a document-outline decision, not
   a visual one — so both are styled here rather than duplicating the block. */
.fb-banner h1,
.fb-banner h2:where(:not(.h1-look)),
/* h1 AND h2: Tivoli's band is still the page's second <h1>, Ticino's was demoted to <h2> on the owner's instruction (_PHASE-6-LOG.md A8). The band looks the same either way — the level is a document-outline decision, not a visual one — so both are styled here rather than duplicating the block. */ .fb-banner h2:where(.h1-look){
  position:relative;
  margin:0;
  font-family:var(--font-display);
  font-size:clamp(1.5rem,1.1rem + 1.6vw,2.35rem);
  font-weight:800; line-height:1.15;
  color:var(--paper-000);
  letter-spacing:.01em;
  text-wrap:balance;
}
/* Short amber rule under the heading. */
.fb-banner h1::after,
.fb-banner h2:where(:not(.h1-look))::after,
/* Short amber rule under the heading. */ .fb-banner h2:where(.h1-look)::after{
  content:"";
  display:block;
  width:64px; height:3px; border-radius:3px;
  margin:18px auto 0;
  background:var(--amber-500);
}

/* Ticino's band carries a call button of its own, where Tivoli's is
   heading-only. It sits under the amber rule, centred. Still a flex row
   that wraps: it held two buttons until the owner removed the duplicate
   "Vedi i prezzi", and one button must not be stranded if another returns. */
.fb-banner__actions{
  position:relative;
  margin-top:clamp(22px,2.6vw,30px);
  display:flex; flex-wrap:wrap; justify-content:center;
  gap:clamp(12px,1.4vw,16px);
}

/* 7e-quinquies. Services section for the city pages that have NO
   per-service cards — Velletri and Tivoli.

   Those pages are one heading, one long paragraph and a seven-item tick
   list. Run through .fb-story that came out as a narrow column of prose
   with the right-hand 40% of the page empty and the list hanging off the
   bottom: technically correct, visibly unfinished.

   Here the two halves are given jobs. The prose keeps a readable measure
   on the left; the tick list becomes a raised panel on the right that
   holds the column and sticks while the prose scrolls past it. Below
   1000px it stacks, panel last, which is the right reading order anyway.

   No copy is added — the panel has no heading of its own because the old
   page does not give it one. */
.fb-services{
  background:
    linear-gradient(180deg,var(--paper-000) 0%,var(--paper-050) 100%);
}
.fb-services__grid{
  display:grid;
  gap:clamp(28px,3.5vw,54px);
  /* stretch, not start: the panel fills the full height of the row so
     the column never ends in a stump of dead space under it */
  align-items:stretch;
}
@media (min-width:1000px){
  .fb-services__grid{
    grid-template-columns:minmax(0,1.32fr) minmax(320px,.8fr);
  }
}

.fb-services__title{
  margin:0 0 20px;
  font-family:var(--font-display);
  font-size:clamp(1.6rem,1.2rem + 1.6vw,2.45rem);
  font-weight:800; line-height:1.15;
  color:var(--green-900); letter-spacing:-.01em;
  text-wrap:balance;
}
/* Amber rule, matching the banner's, so the two read as one family. */
.fb-services__title::after{
  content:"";
  display:block;
  width:56px; height:3px; border-radius:3px;
  margin:16px 0 0;
  background:var(--amber-500);
}
.fb-services__lead p{
  margin:0 0 16px;
  font-size:16.5px; line-height:1.85;
  color:var(--ink-700);
  text-align:left;
}
.fb-services__lead p:last-child{ margin-bottom:0; }
.fb-services__lead strong{ color:var(--green-900); font-weight:700; }
.fb-services__lead a{ color:var(--green-700); font-weight:700; }
.fb-services__lead a:hover{ color:var(--amber-600); }

/* The tick list's panel.

   A white card with hairlines was the obvious thing and it looked like
   nothing — a list with a border round it. This is the opposite side of
   the page's contrast instead: a dark brand-green slab against the pale
   section, so the column reads as a deliberate block rather than
   leftover space. The rows sit on it as translucent chips.

   No sticky. The panel is nearly as tall as the prose, so sticking
   bought about 50px of travel and just felt like a bug. It stretches to
   the row height instead and the chips space themselves down it. */
.fb-services__panel{
  position:relative;
  isolation:isolate;
  overflow:hidden;
  border-radius:var(--radius-l);
  padding:clamp(22px,2.6vw,34px);
  background:
    linear-gradient(158deg,
      var(--green-950) 0%,
      var(--green-900) 58%,
      var(--green-800) 100%);
  box-shadow:var(--shadow-pop);
  display:flex; flex-direction:column; justify-content:center;
}
/* Amber wash in the corner, the same light the banner uses. */
.fb-services__panel::before{
  content:"";
  position:absolute; z-index:-1;
  inset:auto -30% -40% auto;
  width:min(420px,85%); aspect-ratio:1;
  border-radius:50%;
  background:radial-gradient(circle,rgba(255,81,0,.28) 0%,rgba(255,81,0,0) 70%);
  pointer-events:none;
}
/* Accent bar across the top edge. */
.fb-services__panel::after{
  content:"";
  position:absolute; inset:0 0 auto 0; height:4px;
  background:linear-gradient(90deg,var(--amber-500),var(--amber-400) 55%,transparent);
}

.fb-services__panel .fb-checklist{
  margin:0;
  grid-template-columns:1fr;
  gap:clamp(8px,1vw,12px);
}
/* Each service is a chip on the dark field, not a row with a rule. */
.fb-services__panel .fb-checklist li{
  gap:14px;
  padding:12px 14px;
  border-bottom:0;
  border:1px solid rgba(255,255,255,.10);
  border-radius:14px;
  background:rgba(255,255,255,.06);
  color:var(--paper-000);
  font-size:15.5px; font-weight:600;
  transition:background .16s ease, border-color .16s ease, transform .16s ease;
}
.fb-services__panel .fb-checklist li:hover{
  background:rgba(255,255,255,.12);
  border-color:rgba(255,255,255,.22);
  transform:translateX(4px);
}
/* The tick sits in its own lighter tile so the orange always reads,
   whatever part of the gradient it lands on. */
.fb-services__panel .fb-checklist img{
  padding:6px;
  border-radius:10px;
  background:rgba(255,255,255,.12);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.10);
}

/* 7e-ter. Tick list.

   Velletri lists its services as one paragraph of seven 23px check
   images separated by <br>. Rendered as a real <ul> here: the seven
   images, their alt text and every label survive unchanged, but a list
   of services becomes a list rather than a run-on line.

   The icons keep their own dimensions, so nothing is scaled. */
.fb-checklist{
  list-style:none; margin:20px 0 0; padding:0;
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(220px,1fr));
  gap:10px clamp(18px,2.5vw,32px);
}
.fb-checklist li{
  display:flex; align-items:center; gap:10px;
  padding:8px 2px;
  border-bottom:1px solid var(--line-200);
  font-size:15.5px; font-weight:600; line-height:1.4;
  color:var(--green-900);
}
.fb-checklist img{ flex-shrink:0; }

/* 7e-septies. Gorizia's two short benefit lists.

   The old page puts them in a pair of vc_col-sm-6 columns inside the intro,
   each headed by a one-line lead-in set in orange — "I vantaggi del servizio
   Fabbro:" and "Pronto Intervento Fabbro Gorizia offre:". The colour is the
   only thing marking those lines as headings, so it moves here as a token
   (CSS rule 3 bans the inline style, but dropping the emphasis entirely
   would flatten two labels into body text).

   Side by side from 700px up, stacked below it. The lists themselves reuse
   .fb-checklist, which inside a ~290px column resolves to a single track. */
.fb-perks{
  display:grid;
  grid-template-columns:1fr;
  gap:clamp(18px,2.4vw,30px);
  /* Bottom margin as well as top: the last list row ends on a hairline, and
     the CTA button that follows sat almost against it. */
  margin:clamp(22px,2.6vw,30px) 0 clamp(26px,3vw,36px);
}
@media (min-width:700px){
  .fb-perks{ grid-template-columns:repeat(2,minmax(0,1fr)); }
}
.fb-perks__lead{
  margin:0 0 10px;
  font-family:var(--font-display);
  font-size:15px; font-weight:800;
  color:var(--amber-600);
  letter-spacing:.01em;
}
.fb-perks .fb-checklist{ margin-top:0; }

/* 7e-bis. Some city pages write their section label as a paragraph
   rather than a heading — Cremona's "Servizi" is a <p><strong>, and
   promoting it to an H3 would add a heading the old page never had
   (hard rule 9). Keep the <p>; give it the presence the H3 has on the
   pages that do use one. Sizing matches global.css's h3. */
.fb-head-label{
  margin:0;
  font-family:var(--font-display);
  font-size:clamp(1.15rem,1.05rem + .5vw,1.45rem);
  font-weight:700; line-height:1.3;
  letter-spacing:-.01em;
  color:var(--ink-900);
}

/* Verbano Cusio Ossola only: the source's last row carries no label or
   heading at all, just one more CTA button beside the call bar — its
   own background was a Torino-branded photo (not this page's city),
   dropped as presentation rather than shown wrong (see the page's own
   header comment). No dark .fb-emergency treatment either: that
   component exists to carry a heading/label, and there is none here to
   justify it. Just enough padding so the lone button isn't flush
   against the cards above it. */
.fb-cta-plain{
  padding:clamp(40px,5vw,64px) 5vw;
}
/* Same nowrap overflow already fixed for Asti's closing button
   (fabbro.css §6, .fb-emergency-inner > .cta-btn): .cta-btn is nowrap
   by design, fine with room to grow, but this page's own number
   ("CHIAMA SUBITO 0323086546") doesn't fit 320px's available width
   without wrapping, and an overflowing button here compounds into the
   position:fixed .call-bar the same way it did there. */
.fb-cta-plain .cta-btn{
  white-space:normal;
  max-width:100%;
}

/* 7f. Closing coverage band — the Italy map some city pages end on.
   Centred on its own it read as a stray image in white space, so it
   now anchors one edge of a dark closing band with the call CTA
   anchored to the other: the same "map + phone" pairing the page is
   really making. Reusable on any city page that ends the same way. */
.fb-closing-media{
  background:var(--green-950);
  padding:clamp(40px,5vw,68px) 0;
  /* the map is allowed to run off the page edge below */
  overflow:hidden;
}
.fb-closing-media__grid{
  display:grid;
  grid-template-columns:1fr;
  align-items:center;
  justify-items:center;
  gap:clamp(26px,4vw,48px);
  padding-inline:var(--gutter);
}
.fb-closing-media__media img{
  display:block; height:auto;
  width:clamp(215px,46vw,320px);
}
/* the band is dark, so the outline button needs the light treatment */
.fb-closing-media .cta-btn--secondary{
  background:transparent; color:var(--paper-000);
  border-color:var(--paper-000);
}
.fb-closing-media .cta-btn--secondary:hover{
  background:var(--paper-000); color:var(--green-900);
}

@media (min-width:860px){
  /* Map and buttons are one centred lockup, not two items pinned to
     opposite edges of a 1240px band. Two tries at pinning them to the
     edges left either a hole down the middle or a map cropped to a
     sliver: the artwork is portrait and narrow, so it cannot carry a
     full-width row on its own. Capping the group keeps the pair
     balanced while the dark band still runs edge to edge. */
  .fb-closing-media__grid{
    grid-template-columns:auto auto;
    justify-content:center;
    align-items:center;
    gap:clamp(40px,6vw,80px);
    max-width:760px; margin-inline:auto;
  }
  /* Sized by width, never by height. With height set and width:auto the
     global img{max-width:100%} resolves against an auto grid column
     whose own width depends on the image — the browser breaks the loop
     by squashing the map (241px wide where its aspect needs 340px).
     A definite width sizes the column and the height follows. */
  .fb-closing-media__media img{
    width:clamp(250px,26vw,340px); height:auto;
    /* and max-width:100% has to go with it: against an auto track it
       clamps the image back to the track the image is meant to size.
       The width above is viewport-relative, so nothing can overflow. */
    max-width:none;
  }
  .fb-closing-media__actions{
    flex-direction:column; align-items:stretch;
    gap:14px;
  }
}

/* Eyebrow over a chip list. Needs real space above it — it follows a
   heading, and global's .about__content h2{margin-bottom:8px} leaves
   the two sitting on top of each other. */
.fb-areas__title{
  display:flex; align-items:center; gap:10px;
  font-family:var(--font-display);
  font-size:.82rem; font-weight:700; letter-spacing:.06em;
  color:var(--ink-500); text-transform:uppercase;
  margin:28px 0 14px;
}
.fb-areas__title::after{
  content:""; flex:1; height:1px; background:var(--line-200);
}

/* Faenza only: the source wraps its intro photo in its own <h2>
   caption. Hard rule 9 protects the heading's LEVEL and TEXT, not
   the old page's visual weight — global.css's default h2 (48px/800)
   read as an oversized, ugly floating headline over the photo, so
   it is restyled as a small pill tag here instead. Same visual
   language as .svc-pricing-pill (prezzi.css) and .section-kicker
   (global.css) already use elsewhere — no new tokens. */
.about__media-tag{
  display:inline-flex; align-items:center;
  font-family:var(--font-body); font-weight:700;
  font-size:.8rem; letter-spacing:.03em; text-transform:uppercase;
  color:var(--green-800); background:var(--green-100);
  padding:6px 16px; border-radius:999px;
  margin:0 0 14px;
}

/* ============================================================
   8. GENOVA-ONLY COMPONENTS

   This is the richest fabbro page built so far — five service
   write-ups instead of three or four, a keyword taxonomy rendered as
   nested <ul>s, and a closing band of twenty real <h5> headings. None
   of the existing card/list/tag components fit these three shapes, so
   three new ones are added here rather than force-fitting the markup
   into something that already existed for a simpler page.
============================================================ */

/* 8a. Genova's tile strip is the first with real per-tile links —
   three of its four tiles go to a sub-page or a related page instead
   of being plain icon+label. .tile stays a <div> (global.css expects
   an <a> CHILD for its :focus-within/.tile a:focus-visible rules, not
   the tile itself becoming the link), so the anchor here just has to
   pick up the column layout .tile normally provides directly. */
.tile > a{
  display:flex; flex-direction:column; align-items:center;
  gap:14px; width:100%;
  text-decoration:none; color:inherit;
}

/* 8b. Two short centred Q&A blurbs between the intro and the keyword
   list — "Pronto Intervento" / "Riparazione", each a real <h3> plus
   one short centred paragraph. Side by side above 700px, since two
   one-line questions stacked the full container width left a lot of
   empty measure either side of very short lines. */
.fb-blurbs{
  display:grid; grid-template-columns:1fr; gap:clamp(24px,3vw,40px);
  max-width:900px; margin:0 auto clamp(40px,4.5vw,64px);
  text-align:center;
}
@media (min-width:700px){
  .fb-blurbs{ grid-template-columns:repeat(2,1fr); }
}
.fb-blurbs h3{
  margin:0 0 10px;
  font-family:var(--font-display);
  font-size:clamp(1.1rem,1rem + .4vw,1.35rem);
  font-weight:800; color:var(--green-900);
}
.fb-blurbs p{
  margin:0; font-size:16px; line-height:1.7; color:var(--ink-700);
}

/* 8c. "In cosa possiamo aiutarti" — a keyword taxonomy the old page
   marks up as a real nested list (one top-level <li> naming the
   category, holding a <ul> of specific services). Reproduced as the
   same nested structure — hard rule 9 protects heading text and DOM
   meaning, not just headings, and rewriting this into flat chips would
   have thrown away the parent/child relationship the source encodes.

   Each category is its own card (background, border, radius — the
   same card language .tile/.fb-step/.feature-card already use), so
   three short lists don't just float in empty space. Three columns
   from 900px, two from 560px, one full-width card below that.

   Inside every card the sub-items are their own 2-column grid AT
   EVERY SIZE, not a single stacked list — the items are short enough
   ("riparazione infissi", "montaggio serramenti") that one column
   left a card's whole right half empty, on a phone as much as on a
   1280px screen (checked directly against the built page, not
   assumed). A few of the longer entries wrap to two lines in the
   narrower mobile column; a smaller size at that breakpoint (below)
   keeps that from feeling cramped. */
.fb-keyword-cols{
  display:grid; grid-template-columns:1fr; gap:16px;
}
@media (min-width:560px){
  .fb-keyword-cols{ grid-template-columns:repeat(2,minmax(0,1fr)); }
}
@media (min-width:900px){
  .fb-keyword-cols{
    grid-template-columns:repeat(3,minmax(0,1fr));
    gap:clamp(20px,2.4vw,28px);
  }
}
.fb-keyword-cols > ul{
  margin:0; padding:clamp(20px,2.6vw,26px);
  list-style:none;
  background:var(--paper-050);
  border:1px solid var(--line-200);
  border-radius:var(--radius-m);
  box-shadow:var(--shadow-card);
  transition:transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.fb-keyword-cols > ul:hover{
  transform:translateY(-3px);
  box-shadow:var(--shadow-pop);
  border-color:transparent;
}
.fb-keyword-cols > ul > li{
  display:inline-block;
  font-family:var(--font-display);
  font-weight:800; font-size:16px; color:var(--green-900);
  margin:0 0 16px;
  padding-bottom:12px;
  border-bottom:2px solid var(--amber-500);
}
.fb-keyword-cols ul ul{
  margin:0; padding:0; list-style:none;
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:10px 14px;
}
.fb-keyword-cols ul ul li{
  font-family:var(--font-body); font-weight:400;
  font-size:14px; line-height:1.45; color:var(--ink-700);
  padding-left:14px; position:relative;
}
.fb-keyword-cols ul ul li::before{
  content:""; position:absolute; left:0; top:.5em;
  width:5px; height:5px; border-radius:50%;
  background:var(--amber-500);
}
.fb-keyword-cols a{ color:var(--green-700); font-weight:700; }
.fb-keyword-cols a:hover{ color:var(--amber-600); }

@media (max-width:399px){
  /* The narrowest phones: two 14px columns inside a card padded on
     both sides left ~110px per column, where "apertura porte
     bloccate" (23 characters) was wrapping to three cramped lines.
     Tightened size and padding match the established phone-size
     pattern already used for .fb-tag/.fb-service-card at this range. */
  .fb-keyword-cols ul ul{ gap:8px 10px; }
  .fb-keyword-cols ul ul li{ font-size:12.5px; padding-left:12px; }
  .fb-keyword-cols ul ul li::before{ top:.45em; }
}

/* 8d. The closing keyword band — twenty real <h5> elements (the old
   page's own markup, each with a decorative fa-check icon in front of
   it), grouped into four columns of five. Font Awesome is not loaded
   on the new site (hard rule 5 bans adding a third-party icon font),
   so the empty decorative <i> becomes the same inline check SVG the
   hero trust-list already uses elsewhere on this page — nothing about
   the icon was ever real content, only its presence. Two of the
   twenty headings carry the source's own real links; the rest are
   plain text, exactly as in the source. */
/* DOM order matches the source's own four columns exactly (five
   headings per group, in source order) — grid-auto-flow:column with a
   set row count places item 6 at the top of column 2 instead of beside
   item 2, so the visual columns match the source's grouping rather
   than an interleaved row-major reflow. */
/* The source sets this H4 orange via an inline style (CSS rule 3 bans
   that); the same amber the rest of the page's CTAs already use. */
.fb-h5-grid-title{
  margin:0 0 24px;
  font-family:var(--font-display);
  font-size:clamp(1.1rem,1rem + .4vw,1.35rem);
  font-weight:800; color:var(--amber-600);
}

/* Two columns from the base (mobile) up, not just from 700px — twenty
   short headings in one stacked column made for a long scroll on a
   phone. grid-auto-flow:column with a set row count keeps item 6 at
   the top of column 2, matching the source's own column grouping,
   the same reasoning as the 700px/1100px steps above it. */
.fb-h5-grid{
  display:grid; gap:8px 20px;
  grid-template-columns:repeat(2,minmax(0,1fr));
  grid-auto-flow:column;
  grid-template-rows:repeat(10,auto);
}
@media (min-width:700px){
  .fb-h5-grid{ gap:10px 32px; }
}
@media (min-width:1100px){
  .fb-h5-grid{
    grid-template-columns:repeat(4,minmax(0,1fr));
    grid-template-rows:repeat(5,auto);
  }
}
.fb-h5-grid h5{
  display:flex; align-items:center; gap:8px;
  margin:0; padding:9px 0;
  border-bottom:1px solid var(--line-200);
  font-family:var(--font-body); font-weight:600;
  font-size:14.5px; line-height:1.35; color:var(--green-900);
}
.fb-h5-grid h5 svg{ flex-shrink:0; color:var(--amber-500); }
.fb-h5-grid a{ color:inherit; text-decoration:none; }

@media (max-width:479px){
  /* The narrowest phones: two columns at 14.5px left entries like
     "Sostituzione Serrande Elettriche" pushing right up against the
     gap. Tightened size/gap/icon match the established phone-size
     pattern already used for .fb-tag and .fb-keyword-cols at this
     range, rather than a one-off number. */
  .fb-h5-grid{ gap:6px 12px; }
  .fb-h5-grid h5{
    gap:6px; padding:7px 0;
    font-size:12px; line-height:1.3;
  }
  .fb-h5-grid h5 svg{ width:13px; height:13px; }
}
.fb-h5-grid a:hover{ color:var(--amber-600); text-decoration:underline; }

/* ============================================================
   9. COVERAGE NOTE — Imperia only (so far).

   A real <h3> plus two body paragraphs sitting between the service
   cards and the closing band — the source's own "NECESSITI DI UN
   FABBRO VICINO A TE A SANREMO O IMPERIA?" section, explaining the
   business also covers Sanremo (same province, legitimate service-area
   copy, not a wrong-city fault). Centred heading reuses the existing
   .features__head--center look. Full container width, not a narrower
   centred column — the source's own row is col-sm-12, and a capped
   measure here would just be inventing a constraint the old page
   never had.
============================================================ */
.fb-note p{
  margin:0 0 16px; font-size:16.5px; line-height:1.75; color:var(--ink-700);
}
.fb-note p:last-child{ margin-bottom:0; }
.fb-note strong{ color:var(--green-900); font-weight:700; }

/* ============================================================
   10. APERTURA PORTE — hub page and its city pages

   The first taglist to hold real navigable links rather than
   plain-text keyword runs — fb_taglist() in _taglist.php has no
   anchor support, so the DOVE OPERIAMO city index on the hub page is
   hand-written <li class="fb-tag"><a>…</a></li> instead. The base
   .fb-tag styling (dot marker, hairline, spacing) still applies as-is;
   only the click target needs to fill the whole row.
============================================================ */
.fb-tag a{
  display:block; width:100%;
  color:inherit; text-decoration:none;
}
.fb-tag a:hover,
.fb-tag a:focus-visible{
  color:var(--amber-600); text-decoration:underline;
}

/* The source's "DOVE OPERIAMO" heading and rule sit above the whole
   row, not inside either column — same shape as .fb-services-inner's
   head, centred above its grid. */
.fb-coverage-head{
  text-align:center;
  margin-bottom:clamp(32px,4vw,48px);
}
.fb-coverage-cta{
  margin-top:clamp(32px,4vw,48px);
  text-align:center;
}

/* Apertura Porte's closing band reads mostly as a link directory, and
   the base .fb-emergency heading (up to 38px/800) and 16.5px body copy
   read heavy on top of it — owner's call, 24 Sep 2026. Trims both down
   a step. Scoped to this modifier only: the base component and every
   page already using it (the fabbro hub, Roma, Torino, Udine,
   Alessandria, Asti) are unaffected. */
.fb-emergency--modest h2:where(:not(.h1-look)){
  font-size:clamp(1.25rem,1.05rem + .8vw,1.6rem);
  font-weight:700;
}
.fb-emergency--modest p{
  font-size:15px;
}

/* Apertura Porte Milano's 4-tile strip labels are plain bold text on
   the old page (<p><img><strong>…</strong></p>), not a heading — unlike
   the hub's "I SERVIZI" cards, which use real <h4>s. Promoting these to
   <h4> would add heading structure the source never had (hard rule 9),
   so .fb-service-card__label carries the exact same look as
   .fb-service-card h4 on a <p> instead. */
.fb-service-card__label{
  margin:0;
  font-family:var(--font-display);
  font-size:16px; font-weight:800; letter-spacing:.01em;
  color:var(--green-900); line-height:1.35;
}

/* A little breathing room between the intro's last paragraph and its
   call button — .fb-story__head p:last-child clears its own margin,
   which otherwise left the button flush against the text.

   white-space:normal/max-width:100% guard against .cta-btn's default
   nowrap (fabbro.css §1) — fine for the short "CHIAMA SUBITO [number]"
   label every sibling page's .fb-story__head button uses, but
   Venezia's equivalent button reads "CONTATTACI AL NUMERO DI TELEFONO
   [number]", a full sentence that overflowed 320px by ~196px.
   white-space:normal only wraps when a line actually needs it, so the
   short siblings render identically — confirmed unchanged on Milano/
   Brescia/Monza/Bergamo/Roma/Verona/Padova after this. */
.fb-story__head .cta-btn{
  margin-top:8px;
  white-space:normal;
  max-width:100%;
}
/* .fb-story__head a{color:var(--green-700)} (§7d, above) is 0,1,1 —
   more specific than .cta-btn's own 0,1,0 color rule — so without this
   the button's white text rendered green-on-orange. Same collision
   already documented for .about__content a.btn--primary. */
.fb-story__head a.cta-btn,
.fb-story__head a.cta-btn:hover,
.fb-story__head a.cta-btn:focus-visible{ color:var(--paper-000); }

/* Apertura Porte Milano's "Servizi" row: five real photographs (not
   64px icons) each with their own <h4> and paragraph — the old page's
   vc_box_border_grey bordered rectangle, reproduced as a plain framed
   card since none of the icon-chip cards elsewhere (.fb-service-card,
   .feature-card) are built for a landscape photo.

   A fixed 3-column grid, not auto-fit — owner's call, 24 Sep 2026. Five
   cards means the second row only ever holds two; the sixth slot
   (.fb-photo-card--cta, below) is a real grid item now, sized down to
   sit beside them and complete the row, rather than a separate block
   floating under the whole grid. */
.fb-photo-cards{
  display:grid; gap:clamp(24px,3vw,36px);
  grid-template-columns:1fr;
  /* .fb-services-inner (the section this grid sits in) centres its own
     heading/rule; the cards' body copy reads as rivers of whitespace
     centred at this length, so it's set back to left here. */
  text-align:left;
}
@media (min-width:620px){
  .fb-photo-cards{ grid-template-columns:repeat(2,minmax(0,1fr)); }
}
@media (min-width:900px){
  .fb-photo-cards{ grid-template-columns:repeat(3,minmax(0,1fr)); }

  /* Exactly five cells (Padova: four cards + the CTA/photo cell) — a
     plain 3-up grid left the second row as two cards and a gap where a
     third would be. A pure-CSS quantity query (Heydon Pickering), same
     technique already used for the even/six-card cases in
     .features__grid--rows: :has() lets the GRID react to its own child
     count at render time, so a page with a different card count is
     unaffected and nothing is hardcoded per page. Six columns split
     3+3+3 / 3+3 give the first row three equal thirds and the second
     row two equal halves. */
  .fb-photo-cards:has(> .fb-photo-card:nth-child(5):last-child){
    grid-template-columns:repeat(6,minmax(0,1fr));
  }
  .fb-photo-cards:has(> .fb-photo-card:nth-child(5):last-child) .fb-photo-card:nth-child(-n+3){
    grid-column:span 2;
  }
  .fb-photo-cards:has(> .fb-photo-card:nth-child(5):last-child) .fb-photo-card:nth-child(n+4){
    grid-column:span 3;
  }
}
.fb-photo-card__media{
  display:block;
  border-radius:var(--radius-m);
  border:1px solid var(--line-200);
  overflow:hidden;
  margin:0 0 18px;
}
.fb-photo-card__media img{ display:block; width:100%; height:auto; }
.fb-photo-card h4{
  margin:0 0 10px;
  font-family:var(--font-display);
  font-size:17px; font-weight:800; color:var(--green-900);
}
.fb-photo-card p{
  margin:0; font-size:15px; line-height:1.75; color:var(--ink-700);
}

/* The row's sixth slot is not a card on the old page — a call button
   and the coverage map, filling the cell exactly like an ordinary
   card's photo does rather than sitting in their own boxed-within-a-
   boxed-card frame (owner's call, 24 Sep 2026 — an earlier version's
   padding/background/border here read as a container inside the grid
   cell's own container). */
.fb-photo-card--cta{
  display:flex; flex-direction:column; align-items:stretch;
  justify-content:center;
  gap:16px;
  text-align:center;
}
.fb-photo-card--cta .cta-btn{
  justify-content:center;
}
.fb-photo-card--cta img{
  display:block; height:auto;
  width:100%;
  border-radius:var(--radius-m);
  border:1px solid var(--line-200);
}

/* ============================================================
   11. APERTURA PORTE VENEZIA — a text-only source page, laid out
   rather than transcribed.

   This page's source carries no photos at all (checked: one <img> on
   the whole document, the favicon), no tile strip, no service cards
   and no coverage map — just prose under H2/H3/H4/H5 headings. Run
   through .fb-story it came out as a blog post: one narrow column of
   grey text, every section looking like the last. Owner's call, 24
   Sep 2026 — same copy, same heading levels (hard rules 2 and 9),
   carried instead by a dark banner, a callout card, icon cards and a
   dark checklist panel, so the page has the same rhythm as its
   photo-led siblings without inventing any content to fill it.
============================================================ */

/* 11a. Intro band — the page's H2, its own <hr> and its lead line on
   §7e-quater's dark .fb-banner. That component draws an amber rule
   with h2::after; this page brings a real <hr> of its own, so the
   pseudo-element is switched off here rather than drawing two. */
.fb-banner--lead h2:where(:not(.h1-look))::after{ display:none; }
.fb-banner--lead h2:where(:not(.h1-look)) a{
  color:inherit; text-decoration:underline; text-underline-offset:3px;
}
.fb-banner--lead hr{
  width:96px; height:3px; border:0; border-radius:3px;
  background:var(--amber-500);
  margin:20px auto 22px;
}
.fb-banner--lead p{
  position:relative;
  max-width:62ch; margin:0 auto;
  font-size:clamp(1rem,.95rem + .3vw,1.15rem);
  line-height:1.7; color:var(--green-100);
}
/* .cta-btn is nowrap by design (§1); this page's banner button is a
   full sentence ("CONTATTACI AL NUMERO DI TELEFONO …"), so it wraps
   here rather than running off a phone screen. */
.fb-banner__actions .cta-btn{
  white-space:normal;
  max-width:100%;
}

/* 11b. Callout card — "Perché scegliere noi come fabbro locale a
   Venezia?" is one heading, one paragraph and one call button. As a
   plain centred column it read as filler between two sections; as a
   raised card with an amber edge it reads as the claim it is.

   Owner's call, 24 Sep 2026: the card sits in the middle of a
   three-column row, flanked by two photos. Those photos are NOT from
   this page's source — it has no images at all (see the page's own
   header comment) — they were chosen by the owner from the uploads
   the sibling Apertura Porte pages already use, so they carry empty
   alt text: they are decoration, and inventing alt copy for them
   would be putting words on the page that the old site never had. */
.fb-callout{ background:var(--paper-050); }
.fb-callout__grid{
  display:grid;
  gap:clamp(20px,3vw,34px);
  align-items:center;
  /* Below 1000px the card leads and the two photos share a row under
     it — a decorative image above the heading would push the actual
     claim off a phone screen. */
  grid-template-columns:repeat(2,minmax(0,1fr));
}
.fb-callout__grid > .fb-callout__card{
  grid-column:1 / -1;
  order:-1;
}
/* A grid item's automatic minimum is its min-content width, and
   .cta-btn is nowrap by design (§1) — so at 320px the button's own
   unbreakable width pushed the card ~5px past the track. min-width:0
   lets the item shrink to its column; white-space:normal only wraps
   when a line actually needs it, so the button is unchanged at every
   width where it already fitted. Same pair of fixes .fb-tag and
   .fb-emergency__copy already carry for the same reason. */
.fb-callout__grid > *{ min-width:0; }
.fb-callout__card .cta-btn{
  white-space:normal;
  max-width:100%;
}
@media (min-width:1000px){
  /* Side columns widened from .72fr at the owner's request, 24 Sep
     2026. Capped there rather than pushed further: the photos are
     350px natives, so anything past ~310px would upscale them, and
     the middle column still needs room for the paragraph. */
  .fb-callout__grid{
    grid-template-columns:minmax(0,.9fr) minmax(0,1.4fr) minmax(0,.9fr);
  }
  .fb-callout__grid > .fb-callout__media:first-child{ grid-column:1; }
  .fb-callout__grid > .fb-callout__card{ grid-column:2; order:0; }
  .fb-callout__grid > .fb-callout__media:last-child{ grid-column:3; }
}
.fb-callout__media img{
  display:block;
  width:100%; height:auto;
  border-radius:var(--radius-m);
  border:1px solid var(--line-200);
  box-shadow:var(--shadow-card);
}
.fb-callout__card{
  max-width:840px; margin-inline:auto;
  background:var(--paper-000);
  border:1px solid var(--line-200);
  border-top:4px solid var(--amber-500);
  border-radius:var(--radius-l);
  box-shadow:var(--shadow-card);
  padding:clamp(28px,4vw,48px);
  text-align:center;
}
.fb-callout__card h3{
  margin:0 0 18px;
  font-family:var(--font-display);
  font-size:clamp(1.35rem,1.1rem + 1vw,1.9rem);
  font-weight:800; line-height:1.25;
  color:var(--green-900); letter-spacing:-.01em;
  text-wrap:balance;
}
/* Left-aligned inside a centred card: the paragraph is long enough
   that centring it opens rivers, the same reason .about__content and
   .fb-photo-cards already set their copy left. */
.fb-callout__card p{
  margin:0 0 28px;
  font-size:16.5px; line-height:1.8; color:var(--ink-700);
  text-align:left;
}

/* 11c. Section lead — the two paragraphs that sit under "Servizi
   Fabbro a Venezia." and above the cards. */
.fb-section-lead{
  max-width:860px; margin:0 auto clamp(32px,4vw,52px);
}
.fb-section-lead p{
  margin:0 0 16px;
  font-size:16.5px; line-height:1.8; color:var(--ink-700);
}
.fb-section-lead p:last-child{ margin-bottom:0; }
.fb-section-lead a{ color:var(--green-700); font-weight:700; }
.fb-section-lead a:hover{ color:var(--amber-600); }

/* The old page's own em-dash divider ("—————–") opens several of
   these blocks. It is copy, so hard rule 7 keeps it in the DOM — but
   muted to the hairline it is standing in for, instead of reading as
   stray punctuation in the middle of a sentence. */
.fb-rule-dashes{
  color:var(--line-200);
  letter-spacing:-.05em;
}

/* 11d. The three H5 sub-sections as cards. global.css's own
   .feature-card :is(h2…h6) rule already styles an H5 in a card, so
   the heading LEVEL is untouched (hard rule 9) — only its setting.
   The icons are decorative and aria-hidden: this page's source has
   none of its own, and §8d already took the same licence when Font
   Awesome's empty <i> became an inline SVG. */
@media (max-width:859px){
  /* .features__grid--rows centres its cards below 860px, which suits
     an icon over a short label; these cards carry full paragraphs, so
     only the icon stays centred. */
  .fb-venezia-cards .feature-card{ text-align:left; }
  .fb-venezia-cards .feature-card__icon{ margin-inline:0; }
}

/* 11e. Closing panel — the six-item <ul> becomes .fb-checklist chips
   on §7e-quinquies' dark .fb-services__panel. That component's tick
   rule targets the check.png the Velletri/Tivoli pages reproduce from
   their own markup; this list has no icon of its own, so the tick is
   an inline decorative SVG and needs the same chip treatment.
   box-sizing is stated because the 35px box is padding-inclusive.

   >>> SPECIFICITY <<<
   Written as `.fb-services h3.…` (0,2,1), not as a bare class, because
   §4's `.fb-services h3` (0,1,1) already sets colour/size/weight on
   any h3 inside this section and beats a plain 0,1,0 class. The size
   and weight are restated here for the same reason — the same trap
   .mega-menu a/.mega-region__link and .fb-story__head a/.cta-btn hit
   earlier in this file.

   NOTE: that collision also means `.fb-services__title` itself loses
   to `.fb-services h3` on the Velletri/Tivoli/Anzio pages, where the
   section title has been rendering at §4's 19–24px subtitle size
   instead of its own 1.6–2.45rem. Left alone here — it changes how
   three already-approved pages look, so it is the owner's call, not
   a side-effect of this page's build. */
.fb-services h3.fb-services__title--accent{
  margin:0 0 20px;
  font-size:clamp(1.35rem,1.1rem + 1vw,1.9rem);
  font-weight:800;
  line-height:1.2;
  color:var(--amber-600);
}
.fb-services h3.fb-services__title--accent a{ color:inherit; }

/* The closing grid places the panel in a spanning right-hand column
   so the left one carries the heading, the lead-in AND the closing
   paragraph. Explicit placement rather than a wrapper div: it keeps
   the DOM in the old page's own reading order (heading, lead-in,
   list, closing line) while filling a column that was otherwise two
   thirds empty beside the panel. */
.fb-venezia-close{
  display:grid;
  gap:clamp(28px,3.5vw,54px);
  align-items:start;
}
@media (min-width:1000px){
  .fb-venezia-close{
    grid-template-columns:minmax(0,1.32fr) minmax(320px,.8fr);
  }
  .fb-venezia-close > .fb-services__title{ grid-column:1; grid-row:1; }
  .fb-venezia-close > .fb-venezia-close__lead{ grid-column:1; grid-row:2; }
  .fb-venezia-close > .fb-services__panel{ grid-column:2; grid-row:1 / span 3; }
  .fb-venezia-close > .fb-services__tail{ grid-column:1; grid-row:3; margin:0; }
}
.fb-venezia-close__lead{
  margin:0;
  font-size:16.5px; line-height:1.8; color:var(--ink-700);
}
.fb-services__panel .fb-checklist svg{
  box-sizing:border-box;
  flex-shrink:0;
  width:35px; height:35px; padding:6px;
  border-radius:10px;
  background:rgba(255,255,255,.12);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.10);
  color:var(--amber-400);
}
.fb-services__tail{
  margin:clamp(28px,3.4vw,44px) 0 0;
  font-size:16.5px; line-height:1.8; color:var(--ink-700);
}
.fb-services__tail a{ color:var(--green-700); font-weight:700; }
.fb-services__tail a:hover{ color:var(--amber-600); }

/* ============================================================
   RESPONSIVE
============================================================ */
@media (max-width:980px){
  .fb-service-grid{ grid-template-columns:repeat(2,1fr); }
}

@media (max-width:820px){
  .fb-step-grid{ grid-template-columns:1fr; }
}

@media (max-width:620px){
  /* Two columns on a phone, not one. The four cards were stacking into a
     single tall column below 620px — a lot of scrolling for four short
     labels. Kept at two, tightening the icon, the padding and the
     heading so a pair fits side by side without cramming; the labels
     ("MONTAGGIO PORTE BLINDATE", 24 characters) wrap to two lines at this
     width rather than one, same as they already do at the 980px/2-up
     tablet size above. */
  .fb-service-grid{ grid-template-columns:repeat(2,1fr); gap:14px; }
  .cta-group{ flex-direction:column; align-items:stretch; }
  .fb-service-card{ padding:20px 12px 18px; border-radius:18px; }
  .fb-service-media{
    width:64px; height:64px; margin:0 auto 14px;
    border-radius:16px;
  }
  .fb-service-media img{ width:36px; height:36px; }
  /* Same 12.5px the mobile .fb-tag below already uses — the established
     "tightened" size for this breakpoint, not a one-off. */
  .fb-service-card h4{ font-size:12.5px; line-height:1.3; }
  /* Two columns on a phone for both runs: the entries are short and
     repetitive, so a pair of narrow columns still scans cleanly and
     halves a list that would otherwise be 29 and 40 rows of scrolling.
     Entries that wrap keep their dot on the first line. */
  .fb-taglist{ grid-template-columns:repeat(2,minmax(0,1fr)); column-gap:16px; }
  .fb-tag{
    align-items:flex-start;
    font-size:12.5px; gap:8px; padding:9px 0;
  }
  .fb-tag::before{ margin-top:5px; }
}


/* ============================================================
   12. NESTED SERVICE PAGES — .fb-svc

   The per-service pages that live under a city
   (/fabbro-genova/riparazione-serrature-genova/ and its siblings)
   are shaped differently from a city page: no tile strip, no
   pricing cards, no service-card artwork. What they have is a
   short benefit list, two or three long prose blocks and a
   keyword index — which, run through the city-page components
   alone, came out as correct but unfurnished walls of text.

   Everything below is scoped to .fb-svc on <main>, so none of the
   ninety-odd city pages can be reached by it.
============================================================ */

/* 12a. The hero.

   The old page opens on one band carrying three things: the
   heading, a five-item benefit list and the call button. Run
   through .fb-banner that had to be split in two — .fb-banner
   paints only h1/h2 white, so the five <h4> items (headings in the
   source, and headings they stay, hard rule 9) would have rendered
   near-black on navy and had to move to a light section below it.
   The result was a thin dark strip followed by a row of stranded
   cards: two weak sections where the source had one strong one.

   This band owns its own colour, so the items come home. Depth
   comes from three stacked layers rather than a flat fill — an
   amber glow high on one side, a cooler one low on the other, over
   a diagonal brand gradient — and the items sit on it as
   translucent chips that borrow the band's own light instead of
   punching white holes in it. */
.fb-svc-hero{
  position:relative;
  isolation:isolate;
  overflow:hidden;
  padding:clamp(46px,6.5vw,88px) 5vw clamp(42px,5.5vw,76px);
  text-align:center;
  color:var(--paper-000);
  background:
    radial-gradient(1000px 460px at 80% -14%, rgba(255,81,0,.26) 0%, rgba(255,81,0,0) 60%),
    radial-gradient(720px 380px at 6% 124%, rgba(41,145,214,.14) 0%, rgba(41,145,214,0) 62%),
    linear-gradient(152deg,
      var(--green-950) 0%,
      var(--green-900) 58%,
      var(--green-800) 100%);
}

/* Two passes over the band, both decorative.

   A vignette first: without it the glows read as two bright patches
   on a flat field, and darkening the corners pulls them back into
   one lit surface, settling the eye on the heading and the button.

   Then a fine dot grid at roughly 5% white. On its own a gradient
   this large reads as a flat digital wash however it is tuned; the
   grid gives the surface a texture to catch, and at 22px it is felt
   rather than seen. */
.fb-svc-hero__veil{
  position:absolute;
  inset:0;
  z-index:0;
  pointer-events:none;
  background:
    radial-gradient(120% 92% at 50% 44%,
      rgba(0,0,0,0) 38%,
      rgba(0,0,0,.30) 100%),
    radial-gradient(rgba(255,255,255,.055) 1px, rgba(255,255,255,0) 1px);
  background-size:auto, 22px 22px;
}

/* Hairline top and bottom, so the band reads as a deliberate edge
   against the header above and the page below rather than a block
   that simply stops. */
.fb-svc-hero::before,
.fb-svc-hero::after{
  content:"";
  position:absolute; left:0; right:0; height:1px;
  background:linear-gradient(90deg,
    transparent, rgba(255,255,255,.20) 28%, rgba(255,255,255,.20) 72%, transparent);
}
.fb-svc-hero::before{ top:0; }
.fb-svc-hero::after{ bottom:0; }

.fb-svc-hero__inner{
  position:relative;
  z-index:1;
  max-width:980px;
  margin:0 auto;
}

.fb-svc-hero h1,
.fb-svc-hero h2:where(.h1-look){
  margin:0;
  color:var(--paper-000);
  font-family:var(--font-display);
  font-size:clamp(1.6rem,1.1rem + 2.3vw,2.85rem);
  font-weight:800;
  line-height:1.12;
  letter-spacing:-.01em;
  text-wrap:balance;
  /* Lifts the heading off the amber glow it crosses at the top
     right, where white-on-light-amber was the weakest contrast on
     the band. */
  text-shadow:0 2px 20px rgba(0,0,0,.38);
}

/* The five benefit items. Chips, not cards: each is two or three
   words, so a bordered box per item gave five tall rectangles
   carrying one short line each. Centred and wrapping, they read as
   one row of credentials under the heading — which is the job the
   source gives them. */
.fb-svc-hero__list{
  display:flex;
  flex-wrap:wrap;
  justify-content:center;
  gap:10px 12px;
  max-width:880px;
  margin:clamp(24px,3vw,34px) auto 0;
}

.fb-svc-hero__list h4{
  margin:0;
  display:inline-flex;
  align-items:center;
  padding:11px 20px;
  border-radius:999px;
  /* Lit from above rather than filled flat, with a hairline inner
     highlight on the top edge — the chips sit ON the band instead of
     looking like holes cut in it. */
  background:linear-gradient(180deg,
    rgba(255,255,255,.14) 0%,
    rgba(255,255,255,.05) 100%);
  border:1px solid rgba(255,255,255,.20);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.16),
    0 2px 10px rgba(0,0,0,.20);
  color:var(--paper-000);
  font-family:var(--font-body);
  font-size:clamp(.82rem,.78rem + .18vw,.95rem);
  font-weight:600;
  line-height:1.3;
  letter-spacing:.01em;
  transition:background .18s ease, border-color .18s ease, transform .18s ease;
}

.fb-svc-hero__list h4:hover{
  background:linear-gradient(180deg,
    rgba(255,255,255,.20) 0%,
    rgba(255,255,255,.09) 100%);
  border-color:var(--amber-500);
  transform:translateY(-2px);
}

.fb-svc-hero__actions{
  margin-top:clamp(26px,3vw,36px);
  display:flex;
  flex-wrap:wrap;
  justify-content:center;
  gap:14px;
}

/* .cta-btn is nowrap by design; on a 320px screen this page's own
   label ("CHIAMA 0107766806") has to be allowed to wrap rather than
   push the band — the same fix §7e-sexies already applies to
   .fb-cta-plain. */
.fb-svc-hero__actions .cta-btn{
  white-space:normal;
  max-width:100%;
}


/* 12b. Prose columns as panels.

   The "serramenti / infissi" row is two paragraph blocks of 90-odd
   words each, side by side on the tinted band. Unpanelled they ran
   edge to edge as one undifferentiated field of justified text with
   nothing marking where the first ended and the second began.

   align-items:stretch on the row so the two panels match height —
   global.css §9 centres .about__grid, which left the shorter one
   floating against the taller one's middle. */
.fb-svc .about__grid--panels{ align-items:stretch; }

/* Tinted, not white: §12e turns the band around these white, so a
   white panel on it would have nothing to stand against. The tint
   also keeps the pair reading as one unit against the plain prose
   above and below. */
.fb-svc-panel{
  background:linear-gradient(168deg,
    var(--green-050) 0%,
    var(--paper-050) 100%);
  border:1px solid var(--line-200);
  border-radius:var(--radius-l);
  padding:clamp(24px,3vw,40px);
}

/* The section titles here are <h4> in the source — a level the page
   uses for section headings, not sub-points. At global.css's h4 size
   they read smaller than the body they introduce. Lifted, and given
   the same short amber rule the .fb-banner heading carries, so the
   two agree. */
.fb-svc-panel > h4:first-child,
.fb-svc-prose > h4:first-child{
  margin:0 0 18px;
  font-size:clamp(1.15rem,1.05rem + .45vw,1.4rem);
  line-height:1.25;
  color:var(--green-900);
  letter-spacing:.01em;
}

.fb-svc-panel > h4:first-child::after,
.fb-svc-prose > h4:first-child::after{
  content:"";
  display:block;
  width:52px; height:3px; border-radius:3px;
  margin-top:14px;
  background:var(--amber-500);
}


/* 12b-bis. The .about rows.

   global.css §9's .about__content is built for a short lead beside a
   photo. These pages run three and four paragraphs through it under
   headings two and three sizes larger, and the defaults gave a
   heading sitting flush on its own first line with no air between
   them — top-heavy, and the reason the rows read as unfinished.

   All of it is scoped to .fb-svc: .about__content is on ninety-odd
   city pages and none of them should move. */
.fb-svc .about__content > h2:where(:not(.h1-look)):first-child,
.fb-svc .about__content > h3:first-child{
  margin:0 0 20px;
  color:var(--green-900);
  line-height:1.15;
}

/* The same short amber rule the hero and the panels carry, so the
   page has one accent rather than three unrelated treatments. */
.fb-svc .about__content > h2:where(:not(.h1-look)):first-child::after,
.fb-svc .about__content > h3:first-child::after{
  content:"";
  display:block;
  width:52px; height:3px; border-radius:3px;
  margin-top:16px;
  background:var(--amber-500);
}

/* The opening line of each column, lifted out of the body colour. */
.fb-svc .about__content > h2:where(:not(.h1-look)):first-child + p,
.fb-svc .about__content > h3:first-child + p{
  font-size:17px;
  line-height:1.75;
  color:var(--ink-900);
}

/* .cta-group centres by default (fabbro.css §1), which left the
   button floating under a left-aligned column. */
.fb-svc .about__content .cta-group{
  justify-content:flex-start;
  margin-top:26px;
}

/* .cta-btn is nowrap by design; the tapparelle sibling's own label
   ("Chiama Adesso! 0107766806") is long enough to push past a 320px
   column otherwise — same fix §7e-sexies already applies elsewhere. */
.fb-svc .about__content .cta-group .cta-btn{
  white-space:normal;
  max-width:100%;
}

/* .about__content a{color:var(--green-500)} (global.css §9) outspecifies
   .cta-btn's own white text the same way it did .btn--primary/.btn--white
   before those got their own exception (global.css:1236, fabbro.css:585)
   — .cta-btn was never added to that list, and it shipped here as blue
   text on an orange button, unreadable. Same fix, same slot. */
.fb-svc .about__content a.cta-btn,
.fb-svc .about__content a.cta-btn:hover,
.fb-svc .about__content a.cta-btn:focus-visible{
  color:var(--paper-000);
}

.fb-svc .about__media img{
  border-radius:var(--radius-l);
  box-shadow:var(--shadow-card);
}

/* A short photo beside three long paragraphs made .about__grid's default
   align-items:center float the photo in the middle of a much taller row
   — on a tinted band that empty space above and below it read as a
   hole in the page rather than as breathing room. Anchoring both
   columns to the top removes the float; the row is simply as tall as
   its taller column now, with no dead space to explain. Scoped to rows
   that actually need it via a modifier rather than changing every
   .about__grid on the page. */
.fb-svc .about__grid--top{ align-items:start; }

/* The SOS Fabbro row's photo is a small portrait crop (225×300
   native) — .about__grid's default 50/50 split, or even
   --wide-text's 62/38, still hands it far more column than a photo
   that size can use without upscaling past its own resolution and
   going soft (global.css's .about__media already caps at 400px for
   exactly this reason, on a source built for a 724px original).
   Instead of splitting by ratio, the media column is fixed to just
   past the photo's own width and the text column takes whatever is
   left — the text gets the space the photo was never going to use,
   at any viewport width above 900px. */
@media (min-width:900px){
  .fb-svc .about__grid--media-narrow{
    grid-template-columns:minmax(0,1fr) minmax(0,320px);
  }
}

/* fabbro-39-225x300.jpg is the exact file this page serves (hard rule
   1 — no derivative swap), so 225 is its real, final rendered width.
   The track above is 290, not 225: the photo now sits inside
   .fb-svc-photo-card, whose own padding needs room too — capping the
   IMAGE at its true size while giving the CARD the extra 65px means
   the photo still renders at exactly its native resolution (never
   upscaled, never soft), and the padding around it is real padding,
   not more empty page background pretending to be breathing room. */
/* 225px would match the photo's native resolution exactly, but at
   that width the caption ("Riparazione Tapparelle Genova") spans the
   box edge to edge with zero margin either side — technically not
   overflowing, but visually pressed against the card's own padding,
   reading as cut off. 250px gives the caption breathing room; the
   photo itself upscales by 25px, a soft trade worth making since the
   alternative is text that looks clipped on every load.

   width:100% is required alongside max-width here: .fb-svc-photo-card
   is a column flexbox with align-items:center, so its non-stretched
   children shrink-wrap to their own content's intrinsic size — the
   image's native 225px — rather than growing to fill anything wider,
   no matter how high max-width is raised. width:100% gives the box a
   definite size to resolve against instead of shrinking to content,
   which is what actually lets it reach the new cap. */
.fb-svc .about__media--compact{ width:100%; max-width:250px; }

/* global.css §9 caps every .about__content p at max-width:70ch — a
   readability measure that's right for a 50/50 photo+text row, but
   it silently overrode every width change made to this row: the
   grid column kept getting wider while the paragraphs stayed capped
   at ~588px regardless, which is why widening .about__grid alone
   never shortened the text block. Lifted only in this row, where
   the column is deliberately much wider than a normal .about__content
   half specifically so the paragraphs can use it. */
.fb-svc .about__grid--media-narrow .about__content p{
  max-width:none;
}

/* 13f. The photo card — the source's photo, caption and call button
   as one self-contained unit, replacing a bare image floating beside
   three paragraphs of copy that ran on well past where the photo
   ended. Same tint-card language as the closing sidebar (§13e), so
   the two "shorter column beside longer prose" rows on this page
   read as one deliberate pattern rather than two different fixes. */
.fb-svc-photo-card{
  display:flex;
  flex-direction:column;
  align-items:center;
  background:linear-gradient(168deg,
    var(--green-050) 0%,
    var(--paper-050) 100%);
  border:1px solid var(--line-200);
  border-radius:var(--radius-l);
  padding:clamp(20px,2.6vw,28px);
}

.fb-svc-photo-card .cta-group{
  margin-top:20px;
  width:100%;
}

/* .cta-btn is nowrap by design; the card is far narrower than the
   button's own label ("Chiama Adesso! 0107766806") needs on one
   line — same wrap fix used everywhere else .cta-btn sits in a
   column narrower than its text. */
.fb-svc-photo-card .cta-btn{
  display:flex;
  white-space:normal;
  max-width:100%;
  text-align:center;
}


/* 13e. The closing sidebar — nine short entries under a <h2>-led
   prose block. First built inside a side-by-side grid
   (.about__grid--panels), which stretched the card to match the
   three-paragraph column's full height — a defined edge instead of
   plain page background, but still a card mostly empty below its own
   list. Owner's call (28 Sep 2026): stack instead of stretch. The
   card now sizes to exactly what the list needs — no forced height —
   and the prose runs the section's full width underneath it. See
   §13g for the stack itself. */
.fb-svc-sidebar{
  display:flex;
  flex-direction:column;
  background:linear-gradient(168deg,
    var(--green-050) 0%,
    var(--paper-050) 100%);
  border:1px solid var(--line-200);
  border-radius:var(--radius-l);
  padding:clamp(24px,3vw,36px);
}

.fb-svc-sidebar h3{
  margin:0 0 18px;
  color:var(--green-900);
  font-size:clamp(1.3rem,1.15rem + .5vw,1.6rem);
}

.fb-svc-sidebar h3::after{
  content:"";
  display:block;
  width:44px; height:3px; border-radius:3px;
  margin-top:14px;
  background:var(--amber-500);
}

.fb-svc-sidebar .fb-taglist{ margin:0; }


/* 13g. The stack — sidebar card, then full-width prose beneath it.
   Plain block flow: no grid, so nothing stretches the sidebar to
   match the prose, and the prose isn't confined to a column beside
   it either. The sidebar's own margin-bottom is the only thing doing
   the spacing a grid gap used to. */
.fb-svc-stack .fb-svc-sidebar{
  margin-bottom:clamp(28px,3.5vw,40px);
}

/* Same fix as the SOS Fabbro row above: global.css §9 caps
   .about__content p at max-width:70ch regardless of container width,
   sized for a column that shares its row with a photo. This prose no
   longer shares a row with anything — lifted so it actually reaches
   the section's full measure instead of stopping two-thirds across
   it. */
.fb-svc-stack .about__content p{
  max-width:none;
}


/* 12b-ter. The capability list.

   This is the page saying what it actually does, and .fb-checklist
   rendered it as bold text over hairlines — the least alive thing on
   a page that is mostly grey paragraphs already. Tiles, each with a
   real tick, in the brand's own colours.

   The tick is a mask rather than a background image, so its colour
   is still --amber-500 rather than a hex baked into a data URI. */
.fb-svc .fb-checklist{
  grid-template-columns:repeat(auto-fit,minmax(min(240px,100%),1fr));
  gap:10px;
  margin-top:22px;
}

.fb-svc .fb-checklist li{
  align-items:flex-start;
  gap:12px;
  padding:14px 16px;
  border-bottom:0;
  border-radius:var(--radius-s);
  background:var(--paper-000);
  border:1px solid var(--line-100);
  font-size:15px;
  font-weight:600;
  line-height:1.5;
  color:var(--green-900);
  transition:border-color .18s ease, box-shadow .18s ease, transform .18s ease;
}

.fb-svc .fb-checklist li:hover{
  transform:translateY(-2px);
  border-color:var(--amber-400);
  box-shadow:var(--shadow-card);
}

.fb-svc .fb-checklist li::before{
  content:"";
  flex-shrink:0;
  width:19px; height:19px;
  margin-top:.12em;
  background:var(--amber-500);
  /* Where mask-image is unsupported the mask is simply ignored and
     the amber box would show as-is; the radius makes that fallback a
     dot rather than a square. The tick sits inside the inscribed
     circle, so it costs nothing where masks do work. */
  border-radius:50%;
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12.7l5.4 5.4L20 6.4'/%3E%3C/svg%3E") center / contain no-repeat;
  mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12.7l5.4 5.4L20 6.4'/%3E%3C/svg%3E") center / contain no-repeat;
}


/* 12c. The closing prose block.

   .about__content carries its own measure, which is right beside a
   photo and wrong on its own: this ran in a 620px column with the
   other half of the row empty.

   It is also the page's closing argument and its last call to
   action, and as bare paragraphs on white it was the flattest thing
   on the page. Given a panel of its own — a soft tint falling away
   to white, so it reads as a considered close rather than more of
   the same body copy. */
.fb-svc-prose{
  max-width:880px;
  margin-inline:auto;
}

/* The opening line carries the claim the rest of the block supports,
   so it is set as a lead rather than as the first of five identical
   grey paragraphs. */
.fb-svc-prose > p:first-of-type{
  font-size:clamp(1.02rem,.98rem + .3vw,1.18rem);
  line-height:1.7;
  color:var(--green-900);
  font-weight:500;
}

/* The line that introduces the list — short, and the hinge between
   the prose and the tiles under it. */
.fb-svc-prose > p:last-of-type{
  margin-top:26px;
  font-weight:700;
  color:var(--green-900);
}


/* 12d. The closing list.

   .fb-checklist tracks are minmax(220px,1fr), which suits a run of
   short like-sized labels. This list is four entries running from
   three words to a full closing paragraph (the source leaves that
   paragraph inside the <li> — see _PHASE-6-LOG.md C17), and across
   four tracks they came out wildly ragged. One column, so the long
   one simply reads as the long one. */
/* One column here, not the auto-fit tracks the capability list uses:
   these four entries run from three words to a whole closing
   paragraph (the source leaves it inside the <li> — see
   _PHASE-6-LOG.md C17), and across tracks they came out ragged. */
.fb-svc-prose .fb-checklist{
  grid-template-columns:1fr;
  gap:10px;
}

.fb-svc-prose .fb-checklist li{
  font-weight:500;
  line-height:1.65;
  color:var(--ink-700);
}

.fb-svc-prose .fb-checklist strong{ color:var(--green-900); }

/* The page's last phone number, sitting in body copy at the very end
   of the closing list. */
.fb-svc-prose .fb-checklist a[href^="tel:"]{
  font-weight:800;
  color:var(--amber-600);
  text-decoration:none;
  white-space:nowrap;
}

.fb-svc-prose .fb-checklist a[href^="tel:"]:hover{ text-decoration:underline; }


/* 12e. Section rhythm.

   Read end to end the page was one near-white field from the hero to
   the footer: every band the same tone, so nothing marked where one
   argument ended and the next began, and the whole middle read flat
   however the individual blocks were styled. Alternating the bands
   gives the page a pulse — tinted where the page lists what it does,
   white where it explains. */
.fb-svc-band{
  background:linear-gradient(180deg,
    var(--green-050) 0%,
    var(--paper-050) 100%);
}

.fb-svc-closing{
  background:
    radial-gradient(900px 420px at 88% 6%, rgba(41,145,214,.10) 0%, rgba(41,145,214,0) 60%),
    linear-gradient(180deg, var(--green-050) 0%, var(--paper-000) 100%);
  border-top:1px solid var(--line-200);
  border-bottom:1px solid var(--line-200);
}

/* Body copy across the whole page. 16.5px grey at 1.8 was legible
   and characterless; a little more size and a darker ink make the
   long blocks read as prose someone wrote rather than as filler. */
.fb-svc .about__content p,
.fb-svc-prose p{
  font-size:16.8px;
  line-height:1.78;
}

/* The page's last phone number, sitting in body copy at the very end
   of the closing list. */
.fb-svc-prose .fb-checklist a[href^="tel:"]{
  font-weight:700;
  color:var(--amber-600);
  text-decoration:none;
  white-space:nowrap;
}

.fb-svc-prose .fb-checklist a[href^="tel:"]:hover{
  text-decoration:underline;
}


/* ============================================================
   13. SECOND SERVICE PAGE — additions for
   /fabbro-genova/tapparelle-e-persiane-genova/ and its siblings.

   This page carries three shapes .fb-svc's first page (Riparazione
   Serrature) did not: a one-line call-out band, a short icon row,
   and a photo with its own caption. All scoped to .fb-svc so the
   ninety-odd city pages stay untouched.
============================================================ */

/* 13a. The call-out band — the source's own H2, wrapping a tel:
   link, sitting beside a lead heading in a light grey row (source:
   background-color #e5e5e5, which var(--line-200) already matches
   almost exactly — reused rather than a new near-identical hex). */
.fb-svc-callout{ background:var(--line-200); }

/* Unscoped, this <h2> inherits global.css's default h2 clamp — built
   for a full section heading, and it renders at 47px here, in a
   compact two-column banner sitting beside a call button. Way out of
   proportion for a supporting line, not a page-section moment. Sized
   down to something that reads as a strong lead-in instead. */
.fb-svc-callout .about__content > h2:where(:not(.h1-look)):first-child{
  margin:0;
  font-size:clamp(1.4rem,1.2rem + 1.1vw,1.85rem);
  line-height:1.3;
}
.fb-svc-callout .about__content > h2:where(:not(.h1-look)):first-child::after{ display:none; }

/* The right column's H2 IS the call-to-action in the source — a
   heading-level link, not a button demoted from one. Hard rule 9
   keeps it an <h2>; this makes it read as the obvious next thing to
   press without turning it into a <button> or dropping its level. */
.fb-svc-callout-cta{
  display:flex;
  align-items:center;
  justify-content:center;
  text-align:center;
}

.fb-svc-callout-cta h2:where(:not(.h1-look)){
  margin:0;
  width:100%;
}

.fb-svc-callout-cta h2:where(:not(.h1-look)) a{
  display:flex;
  align-items:center;
  justify-content:center;
  gap:12px;
  padding:22px 28px;
  background:var(--amber-500);
  color:var(--paper-000);
  border-radius:var(--radius-m);
  box-shadow:0 10px 24px rgba(243,90,0,.28);
  font-family:var(--font-display);
  font-size:clamp(1.15rem,1.05rem + .4vw,1.5rem);
  font-weight:800;
  letter-spacing:-.01em;
  text-decoration:none;
  transition:background .18s ease, transform .18s ease, box-shadow .18s ease;
}

.fb-svc-callout-cta h2:where(:not(.h1-look)) a:hover{
  background:var(--amber-600);
  transform:translateY(-2px);
  box-shadow:0 14px 30px rgba(243,90,0,.4);
}

.fb-svc-callout-cta h2:where(:not(.h1-look)) a::before{
  content:"";
  flex-shrink:0;
  width:22px; height:22px;
  background:currentColor;
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.127.96.361 1.903.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0 1 22 16.92z'/%3E%3C/svg%3E") center / contain no-repeat;
  mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.127.96.361 1.903.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0 1 22 16.92z'/%3E%3C/svg%3E") center / contain no-repeat;
}


/* 13b. The icon strip — a centred lead sentence over four short
   "icon + label" items. The source's icons are empty Font Awesome
   <i> tags (icon-tools, decorative, no text lost); replaced with one
   inline SVG reused four times, same practice as §8d elsewhere in
   this file. */
.fb-svc-icons-lead{
  max-width:760px;
  margin:0 auto clamp(28px,3.5vw,40px);
  text-align:center;
  color:var(--ink-900);
  font-weight:600;
}

.fb-svc-icons{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(min(180px,100%),1fr));
  gap:clamp(20px,2.6vw,32px);
  max-width:900px;
  margin:0 auto;
  text-align:center;
}

.fb-svc-icon{
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:12px;
}

.fb-svc-icon__glyph{
  display:grid;
  place-items:center;
  width:52px; height:52px;
  border-radius:50%;
  background:var(--green-050);
  color:var(--green-800);
}

.fb-svc-icon__glyph svg{ width:24px; height:24px; }

.fb-svc-icon strong{
  font-size:.95rem;
  color:var(--green-900);
}


/* 13c. Photo caption — the source's own <h5> under the intro photo.
   Kept at its source level; styled as a small centred caption line
   rather than a fourth heading tier competing with the prose beside
   it.

   global.css's shared h1-h6 rule sets line-height:1.08, tuned for
   large display headings where a tight line-box doesn't matter. At
   this caption's small size, 1.08 makes the line-box shorter than
   the glyphs actually painted — mostly invisible on its own, but
   .about__media has its own overflow:hidden (global.css §9, there to
   clip the PHOTO to its rounded corners), and that hard edge lands
   exactly at the tight line-box's boundary and slices the bottom off
   the caption's descenders. A real line-height here fixes it at the
   source rather than fighting the ancestor's clip. */
.fb-svc .about__media h5{
  margin:16px 0 0;
  text-align:center;
  font-size:.95rem;
  line-height:1.5;
  font-weight:700;
  color:var(--green-900);
}


/* 13d. Section divider — the source's own <hr>-equivalent between
   the photo row and the closing sidebar row.

   Both neighbouring sections are .about, which already carries its
   own padding-block:clamp(56px,8vw,108px) top AND bottom (global.css
   §9) — at a typical desktop width that's over 100px of whitespace
   on each side of this rule before its own margin adds anything. The
   first pass gave it a further clamp(32px,4vw,56px), which stacked on
   top of both sections' padding rather than replacing it, and the two
   .about sections ended up roughly 300px apart. The sections' own
   padding is already doing the separating; this only needs enough
   margin to keep the rule from touching either section's content. */
.fb-svc-divider{
  max-width:1000px;
  margin:0 auto;
  border:0;
  border-top:1px solid var(--line-200);
}


/* ============================================================
   14. PREVENTIVO FABBRO {CITY} — /preventivi/intervento-fabbro-{city}/

   Shared across the whole "Preventivo Fabbro" page family (first
   built for Monza, reused as-is for Parma and any city after it) —
   not page-specific despite the section name.

   global.css's .feature-card__icon is a fixed 48x48 box; §7c above
   already overrides that for the 128px photographic icon family
   (.feature-card__icon img{width:128px;height:128px}, plus
   .feature-card__icon:has(img){width:fit-content;padding:16px} to
   let the chip grow to fit it). This family's own "I Servizi" icons
   are the 64x64 flat-icon family the tile strips use, not that 128px
   family, so both of those rules fight a plain .fb-icon-64 override:
   the img rule forces the image itself back to 128px regardless of
   its own width/height attributes, and the :has(img) rule's
   specificity (0,2,0) beats a single .fb-icon-64 class. Both
   overridden here with matching or higher specificity, so these
   pages' cards render at their own real 64x64 without touching
   §7c or any other feature-card on the site. */
.feature-card__icon.fb-icon-64{
  width:64px;
  height:64px;
  padding:0;
}
.feature-card__icon.fb-icon-64 img{
  width:64px;
  height:64px;
}

/* global.css justifies .feature-card p at >=900px ("Justified text
   creates rivers on narrow screens" — its own comment, written for
   the usual 3-up grid). This family's grid is 4-up (--cols-max:4,
   narrower columns than that comment assumed), so the same rivers
   show up on desktop too. Owner's call (Monza, kept for every page in
   the family): left-align unconditionally on .fb-preventivo cards
   only; every other feature-card on the site keeps the
   justify-at-desktop behaviour untouched. */
.fb-preventivo .feature-card p{
  text-align:left;
}
