/* restore extras — generated by restore_04_polish.py */

/* Consent overlays: the restore ships no analytics or third-party tracking at all, so there
   is nothing to consent to. Their scripts are gone too, meaning the banner can never be
   dismissed and would cover the top of every page. Removing the markup is unreliable when a
   JS bundle re-renders it, so it is hidden here as well. */
.cookies-banner, .cookies-banner-content, .cookie-banner, .cookie-consent, .cookie-notice,
.cc-window, .cc-banner, #cookie-law-info-bar, #cookieChoiceInfo, .gdpr-banner,
#tarteaucitronRoot, .consent-overlay, .cookiebar {
  display: none !important;
}
body.cookie-banner-open, body.has-cookie-banner, html.cookies-open {
  overflow: auto !important;
}

/* Dead account/login modals left by the CMS (no backend on a static host) */
.modal-login, #loginModal, .login-modal { display: none !important; }

/* Carousel slots the platform's JS bundles would have filled at runtime: without a working
   bundle they stay as <img> elements with no src and render as broken-image icons. Nothing is
   lost by hiding them — they never had content in the restore. */
img:not([src]), img[src=""], img[src="#"] { display: none !important; }

/* The client's backlink block must read as the page's own copy. Where a theme only colours
   links inside specific containers, the anchor would otherwise look like plain text — inherit
   the surrounding colour but keep an underline so it is still visibly a link. */
.content-wraparea a { color: inherit; text-decoration: underline; }

/* A few px of horizontal overflow on phones (an absolutely-positioned login list, a wide footer
   logo) makes the whole page pannable sideways, which reads as broken.
   NB: use `clip`, never `hidden`, and never on html together with height:100%. `overflow:hidden`
   turns the element into a scroll container: on themes that set html{height:100%} it stops body's
   overflow propagating to the viewport, the window stops scrolling entirely and every
   scroll-driven behaviour (sticky nav, back-to-top, in-page anchors, PageDown/End) dies.
   `clip` suppresses the sideways pan without creating a scroll container. */
body { overflow-x: clip; }
/* ---- end generated block; anything below is preserved across re-runs ---- */

/* The article hero image (templates' `header-2.jpg`) is not in the restore, so
   .blog-details-img-wrapper never gains the `.active` class that gives it a dark background.
   template.css still paints the article <h1> white at <=768px (rule at line 3064), which left
   the page title invisible — white on white — on every phone-width view of every com-content
   article page, including the legal pages. Scope the white back to the case it was written for. */
.view-article .article-details .blog-details-img-wrapper:not(.active) .article-header h1,
.view-article .article-details .blog-details-img-wrapper:not(.active) .article-header h2 {
  color: #353b41;
}

/* Without the hero the same wrapper also has no padding, so the 80px display title sits flush
   against the bottom of the sticky header and its ascenders read as clipped. */
.view-article .article-details .blog-details-img-wrapper:not(.active) {
  padding-top: 40px;
  padding-bottom: 10px;
}

/* =============================================================================================
   VISUAL FINISH PASS, 2026-08-17. Everything below was written after looking at rendered
   screenshots of this site at 1440px and 390px, page type by page type. Each block names the
   defect it repairs. Companion script: _scripts/luso_visual_finish.py (markup side).
   ============================================================================================= */

/* --- 1. Bands whose photograph is not in the restore ------------------------------------------
   `.luso-noimg` was painting a FLAT #2560A5 rectangle. On the homepage that is 860px of unbroken
   blue with two lines of type floating in it and 400px of nothing underneath; on /clube-lusoclinic/
   it was 860px of blue with nothing at all. Flat colour at that size does not read as a design
   decision, it reads as a block nobody filled.
   Replace it with the clinic's own palette used as a hero would use it: the brand blue #2560A5
   deepened to #17406f in a diagonal, a soft off-centre highlight so the surface has depth, and the
   site's own swirl mark (taken verbatim from the "Marque aqui a sua consulta" SVG the theme already
   ships) set large and very faint as a watermark. No new colour is introduced. */
.luso-noimg {
  background-color: #2560A5 !important;
  background-image:
    radial-gradient(115% 90% at 22% 8%, rgba(255, 255, 255, .17) 0%, rgba(255, 255, 255, 0) 58%),
    linear-gradient(135deg, #2b6cb8 0%, #2560A5 42%, #17406f 100%) !important;
  background-repeat: no-repeat !important;
  background-size: cover !important;
  position: relative;
  overflow: hidden;
}
/* A watermark was tried here and removed: any mark that is not the clinic's own logotype reads as
   a stray doodle at hero size, which is worse than an honest surface. The depth comes from the
   gradient and the highlight above. */
.luso-noimg h1, .luso-noimg h2, .luso-noimg h3, .luso-noimg h4,
.luso-noimg p, .luso-noimg span, .luso-noimg li { color: #fff !important; }
.luso-noimg a:not(.sppb-btn) { color: #fff !important; text-decoration: underline; }

/* template.css pins .sppb-slide-item-bg at height:860px because the original slide carried a
   full-bleed photograph. With no photograph the same 860px is empty air, so give the caption a
   band it fills. The homepage caption is 2 lines of 46px type; 460px holds it with the breathing
   room the design intends and keeps the wave divider immediately below the fold line. */
.luso-noimg.sppb-slide-item-bg { height: 460px; }
@media (max-width: 767px) {
  .luso-noimg.sppb-slide-item-bg { height: 400px; }
}

/* A hero slide whose ONLY content was the photograph has nothing left to show. Collapsing it is
   the honest layout: /clube-lusoclinic/ then opens on its own wave divider and headline instead of
   a screen-tall empty rectangle. */
.luso-slide-empty,
.sppb-slider-wrapper:has(> .sppb-slider-item-wrapper .luso-slide-empty) { display: none !important; }

/* --- 2. Page-builder columns that ended up empty ----------------------------------------------
   /contatos/ rendered 740px of blank white to the left of the address, and /clube-lusoclinic/ three
   more voids where the membership-card artwork would have been. A flex row with one empty half is
   not a layout; drop the empty half and centre what is left. */
.luso-col-empty { display: none !important; }
.sppb-row:has(> .luso-col-empty) { justify-content: center; }
/* ...and let the surviving half take the whole row, so the copy starts at the container's own left
   margin like every other block on the page instead of floating in the middle of a blank band. */
.sppb-row:has(> .luso-col-empty) > [class*="sppb-col-"]:not(.luso-col-empty) {
  flex: 0 0 100%;
  max-width: 100%;
}

/* --- 3. Every link on the site was bootstrap's default blue ------------------------------------
   Measured, not guessed: getComputedStyle on the megamenu, the top bar and the footer all returned
   rgb(0,123,255) - bootstrap.min.css's `a{color:#007bff}`. The theme's own colour file
   (templates/shaper_salon/css/presets/preset1.css + custom.css) is the one the build could not
   fetch, so nothing ever overrode bootstrap and the whole site was wearing a framework blue that
   appears nowhere in its design. #2560A5 is the clinic's blue: it is the colour the pages
   themselves carry inline, 100+ times, in the page-builder CSS of every section.
   This one rule is why the site read as "the CSS is there and it still looks like a template".
   Buttons are deliberately NOT touched: `a` is specificity 0-0-1, so every `.sppb-btn` class rule
   and every `#btn-…` inline rule the page carries still wins. */
a { color: #2560A5; }
a:hover, a:focus, a:active { color: #17406f; }

/* A menu label with no page behind it is not a link: same colour as its siblings, but no hand. */
#sp-menu1 ul.menu > li > a:not([href]),
.sp-megamenu-parent > li > a:not([href]),
.sp-module ul.menu > li > a:not([href]),
.offcanvas-menu ul.menu > li > a:not([href]),
.sp-dropdown-items > li > a:not([href]) { color: #2560A5 !important; cursor: default; }

/* --- 4. RSForm rendering every validation message at once --------------------------------------
   The contact form on /contatos/ (and the four other RSForm pages) printed "Por favor escreva o seu
   nome completo.", "Email inválido.", "Invalid Input", "Obrigatório" and "Opção obrigatória" under
   its fields in the resting state: RSForm's own script normally hides `.formNoError` and that
   script is not part of a static build. A form that opens covered in red-flag text reads broken. */
.formNoError { display: none !important; }
.rsform-error, .formError { display: none !important; }

/* The form's buttons were bootstrap's default blue and DANGER RED, which belongs to no palette on
   this site. Dress them as the page-builder buttons the rest of the site uses. */
.rsform-submit-button, .rsform-reset-button,
form[id^="userForm"] .btn-primary, form[id^="userForm"] .btn-danger {
  background-color: #2560A5;
  border-color: #2560A5;
  color: #fff;
  border-radius: 0;
  padding: 10px 26px;
  letter-spacing: 1px;
  text-transform: uppercase;
  font-size: 13px;
}
form[id^="userForm"] .btn-danger {
  background-color: transparent;
  color: #2560A5;
}
.rsform-submit-button:hover, form[id^="userForm"] .btn-primary:hover {
  background-color: #17406f;
  border-color: #17406f;
}

/* --- 5. Accordion on /contatos/ ---------------------------------------------------------------
   Its panels are opened by the polish step because the toggling script is not shipped; the chevron
   is therefore decorative and must not invite a click, and the sentence that now fills each panel
   needs the same rhythm as the button it replaced. */
.sppb-panel-heading { cursor: default; }
.sppb-panel-heading .sppb-toggle-direction { display: none; }
.luso-panel-note { margin: 0; padding: 4px 0 2px; font-size: 15px; line-height: 1.6; }

/* --- 6. Title bands that DO have a photograph --------------------------------------------------
   The site's own template settings paint .sp-page-title h2 in #2560A5, and /magazine/ and
   /marcacao-de-consulta/ put that blue straight onto a bright turquoise water photograph: legible
   only if you squint. template.css already reserves .sp-page-title:after for an overlay (it holds a
   1px transparent gif), so put a real scrim there. Also stop `background-attachment: fixed`, which
   on a 200px band crops the photo to a sliver on phones. */
.sp-page-title { background-attachment: scroll !important; }
.sp-page-title:not(.luso-noimg):after {
  background-image: radial-gradient(70% 62% at 50% 50%,
    rgba(255, 255, 255, .74) 0%, rgba(255, 255, 255, .40) 55%, rgba(255, 255, 255, .06) 100%) !important;
  top: 0;
  height: auto !important;
}
.sp-page-title .container { position: relative; z-index: 2; }
@media (max-width: 767px) {
  .sp-page-title { padding: 55px 0 65px !important; }
  .sp-page-title h2 { font-size: 40px !important; line-height: 1.1; }
}

/* --- 7. Captions laid straight on a photograph -------------------------------------------------
   The four "Oportunidades" tiles on the homepage carry white display type over the photo itself.
   On the two light frames (Nutricionista, Esteticista) the label all but disappears. Every tile in
   the same strip gets the same bottom-up scrim, so they read as one set. */
.sppb-addon-feature .sppb-img-container { position: relative; display: block; }
.sppb-addon-feature .sppb-img-container:after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 55%;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(14, 41, 71, 0) 0%, rgba(14, 41, 71, .55) 100%);
}
.image-slider-item .item-title,
.sppb-carousel-caption { text-shadow: 0 1px 12px rgba(14, 41, 71, .55); }

/* The `sppb-addon-person` tiles on /carreiras/ lay the same white display type straight on the
   photograph, and two of the four frames (Nutricionista, Esteticista) are near-white clinic
   interiors, so the name all but vanished. Same scrim, same strip logic - the four tiles read as
   one set. The overlay sits under the name, never over it. */
.sppb-addon-person .sppb-person-image { position: relative; }
.sppb-addon-person .sppb-person-image:after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 55%;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(14, 41, 71, 0) 0%, rgba(14, 41, 71, .55) 100%);
}
/* Do NOT give `.sppb-person-information` a position here. It is absolutely positioned over the
   photograph by the theme; a `position: relative` (tried, screenshotted) drops all four names out
   of their frames and onto the white below. It is the later sibling of `.sppb-person-image`, so it
   already paints above the scrim without any z-index. */
.sppb-addon-person .sppb-person-name { text-shadow: 0 1px 12px rgba(14, 41, 71, .55); }

/* --- 8. The sticky booking button --------------------------------------------------------------
   #marcarConsulta is inline-styled `right:0; bottom:10%`, and its SVG renders at natural size. At
   390px that box lands in the middle of the right edge and sat ON TOP of the homepage's
   "FEITAS A PENSAR EM SI!" line, hiding the last two words. Inset it, pin it near the bottom, and
   shrink it on a phone so it stops covering copy. (The inline style forces !important.) */
#marcarConsulta { right: 14px !important; bottom: 20px !important; }
#marcarConsulta svg { display: block; width: 132px; height: auto; }
@media (max-width: 767px) {
  #marcarConsulta { right: 8px !important; bottom: 10px !important; }
  #marcarConsulta svg { width: 100px; }
}

/* --- 10. Magazine index ------------------------------------------------------------------------
   The leading pair and the 3-up grid below it use different card shells, so a broken thumbnail in
   the leading pair left one card 200px shorter than its neighbour. Give every card the same image
   ratio and let the row align on its top edge. */
.article-list .article-intro-image img { width: 100%; height: 100%; object-fit: cover; display: block; }
.article-list .article-intro-image { aspect-ratio: 16 / 10; overflow: hidden; margin-bottom: 18px; }
.articles-leading .article { margin-bottom: 45px; }
.article-list .row { align-items: flex-start; }
.article-list .article-body { padding-bottom: 6px; }

/* Brand tile standing in for a card thumbnail that is not in the restore (see
   brand_thumb_for_imageless_cards). Same ratio and same bottom margin as a real thumbnail, so the
   grid keeps its rhythm; the wordmark makes it read as a brand tile, not as a failed image. */
.luso-thumb {
  aspect-ratio: 16 / 10;
  margin-bottom: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
  background-image:
    radial-gradient(110% 90% at 24% 10%, rgba(255, 255, 255, .16) 0%, rgba(255, 255, 255, 0) 60%),
    linear-gradient(135deg, #2b6cb8 0%, #2560A5 45%, #17406f 100%);
}
.luso-thumb span {
  font-family: "Abril Fatface", Georgia, serif;
  font-size: 30px;
  color: #fff;
  opacity: .92;
  letter-spacing: .5px;
}

/* --- 11. Membership tiers on /clube-lusoclinic/ ------------------------------------------------
   Set the tier name above its benefits list in the page's own display face, with the same rule the
   page uses between blocks. */
.luso-tier {
  text-align: inherit;
  color: #2560A5;
  margin: 0 0 2px;
  letter-spacing: .5px;
}
.luso-tier + .sppb-addon-title { color: #8a8a8a; margin-top: 0; }

/* A section that lost its image column keeps padding sized for a photograph, which left ~250px of
   white between the three membership blocks on /clube-lusoclinic/.
   Re-measured 2026-08-17: with this rule in place each tier section is 500px around ~400px of
   content, and the remainder is the page's OWN rhythm - the tier heading addon carries
   `padding:50px 0 0` and 50px line-height titles in its inline styling. That is the design, so it
   stays; only the padding sized for a photograph is taken back here. */
.sppb-section:has(.luso-col-empty) { padding-top: 24px !important; padding-bottom: 24px !important; }

/* --- 13. The authored /estetica/ hub printed its title twice -----------------------------------
   The page-title band already sets "Estética" at 80px; the hub's own <h1> repeated it at 80px
   immediately below, so the page opened with the same word twice in the same size. Keep the <h1>
   in the document (it is the page's heading for a reader and for search) and take it out of the
   visual flow. */
[data-luso-authored] > .sppb-row-container h1.sppb-addon-title {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --- 14. The promo carousel's own navigation ---------------------------------------------------
   Removing the dead `Joomla.getOptions` call (see _scripts/luso_sliders.py) let the page's own
   owl.carousel init run again, so `.image-slider` is a real carousel once more. owl only ships
   its skeleton css; the skin lived in the theme's preset1/custom pair, which has no capture, so
   navText rendered as two bare Font Awesome arrows piled in the bottom-left corner of the band.
   Dress them as the round side controls this addon is drawn for, in the clinic's own blue. */
.image-slider { position: relative; }
.image-slider .owl-nav { margin: 0; }
.image-slider .owl-nav button.owl-prev,
.image-slider .owl-nav button.owl-next {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .92) !important;
  color: #2560A5;
  font-size: 18px;
  line-height: 44px;
  text-align: center;
  box-shadow: 0 2px 10px rgba(14, 41, 71, .25);
  z-index: 3;
}
.image-slider .owl-nav button.owl-prev { left: -6px; }
.image-slider .owl-nav button.owl-next { right: -6px; }
.image-slider .owl-nav button:hover { background: #fff !important; color: #17406f; }
.image-slider .owl-dots { text-align: center; margin-top: 14px; }
.image-slider .owl-dots button.owl-dot span {
  display: inline-block;
  width: 8px;
  height: 8px;
  margin: 0 4px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .45);
}
.image-slider .owl-dots button.owl-dot.active span { background: #fff; }
/* The centre slide is scaled up by the addon's own onInitialized hook (.active-one/.active-two);
   without a transition it snaps. Match the 400ms the prev/next triggers already use. */
.image-slider .owl-item img { transition: transform .4s ease; }

/* --- 15. Role names running off their tile -----------------------------------------------------
   The four `sppb-addon-person` tiles on /carreiras/ (and the same strip on the homepage) set the
   name in Abril Fatface at a fixed display size over the photograph. In a 4-up row that column is
   ~250px, and "Nutricionista" is one 13-character word that cannot wrap: at 1440px it ran past the
   right edge of its own photograph, and "Esteticista" with it. Tie the size to the column instead
   of the window's whim, and let a long name break rather than escape. The cap is the size the
   design already uses at full width, so nothing gets bigger. */
.sppb-addon-person .sppb-person-information > span.sppb-person-name,
.sppb-addon-persion .sppb-person-information > span.sppb-person-name {
  display: block;
  max-width: 100%;
  font-size: clamp(17px, 2vw, 30px);
  line-height: 1.12;
  overflow-wrap: break-word;
}

/* --- 12. Fine print set at 8px -----------------------------------------------------------------
   The homepage promo band's disclaimer is 8px in the site's own inline styling. At that size it is
   not readable on any screen; 12px still reads as fine print. */
#sppb-addon-1618247001561 { font-size: 12px !important; letter-spacing: .04em; }

/* --- 16. Medicina Dentaria: seven cards, one photograph ----------------------------------------
   The category page repeated /img/20210311-dentista-categoria as the whole of all seven cards,
   and the six sub-pages hold no photograph of their own to borrow. Rebuilt as described cards:
   the visitor now learns what each treatment is before clicking, the last card no longer reads as
   an orphan because every card has a frame, and the real photograph is used once, above them. */
.luso-cardgrid {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 22px; margin: 34px 0 12px;
}
.luso-card {
  flex: 1 1 280px; max-width: 320px;
  display: flex; flex-direction: column; align-items: flex-start;
  padding: 26px 24px 20px; background: #fff;
  border: 1px solid #e2e9f3; border-radius: 12px;
  box-shadow: 0 2px 10px rgba(37, 96, 165, .06);
  text-decoration: none; color: inherit; text-align: left;
  transition: box-shadow .25s ease, transform .25s ease, border-color .25s ease;
}
.luso-card:hover, .luso-card:focus {
  text-decoration: none; color: inherit;
  border-color: #b9cde6; box-shadow: 0 10px 26px rgba(37, 96, 165, .14); transform: translateY(-3px);
}
.luso-card-icon {
  display: flex; align-items: center; justify-content: center;
  width: 52px; height: 52px; margin-bottom: 16px; border-radius: 50%;
  background: #eaf1fa; color: #2560a5; font-size: 22px;
}
.luso-card-title { display: block; margin: 0 0 8px; font-size: 19px; line-height: 1.25; color: #2560a5; }
.luso-card-text { display: block; flex: 1 1 auto; margin-bottom: 16px; font-size: 14.5px; line-height: 1.6; color: #5b6472; }
.luso-card-more { font-size: 12px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase; color: #2560a5; }
.luso-card-more::after { content: " \203A"; }

/* --- 17. Clube LusoClinic: three tiers are a comparison, so they must sit side by side ----------
   Each tier is its own sppb-section with two md-6 columns, one of which held a tier photograph the
   archive never captured. The result was three half-width lists down the left of a 1440px page,
   each trailing ~200px of empty air, with the right half blank to the footer. Float the three
   sections into one row, drop the empty photo columns, and give each tier a card frame so the
   reader can run an eye across them. Below 768px they stack, which is what a phone wants. */
#section-id-1590522264058, #section-id-1590525033335, #section-id-1590525033343 { box-sizing: border-box; }
#section-id-1590522264058 .luso-col-empty,
#section-id-1590525033335 .luso-col-empty,
#section-id-1590525033343 .luso-col-empty { display: none !important; }
#section-id-1590522264058 .sppb-col-md-6,
#section-id-1590525033335 .sppb-col-md-6,
#section-id-1590525033343 .sppb-col-md-6 { flex: 0 0 100%; max-width: 100%; }
#section-id-1590522264058 > .sppb-container-inner,
#section-id-1590525033335 > .sppb-container-inner,
#section-id-1590525033343 > .sppb-container-inner {
  background: #fff; border: 1px solid #dde5f0; border-radius: 12px;
  padding: 26px 22px; box-shadow: 0 2px 10px rgba(37, 96, 165, .06);
}
#section-id-1590522264058 h3.luso-tier,
#section-id-1590525033335 h3.luso-tier,
#section-id-1590525033343 h3.luso-tier {
  margin-bottom: 4px; color: #2560a5; border-bottom: 2px solid #eaf1fa; padding-bottom: 10px;
}
#section-id-1590522264058 ul, #section-id-1590525033335 ul, #section-id-1590525033343 ul {
  padding-left: 18px; font-size: 14.5px; line-height: 1.55;
}
@media (min-width: 768px) {
  #section-id-1590522264058, #section-id-1590525033335, #section-id-1590525033343 {
    float: left; width: 33.333%; padding: 0 9px;
  }
  /* the three tiers are the last children of this column, so the float has to be cleared here */
  #column-id-1531285853057 > .sppb-column-addons::after { content: ""; display: block; clear: both; }
}

/* --- 18. The savings the club page promised and then did not show ------------------------------
   "Repare no que pode poupar!" was followed by an empty image-slider addon: a heading over
   nothing. It now carries the tier comparison, built only from figures printed on this page. */
.luso-compare-wrap { overflow-x: auto; margin: 26px 0 10px; }
.luso-compare { width: 100%; border-collapse: collapse; font-size: 15px; background: #fff; }
.luso-compare th, .luso-compare td { padding: 12px 14px; border-bottom: 1px solid #e6ecf5; text-align: center; }
.luso-compare thead th { background: #2560a5; color: #fff; font-size: 13px; letter-spacing: .06em; text-transform: uppercase; }
.luso-compare tbody th { text-align: left; font-weight: 600; color: #333; }
.luso-compare tbody tr:nth-child(even) { background: #f7fafd; }
.luso-compare tbody tr:last-child th, .luso-compare tbody tr:last-child td { font-weight: 700; color: #2560a5; }

/* --- 19. Promo strip: the posters were dated, the treatments are not ---------------------------
   The five slides were Christmas 2021 posters with "Valores validos ate 31/12/2021" printed in
   them. They are now photographs of treatments still offered, so each slide needs the caption the
   poster used to carry, and needs to look clickable. */
.image-slider .luso-promo { position: relative; display: block; color: #fff; text-decoration: none; }
.image-slider .luso-promo img { display: block; width: 100%; }
.image-slider .luso-promo-label {
  position: absolute; left: 0; right: 0; bottom: 0; padding: 34px 18px 16px;
  font-size: 17px; line-height: 1.25; color: #fff; text-align: left;
  background: linear-gradient(rgba(15, 32, 54, 0), rgba(15, 32, 54, .78));
}
.image-slider .luso-promo:hover .luso-promo-label { text-decoration: underline; }

/* --- 20. Addons the archive left with nothing inside -------------------------------------------
   SP Page Builder keeps the wrapper even when its image or slider is gone, so several pages
   carried invisible boxes that still took vertical space - the ~120px gap under "Conheca o melhor
   para si e para toda a familia!" was one of them. */
.sppb-addon-single-image-container:empty,
.sppb-addon-image-slider:empty { display: none; }
.sppb-addon-single-image:has(> .sppb-addon-content > .sppb-addon-single-image-container:empty) { display: none; }

/* --- 21. The contact form was the one grid on the site that did not stack ----------------------
   The three fields sit in Bootstrap's non-responsive .col-4, so at 390px they stayed in one row at
   about 90px each with their labels wrapping. */
@media (max-width: 767.98px) {
  .rsform .form-row > [class^="col-"], .rsform .form-row > [class*=" col-"] {
    flex: 0 0 100%; max-width: 100%;
  }
}

/* --- 22. The booking badge covered what it floated over ----------------------------------------
   The fixed "Marque aqui a sua consulta" badge is sized for the desktop; at 390px it sat on top of
   page content and, on the longer pages, on the footer's privacy-policy link. Shrink it at phone
   width and keep the footer clear of it. */
@media (max-width: 767.98px) {
  [style*="z-index: 99999"] { transform: scale(.6); transform-origin: 100% 100%; opacity: .95; }
  #sp-footer, #sp-bottom { padding-bottom: 70px; }
}

/* --- 23. Two corrections found by looking at the rebuilt pages ---------------------------------
   (a) The dental card strip sits in an md-8 column flanked by two empty md-2 columns, which left
       room for only two cards per row - seven cards then ended on a lone tile, the very thing the
       repeated-photo layout was criticised for. Drop the empty gutters, cap the lead photograph at
       its natural width so it is not upscaled, and the seven cards fall 4 + 3.
   (b) The promo band's fine print is white-on-blue; its new link inherited the site's blue and
       vanished into the background. */
#column-wrap-id-1531724652286, #column-wrap-id-1532505030326 { display: none; }
@media (min-width: 768px) {
  #column-wrap-id-1532505030325 { flex: 0 0 100%; max-width: 100%; }
  .luso-cardgrid .luso-card { flex: 1 1 240px; max-width: 268px; }
}
#sppb-addon-1589836367356 img { max-width: 680px; margin-left: auto; margin-right: auto; }
#sppb-addon-1618247001561 a { color: #fff; text-decoration: underline; }

/* --- 24. A deck of four promotions, laid out for four ------------------------------------------
   The strip was emitted twice over (see _scripts/luso_promo_dedupe.py) to fill the five tiles the
   page's own owl init asks for at >=996px. With the duplicates gone the deck holds four, so the
   view is four wide - but the theme's fan is keyed to the five-slot row and its widths are
   `!important`: four tiles at 160/160/350/160 leave ~190px of blue at the right and owl's own
   step (container/items) no longer matches what is painted. Re-cut the same fan for four slots,
   at the two container widths bootstrap actually uses (1140 at >=1200, 940 at 992-1199), so the
   painted row still measures exactly one container: 222*3 + 354 + 4*30 = 1140.
   The big tile stays under the addon's 360px stage height, which is why it is 354 and not 390. */
@media (min-width: 1200px) {
  .sppb-addon-image-slider .owl-item.active { width: 222px !important; }
  .sppb-addon-image-slider .owl-item.active.active-three { width: 354px !important; }
}
@media (min-width: 996px) and (max-width: 1199.98px) {
  .sppb-addon-image-slider .owl-item.active { width: 173px !important; }
  .sppb-addon-image-slider .owl-item.active.active-three { width: 301px !important; }
}

/* --- 25. The Clinicas row was a two-line column beside a 1000px one ----------------------------
   /contatos/ puts "Clinicas" and two sentences in one md-6 and the four clinic panels in the
   other, so at 1440 the left half ran empty for about 900px under three lines of type - on the
   second page a visitor opens. Nothing is missing from the row; it is one column too many. Let the
   heading introduce the row across its full width and set the four clinics two-up beneath it, so
   the panels get the width their long headings need and the hole closes. Phone is untouched: below
   768px the row already stacks and the panels are one-up. */
@media (min-width: 768px) {
  #column-wrap-id-1582204418693,
  #column-wrap-id-1582204418696 { flex: 0 0 100%; max-width: 100%; }
  #sppb-addon-1582204418681 .sppb-panel-group {
    display: grid; grid-template-columns: 1fr 1fr; gap: 0 24px; align-items: start;
  }
}

/* --- 26. The treatment rail, which held one button and then nothing ----------------------------
   66 pages share this template (see _scripts/luso_treatment_rail.py), so the empty third of the
   page repeated more often than any other defect on the site. The rail now carries the section's
   other treatments and the contact route the contacts page publishes - the site's own material,
   set quietly so it stays a rail and does not compete with the article.
   Hidden below 768px on purpose: there the column stacks ABOVE the article, where a list of links
   would push the treatment's own title off the first screen. */
.luso-rail { display: none; }
@media (min-width: 768px) {
  .luso-rail { display: block; margin-top: 30px; padding-right: 26px; }
  .luso-rail .luso-rail-title {
    margin: 0 0 10px; font-size: 12.5px; font-weight: 700; letter-spacing: .08em;
    text-transform: uppercase; color: #2560a5;
  }
  .luso-rail-list { list-style: none; margin: 0 0 28px; padding: 0; }
  .luso-rail-list li { border-bottom: 1px solid #e6ecf5; }
  .luso-rail-list a {
    display: block; padding: 9px 0; font-size: 14.5px; line-height: 1.35;
    color: #4a5462; text-decoration: none;
  }
  .luso-rail-list a:hover { color: #2560a5; }
  .luso-rail-contact { margin: 0; font-size: 14.5px; line-height: 1.75; color: #4a5462; }
}

/* --- 35. The two genetic-test pages ended on a headline with nothing under it -------------------
   (Numbered 35, not 25: a section number here is a unique identifier stamped when the fix was
   written, not a reading order. This block and the next one were added in a round that re-used 25
   and 26, which were already taken above, so the file's own index pointed at two places at once.)
   /teste-foodhealth/ and /teste-guthealth/ both closed with "Já pode fazer o seu teste nas
   clínicas LusoClinic!" and an empty content div. They now carry the campaign photograph the site
   published for that test and two real destinations. The photograph is 1200px wide and would be
   upscaled to the 1170px measure; hold it to a readable width and centre it, and let the two
   buttons wrap instead of colliding at 390px. */
.luso-test-shot img { max-width: 620px; margin-left: auto; margin-right: auto; border-radius: 4px; }
.luso-test-cta { display: flex; flex-wrap: wrap; gap: 12px; justify-content: center; margin-top: 22px; }
/* SP Page Builder paints every .sppb-btn-custom from a per-button #btn-<id> rule printed into the
   page's own inline <style>; a button we add has no such rule and would render as transparent text
   on white. These two carry the site's own button colours instead. */
.luso-test-cta .sppb-btn-custom { background-color: #2560A5; color: #fff; font-size: 16px; }
.luso-test-cta .sppb-btn-custom:hover { background-color: #4498ff; color: #fff; }

/* --- 36. Magazine cards now say when they were published ---------------------------------------
   The index carried no date on any card. The label sits under the headline in the face this
   template uses for article meta, quiet enough not to compete with the title. */
.luso-card-date {
  font-family: "Montserrat", "Raleway", sans-serif;
  font-size: 12px; letter-spacing: .8px; text-transform: uppercase;
  color: #9099a5; margin: -6px 0 10px;
}

/* 27 was the Christmas campaign grid. The page it styled (/parceiros-descontos/natal/) was
   withdrawn - the offers expired in 2021 and their prices are burnt into the posters - and the
   rules outlived it: .luso-archive-grid and .luso-season-note matched zero elements on all 97
   pages, while the comment above them went on describing a campaign this site does not have.
   Removed rather than left as dead code, because a buyer who opens the stylesheet reads it. */

/* --- 28. The backlink weave band now reads in the page's own voice ------------------------------
   Its body copy computed at 14px/21px while the COVID band directly above it is 18px/30px - the
   single most obvious tell that a block was injected. These are the COVID band's own declarations
   (#sppb-addon-1604313869470 in the homepage's inline style), applied to the weave addon, phone
   step included. */
#sppb-addon-1755400000102 { font-size: 18px; line-height: 30px; color: #7f7f7f; }
/* The paragraph is now a direct child of .content-wraparea instead of sitting inside a nested
   .sppb-addon-content (see §38), so this weight declaration follows it to the <p>. */
#sppb-addon-1755400000102 .content-wraparea > p { font-weight: 500; }
@media (max-width: 767px) {
  #sppb-addon-1755400000102 { font-size: 16px; line-height: 26px; }
}

/* --- 29. One component, two renderings ---------------------------------------------------------
   The four role tiles appear on the homepage teaser and again on /carreiras/. On /carreiras/ they
   sit in a normal page-builder row with ~24px gutters; the homepage row carries .sppb-no-gutter,
   so the same four tiles were butted edge to edge and the two renderings disagreed. Give the
   homepage row the gutter its twin has. (The id is on the homepage markup only - every other
   occurrence of that id is in the copied inline <style>.) */
#section-id-1530777050259 .sppb-row.sppb-no-gutter { margin-left: -12px; margin-right: -12px; }
#section-id-1530777050259 .sppb-row.sppb-no-gutter > [class*="sppb-col-"] {
  padding-left: 12px; padding-right: 12px;
}

/* --- 30. ...and the tile that was 11px short ---------------------------------------------------
   On /carreiras/ three role photographs are 350x498 and the Esteticista one is 700x966, so its
   tile ended 11px above its neighbours and its caption rode correspondingly high. Hold every role
   photograph to the ratio the other three share. */
.sppb-addon-person .sppb-person-image img {
  aspect-ratio: 350 / 498; width: 100%; height: auto; object-fit: cover; display: block;
}

/* --- 31. The most expensive membership tier looked disabled ------------------------------------
   On /clube-lusoclinic/ the CLUBE and FAMILY CLUBE price tiles are the clinic's blue on pale blue
   (#column-id-1590514443840 / ...842: background #F2F5FF, 5px #2560A5 shadow); PLATINUM CLUBE was
   #adadad type on #fbfbfb behind a grey shadow, so the top tier read as greyed out. The archive
   shares this, and it is still wrong: put the top tier in the same livery as its two siblings. */
#column-id-1590514443844 { background-color: #F2F5FF !important; box-shadow: 0 0 5px 0 #2560A5 !important; }
#sppb-addon-1590516605273 .sppb-addon-title { color: #2560A5 !important; }
#sppb-addon-1590516605259 .sppb-pricing-price { color: #2560A5 !important; }

/* --- 32. The only price list on the site arrived cut off on a phone ----------------------------
   Measured on /parceiros-descontos/packs-promocionais/ at 390px: each of the four tables laid out
   at 414px inside a 360px .table-responsive, so the fourth column ("12 SESSÕES COM 20% DESCONTO")
   was sliced through - the header read "1... SESS... CO... 20... DESC" and 196€/168€/216€ showed as
   19/168/21. The wrapper does scroll, but Chrome's overlay scrollbars mean a resting page offers no
   hint that there is a column to swipe to, and a price a visitor never learns is a price the page
   did not publish.
   Two measures, in this order: take the 54px back so the table simply fits (the cells are set at
   the desktop's padding and type size, which no phone needs), and force a real, always-drawn
   scrollbar so that any table that still overflows says so. Styling ::-webkit-scrollbar is what
   turns Chrome's overlay scrollbar into a classic one that is visible at rest.
   Applies to the four pages that carry a table: packs-promocionais, estetica/pedicure-medical,
   estetica/osteopatia and estetica/extensao-de-pestanas. */
@media (max-width: 767.98px) {
  .table-responsive > table.table th,
  .table-responsive > table.table td { padding: 8px 5px; font-size: 11.5px; }
  .table-responsive > table.table td p { font-size: 11.5px; line-height: 1.5; margin-bottom: 0; }
  .table-responsive { scrollbar-width: thin; scrollbar-color: #2560A5 #e6ecf5; padding-bottom: 2px; }
  .table-responsive::-webkit-scrollbar { height: 8px; }
  .table-responsive::-webkit-scrollbar-track { background: #e6ecf5; border-radius: 4px; }
  .table-responsive::-webkit-scrollbar-thumb { background: #2560A5; border-radius: 4px; }
}

/* --- 33. /contatos/ centred a 200px column against a 1000px one --------------------------------
   The "Clínicas" row is `.sppb-row.sppb-align-center`, so at 1440px its heading and two sentences
   were centred against the four clinic panels beside them: ~430px of empty white above the heading
   and ~400px below, the largest hole left on the site. Top-align this one row so the heading starts
   level with the first panel it introduces. Scoped by section id: the row above it (map against
   contact block) is two blocks of similar height and centring is right there.
   sppagebuilder.css writes `.sppb-align-center{align-items:center!important}`, so an id selector is
   not enough on its own - the override has to carry !important as well. */
#section-id-1582204418692 > .sppb-row-container > .sppb-row.sppb-align-center {
  align-items: flex-start !important;
}

/* --- 34. Bare web addresses printed as text ----------------------------------------------------
   The partnership pages close on a partner's address inside an <a> with no href (the outbound-links
   policy keeps the element and drops the link). A URL has no spaces, so it cannot wrap: on
   /parceria-laser-system/ the deep link measured 407px against a 390px viewport with no ancestor
   that scrolls, and was clipped mid-path. That anchor now carries the host alone, like its siblings;
   this rule is the net under the other three, so no address can ever run off the page. */
.sppb-addon-content a:not([href]) { overflow-wrap: anywhere; }

/* --- 37. The footer's dashed rule was declared as a photograph ---------------------------------
   /img/arrow-c10537a4.webp is 362x6 and 193 bytes: a dashed line in the clinic's blue, printed
   twice in the footer of all 97 pages as `<img ... alt="Image">`. As markup that is wrong twice
   over - a screen reader announces "Image" 194 times across the site, and qa_client_bar counts a
   horizontal rule as a content photograph reused on 97 pages. It is decoration, so it lives here.
   Measured before and after: the element it replaces rendered 350x6 in the 350px footer column.
   `aspect-ratio` keeps the height following the width the way `height:auto` did on the <img>, and
   `background-size:100% 100%` fills the box exactly as the bitmap did, so the rule is unchanged
   to the pixel rather than merely similar. */
.luso-rule {
  display: inline-block; width: 362px; max-width: 100%; aspect-ratio: 362 / 6;
  background: url(/img/arrow-c10537a4.webp) center center / 100% 100% no-repeat;
}

/* --- 38. The backlink band lost its borrowed illustration and took the full measure -------------
   The band was a 6/6 row: the paragraph on the left, and on the right the calendar illustration
   that is step 1 of the three-picture booking sequence on /medicina/consulta-online/ and
   /estetica/consulta-online/. Beside the one paragraph the client is paying for, an unrelated
   cartoon is exactly what makes a woven block read as an ad unit; and it put that illustration on
   a third page. The column is now md-12, so hold the line length to something readable instead of
   letting a single paragraph run the full 1110px measure, and keep it optically centred under the
   COVID band above it. */
#sppb-addon-1755400000102 .content-wraparea { max-width: 860px; margin-left: auto; margin-right: auto; }
/* The heading inherited the addon's #7f7f7f body colour and rendered visibly washed out beside
   "COVID19 - Plano de Contingência Lusoclinic" directly above it - the same tell §28 was written
   to remove from the body copy. These are the COVID band's own title declarations
   (#sppb-addon-1604313869470 .sppb-addon-title in the homepage's inline style), phone step
   included, so the two headings are now the same object. */
#sppb-addon-1755400000102 .sppb-addon-title {
  color: #353B41; font-size: 40px; line-height: 40px; font-weight: 400; margin-bottom: 23px;
}
@media (max-width: 767px) {
  #sppb-addon-1755400000102 .sppb-addon-title { font-size: 35px; line-height: 32px; margin-bottom: 20px; }
}

/* --- 39. ...and the same deck at the widths the three-up view covers ----------------------------
   §24 re-cut the theme's five-slot fan for the two FOUR-item views, which is everything from
   996px up. The page's own owl init switches to items:3 at 480px, so the whole 480-995 band was
   still running on the theme's untouched widths and every round before this one shot 1440 and 390
   only. Measured from the stage rather than eyeballed:

     * at 900 and 768 the three tiles are 125/200/125 and fill 510px of a 690px stage, so 180px of
       bare blue sits at the right of the deck and reads as a tile that failed to load;
     * at 480 the theme's own `max-width: 480px` rule (88vw) collides with items:3 - tile 1 is
       painted 422px wide inside a 450px stage and tiles 2 and 3 are laid out at x=467, outside it;
     * 576-767 was already exact (125 + 200 + 125 + two 30px gutters = the 510px stage) which is
       why the two widths the last review did measure looked right.

   Owl lays the row out as floats inside a stage it sizes itself, so the row measures
   w1 + w2 + w3 + 2 gutters and has to equal the stage exactly. The fan keeps the theme's
   small/BIG/small shape at 1 : 1.6 : 1, and the middle tile stays under the addon's 360px stage
   height. Each bootstrap container width gets its own branch because the stage follows it:
   690px at 768-991, 930px at 992-995, and below 576 the container is fluid, so there the same
   arithmetic is written in vw - the unit the theme itself already uses for this component. */
@media (min-width: 480px) and (max-width: 575.98px) {
  .sppb-addon-image-slider .owl-item.active,
  .sppb-addon-image-slider .owl-item.active.active-three {
    width: calc(27.7778vw - 25px) !important;
  }
  .sppb-addon-image-slider .owl-item.active.active-two {
    width: calc(44.4444vw - 40px) !important;
  }
}
@media (min-width: 768px) and (max-width: 991.98px) {
  .sppb-addon-image-slider .owl-item.active,
  .sppb-addon-image-slider .owl-item.active.active-three { width: 175px !important; }
  .sppb-addon-image-slider .owl-item.active.active-two { width: 280px !important; }
}
/* The 992-995 sliver is the one place where the 3-item view meets bootstrap's 960px container,
   and it needs the vertical rules too: the theme only hands the three-up view its 20px/30px tile
   offsets below 991px, so up here the middle tile kept the four-up view's 80px drop and a 354px
   tile fell 74px through the floor of the addon's 360px stage. 310 + 20 offset + the owl-item's
   own 30px is exactly 360, which is why the middle is 310 and not the 387 the ratio would ask. */
@media (min-width: 992px) and (max-width: 995.98px) {
  .sppb-addon-image-slider .owl-item.active,
  .sppb-addon-image-slider .owl-item.active.active-three { width: 280px !important; }
  .sppb-addon-image-slider .owl-item.active.active-two { width: 310px !important; }
  .sppb-addon-image-slider .owl-item.active.active-two > .item { margin-top: 20px; }
  .sppb-addon-image-slider .owl-item.active.active-three { margin-top: 30px; }
}
/* The caption is set at 17px with 18px of side padding, which was written for the 222px and 354px
   tiles of the four-up deck. In the three-up view the small tiles are 108-125px, so 36px of that
   padding leaves ~80px of measure and "Blefaroplastia" ran past the edge of its own tile - visible
   in the 576px render before this round as well, so it is not damage from the widths above. Step
   the label down for the two narrow containers only; from 768 up the tiles are 175px and wider and
   the 17px setting fits on two lines. */
@media (min-width: 480px) and (max-width: 767.98px) {
  .image-slider .luso-promo-label { padding: 26px 8px 9px; font-size: 12.5px; line-height: 1.2; }
}

/* --- 40. Two partnership banners printed their title on top of the partner's own wordmark -------
   The archived /parceiros-descontos/parceria-germano-de-sousa/ and .../parceria-beauty-machines/
   both carry an EMPTY <h2> in the title band, and that is deliberate: their banner IMAGE already
   is the wordmark - "GERMANO DE SOUSA / CENTRO DE MEDICINA LABORATORIAL" and "Beauty Machines /
   Venda e Aluguer de Equipamentos de Estetica". A previous round invented a heading for them and
   the two texts landed on the same pixels, at 1440 and worse at 390 where the injected title wraps
   to two lines across the logo. Their four siblings are not touched: bleem, laser-system,
   breaking-my-limits and packs-promocionais all have a non-empty archived h2 over a photograph.

   The heading is not deleted - a title band with no heading at all costs the page its document
   outline and its most weighted piece of on-page text - it is taken off the picture. Both pages
   open with the same words as the first heading of the body, so nothing a visitor reads is lost.
   Not `display: none`, which drops the text from the accessibility tree as well as the screen. */
.sp-page-title h2.luso-title-offpicture {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden; white-space: nowrap;
  clip: rect(0 0 0 0); clip-path: inset(50%);
}

/* --- 41. The homepage hero is a photograph again -----------------------------------------------
   §1 gave this band an honest brand-blue surface because the archive has no usable still: the one
   hero image the 2023 homepage carried is /images/2021/12/06/20211206-natal.jpg, the Christmas
   campaign round 4 withdrew from this site, and the institutional MP4 behind it was 448 MB and
   never fetched. A flat surface was the right answer while that was the whole choice. It is not
   the right answer now that a still can be made: every other title band on the site is a
   photograph, and the homepage was the one page that was not.

   The picture goes UNDER the scrim, not instead of it. The gradient stack below is §1's, byte for
   byte, with the photograph appended as the last (bottom) layer - so the headline keeps exactly
   the contrast it had, measured at 4.97:1 against white before the file was accepted, while the
   band gains depth and texture. What the image may show was constrained before it was generated:
   no people, no faces, no text, no signage, no logos, nothing that could be read as a claim about
   this clinic's rooms, staff, equipment or results. It is a calm out-of-focus treatment-room
   interior in the site's own blue and white - mood, not evidence.

   Scoped to .luso-hero-photo, which exists on index.html only. /clube-lusoclinic/'s .luso-noimg
   slide stays collapsed by §2; it had no caption either, so a photograph there would be
   decoration standing in for content. */
.luso-hero-photo.luso-noimg {
  background-image:
    radial-gradient(115% 90% at 22% 8%, rgba(255, 255, 255, .17) 0%, rgba(255, 255, 255, 0) 58%),
    linear-gradient(135deg, rgba(43, 108, 184, .86) 0%, rgba(37, 96, 165, .82) 42%,
                            rgba(23, 64, 111, .88) 100%),
    url(/img/lusoclinic-hero-tratamentos-e7629a13.webp) !important;
  background-position: center center, center center, center 38% !important;
}

/* --- 42. The magazine article's hero, rendered the way the theme rendered it --------------------
   /magazine/sorria-com-invisalign/ is the site's only real article and it opened on a bare 80px
   heading. Its photograph was archived and was already shipped for the index card
   (20200425-Artigo-Invisalign_large), and putting the <img> back changed nothing on screen,
   because template.css hides it: `.blog-details-img-wrapper .article-full-image {display:none}`.
   That img was never the hero - it was the data the theme's JS read to set the WRAPPER's
   background-image before adding `.active`, which is the class carrying the design (150/270
   padding, cover, and a :before scrim). The build now does the JS's job in the markup.

   Two consequences to repair here. §? in restore-provisional forced the title dark for
   `:not(.active)` - correct while there was no hero, moot now - and the theme's own base rule
   would otherwise paint an 80px #000 title over a photograph. template.css already turns it white
   under 767px (line 3065); that is plainly the intent, so it applies at every width.

   The scrim goes from rgba(0,0,0,.3) to .55 for this one page, and the figure was measured rather
   than chosen: the photograph is a high-key white studio shot, so the brightest pixels under the
   title matter more than the average. Sampling the rendered band through a canvas that reproduces
   background-size:cover and compositing the scrim over it (_scripts/_luso_r7_contrast.js) gave the
   white title 3.60:1 at 1440 and 3.51:1 at 390 with .45 - which passes AA for 80px display type
   but not for text in general - and 5.08:1 / 4.95:1 with .55, which clears 4.5:1 outright. Scoped
   to the wrapper, so no other page can inherit it, and no other page has a hero to inherit it. */
.view-article .article-details .blog-details-img-wrapper.active:before {
  background-color: rgba(0, 0, 0, .55);
}
.view-article .article-details .blog-details-img-wrapper.active .article-header h1,
.view-article .article-details .blog-details-img-wrapper.active .article-header h2 {
  color: #fff;
  text-shadow: 0 2px 18px rgba(0, 0, 0, .35);
}

/* --- HIT AREA ----------------------------------------------------------------------------------
   WCAG 2.5.8 puts the floor for anything a finger must hit at 24x24 CSS px, 2.5.5 the standard at
   44. Nearly every failure on this site is one shape: a standalone link set `display:inline`, so
   its border box is the height of its glyphs - the hub lists are 103x16, the top menu 60x15 -
   while the line box around them is 21px. Vertical padding on an INLINE box enlarges the border
   box, and with it the hit target, WITHOUT changing the height of the line box: the lists keep
   their exact spacing and simply become hittable. That is why these are padding and not
   line-height, and why nothing below is a redesign.
   --------------------------------------------------------------------------------------------- */
.luso-hub-list li a,
.sppb-addon-content > a,
.sppb-feature-box-title a,
.sppb-addon-single-image-container > a,
.sp-module-content ul.menu li a { padding-block: 5px; }
/* The social column's links are 21px wide and 38 tall - tall enough, too narrow to hit. */
.sppb-icons-group-list li a { display: inline-block; min-width: 24px; text-align: center; }
/* The promo slider's dots were 16x21. The visible dot is the <span> inside and is left alone; only
   the button's own box grows to the 24px floor. */
.image-slider .owl-dots button.owl-dot { min-width: 24px; min-height: 24px; padding: 0; }
/* The careers form's field labels are 21px tall. A <label for=...> is a control - tapping it moves
   focus into its field, which is how a lot of people fill a form on a phone - so it takes the same
   24px floor. Two pixels of vertical padding, which the row's own margin absorbs. */
.form-group.row > label.control-label { padding-block: 2px; }

/* The two top-bar links, "Academia" and "Magazine", were already padded to a 25px box by the rule
   above - and a pointer only reached 21 rows of them, on every page, at 1440. The module that
   holds them is exactly as tall as its 19.5px line box, so the padding overflows 2px BELOW it and
   the first row of the megamenu underneath (li.sp-menu-item, y=27) takes those pixels. Giving the
   module room for its own links removes the collision instead of hiding it, and the padding goes
   to 6px so the box clears the 24px floor with something to spare rather than landing on it.
   Measured with _scratch/probe_overlap.js: 20 owned rows before, the full box after. */
#sp-menu1 .sp-module { margin-bottom: 10px; }
#sp-menu1 .sp-module-content ul.menu li a { padding-block: 6px; }

/* --- THE FORMS' OWN ANSWER ---------------------------------------------------------------------
   js/restore-forms.js prints one line under the submit saying what the press did, and marks the
   fields that are still empty. RSForm's own messages stay hidden (rule 4 above): they were written
   for a validator that is no longer here, and they all appeared at once. */
.luso-form-status {
  margin: 14px 0 0; padding: 10px 12px; font-size: 14px; line-height: 1.5;
  border-left: 3px solid currentColor;
}
.luso-form-status--sent { color: #17603a; background: #eef7f1; }
.luso-form-status--bad  { color: #8a1f1f; background: #fbeeee; }
.rsform-input-box.luso-field-bad, .rsform-text-box.luso-field-bad,
.rsform-select-box.luso-field-bad, .rsform-calendar-box.luso-field-bad {
  border-color: #8a1f1f; box-shadow: 0 0 0 1px #8a1f1f;
}
.rsform-checkbox.luso-field-bad { outline: 2px solid #8a1f1f; outline-offset: 2px; }

/* Where the CV and the treatment photographs used to have a file picker. A static site has nothing
   to upload TO, and a mailto: cannot carry an attachment, so the control was removed rather than
   left as a promise that cannot be kept; this says, before anything is typed, how the file
   actually travels. */
.luso-attach-note {
  margin: 0; padding: 10px 12px; font-size: 14px; line-height: 1.5;
  color: #2f3a45; background: #f2f6fa; border-left: 3px solid #2560A5;
}
