/* ============================================================
   Hablemos — design tokens (from Brand_guidelines.pdf)
   ============================================================ */
:root {
	--gold: #d3ac6e;
	/* A deeper companion for gold text on light surfaces. The main gold
	   remains untouched for backgrounds and large brand accents; this
	   shade exists only where the original 1.95:1 contrast was too low. */
	--gold-ink: #97661f;
	--red: #a53047;
	--cream: #f7f5f0;
	--ink: #1a1512;
	--paper: #f0e6d2;
	/* The dark accent for scenes/cards/the marquee — everywhere "ink"
	   was standing in as a plain black. A muted slate-navy (client asked
	   for blue) desaturated enough not to fight the warm gold/bordô
	   instead of a cold, saturated blue. The footer keeps true --ink;
	   this is deliberately a different, separate token. */
	--night: #2a3444;

	/* ---- Type scale -------------------------------------------------
	   Body copy is 16px everywhere, desktop and mobile — every inner
	   page used to set its own (18px here, 19px there, 15px in a note),
	   which is why sections read as if they'd been built by different
	   people. Headings step down from it on a fixed ratio so the
	   hierarchy is the same on every page.
	   Sizes that must shrink on small screens use clamp() against vw so
	   there is ONE declaration per role instead of a desktop value plus
	   a mobile override that drifts out of sync. */
	--hb-text: 16px;
	--hb-text-lh: 1.7;
	--hb-text-sm: 14px;
	--hb-lede: clamp(17px, 1.4vw, 20px);
	--hb-eyebrow: 12px;

	--hb-h1: clamp(2.1rem, 5vw, 4rem);          /* page cover headline */
	--hb-h2-hero: clamp(2.2rem, 5.6vw, 4.6rem); /* full-bleed scene claim */
	--hb-h2: clamp(1.6rem, 2.6vw, 2.2rem);      /* section heading */
	--hb-h3: clamp(1.1rem, 1.7vw, 1.35rem);     /* card / step heading */

	/* ---- Vertical rhythm --------------------------------------------
	   One spacing scale for the whole site. Section padding is a single
	   symmetric token: the old sections mixed values like `13vh 6vw` and
	   `10vw 4vw 8vw`, so the gap below a section was visibly larger than
	   the gap above the next one and the page rhythm limped. */
	--hb-s1: 8px;
	--hb-s2: 16px;
	--hb-s3: 24px;
	--hb-s4: 40px;
	--hb-s5: 64px;
	--hb-s6: 96px;
	--hb-section-y: clamp(72px, 8.5vw, 128px);

	/* Used by .hb-empresas--image (main.css) for its own photo/copy
	   column split. */
	--hb-empresas-gap: clamp(40px, 6vw, 96px);

	/* ---- Layout grid -------------------------------------------------
	   Every section shares this gutter and max width, so content lines
	   up vertically from the cover to the footer instead of each block
	   choosing its own inset. */
	--hb-gutter: clamp(20px, 5vw, 80px);
	--hb-max: 1240px;
	--hb-radius: 4px;

	/* THE ONE LEFT EDGE.
	   Everything that should line up vertically down the page — section
	   padding, the nav logo, the menu button, the footer — insets by
	   this. Custom properties resolve at use time, so the `100%` inside
	   it measures the element it is applied to, which is what makes one
	   declaration work for all of them.
	   Before this existed the nav sat at 3vw (42px), the footer at 4vw
	   (56px) and content at 72.5px: three different left edges stacked
	   down the same page.
	   --hb-inset-fixed is the position:fixed twin — fixed elements
	   measure against the viewport, which includes the scrollbar, so it
	   subtracts --hb-sbw to land on the same pixel. */
	--hb-inset: max(var(--hb-gutter), calc((100% - var(--hb-max)) / 2));
	--hb-inset-fixed: max(var(--hb-gutter), calc((100vw - var(--hb-sbw, 0px) - var(--hb-max)) / 2));
	/* The fixed nav's own height, as a token. It was written as the
	   literal 82px in five different files to compensate cover padding
	   and centre the menu button — but the nav is 68px on a phone, so
	   every one of those was over-compensating by 14px there. One value,
	   one override, and the compensations follow automatically. */
	--hb-nav-h: 82px;
	/* ESPACO DAS CAPAS. Terceira versao, e desta vez a medir a coisa certa.
	
	   A barra e opaca e creme, a mesma cor da capa por baixo dela, por isso
	   nao ha corte visivel entre as duas. Isso ja se sabia. O que estava
	   errado era a conclusao.
	
	   v1: padding-top = passo + altura da barra (82). Medido 204 acima
	       contra 122 abaixo. Queixa: espaco a mais em cima.
	   v2: padding simetrico. Medido 153/153 -- e queixa: espaco a mais em
	       BAIXO. Eu tinha igualado o padding da CAIXA, que nao e o que se
	       ve. O que se ve e o VAZIO, e os primeiros 63px do espaco de cima
	       nao estao vazios: tem o logotipo dentro. Medido tinta a tinta:
	       91 acima (base do logo ate ao sobrolho) contra 153 abaixo.
	   v3: (barra + logo) / 2, partindo do principio que a barra e a capa
	       sao um so campo creme sem costura. Medido em mobile: 55 acima
	       contra 76 abaixo. Ainda errado.
	
	   O que estava errado era a PREMISSA, nao a aritmetica. A barra tem
	   border-bottom: 1px solid em tinta cheia -- 16.6 de contraste sobre
	   creme, um traco perfeitamente visivel. Nao ha campo creme continuo
	   nenhum: a barra e uma banda fechada, e a capa comeca no traco. A
	   referencia certa nunca foi o logotipo, e a base da barra.
	
	   Logo: passo em baixo, passo + altura da barra em cima. Com
	   justify-content: center a folga divide-se ao meio dos dois lados,
	   por isso o vazio visivel fica igual em qualquer altura de ecra. */
	--hb-logo-h: 44px;
	--hb-cover-lead: var(--hb-nav-h);
}

/* ============================================================
   HORIZONTAL CAROUSEL SYSTEM

   One system for all three carousels — the homepage service cards,
   the Cursos/Exames level & date paths, and the Sobre nós chapters.
   Each track carries [data-carousel]; nothing else is needed.

   WHY THIS EXISTS: below 900px and under prefers-reduced-motion all
   three used to collapse into VERTICAL stacks. That was a fix for a
   real bug (GSAP's pin is unreliable on mobile viewports whose height
   changes as browser chrome hides), but it turned a horizontal
   carousel into something else entirely on the majority of visits.

   Native CSS scroll-snap does the job properly: real swipe, real
   snapping, keyboard scrolling and screen-reader access for free, no
   JavaScript, and it doubles as the reduced-motion mode. GSAP's pin
   stays desktop-only for the Cursos/Exames paths and the Sobre nós
   timeline, where it does the one thing CSS can't — translate vertical
   scroll into horizontal travel. The homepage cards are the one
   exception: their pin now runs at every width (svh-based heights
   below fix the viewport-jump bug directly instead of avoiding it —
   see motion.js's cardsPinTween), so they're carved out of the native
   fallback here on purpose.
   ============================================================ */
/* SPECIFICITY NOTE: selectors are doubled ([data-carousel][data-carousel],
   .hb-timeline.hb-timeline) purely to win. page.css and story.css load
   AFTER this file and set the desktop geometry with equal-specificity
   single selectors — `.hb-timeline__track { width: max-content }` and
   friends — so a plain attribute selector here loses on source order and
   the track silently never becomes a scroller. */
/* pointer:coarse joins the list: a tablet in landscape is wide enough to
   miss the 900px breakpoint but is still a finger, and the pinned
   alternative is a mouse-scroll device.

   Split in two, where this used to be one combined query. Reduced
   motion ALWAYS falls every [data-carousel] back to this native
   scroller, homepage cards included — motion.js never builds a GSAP
   pin in that branch regardless of viewport, so .hb-cards needs this
   fallback or its cards would sit in an unscrollable 100svh-tall flex
   row with only the first one ever visible. The narrow-viewport/
   coarse-pointer query below is the one that changed: it no longer
   touches .hb-choose/.hb-cards, because that pin now runs at every
   width (see motion.js's cardsPinTween) and needs to keep its pinned
   desktop geometry instead of this stacked/scroll-snap layout. */
@media (prefers-reduced-motion: reduce) {
	[data-carousel][data-carousel] {
		display: flex;
		flex-direction: row;
		width: 100%;
		height: auto;
		overflow-x: auto;
		overflow-y: hidden;
		scroll-snap-type: x mandatory;
		padding-inline: 6vw;
		scroll-padding-inline: 6vw;
		overscroll-behavior-x: contain;
		-webkit-overflow-scrolling: touch;
		scrollbar-width: none;
	}
	[data-carousel][data-carousel]::-webkit-scrollbar { display: none; }
	[data-carousel][data-carousel] > * {
		flex: 0 0 88vw;
		width: 88vw;
		height: auto;
		min-height: 62svh;
		scroll-snap-align: center;
		scroll-snap-stop: always;
	}
	.hb-choose.hb-choose,
	.hb-page2__path.hb-page2__path,
	.hb-timeline.hb-timeline {
		height: auto;
		overflow: visible;
	}
}
@media (max-width: 900px), (pointer: coarse) {
	/* .hb-timeline__track junta-se a .hb-cards nas excecoes: o pin do
	   timeline de Sobre nos passou a correr em todas as larguras, a
	   pedido, para o scroll do dedo fazer passar os capitulos tal como
	   faz na homepage. Precisa por isso de manter a geometria de pin em
	   vez de virar scroller nativo aqui. O bug de viewport que motivou
	   este fallback esta atacado na origem: story.css passou de 100vh
	   para 100svh (a altura MINIMA do viewport, que o esconder da barra
	   do browser nao consegue aumentar) e ScrollTrigger.config manda
	   ignorar o resize dessa transicao. */
	[data-carousel][data-carousel]:not(.hb-cards) {
		display: flex;
		flex-direction: row;
		width: 100%;
		height: auto;
		overflow-x: auto;
		overflow-y: hidden;
		scroll-snap-type: x mandatory;
		/* Panels are 88vw and the scroller is padded 6vw each side, so a
		   panel snapped to centre leaves an even 6vw of the neighbouring
		   panel showing. That sliver is the whole point: it is how a
		   reader knows there is more sideways without being told. */
		padding-inline: 6vw;
		scroll-padding-inline: 6vw;
		overscroll-behavior-x: contain;
		-webkit-overflow-scrolling: touch;
		scrollbar-width: none;
	}
	[data-carousel][data-carousel]:not(.hb-cards)::-webkit-scrollbar { display: none; }
	[data-carousel][data-carousel]:not(.hb-cards) > * {
		flex: 0 0 88vw;
		width: 88vw;
		height: auto;
		min-height: 62svh;
		scroll-snap-align: center;
		scroll-snap-stop: always;
	}
	/* The section around the track must stop being a fixed-height,
	   clipping box, or the track has nowhere to scroll. .hb-choose is
	   deliberately absent here now — see the note above. */
	/* .hb-timeline sai daqui: com o pin a correr tambem em mobile, a
	   seccao tem de continuar a ser a caixa de altura fixa que o pin
	   mede. Fica so o path, que mantem o gate do canPin(). */
	.hb-page2__path.hb-page2__path,
	.hb-timeline.hb-timeline {
		height: auto;
		overflow: visible;
	}
}

/* MOBILE EDITORIAL FLOW
   Carousels on narrow/touch screens become ordinary document sections.
   Their content is read top-to-bottom and can grow without a viewport
   cap; desktop keeps the pinned/horizontal presentation unchanged. */
@media (max-width: 900px), (pointer: coarse) {
	[data-carousel][data-carousel] {
		display: flex;
		flex-direction: column;
		width: 100%;
		height: auto;
		overflow: visible;
		padding: 0;
		scroll-snap-type: none;
	}
	/* Match the specificity of the old native-carousel fallback above,
	   which includes :not(.hb-cards). Without this explicit override the
	   timelines kept its horizontal row despite the later source order. */
	[data-carousel][data-carousel]:not(.hb-cards) {
		flex-direction: column;
		overflow: visible;
		padding: 0;
		scroll-snap-type: none;
	}
	[data-carousel][data-carousel] > * {
		flex: 0 0 auto;
		width: 100%;
		height: auto;
		min-height: 0;
		scroll-snap-align: none;
	}
	[data-carousel][data-carousel]:not(.hb-cards) > * {
		flex: 0 0 auto;
		width: 100%;
		min-height: 0;
		scroll-snap-align: none;
	}
	.hb-choose.hb-choose,
	.hb-page2__path.hb-page2__path,
	.hb-timeline.hb-timeline {
		height: auto;
		overflow: visible;
	}
	.hb-card {
		width: 100%;
		height: auto;
		min-height: 0;
		padding: var(--hb-section-y) var(--hb-inset);
		justify-content: flex-start;
	}
	.hb-card b { position: static; align-self: flex-start; margin-top: var(--hb-s3); }
}

/* The progress rail was removed at the client's request. The
   position of a panel is still exposed to assistive tech via each
   panel's aria-label, and .hb-choose/.hb-page2__path/.hb-timeline keep
   position:relative below because other absolutely-positioned children
   rely on it. */
.hb-choose, .hb-page2__path, .hb-timeline { position: relative; }

* { box-sizing: border-box; }
/* Lenis owns smooth scrolling at the JS level — native scroll-behavior:
   smooth fights it (competing scroll animations = the stuck/janky feel).
   Kept as `auto` so a no-JS fallback still jumps cleanly to anchors. */
html { scroll-behavior: auto; }
html.lenis { scroll-behavior: auto !important; }
body {
	margin: 0;
	background: var(--cream);
	color: var(--ink);
	font-family: 'Franie', Arial, Helvetica, sans-serif;
	overflow-x: hidden;
}
a { color: inherit; text-decoration: none; }
button { font: inherit; }
::selection { background: var(--gold); color: var(--ink); }

/* ============================================================
   Homepage
   ============================================================ */
.hb {
	--r: var(--red);
	--g: var(--gold);
	--c: var(--cream);
	--k: var(--ink);
	background: var(--c);
	color: var(--k);
	min-height: 100vh;
	font-family: 'Franie', Arial, sans-serif;
	overflow: clip;
}

.hb-loader {
	position: fixed;
	/* Above the fullscreen menu (10000) and its toggle button (10001),
	   which at the old z-index of 999 both rendered ON TOP of the loader
	   — the "Menu" button was visible over the entry animation before it
	   had finished. */
	z-index: 10005;
	/* NEVER remove this. The loader is a full-viewport fixed overlay that
	   is purely decorative — nothing in it is clickable. Leaving hit
	   testing on means that if its timeline ever fails to finish (a JS
	   error, GSAP failing to load, a stalled frame loop) the entire site
	   becomes unclickable. This must be a CSS guarantee, not something
	   JavaScript switches off at the end: the whole point is to survive
	   the JavaScript not running. */
	pointer-events: none;
	inset: 0;
	background: var(--r);
	color: var(--g);
	display: grid;
	place-items: center;
	clip-path: inset(0);
	overflow: hidden;
}
/* O FLASH ANTES DO LOADER, resolvido sem tocar no estado inicial.
   O HTML pinta as letras ja no sitio final; so quando o GSAP corre e que
   o .from() as arranca para fora e as traz de volta. Entre uma coisa e
   outra ve-se ¡Hablemos! pronto e quieto, e depois a saltar -- que e o
   "aparece a palavra antes do loader".

   Ja se tentou aqui um transform inicial em CSS e partiu a animacao,
   pela razao que o comentario antigo explicava: .from() le o estado
   ATUAL como destino, por isso um estado inicial em CSS passa a ser
   tambem o estado final e as letras acabavam deslocadas.

   `visibility` nao tem esse problema. Nao mexe em layout, nem em
   transform, nem em opacity -- nao ha nada nela que o .from() possa ler
   como destino. So impede que o elemento seja PINTADO. Os filhos comecam
   invisiveis e o motion.js arma-os (.is-armed) depois de construir a
   timeline, ou seja depois de o GSAP ja ter aplicado o estado deslocado:
   o primeiro frame pintado e o do inicio da animacao, nunca o do fim. */
.hb-loader > * { visibility: hidden; }
.hb-loader.is-armed > * { visibility: visible; }

/* Rede de seguranca em CSS puro, para o caso de o motion.js nunca chegar
   a correr (erro de JS, GSAP que nao carrega). Sem isto o loader fica um
   painel bordo por cima do site para sempre -- ja era assim antes desta
   alteracao, e agora seria um painel bordo VAZIO, pior ainda. Anima
   opacity/visibility, que sao propriedades em que o GSAP nao toca neste
   elemento (ele anima clip-path), por isso nao ha nada a disputar. O
   motion.js cancela-a assim que assume o controlo. */
@keyframes hb-loader-bail { to { opacity: 0; visibility: hidden; } }
.hb-loader { animation: hb-loader-bail 400ms linear 4s forwards; }

.hb-load__mark {
	position: absolute;
	display: block;
	font-size: min(30vw, 380px);
	color: var(--g);
	opacity: .22;
	filter: drop-shadow(0 0 40px var(--g));
}
.hb-load__mark i { color: var(--g); }
.hb-load__letters {
	display: flex;
	overflow: hidden;
	font-family: 'Amatry', Arial, sans-serif;
	font-size: clamp(4rem, 13vw, 13rem);
	font-weight: 400;
	letter-spacing: -.02em;
	z-index: 2;
}
.hb-load__letters span { display: block; }
/* The menu button sits behind the loader, so it can't be seen during the
   entry — this stops it being *clicked* blind as well. Fail-safe by
   construction: motion.js ADDS .hb-booting when it starts the loader and
   removes it when done, so if the script never runs the class is never
   applied and the button simply works. */
body.hb-booting .hb-menu-toggle { opacity: 0; pointer-events: none; }
.hb-loader small {
	position: absolute;
	bottom: 5vh;
	text-transform: uppercase;
	letter-spacing: .2em;
}

.hb-light {
	position: fixed;
	z-index: 5;
	width: 440px;
	height: 440px;
	border-radius: 50%;
	left: var(--hx, -500px);
	top: var(--hy, -500px);
	transform: translate(-50%, -50%);
	background: radial-gradient(circle, #fff8 0, #d3ac6e44 28%, transparent 67%);
	mix-blend-mode: soft-light;
	pointer-events: none;
}

.hb main, .hb-nav { position: relative; z-index: 3; }
.hb-nav {
	position: fixed;
	z-index: 20;
	top: 0; left: 0; right: 0;
	height: var(--hb-nav-h);
	/* Left edge shared with page content and the footer. Right side adds
	   room for the fixed menu button so a long logo can't run under it. */
	padding-left: var(--hb-inset-fixed);
	padding-right: calc(var(--hb-inset-fixed) + 64px);
	display: flex;
	align-items: center;
	border-bottom: 1px solid currentColor;
	background: var(--cream, var(--c));
	color: var(--ink, var(--k));
}
/* At 1200px+ the hamburger toggle is hidden (site.css) and .hb-nav-links
   sits in the flex row instead, so the 64px reserved for that toggle
   is dead space pushing Contactos left of where every other
   right-aligned element (hero CTA, etc.) sits on var(--hb-inset-fixed).
   Must come after the base rule above — same reason as the toggle's
   own override in site.css. */
@media (min-width: 1200px) {
	.hb-nav { padding-right: var(--hb-inset-fixed); }
}
.hb-nav__logo { display: flex; flex-direction: column; gap: 2px; }
.hb-nav__logo .hb-wordmark { font-size: 26px; }

/* THE LOGO, as artwork.
   Header and footer now use the real lockup rather than the wordmark
   set in Amatry. Height drives the size and width follows the file's
   own ratio, so the asset can be swapped for a different one without
   touching any of this. Served at 2x the display size, and the
   width/height attributes are the file's real pixels — they reserve
   the box before the image arrives, so the nav never jumps on load. */
/* align-self: flex-start nao e decoracao. .hb-nav__logo e um flex
   container em column, logo o eixo transversal e a LARGURA, e o
   align-items por omissao (stretch) estica a imagem ate a largura do
   contentor. No cabecalho o contentor encolhe ate 191px, que por acaso
   e a largura certa a 44px de altura, e nao se notava. No rodape o
   contentor tem 356px: o logo saia com racio 6.84 contra 4.33 do
   ficheiro -- 58% mais largo do que devia. */
.hb-logo { display: block; height: var(--hb-logo-h); width: auto; align-self: flex-start; }
.hb-logo--footer { height: 52px; }

/* The tagline is baked into the artwork now, so the separately-set one
   would say it twice. It stays in the loader and the rebrand section,
   where the type IS the device rather than a logo. */
.hb-nav .hb-tagline,
.hb-footer__brand .hb-tagline { display: none; }

.hb-hero {
	/* Was 100svh — that height was sized for the title PLUS the
	   paragraph and button that used to sit under it. With just the
	   title left, full-screen was mostly empty cream below the text. */
	min-height: auto;
	/* Same expression as every cover on the site: clear the nav, then
	   one section step. The homepage used to run on its own ad-hoc vh
	   padding (112/8vh here, 12vh on the years scene, 10vh/4vh on the
	   closing scene), which measured 120/28, 146/97 and 81/32 on a phone
	   while every inner page sat at a uniform 72/72. (The inner-page
	   covers went on to also match their own bottom padding to this same
	   top expression — see .hb-page2__cover in page.css — but the client
	   asked to leave the homepage hero as it already was, so this one
	   stays asymmetric on purpose.) */
	padding: calc(var(--hb-nav-h) + var(--hb-section-y)) var(--hb-inset) var(--hb-section-y);
	background: var(--cream);
	position: relative;
	overflow: hidden;
	display: flex;
	flex-direction: column;
	justify-content: flex-start;
}
/* The homepage hero is intentionally flat: no blurred colour orbs and no
   fade overlay. Its background is the same solid cream used by the section. */
.hb-hero::after { content: none; }
.hb-hero .hb-orb { display: none; }
.hb-orb {
	display: none;
	position: absolute;
	border-radius: 50%;
	filter: blur(55px);
	/* Was .6 — the client flagged the gold/red as too heavy on desktop
	   too (already toned down on mobile earlier). Down to .35 here,
	   matching red's own already-lighter .22 below. */
	opacity: .35;
	pointer-events: none;
	animation: hb-orb-float 9s ease-in-out infinite alternate;
}
.hb-orb--gold {
	width: 42vw; height: 42vw; background: var(--gold); right: -10vw; top: -12vw;
	translate: calc(var(--nx, 0) * 45px) calc(var(--ny, 0) * 35px);
}
.hb-orb--red {
	width: 28vw; height: 28vw; background: var(--red); opacity: .22; left: -6vw; bottom: -10vw;
	animation-delay: -4s;
	translate: calc(var(--nx, 0) * -55px) calc(var(--ny, 0) * -40px);
}
@keyframes hb-orb-float {
	from { transform: translateY(0) scale(1); }
	to { transform: translateY(-3vw) scale(1.06); }
}
@media (prefers-reduced-motion: reduce) {
	.hb-orb { animation: none; }
}

/* margin-top was `auto`, which in a flex column eats ALL the free space
   above the element — and the section is also justify-content:
   space-between, so the two were fighting: the title was pushed to 325px
   while the nav ends at 82, leaving 243px of nothing under the header.
   The section's own padding-top already clears the nav; the title just
   has to start there. */
/* line-height was .86 — Amatry's own ascent+descent runs ~1.12x its
   font-size, so any time this title wraps to two lines (which it does at
   most viewport widths, being a long phrase at a very large size) the
   glyphs of one line overlapped the next by ~42px. Measured on the live
   page: 0.86 overlapped by 41.9px, 1.12 was the exact break-even point,
   1.15 clears it with a small margin (-2 / -4.5px) at every size this
   scales to, since the ratio is inherited and recomputed per element. */
.hb-hero__title { position: relative; z-index: 2; margin: 0 0 3vw; font-weight: 400; letter-spacing: -.03em; line-height: 1.15; }
.hb-hero__title > span { display: block; font-family: 'Amatry', Arial, sans-serif; font-size: clamp(2rem, 4.6vw, 4rem); }
.hb-hero__title strong { display: block; font-weight: 400; font-family: 'Amatry', Arial, sans-serif; font-size: clamp(3.4rem, 11vw, 10rem); }
.hb-hero__title strong em { font-style: normal; color: var(--red); }
/* Reverted to the simple below-the-title layout — button back in its
   own row under the title, plain design, nothing chasing the wordmark.
   Every attempt at "same line as ¡Hablemos!" (nested in the title,
   fixed-pixel offsets, flex row with the wordmark) ran into a
   different problem each time; this is the stable version to build
   back up from. */
.hb-hero__bottom {
	position: relative;
	z-index: 2;
	display: flex;
	justify-content: flex-end;
}
.hb-round-cta {
	flex: 0 0 auto;
	width: 132px; height: 132px;
	border-radius: 50%;
	background: var(--red);
	color: var(--cream);
	display: flex;
	align-items: center;
	justify-content: center;
	text-align: center;
	font-weight: 700;
	line-height: 1.15;
	position: relative;
	transition: transform .4s ease;
}
.hb-round-cta:hover { transform: scale(1.08); }
.hb-round-cta span { position: absolute; right: 25px; top: 22px; }

/* Hero only — pulls the button up to sit against the headline instead
   of below it. Scoped to this modifier, not the base rule, so the
   other three .hb-round-cta buttons on the site (Empresas' homepage
   section, both .hb-cta-bar closings) keep their normal position in
   flow. */
.hb-round-cta.hb-round-cta--hero {
	width: 154px;
	height: 154px;
	font-size: 20px;
	margin-top: -277px;
}
.hb-round-cta.hb-round-cta--hero span { right: 29px; top: 25px; }

/* ============================================================
   Empresas — third pass, for real lightness this time, not just a
   component swap. No new background, no orb, no box, no eyebrow —
   literally the hero's own cream surface, no seam, the way the client
   asked for ("continuação da hero em branco"). One heading, one
   sentence, one action per section — the "Minimal Single Column"
   pattern (heading > short line > CTA), not the denser "hero +
   features" shape the last two rounds kept reaching for. The five
   programme points (Zoom, per-sector content, team size, schedule,
   follow-through) aren't gone — they're already on /empresas/ (the
   "Como funciona" cards) in almost the same words; repeating them
   here was weight nobody asked to carry before deciding whether to
   click. The table stays exactly as the client asked: no card, no box.
   ============================================================ */
.hb-empresas {
	/* .hb-round-cta goes position:absolute under 760px (main.css mobile
	   block) expecting a positioned ancestor to pin against — .hb-hero
	   provides its own; this section needs to provide the same, or the
	   button anchors to the whole document instead of this section. */
	position: relative;
	padding: var(--hb-section-y) var(--hb-inset);
	background: var(--cream);
	color: var(--ink);
}
.hb-empresas h2 {
	font-family: 'Amatry', Arial, sans-serif;
	font-weight: 400;
	font-size: var(--hb-h2-hero);
	line-height: 1.05;
	letter-spacing: -.01em;
	margin: 0 0 var(--hb-s3);
	color: var(--red);
	max-width: 16ch;
}
.hb-empresas p { font-family: 'Franie', Arial; }
.hb-empresas__lede { font-size: var(--hb-lede); line-height: 1.5; margin: 0 0 var(--hb-s4); max-width: 56ch; }
.hb-empresas__ctas { display: flex; align-items: center; flex-wrap: wrap; gap: var(--hb-s4); margin-bottom: var(--hb-s4); }
.hb-empresas__also { font-size: 14px; opacity: .65; margin: 0; max-width: 58ch; }

/* Turmas can't share the exact same white as the section above it —
   this is the whole reason .hb-page2__section--accent (page.css)
   already leans on --paper instead of --cream elsewhere on the site;
   same move here, one section further along the page. */
.hb-empresas--turmas { background: var(--paper); }

/* Both two-column bands share this heading size: --hb-h2-hero (the
   base .hb-empresas h2 rule) is tuned to a FULL-width line — it scales
   off the viewport, not the column, so at the same size in a ~55%
   column "Formação em espanhol" wrapped mid-word onto four lines
   instead of the two the <br> asks for. Smaller and unconstrained
   fits either heading on its two intended lines regardless of exactly
   how wide the text column ends up. */
.hb-empresas--image .hb-empresas__heading,
.hb-empresas--turmas .hb-empresas__heading {
	font-size: clamp(2rem, 3.2vw, 3.1rem);
	max-width: none;
}

/* ---- image left / copy right (the "Formação para empresas" band) ----
   Same "image fills the container" treatment as .hb-cards/.hb-card:
   the photo is taken out of flow and bled against the SECTION's own
   top/bottom edges (position:absolute, ignoring the section's own
   vertical padding), while the copy stays a normal, padded, centred
   column. Grid + align-items:stretch (the previous approach) only ever
   stretches the figure to match the TEXT column's own content height —
   correct in principle, but this text stack is short, so the photo
   came out nearly square with a lot of dead cream above and below it,
   never actually reading as "full height". Absolute positioning ties
   the photo to the section instead of the text, so it stays tall and
   full-bleed regardless of how short the copy next to it is. */
.hb-empresas--image {
	position: relative;
}
/* left:0, not var(--hb-inset) — the photo bleeds all the way to the
   browser edge (same move as .hb-cards/.hb-card's own figure, which
   sits flush at the panel's true edge, not inset from it). Width grows
   by --hb-inset to compensate, so the RIGHT edge — where the gap to
   the copy starts — lands in exactly the same place it did before. */
/* Was 2/5, then 0.45 — now an even 0.5/0.5 split with the copy, per
   the client's own call. No rounded corners on this one: flush against
   the browser's own edge, a 10px radius there read as a stray notch
   rather than a deliberate frame. */
.hb-empresas--image .hb-figure {
	position: absolute;
	top: 0;
	bottom: 0;
	left: 0;
	width: calc(var(--hb-inset) + (100% - 2 * var(--hb-inset) - var(--hb-empresas-gap)) * 0.5);
	border-radius: 0;
}
.hb-empresas--image .hb-empresas__content {
	margin-left: calc((100% - var(--hb-empresas-gap)) * 0.5 + var(--hb-empresas-gap));
	display: flex;
	flex-direction: column;
	justify-content: center;
}

@media (max-width: 900px) {
	/* Client's own order on a phone: title, then the photo right away,
	   then the rest of the copy and the buttons. display:contents drops
	   .hb-empresas__content out of the box tree — its children become
	   direct grid items again, siblings of the figure, free to reorder
	   with 'order' below. No row-gap here: every child already carries
	   its own margin-bottom (the rules above), and row-gap ON TOP of
	   those margins is what summed into the oversized gaps the client
	   flagged. */
	/* Desktop bleeds the photo with position:absolute (above) — 'order'
	   only works inside a flex/grid container, so this stacked layout
	   needs its own display:grid to keep reordering the (unwrapped)
	   children, and the figure needs pulling back out of that absolute
	   positioning into normal flow. */
	.hb-empresas--image {
		display: grid;
		grid-template-columns: 1fr;
		align-items: normal;
	}
	/* border-radius back to the base .hb-figure default (site.css): the
	   desktop rule's radius:0 is for the edge-to-edge bleed against the
	   browser's own edge, which doesn't happen in this stacked layout —
	   here the photo is a normal inset card like every other figure. */
	.hb-empresas--image .hb-figure { position: static; width: 100%; border-radius: 10px; }
	.hb-empresas--image .hb-empresas__content { display: contents; margin-left: 0; }
	.hb-empresas__figure { height: auto; aspect-ratio: 3 / 2; order: 2; margin-bottom: var(--hb-s4); }
	.hb-empresas--image .hb-empresas__heading { order: 1; }
	.hb-empresas--image .hb-empresas__lede { order: 3; }
	.hb-empresas--image .hb-empresas__ctas { order: 4; margin-bottom: var(--hb-s3); }
	.hb-empresas--image .hb-empresas__also { order: 5; }
}

/* ---- turmas: copy left, the client's table right, side by side ----
   Same one-row-two-cells fix as above. */
.hb-empresas--turmas {
	display: grid;
	grid-template-columns: minmax(0, .9fr) minmax(0, 1.15fr);
	column-gap: clamp(40px, 5vw, 80px);
	align-items: center;
}
.hb-empresas--turmas .hb-empresas__turmas-table { margin: 0; max-width: none; }
.hb-empresas--turmas .hb-empresas__also { margin: var(--hb-s3) 0 0; }

@media (max-width: 900px) {
	.hb-empresas--turmas { grid-template-columns: 1fr; row-gap: var(--hb-s4); }
}

@media (max-width: 760px) {
	/* .hb-round-cta's own mobile rule (above, general) makes it
	   position:absolute against the hero's own positioned wrapper —
	   this section has no such wrapper (the button sits in normal flow
	   after the paragraph, not overlapping it), so that has to be
	   cancelled here or the button floats to the section's own corner
	   instead of sitting next to "Conhecer a formação". Also sized down
	   a little further and given a tighter gap so it fits beside the
	   text link instead of wrapping under it — the client asked for
	   them side by side. At 375px the row has 335px to work with: the
	   100px button plus the 24px base gap already left only 211px for
	   the link, 18px short of its own width at the base 16px — the
	   link's font-size comes down a notch here too, matched to a
	   tighter gap, so both fit on one row instead of wrapping. */
	.hb-empresas .hb-round-cta { position: static; width: 100px; height: 100px; }
	.hb-empresas--image .hb-empresas__ctas { gap: var(--hb-s2); }
	.hb-empresas--image .hb-empresas__ctas .hb-years__cta { font-size: 14px; }
}

.hb-marquee {
	/* Was rotated -1deg with a 102%/-1% bleed to cover the corners that
	   rotation left hanging past the viewport edge — read as crooked
	   rather than deliberate, so it's a plain level bar now, full width,
	   no bleed needed since there's no rotation left to cover. */
	position: relative;
	z-index: 3;
	background: var(--night);
	color: var(--cream);
	overflow: hidden;
	padding: 17px 0;
	width: 100%;
}
.hb-marquee__track {
	display: flex;
	width: max-content;
	will-change: transform;
}
.hb-marquee__track span {
	display: inline-block;
	font-family: 'Franie', Arial; font-weight: 700; font-size: 20px; white-space: nowrap;
	animation: hb-marquee-bounce 1.6s ease-in-out infinite;
}
.hb-marquee__track span:nth-child(10n+1) { animation-delay: 0s; }
.hb-marquee__track span:nth-child(10n+2) { animation-delay: .12s; }
.hb-marquee__track span:nth-child(10n+3) { animation-delay: .24s; }
.hb-marquee__track span:nth-child(10n+4) { animation-delay: .36s; }
.hb-marquee__track span:nth-child(10n+5) { animation-delay: .48s; }
.hb-marquee__track span:nth-child(10n+6) { animation-delay: .6s; }
.hb-marquee__track span:nth-child(10n+7) { animation-delay: .72s; }
.hb-marquee__track span:nth-child(10n+8) { animation-delay: .84s; }
.hb-marquee__track span:nth-child(10n+9) { animation-delay: .96s; }
.hb-marquee__track span:nth-child(10n+10) { animation-delay: 1.08s; }
@keyframes hb-marquee-bounce { 50% { transform: translateY(-7px) rotate(-3deg); color: var(--gold); } }
.hb-marquee__track b { display: inline-block; color: var(--gold); margin: 0 26px; font-size: 11px; font-style: normal; }
@media (prefers-reduced-motion: reduce) { .hb-marquee__track span { animation: none; } }

.hb-scene { min-height: 120vh; padding: var(--hb-section-y) var(--hb-inset); position: relative; }

/* A PINNED SECTION MUST FIT THE VIEWPORT — this was 150vh tall while
   pinned at top:0 in a 100vh window, so its bottom third (the whole
   "Talvez já nos conheças" copy block) sat permanently below the fold
   and was never seen, no matter what its opacity animated to.
   Exactly 100vh with the five blocks distributed by space-between
   guarantees every one of them is on screen for the whole pin. */
.hb-rebrand {
	background: var(--gold); color: var(--red);
	height: 100vh;
	padding: calc(var(--hb-nav-h) + var(--hb-section-y)) var(--hb-inset) var(--hb-section-y);
	position: relative;
	/* Uma coluna a esquerda, centrada na vertical como um bloco unico.
	   Era space-between, que empurrava o sobrolho para o topo e a copy
	   para o fundo e deixava o meio a flutuar. */
	display: flex;
	flex-direction: column;
	justify-content: center;
	align-items: flex-start;
	/* Zero: o ar vai por margens declaradas em cada junta, e nao por um
	   gap igual entre tudo. Os cinco blocos nao valem o mesmo -- tres
	   deles sao uma frase so e devem ficar juntos. Medido antes:
	   16/16/40/56, encostados por igual e sem hierarquia nenhuma. */
	gap: 0;
	text-align: left;
}
/* Cross-dissolve para a seccao seguinte, que e vermelha. */
.hb-rebrand__fade { position: absolute; inset: 0; background: var(--r); opacity: 0; pointer-events: none; z-index: 5; }

.hb-rebrand__eyebrow {
	display: block;
	text-transform: uppercase;
	letter-spacing: .18em;
	font-size: 12px;
	/* Tinta, nao bordo: 12px a .18em em bordo sobre dourado da 3.18 de
	   contraste, abaixo do limiar para texto pequeno. Em tinta da 8.53. */
	color: var(--ink);
	/* A maior junta da seccao: o sobrolho e a etiqueta, e a frase so
	   comeca depois dele. */
	margin-bottom: clamp(26px, 6vh, 72px);
}

/* O PALCO. Uma celula, dois nomes.
   min-height fixa a altura pela peca mais alta (o ¡Hablemos!), para o
   bloco nao encolher quando o nome antigo desaparece -- se a altura
   seguisse o conteudo, a copy la em baixo dava um salto a meio da
   transformacao.
   Os dois estao centrados na vertical, por isso o risco do nome antigo e
   o eixo do nome novo caem na mesma linha: e essa linha que faz a
   costura. */
.hb-rebrand__stage {
	position: relative;
	display: grid;
	justify-items: start;
	align-items: center;
	width: 100%;
	min-width: 0;
	/* Mais alto do que era (5rem / 9.5rem): os dois nomes partilham esta
	   celula e precisavam de campo a volta para nao parecerem entalados. */
	min-height: clamp(5.5rem, min(12vw, 20vh), 11rem);
	/* Junta curta acima -- o palco fecha a frase que vem antes dele -- e
	   junta longa abaixo, que e onde a seccao respira antes da copy.
	   Em vh e nao em px: medido a 800px de altura o conteudo ja nao cabia
	   na caixa (transbordava 21px), e valores fixos agravariam isso em
	   ecra baixo. Assim o ar encolhe com o ecra em vez de partir. */
	margin: clamp(14px, 2.2vh, 28px) 0 clamp(34px, 8.5vh, 104px);
}
.hb-rebrand__ghost,
.hb-rebrand__logo { grid-area: 1 / 1; }

/* "30+ anos de historia" e "transformam-se em": as duas dobradicas da
   frase. Estavam atiradas para cantos opostos da mesma linha, o que as
   fazia ler como dois orfaos em vez de como parte do que se esta a
   dizer. Ficam agora onde se dizem, e em tinta -- 11px em bordo sobre
   dourado eram ~2.7 efetivos. */
.hb-rebrand__from,
.hb-rebrand__becomes {
	display: block;
	color: var(--ink);
	opacity: .72;
}
/* Encostadas uma a outra: sao duas linhas da mesma frase, nao dois
   blocos separados. */
.hb-rebrand__from { margin-bottom: .5em; }
.hb-rebrand__from {
	font-family: 'Amatry', Arial, sans-serif;
	font-size: 11px;
	text-transform: uppercase;
	letter-spacing: .15em;
}
.hb-rebrand__becomes {
	font-family: 'Franie', Arial, sans-serif;
	font-style: italic;
	font-size: clamp(15px, 1.1vw, 18px);
	letter-spacing: 0;
}

/* O NOME ANTIGO. Cheio e nao vazado: o contorno existia so para o
   separar do ¡Hablemos! que lhe passava por cima. Sem sobreposicao esse
   problema desapareceu, e cheio le-se mais calmo -- risco e contorno ao
   mesmo tempo eram dois efeitos na mesma palavra.
   O tamanho tambem desceu: era 4.5vw a atravessar a coluna inteira,
   monumental porque era fundo. Agora e uma linha da frase, e o momento
   grande e o nome novo, logo a seguir. */
.hb-rebrand__ghost {
	max-width: 100%;
	min-width: 0;
	font-size: clamp(1.4rem, 3.4vw, 3.1rem);
	font-weight: 900;
	line-height: 1.05;
	letter-spacing: -.02em;
	color: var(--ink);
	/* .78 e nao .5: ja nao esta por tras de nada, esta sozinho no palco
	   ate ser engolido. Tem de se LER antes de desaparecer, senao a troca
	   nao se percebe. */
	opacity: .78;
}

/* O RISCO, DESENHADO POR LINHA.
   Um background no texto inline em vez de uma barra absoluta: com
   box-decoration-break: clone cada fragmento de linha ganha a sua
   propria caixa de fundo, por isso 100% significa "a largura desta
   linha" -- uma linha ou cinco, cada uma leva um traco do seu proprio
   comprimento, e uma so custom property anima todas. Uma barra absoluta
   partia-se assim que o nome quebrava em duas linhas em mobile.
   Fica em bordo: e a cor da marca nova a passar por cima do nome que
   sai, e o unico momento saturado da composicao. */
.hb-rebrand__ghost-text {
	position: relative;
	--hb-strike: 0%;
	-webkit-box-decoration-break: clone;
	box-decoration-break: clone;
	background-image: linear-gradient(var(--r), var(--r));
	background-repeat: no-repeat;
	/* 50%, o centro exato: e sobre esta linha que o nome antigo se
	   fecha e o novo se abre, por isso tem de ser o eixo da celula. */
	background-position: 0 50%;
	background-size: var(--hb-strike) .075em;
}

/* O NOME NOVO. Sem halo: o text-shadow em dourado existia para abrir
   caminho por dentro da mancha do nome antigo. Sem sobreposicao nao ha
   nada de que se separar, e um halo sem funcao le-se como nevoa. */
.hb-rebrand__logo {
	text-align: left;
	/* clip-path corta em relacao a caixa, por isso a caixa tem de ser
	   apenas o texto -- com width auto o clip abriria a partir do centro
	   de uma faixa vazia a toda a largura da coluna. */
	justify-self: start;
	will-change: clip-path;
}
.hb-rebrand__logo .hb-wordmark {
	display: block;
	font-size: clamp(2.6rem, min(9vw, 15vh), 7.6rem);
	line-height: .95;
}
.hb-rebrand__logo .hb-tagline {
	display: block;
	text-align: left;
	font-size: 13px;
	letter-spacing: .28em;
	text-transform: uppercase;
	opacity: .7;
	margin-top: var(--hb-s1);
}

.hb-rebrand__copy {
	width: min(100%, 940px);
	display: grid;
	gap: var(--hb-s2);
	color: var(--ink);
	text-align: left;
}
.hb-rebrand__copy > div {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
	gap: var(--hb-s3) var(--hb-s4);
}
.hb-rebrand__copy h3 { margin: 0; font-size: var(--hb-h3); line-height: 1.15; font-family: 'Amatry', Arial; font-weight: 400; }
.hb-rebrand__copy p { margin: 0; font-size: var(--hb-text); line-height: var(--hb-text-lh); font-family: 'Franie', Arial; }

/* svh, not vh: this pin now runs on mobile too (see motion.js), where
   vh tracks the LARGE viewport height and grows the instant the
   browser's address bar hides mid-scroll — the pin's spacer was sized
   off whichever height happened to be current at refresh, so the
   section's reserved scroll distance and the actual content height
   drifted apart and the page visibly jumped. svh is always the
   SMALLEST possible height (toolbar shown), which never changes as the
   toolbar comes and goes, so the spacer stays correct for the whole
   pin. Identical to vh on desktop, where there is no dynamic toolbar. */
.hb-choose { height: 100svh; background: var(--night); overflow: hidden; }
.hb-cards { height: 100svh; display: flex; width: max-content; }
/* Viewport minus the classic scrollbar (--hb-sbw, published by
   motion.js) — plain 100vw makes each card wider than the visible area,
   so the last card stops a scrollbar-width short of fully arriving and
   its content sits offset from the sections above and below. */
/* --hb-inset resolves its `100%` against the CONTAINING BLOCK, and a
   card's containing block is the horizontal track (4 panels wide, so
   ~5700px at desktop), not the viewport. Left alone, each card asked
   for (5700 - 1240) / 2 = 2230px of padding per side; with
   box-sizing:border-box that padding became the card's used width
   (4460px), overriding the 1425px flex-basis and blowing the track's
   scroll width to 17840px. Rebinding --hb-inset to its viewport-based
   twin here fixes every var(--hb-inset) inside a card at once,
   including .hb-card b and the mobile override below. */
.hb-card { --hb-inset: var(--hb-inset-fixed); --hb-panel-w: calc(100vw - var(--hb-sbw, 0px)); width: var(--hb-panel-w); height: 100svh; flex: 0 0 var(--hb-panel-w); padding: 10vh var(--hb-inset); display: flex; flex-direction: column; justify-content: center; position: relative; }
.hb-card small { text-transform: uppercase; letter-spacing: .18em; }

/* A card that carries a picture. The intro card deliberately has none —
   it asks the question, it does not answer it — so this is a modifier
   driven by the presence of .hb-card__body rather than a blanket rule.

   Grid with align-items:stretch used to sit here and fill the figure's
   OWN cell — which still left it inset by the card's 10vh/--hb-inset
   padding on every side, a visible band of background colour above,
   below and to the right of the photo instead of a true edge-to-edge
   picture. Fixed by taking the figure out of flow and letting it bleed
   against the card's own border box: padding moves from the card onto
   .hb-card__body instead, so the text keeps its inset while the image
   runs flush to the card's top, right and bottom edges. */
.hb-card:has(> .hb-card__body) { padding: 0; }
.hb-card__body {
	display: flex;
	flex-direction: column;
	justify-content: center;
	max-width: 55%;
	padding-block: 10vh;
	padding-inline-start: var(--hb-inset);
	padding-inline-end: var(--hb-s5);
	box-sizing: border-box;
}
.hb-card > .hb-figure {
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	width: 45%;
	aspect-ratio: auto;
}
/* The link arrow is absolutely positioned to the panel's bottom-right,
   which would land it on top of the picture. Inside a card that has one
   it sits under the copy instead. */
.hb-card:has(> .hb-card__body) b { position: static; align-self: flex-start; margin-top: var(--hb-s3); }
/* Was 6.5vw/9vw — at 1400px that rendered at 91px and 126px inside a
   carousel panel that also has to carry a label, a paragraph and a
   link. Capped on the shared hero-heading scale instead. */
.hb-card h2 { font-size: var(--hb-h2-hero); line-height: 1; letter-spacing: -.02em; margin: var(--hb-s4) 0 var(--hb-s3); max-width: 18ch; }
.hb-card h2 em { font-style: normal; color: var(--g); }
.hb-card p { font-size: var(--hb-text); max-width: 46ch; line-height: var(--hb-text-lh); }
.hb-card b { position: absolute; right: var(--hb-inset); bottom: 7vh; border-bottom: 2px solid currentColor; padding-bottom: 10px; font-weight: 600; }
.hb-card--intro { background: var(--night); color: var(--c); }
.hb-card--intro h2 { font-size: var(--hb-h2-hero); letter-spacing: -.04em; }
.hb-card--intro h2 em { font-family: 'Amatry', Arial; font-weight: 400; font-style: italic; }
.hb-card--gold { background: var(--g); color: var(--k); }
.hb-card--gold h2 { color: var(--r); }
.hb-card--cream { background: var(--c); color: var(--k); }
.hb-card--red { background: var(--r); color: var(--c); }

/* The numeral and the heading were both sized off raw vw (22vw = 313px
   and 4.2vw = 60px at 1425), so the copy column ran to six lines and
   overflowed a scene whose height is capped — the first line of the
   heading was cut off above the top edge. Two changes fix it together:
   both sizes now come off the shared scale with a hard ceiling, and the
   scene is allowed to grow past its minimum instead of clipping. The
   "+30" is the supporting figure here, not the headline, so it no
   longer outweighs the sentence it illustrates. */
.hb-years {
	background: var(--c); color: var(--r);
	display: grid;
	grid-template-columns: minmax(0, .85fr) minmax(0, 1fr);
	gap: var(--hb-s5);
	align-items: center;
	min-height: 0;
	height: auto;
	overflow: visible;
}
.hb-years__big {
	/* Keeps the original 22vw growth rate, so on a laptop this renders at
	   essentially the size it always did — the earlier 15vw shrank it at
	   EVERY width, when the only real problem was that raw vw never stops
	   growing. The ceiling is set from the same 1387px pivot as the
	   closing scene below, so both stop together and the page keeps one
	   proportion from a 13" laptop up to a 5K display. */
	font-size: clamp(6rem, 22vw, 19rem);
	font-weight: 400; line-height: .8; letter-spacing: -.03em;
	font-family: 'Amatry', Arial;
	justify-self: start;
}
.hb-years__big i { font-size: .2em; vertical-align: top; font-style: normal; }
/* Just the number, not the "+" — the client asked for "17" in gold,
   the sign stays the section's own bordô. */
.hb-years__big span { color: var(--gold-ink); }
/* Own clamp, not --hb-h2-hero (shared with .hb-empresas/.hb-card) —
   this exact sentence needs to land on 3 lines against the .85fr/1fr
   photo/copy split just above, and at the shared token's size even the
   tightest natural word-wrap still ran to 4 (the tail "anos de
   experiência." alone measured wider than the column). ~12% down from
   the shared clamp is what clears it with real margin, not a
   knife-edge fit. */
.hb-years__copy h2 { font-size: clamp(1.94rem, 4.93vw, 4.05rem); line-height: 1.02; letter-spacing: -.01em; margin: 0 0 var(--hb-s3); }
.hb-years__copy h2 em { font-style: normal; color: var(--g); }
.hb-years__copy p { font-size: var(--hb-text); line-height: var(--hb-text-lh); max-width: 58ch; margin: 0 0 1.2em; }
.hb-years__cta { display: inline-block; margin-top: 1.5vh; font-weight: 700; border-bottom: 2px solid currentColor; padding-bottom: 4px; }

/* ---- closing CTA, take three: same bar, the old scene's copy and button ----
   Replaces .hb-final on the homepage only (that component is still in
   active use on six other page templates, untouched here). Round one
   dropped the 100vh scene for a slim bar but kept its colours; the
   client's follow-up was that it dropped too much along with the
   screen height — she wants "Então, ¡Hablemos!" back at real size (not
   a signature-line mark) and .hb-round-cta itself, not a pill. Same
   restraint as before on everything that WAS legitimately cut: no
   halo, no floating word field, no full-viewport minimum, no
   duplicate address/copyright (the real footer already has them). */
.hb-cta-bar {
	position: relative;
	background: var(--red);
	color: var(--cream);
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--hb-s5);
	padding: var(--hb-s5) var(--hb-inset);
}
.hb-cta-bar__copy { max-width: 62ch; }
.hb-cta-bar__eyebrow {
	font-family: 'Franie', Arial;
	font-style: italic;
	font-size: var(--hb-lede);
	margin: 0;
	opacity: .85;
}
.hb-cta-bar__mark {
	font-size: clamp(2.6rem, 5.6vw, 4.8rem);
	line-height: 1;
	color: var(--gold);
	margin: .1em 0 var(--hb-s3);
}
.hb-cta-bar__mark i { color: var(--cream); }
.hb-cta-bar__text {
	font-size: var(--hb-text);
	line-height: var(--hb-text-lh);
	margin: 0;
	opacity: .92;
}
/* Gold-on-bordô instead of the component's own default (red-on-cream)
   — same circle, same rotate/hover, just the closing scene's palette. */
.hb-cta-bar .hb-round-cta { flex: 0 0 auto; background: var(--gold); color: var(--ink); }
@media (max-width: 760px) {
	.hb-cta-bar { flex-direction: column; align-items: flex-start; gap: var(--hb-s4); padding: var(--hb-s4) var(--hb-inset); }
	.hb-cta-bar__copy { max-width: 100%; }
	/* .hb-round-cta's own mobile rule (main.css, hero section) makes it
	   position:absolute against whichever ancestor is positioned —
	   this bar has no such wrapper expecting an overlapping badge, so
	   that has to be cancelled back to a normal block or the button
	   floats to the bar's own corner instead of sitting under the copy. */
	.hb-cta-bar .hb-round-cta { position: static; margin-top: var(--hb-s2); }
}

.hb-final {
	min-height: 100vh;
	background: var(--r);
	color: var(--g);
	padding: var(--hb-section-y) var(--hb-inset);
	display: flex;
	flex-direction: column;
	align-items: center;
	position: relative;
	overflow: hidden;
}
.hb-final__halo { position: absolute; width: 65vw; height: 65vw; border-radius: 50%; background: #d3ac6e33; filter: blur(50px); }
.hb-final__whisper { position: absolute; inset: 0; pointer-events: none; z-index: 2; }
.hb-final__whisper span {
	position: absolute; font: italic clamp(1.2rem, 2vw, 2rem) 'Franie', Arial; color: #d3ac6e66;
	animation: hb-whisper-float 6.5s ease-in-out infinite;
}
.hb-final__whisper span:nth-child(1) { left: 8%; top: 15%; animation-duration: 7s; animation-delay: 0s; }
.hb-final__whisper span:nth-child(2) { right: 12%; top: 22%; animation-duration: 5.5s; animation-delay: .9s; }
.hb-final__whisper span:nth-child(3) { left: 18%; bottom: 26%; animation-duration: 6.5s; animation-delay: 1.8s; }
.hb-final__whisper span:nth-child(4) { right: 22%; bottom: 18%; animation-duration: 5s; animation-delay: .5s; }
.hb-final__whisper span:nth-child(5) { right: 5%; top: 55%; animation-duration: 7.5s; animation-delay: 1.3s; }
/* Três novas, medidas contra a secção real (não a olho): o logótipo
   ocupa x 18–82% / y 30–50%, a lede x 26–74% / y 46–59%, o botão
   x 44–56% / y 64–81%, e o rodapé a largura toda em y 81–88%. As cinco
   palavras já lá estavam todas fora dessa zona; estas três também —
   dois cantos por cima das que já existem no topo, e uma a meio da
   margem esquerda, a espelhar "claro" do lado direito. */
.hb-final__whisper span:nth-child(6) { left: 3%; top: 6%; animation-duration: 6s; animation-delay: 2.2s; }
.hb-final__whisper span:nth-child(7) { right: 4%; top: 8%; animation-duration: 6.8s; animation-delay: .3s; }
.hb-final__whisper span:nth-child(8) { left: 4%; top: 40%; animation-duration: 5.8s; animation-delay: 1.6s; }
@keyframes hb-whisper-float {
	0%, 100% { transform: translateY(0) rotate(0deg); opacity: .6; }
	50% { transform: translateY(-16px) rotate(-3deg); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) { .hb-final__whisper span { animation: none; } }
/* This scene was set in raw vw — 4vw / 12vw — which has no ceiling, so
   on a large display these lines could grow past the content column
   and get clipped by the section's overflow:hidden. The fix is a
   ceiling, NOT a smaller rate: the vw values below are the originals,
   only the caps are new, so both keep their original proportion to
   each other at every width. */
.hb-final > p:first-of-type { font: italic clamp(1.5rem, 4vw, 3.5rem) 'Franie', Arial; margin: var(--hb-s5) 0 0; z-index: 2; }
.hb-final__logo {
	position: relative; z-index: 2; margin-top: 4vh;
	/* Deliberately faint: a single wide, low-opacity halo reads as the
	   letters sitting on the background rather than glowing off it. The
	   earlier tight+bright pair (10px solid gold) bled into the glyph
	   edges and made the wordmark look blurred instead of lit. */
	filter: drop-shadow(0 0 26px #d3ac6e26);
}
/* ~8% larger than "Então,"'s clamp(1.5rem,4vw,3.5rem) above it — the
   wordmark is the payoff of the sentence and reads better carrying
   slightly more weight than the word that leads into it, without going
   so large it throws off the two-line rhythm they already share. */
.hb-final__logo .hb-wordmark { display: block; font-size: clamp(2.8rem, 13vw, 11.2rem); color: var(--g); }
.hb-final__logo .hb-wordmark i { color: var(--g); }
.hb-final__shine {
	position: absolute; inset: 0;
	background: linear-gradient(100deg, transparent 40%, #fff6e8b3 50%, transparent 60%);
	background-size: 250% 100%;
	-webkit-background-clip: text; background-clip: text;
	color: transparent; -webkit-text-fill-color: transparent;
	animation: hb-shine 4s ease-in-out infinite;
	pointer-events: none;
}
.hb-final__shine i { color: transparent; -webkit-text-fill-color: transparent; }
@keyframes hb-shine {
	from { background-position: -80% 0; }
	to { background-position: 180% 0; }
}
.hb-final__lede { font-size: var(--hb-text); line-height: var(--hb-text-lh); max-width: 46ch; text-align: center; margin: var(--hb-s4) 0 0; z-index: 2; }
.hb-final > a {
	width: 170px; height: 170px;
	border-radius: 50%;
	background: var(--g);
	color: var(--r);
	display: grid;
	place-content: center;
	font-weight: 700;
	position: relative;
	margin-top: 5vh;
	z-index: 2;
	transition: transform .4s, box-shadow .4s;
}
.hb-final > a:hover { transform: scale(1.08) rotate(5deg); box-shadow: 0 0 70px var(--g); }
.hb-final > a b { position: absolute; right: 28px; top: 26px; }
.hb-final footer {
	margin-top: auto;
	padding-top: 6vh;
	width: 100%;
	display: grid;
	grid-template-columns: 1fr auto 1fr;
	align-items: center;
	gap: 20px;
	text-transform: uppercase;
	letter-spacing: .18em;
	font-size: 9px;
	z-index: 2;
}
.hb-final footer span:nth-child(3) { text-align: right; }
.hb-final footer span:nth-child(2) { font-family: 'Franie', Arial; font-style: italic; text-transform: none; letter-spacing: 0; font-size: 12px; text-align: center; }

@media (max-width: 900px) {
	/* The cards carousel now pins at every width (see motion.js's
	   cardsPinTween) and keeps its desktop geometry — nothing to
	   override here. The rebrand pin is still off below 900px: a 100vh
	   pinned section can't hold this much content on a phone, and mobile
	   viewport height shifts as the browser chrome hides. Unpinned it
	   just flows at natural height, so the fixed 100vh + space-between
	   layout has to be undone or the blocks get stretched apart. */
	/* Sem pin em ecra estreito, a seccao corre a altura natural: os 100vh
	   fixos tem de ser desfeitos ou os blocos ficam esticados. A coluna e
	   o gap mantem-se -- a frase le-se igual, so mais junta. */
	.hb-rebrand {
		height: auto;
		gap: var(--hb-s4);
	}
	.hb-rebrand__copy { width: 100%; }
}

@media (max-width: 760px) {
	:root { --hb-nav-h: 68px; --hb-logo-h: 34px; }
	.hb-light { display: none; }

	/* The hero is min-height:100svh with justify-content:space-between —
	   right on a laptop, where the title and the closing line fill the
	   screen. On a phone the content is short, so "space between" put
	   303px of measured nothing in the middle of it. Content-height plus
	   a normal flow: the section still fills the screen when it can, and
	   stops pretending to when it cannot. */
	.hb-hero { min-height: auto; justify-content: flex-start; }

	/* ANEXO 2 — o "+30" sai do telemóvel.
	   At 40vw it is 150px of numeral above the paragraph that explains
	   it, and on a narrow screen it reads as decoration in the way of
	   the sentence rather than as its headline. The number itself is in
	   the copy right next to it ("Mais de 30 anos..."), so nothing is
	   lost. */
	.hb-years__big { display: none; }

	/* ANEXO 3 — o botão redondo.
	   170px was chosen for a 1440px screen; on 375 it is nearly half the
	   width and the two-line label inside it breaks against the circle.
	   Same shape, sized for the screen it is on. */
	.hb-final > a { width: 132px; height: 132px; font-size: 13px; margin-top: var(--hb-s4); }
	/* The arrow is absolutely positioned at 28/26px, measured against the
	   170px circle. On the smaller one those offsets sit far too deep,
	   which is what pushed the label off the circle's centre line.
	   Scaled to the same proportion of the new diameter. */
	.hb-final > a b { right: 22px; top: 20px; }

	/* "PORTO · COIMBRA · ONLINE" was wrapping to two lines inside a
	   124px grid column. The row stacks here, so each line gets the full
	   width and the locations stay on one. */
	.hb-final footer {
		grid-template-columns: 1fr;
		justify-items: center;
		gap: var(--hb-s2);
		padding-top: var(--hb-s4);
		text-align: center;
	}
	.hb-final footer span { white-space: nowrap; }
	.hb-final footer span:nth-child(3) { text-align: center; }
	.hb-nav { height: var(--hb-nav-h); padding-left: var(--hb-inset-fixed); padding-right: calc(var(--hb-inset-fixed) + 40px); }
	/* The bar is 68px here, not 82 — the logo comes down with it. */

	.hb-logo--footer { height: 42px; }
	/* Smaller AND fainter here, not just smaller — at 90vw/65vw with
	   their desktop opacity these two together covered almost the whole
	   screen in solid gold/red, reading as heavy on a phone in a way it
	   doesn't at desktop scale where they're a corner accent. */
	.hb-orb--gold { width: 55vw; height: 55vw; opacity: .3; }
	.hb-orb--red { width: 38vw; height: 38vw; opacity: .2; }
	.hb-hero__title > span { font-size: 9vw; }
	.hb-hero__title strong { font-size: 17vw; }
	.hb-hero__bottom { display: block; }
	.hb-round-cta { width: 102px; height: 102px; position: absolute; right: 5px; bottom: 10px; font-size: 13px; }
	/* The generic rule above expects an ancestor with real height to
	   anchor against (true everywhere else .hb-round-cta shows up). At
	   the hero specifically, .hb-hero__bottom's only child IS the
	   button — position:absolute would take it out of flow, collapsing
	   its own container to 0 height and anchoring "bottom:10px" against
	   that single point instead of the section. Normal flow instead,
	   left-aligned per the client's own call. */
	.hb-hero__bottom .hb-round-cta { position: static; margin: var(--hb-s3) auto 0 0; }
	.hb-hero__bottom .hb-round-cta--hero { width: 120px; height: 120px; font-size: 16px; }
	.hb-hero__bottom .hb-round-cta--hero span { right: 22px; top: 19px; }
	.hb-marquee__track span { font-size: 15px; }
	/* "Centro de Estudos de Espanhol" is white-space:nowrap (the strike
	   line is one 100%-wide bar, so it must stay a single line). At the
	   old 6.2vw that ran 420px wide inside a 335px column — the name was
	   simply cut off at the screen edge. 4.5vw keeps it on one line with
	   room to spare down to ~215px-wide screens. */
	/* O nome antigo quebra em duas linhas aqui, e e por isso que o risco
	   tem de ser desenhado por linha e nao com uma barra: cada fragmento
	   leva um traco do seu proprio comprimento. */
	.hb-rebrand__ghost { font-size: 6.4vw; }
	.hb-rebrand__logo .hb-wordmark { font-size: 15vw; }
	.hb-rebrand__copy { display: block; }
	.hb-rebrand__copy h3 { margin-bottom: 16px; }
	.hb-card { padding: 90px var(--hb-inset); }
	/* One column on a phone, stacked in normal flow — the desktop rule's
	   full-bleed absolute figure only makes sense beside a wide column of
	   text; on an 88vw panel it would cover the copy entirely. Padding
	   and layout both come back to the card itself here. */
	.hb-card:has(> .hb-card__body) { padding: 90px var(--hb-inset); display: flex; flex-direction: column; justify-content: center; }
	.hb-card:has(> .hb-card__body) .hb-card__body { max-width: 100%; padding: 0; }
	/* Texto primeiro, imagem depois — em todo o site.
	   The figure had order:-1 so a panel opened on a picture. Reading
	   order should match the argument: the claim, then the illustration
	   of it. position/height/aspect-ratio reset: the desktop rule bleeds
	   the figure full-height and absolute, which on a stacked mobile card
	   would cover the text underneath instead of sitting below it. */
	/* margin-top: o CTA ("Quero estudar em Espanha") e a fotografia
	   estavam a tocar-se — medido a 375, o fundo do link e o topo da
	   imagem no mesmo pixel, com o proprio sublinhado do link a encostar
	   ao canto da foto. */
	.hb-card > .hb-figure { position: static; width: 100%; height: auto; aspect-ratio: 3 / 2; max-height: 26vh; order: 1; margin-top: var(--hb-s3); }
	.hb-years { display: block; }
	.hb-years__big { font-size: 40vw; margin-bottom: 8vh; }
	.hb-years__copy h2 { font-size: 10vw; }
	.hb-final > p:first-of-type { font-size: 9vw; }
	/* Sized to FIT, not to fill: at the old 22vw this ran 415px wide
	   inside a 375px screen, so ~20px of the first and last glyph of
	   "¡Hablemos!" were being clipped by the section's overflow:hidden.
	   The page showed no horizontal scrollbar, which is exactly why it
	   went unnoticed. 18vw (up slightly from 17, matching the desktop
	   bump above) still measures ~339px at 375px wide — clear of the
	   375px edge with margin to spare. */
	.hb-final__logo .hb-wordmark { font-size: 18vw; }
	.hb-final footer span:nth-child(2) { display: none; }
	.hb-load__mark { font-size: 55vw; }
}

@media (prefers-reduced-motion: reduce) {
	.hb * { animation: none !important; }
	.hb-loader { display: none; }
	.hb-light { display: none; }
}
