/* ============================================================
   Hablemos — shared "inner page" system (Cursos, Traduções, Exames,
   Estudar em Espanha, Empresas, Ticket Educação, Contactos, Horários)
   Cover (headline + lede + orbs) reuses the Sobre nós language;
   content blocks are a simple, consistent editorial pattern.
   ============================================================ */
/* overflow-x: clip, matching what .hb (the homepage root) already does.
   Deliberate bleeds — the rotated sector marquee is 102% wide so its
   angled ends still cover the full width, the cover orbs sit off-edge —
   were extending the document ~14px past the viewport. Nothing visibly
   spilled, because body has overflow-x:hidden, but the document was
   genuinely wider than the screen.

   `clip`, not `hidden`: clip does NOT create a scroll container, so the
   sticky sidebar headings and GSAP's pinned carousels keep working
   against the viewport. `hidden` would silently break both. */
.hb-page2 { background: var(--cream); overflow-x: clip; }

/* ============================================================
   SHARED SECTION GRID — read this before adding a new section.

   Every full-width band on an inner page (cover, section, scene,
   final, and the new components below) gets its padding from exactly
   these two rules. Two things this fixes:

   1) Symmetric vertical rhythm. Sections used to declare their own
      asymmetric padding (`13vh 6vw`, `10vw 4vw 8vw`, `14vh 6vw`), so
      the space below one band and above the next added up to
      different totals down the page — the "more margin-bottom than
      margin-top" effect. One token, applied to both sides, removes it.

   2) A single content column. `padding-inline: max(gutter, (100% -
      max) / 2)` keeps content inside --hb-max and centred on wide
      screens while falling back to the plain gutter on narrow ones —
      so headings, body copy and CTAs all start on the same x-position
      from the cover to the footer, with no markup wrapper needed.
   ============================================================ */
.hb-page2__cover,
.hb-page2__section,
.hb-page2__scene,
.hb-page2__final,
.hb-page2__band {
	padding-block: var(--hb-section-y);
	padding-inline: max(var(--hb-gutter), calc((100% - var(--hb-max)) / 2));
}

/* THE FIRST SECTION OF ANY PAGE CLEARS THE NAV.
   The nav is fixed, so whatever comes first is underneath it. Every page
   happens to open with a cover, which carries that compensation in its
   own rule — except Contactos, which opens with .hb-page2__final and
   therefore left the eyebrow 4px below a 68px nav on a phone. Making it
   structural rather than per-class means a page added later cannot get
   this wrong, and a cover that is already compensated simply restates
   the same value. */
/* SYMMETRY, MEASURED AGAINST THE CLIENT'S OWN SCREENSHOT.
   Top and bottom used to measure 210px/128px on every page — the 82px
   gap (exactly --hb-cover-lead, the nav's own height) read as "mais
   espaçamento em cima do que em baixo". Matching the bottom to the
   FULL top value fixed the imbalance but read as too much padding
   overall ("está com muito espaçamento") — HALF the lead, added to
   both sides, keeps the two symmetric without inflating the total.
   Nothing ends up underneath the nav either way: the cover is
   justify-content: center with a min-height, so the content sits well
   clear of it, and if the heading grows the section grows with it. */
/* Margem final morta. Um <p> em fim de seccao mantem a sua margin-bottom
   (1.4em = 22px nas cenas), que se soma ao padding da seccao: medido 122
   acima da primeira linha contra 158 abaixo da ultima, em Exames. Nada
   vem a seguir, por isso essa margem e espaco morto -- e o padding da
   seccao que deve marcar o ritmo, sozinho. Nao mexe em .hb-point, que
   fecha com border-bottom: ai o espaco segura a linha e e visivel. */
.hb-page2 > section > :last-child,
.hb-page2 > section > :last-child > :last-child,
.hb-story > section > :last-child,
.hb-story > section > :last-child > :last-child {
	margin-bottom: 0;
}

.hb-page2 > section:first-of-type,
.hb-story > section:first-of-type {
	padding-top: calc(var(--hb-section-y) + var(--hb-cover-lead));
	padding-bottom: var(--hb-section-y);
}

/* WordPress offsets the whole document by its 32px desktop admin bar.
   The fixed site nav already participates in the cover compensation,
   so counting that offset again creates exactly 32px more visible space
   above the copy for logged-in editors. Remove it only in that state. */
@media (min-width: 783px) {
	body.admin-bar .hb-page2 > section:first-of-type,
	body.admin-bar .hb-story > section:first-of-type {
		padding-top: calc(var(--hb-section-y) + var(--hb-cover-lead) - 32px);
	}
}

/* Top and bottom both carry HALF of --hb-cover-lead — see the note
   above the structural rule this restates (.hb-page2 > section:
   first-of-type), which is the one that actually wins on every real
   page; this copy exists so a cover used outside that structure isn't
   left with mismatched padding. */
.hb-page2__cover {
	position: relative;
	overflow: hidden;
	padding-top: calc(var(--hb-section-y) + var(--hb-cover-lead));
	padding-bottom: var(--hb-section-y);
	min-height: 62vh;
	display: flex;
	flex-direction: column;
	justify-content: center;
	background: var(--cream);
	color: var(--ink);
}
.hb-page2__eyebrow {
	position: relative; z-index: 2;
	display: block;
	font-family: 'Amatry', Arial, sans-serif;
	font-size: var(--hb-eyebrow);
	text-transform: uppercase;
	letter-spacing: .2em;
	opacity: .55;
	margin-bottom: var(--hb-s2);
}
.hb-page2__headline {
	position: relative; z-index: 2;
	font-size: var(--hb-h1);
	line-height: 1.03;
	letter-spacing: -.02em;
	margin: 0 0 var(--hb-s3);
	max-width: 18ch;
	color: var(--red);
}
.hb-page2__headline em { font-style: normal; color: var(--gold); }
.hb-page2__headline .hb-nowrap { white-space: nowrap; }
.hb-page2__lede {
	position: relative; z-index: 2;
	font-family: 'Franie', Arial;
	font-style: italic;
	font-size: var(--hb-lede);
	line-height: 1.6;
	max-width: 620px;
	margin: 0;
}

.hb-page2__section {
	position: relative;
	overflow: hidden;
	display: flex;
	flex-direction: column;
	justify-content: center;
	border-top: 1px solid #1a151214;
}
.hb-page2__section--accent { background: var(--paper); }
/* Softened repeatedly — 32vw/blur(70px)/opacity .14, then 26vw/.08, then
   20vw/.04, then 16vw/.03 — and still read as too present each round.
   Cut hard this time instead of nudging again: opacity down to barely
   there, kept soft via a wide blur relative to the shape's own size. */
.hb-page2__section::before {
	content: "";
	position: absolute;
	z-index: 0;
	pointer-events: none;
	width: 14vw;
	height: 14vw;
	border-radius: 50%;
	filter: blur(110px);
	background: var(--gold);
	opacity: .016;
	right: -12vw;
	top: -16vw;
	will-change: transform;
}
.hb-page2__section:nth-of-type(even)::before {
	background: var(--red);
	opacity: .012;
	right: auto;
	left: -12vw;
	top: auto;
	bottom: -18vw;
}
.hb-page2__section > * { position: relative; z-index: 1; }
.hb-page2__section {
	--hb-rail: clamp(160px, 25vw, 330px);
	--hb-rail-gap: 6vw;
}
.hb-page2__section h2 {
	font-size: var(--hb-h2);
	line-height: 1.1;
	letter-spacing: -.01em;
	margin: 0 0 var(--hb-s2);
	max-width: 20ch;
	color: var(--red);
}
.hb-page2__body p { font-size: var(--hb-text); line-height: var(--hb-text-lh); margin: 0 0 1.5em; }
.hb-page2__body p:last-child { margin-bottom: 0; }
.hb-page2__body ul { margin: 0 0 1.5em; padding-left: 1.2em; font-size: var(--hb-text); line-height: var(--hb-text-lh); }
.hb-page2__body li { margin-bottom: .6em; }
.hb-page2__body a { text-decoration: underline; text-underline-offset: 3px; }
.hb-page2__body strong { color: var(--red); }

/* ONE COLUMN, ONE LEFT EDGE.
   This used to be a two-column editorial grid: heading in a narrow
   sticky rail on the left, prose indented into a second column. It
   produced three separate faults, all visible at once:

   1) The sticky heading travelled DOWN over the content as you
      scrolled. Once card/fact/step grids were widened to span both
      columns (so three cards could sit as a row instead of stacking),
      they slid straight under the heading and the two overlapped —
      every "desconfigurada" section came from this.
   2) Bodies without a heading were indented ~38% from the left, so
      their text started nowhere near the logo, the nav or any other
      section.
   3) An inline CTA became a stretched grid item, so its 100%-wide
      underline ran the full column instead of hugging its label.

   A single column fixes all three and satisfies the one rule that
   matters here: everything starts on the same left edge as the
   logo. Prose keeps a measured line length via max-width; grids and
   cards get the full container. */
.hb-page2__body {
	margin-left: 0;
	max-width: 100%;
	display: flex;
	flex-direction: column;
	align-items: flex-start;
}
.hb-page2__body > h2 { margin: 0 0 var(--hb-s3); }
/* Reading measure applies to running text only — never to the grids. */
.hb-page2__body > p,
.hb-page2__body > ul { max-width: 68ch; width: 100%; }
.hb-page2__body > .hb-cardgrid,
.hb-page2__body > .hb-facts,
.hb-page2__body > .hb-steps,
.hb-page2__body > .hb-accordion,
.hb-page2__body > .hb-levels,
.hb-page2__body > .hb-page2__table-wrap,
.hb-page2__body > .hb-page2__note,
.hb-page2__body > .hb-cta-row { width: 100%; }
.hb-page2__body > .hb-page2__note { max-width: 68ch; }

/* align-self keeps this shrink-wrapped to its own label inside any flex
   parent — as a stretched item its 100%-wide underline ran the full
   width of the container instead of sitting under the words. */
.hb-page2__cta {
	position: relative;
	align-self: flex-start;
	display: inline-flex;
	align-items: center;
	gap: 2px;
	margin-top: var(--hb-s2);
	font-weight: 700;
	font-size: var(--hb-text);
	padding-bottom: 4px;
	color: var(--red);
	transition: gap .3s ease, opacity .3s ease;
}
.hb-page2__cta::after {
	content: "";
	position: absolute;
	left: 0;
	bottom: 0;
	width: 100%;
	height: 2px;
	background: currentColor;
	transform-origin: left;
	transition: transform .4s cubic-bezier(.65,0,.35,1);
}
.hb-page2__cta:hover { gap: 8px; }
.hb-page2__cta:hover::after { transform: scaleX(1.06); }

.hb-page2__cta--round {
	display: flex;
	width: 148px;
	height: 148px;
	border-radius: 50%;
	background: var(--red);
	color: var(--cream);
	align-items: center;
	justify-content: center;
	text-align: center;
	margin: 0;
	transform: rotate(-6deg);
	transition: transform .4s ease;
	font-size: var(--hb-text);
	padding: 0 8px;
}
.hb-page2__cta--round::after { content: none; }
.hb-page2__cta--round:hover { transform: rotate(0) scale(1.07); }
.hb-page2__final .hb-page2__cta.hb-page2__cta--round { background: var(--gold); color: var(--ink); }

.hb-page2__table-wrap { overflow-x: auto; max-width: 780px; margin: 2vh 0 3vh; }
.hb-page2__table { border-collapse: collapse; width: 100%; min-width: 480px; font-size: 16px; }
.hb-page2__table th, .hb-page2__table td { text-align: left; padding: 14px 18px; border-bottom: 1px solid #1a151222; }
.hb-page2__table th { font-family: 'Amatry', Arial, sans-serif; font-weight: 400; text-transform: uppercase; font-size: 12px; letter-spacing: .1em; opacity: .6; }
.hb-page2__table td:not(:first-child), .hb-page2__table th:not(:first-child) { color: var(--red); font-weight: 600; }
.hb-page2__table tbody tr { transition: background-color .25s ease; }
.hb-page2__table tbody tr:hover { background: color-mix(in srgb, var(--gold) 18%, transparent); }

/* ---- copy left / table right, one row two cells ----
   .hb-page2__body is deliberately single-column by default (see the
   comment above its base rule — a two-column attempt there is what
   caused the "desconfigurada" bugs elsewhere). This modifier opts one
   section back into two columns without touching that default, same
   split ratio as .hb-empresas--turmas (front-page.php) so the table
   reads as a normal-width table rather than being stretched. */
.hb-page2__body.hb-page2__body--split {
	display: grid;
	grid-template-columns: minmax(0, .9fr) minmax(0, 1.15fr);
	column-gap: clamp(40px, 5vw, 80px);
	align-items: center;
}
.hb-page2__body--split .hb-page2__split-copy > h2 { margin: 0 0 var(--hb-s3); }
.hb-page2__body--split .hb-page2__split-copy > p { width: 100%; margin: 0; }
.hb-page2__body--split > .hb-page2__table-wrap { margin: 0; max-width: none; width: 100%; }

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

.hb-page2__note {
	background: var(--gold);
	color: var(--ink);
	padding: var(--hb-s4);
	max-width: 680px;
	border-radius: var(--hb-radius);
	font-size: var(--hb-text);
	line-height: var(--hb-text-lh);
	margin: var(--hb-s4) 0;
}
.hb-page2__note strong { color: var(--ink); }

.hb-page2__final {
	position: relative;
	overflow: hidden;
	min-height: 58vh;
	display: flex;
	flex-direction: column;
	justify-content: center;
	background: var(--red);
	color: var(--cream);
}
.hb-page2__final::before,
.hb-page2__final::after {
	content: "";
	position: absolute;
	z-index: 0;
	pointer-events: none;
	border-radius: 50%;
	filter: blur(80px);
}
.hb-page2__final::before { width: 34vw; height: 34vw; background: var(--gold); opacity: .16; right: -8vw; top: -14vw; }
.hb-page2__final::after { width: 22vw; height: 22vw; background: var(--gold); opacity: .1; left: -6vw; bottom: -10vw; }
.hb-page2__final > * { position: relative; z-index: 1; }
.hb-page2__final h2 {
	color: var(--gold);
	font-size: var(--hb-h2-hero);
	line-height: 1;
	letter-spacing: -.03em;
	max-width: 15ch;
	margin: 0 0 var(--hb-s3);
}
.hb-page2__final .hb-page2__cta { color: var(--cream); }
.hb-page2__final .hb-page2__cta::after { background: var(--cream); }
.hb-page2__final .hb-page2__cta--round { margin: 3.5vh 0 0; }

/* ---- full-bleed scene (cinematic alternative to .hb-page2__section
   for pages that want the Sobre-nós/Home energy instead of the light
   editorial article treatment: one big claim per screen, dark/gold/red
   alternating, generous negative space used as drama, not leftover
   whitespace). ---- */
.hb-page2__scene {
	position: relative;
	overflow: hidden;
	min-height: 60vh;
	display: flex;
	flex-direction: column;
	justify-content: center;
	background: var(--night);
	color: var(--cream);
}
/* A scene that CONTINUES the thought above it rather than opening a new
   one — no full-viewport minimum, so a closing sentence sits tight
   under whatever it concludes (e.g. the Empresas sector marquee) instead
   of floating in a screen of empty dark. */
.hb-page2__scene--tight { min-height: 0; }
.hb-page2__scene--gold { background: var(--gold); color: var(--ink); }
.hb-page2__scene--gold h2 { color: var(--red); }
.hb-page2__scene--red { background: var(--red); color: var(--cream); }
.hb-page2__scene--red h2 { color: var(--gold); }
.hb-page2__scene.hb-page2__scene--light { background: var(--cream); color: var(--ink); }
.hb-page2__scene.hb-page2__scene--light h2 { color: var(--red); }
.hb-page2__scene.hb-page2__scene--light p { opacity: 1; color: var(--ink); }
.hb-page2__scene.hb-page2__scene--light .hb-page2__cta { color: var(--red); }
.hb-page2__scene.hb-page2__scene--light .hb-page2__milestone-num { color: var(--red); opacity: .13; }
/* .hb-fact__num and .hb-levels li both read their colour off the dark
   default (gold number, currentColor-tinted chip) — on --light's cream
   ground that's gold-on-cream, under the 4.5:1 minimum. Same red/gold
   pairing .hb-page2__section already uses for facts and chips on a
   light ground (Horários, Estudar em Espanha, Exames' base chips). */
.hb-page2__scene.hb-page2__scene--light .hb-fact__num { color: var(--red); }
.hb-page2__scene.hb-page2__scene--light .hb-levels li { color: var(--ink); background: color-mix(in srgb, var(--gold) 30%, transparent); }
/* Four words ("Jurídicos"/"Académicos"/"Científicos"/"Empresariais")
   in this narrower column (~700px, the .68fr/1fr split's text side —
   .hb-levels elsewhere only ever holds short A1–C2 codes) measured
   708px needed against 700px available: 8px over, so the fourth chip
   alone wrapped to its own row. Tightened gap + padding here only —
   Exames' level chips are untouched. */
.hb-page2__scene.hb-page2__scene--light .hb-levels { gap: 8px; }
.hb-page2__scene.hb-page2__scene--light .hb-levels li { padding: .45em .7em; }
/* This one was missed in the three rounds that softened
   .hb-page2__section::before below — still at its original size and
   strength, and being the blur on every dark "scene" (the figure/gold/red
   full-bleed sections), it's the one most visible on Traduções, Empresas
   and Cursos. Brought down to the same tier: smaller, fainter, pushed
   further off-canvas so only its already-soft outer edge ever shows. */
.hb-page2__scene::before {
	content: "";
	position: absolute;
	z-index: 0;
	pointer-events: none;
	width: 14vw;
	height: 14vw;
	border-radius: 50%;
	filter: blur(110px);
	background: currentColor;
	opacity: .02;
	right: -12vw;
	top: -16vw;
	transform: translate(calc(var(--nx, 0) * 50px), calc(var(--ny, 0) * 50px));
	transition: transform .7s cubic-bezier(.16,1,.3,1);
}
.hb-page2__scene:nth-of-type(even)::before { right: auto; left: -12vw; top: auto; bottom: -18vw; }
.hb-page2__scene > * { position: relative; z-index: 1; }

/* A scene that carries a picture. The text keeps its own column and the
   image takes the space to its right that a single centred column left
   empty — the image is never BEHIND the words, which is what keeps both
   fully legible and lets the photograph be a photograph instead of a
   texture. Reconstructed to this original grid shape after a wrong-target
   fix briefly rewrote it to flex, then to absolute positioning — this
   component was never the one that needed the "image fills the container"
   change; that request was about the homepage services carousel
   (.hb-cards/.hb-card, main.css) instead. */
.hb-page2__scene--figure {
	display: grid;
	grid-template-columns: 1fr minmax(0, .68fr);
	align-items: stretch;
	gap: var(--hb-s5);
}
.hb-page2__scene--figure .hb-page2__scene__body {
	display: flex;
	flex-direction: column;
	justify-content: center;
	align-items: flex-start;
}
.hb-scene-list {
	margin: var(--hb-s2) 0 0;
	padding: 0;
	list-style: none;
	max-width: 58ch;
	font-size: var(--hb-text);
	line-height: var(--hb-text-lh);
}
.hb-scene-list li { position: relative; padding-left: 1.15em; margin-top: .65em; }
.hb-scene-list li::before { content: "—"; position: absolute; left: 0; color: var(--gold); }
.hb-page2__scene--figure .hb-figure { aspect-ratio: auto; }

/* Estudar em Espanha: this copy is denser than the short statements used
   by the shared figure scene. Give it a calmer editorial hierarchy so the
   long headline does not force the image out of the viewport. */
.hb-page2__scene--process {
	grid-template-columns: minmax(0, .92fr) minmax(340px, .7fr);
	column-gap: clamp(40px, 5vw, 88px);
}
.hb-page2__scene--process .hb-page2__scene__body { min-width: 0; }
.hb-page2__scene--process h2 {
	max-width: 10.5ch;
	font-size: clamp(3.6rem, 5.25vw, 6.4rem);
	line-height: .93;
}
.hb-page2__scene--process .hb-page2__scene__body > p:not(.hb-process-intro) {
	max-width: 38ch;
	margin-top: var(--hb-s1);
}
.hb-process-intro {
	margin-top: var(--hb-s4);
	font-size: clamp(1rem, 1.1vw, 1.2rem);
	letter-spacing: .08em;
	text-transform: uppercase;
}
.hb-page2__scene--process .hb-scene-list {
	width: 100%;
	max-width: 46rem;
	margin-top: var(--hb-s2);
	border-top: 1px solid color-mix(in srgb, var(--gold) 48%, transparent);
}
.hb-page2__scene--process .hb-scene-list li {
	display: block;
	margin: 0;
	padding: .8em 0;
	border-bottom: 1px solid color-mix(in srgb, var(--gold) 48%, transparent);
}
.hb-page2__scene--process .hb-scene-list li::before {
	content: none;
}

@media (max-width: 900px) {
	/* gap:0 — the desktop grid's own gap (var(--hb-s5), 64px) was meant
	   as a horizontal gutter between the two side-by-side columns. On a
	   single-column mobile stack that same gap becomes vertical AND
	   stacks with the figure's own margin-top below, 64+40=104px between
	   text and photo — noticeably more than the ~40px every other
	   text-then-image transition on the site uses. The figure's
	   margin-top is the only spacing needed here now. */
	.hb-page2__scene--figure { grid-template-columns: 1fr; gap: 0; }
	.hb-page2__scene--process h2 { max-width: 12ch; font-size: clamp(3rem, 13vw, 5rem); }
	.hb-page2__scene--process .hb-page2__scene__body > p:not(.hb-process-intro) { margin-top: var(--hb-s1); }
	.hb-process-intro { margin-top: var(--hb-s3); }
	/* Titulo, texto, e so depois a imagem. Estava `order: -1`, que punha
	   a fotografia antes do texto em todas as paginas com esta seccao
	   (Cursos, Estudar em Espanha, Exames, Empresas, Traducoes) — a
	   ordem de leitura deve seguir o argumento e nao ilustra-lo antes de
	   ele existir. `order: 1` para ficar explicito que e deliberado. */
	.hb-page2__scene--figure .hb-figure { order: 1; aspect-ratio: 3 / 2; height: auto; margin-top: var(--hb-s4); }
}

/* Mirrors --figure for the one page that needed the photo on the left
   (Traduções: "quero a imagem do lado esquerdo"). Scoped to desktop
   only — the mobile rule directly above deliberately always runs text
   before image regardless of the desktop order ("a ordem de leitura
   deve seguir o argumento e não ilustrá-lo antes de ele existir"), and
   that reasoning holds just as well mirrored, so this leaves mobile
   alone rather than fighting it back to image-first there too. */
@media (min-width: 901px) {
	.hb-page2__scene--figure.hb-page2__scene--figure-reverse { grid-template-columns: minmax(0, .68fr) 1fr; }
	.hb-page2__scene--figure-reverse .hb-page2__scene__body { order: 2; }
	.hb-page2__scene--figure-reverse .hb-figure { order: 1; }
}
.hb-page2__scene__eyebrow {
	display: block;
	font-family: 'Amatry', Arial, sans-serif;
	font-size: var(--hb-eyebrow);
	text-transform: uppercase;
	letter-spacing: .2em;
	opacity: .6;
	margin-bottom: var(--hb-s2);
}
/* Capped well below the old 7.5rem/8vw. These claims were swallowing a
   whole screen on their own and forcing the supporting copy off the
   fold on laptops — and on phones a 8vw headline plus its lede was
   most of a viewport of scroll for one sentence. */
.hb-page2__scene h2 {
	font-size: var(--hb-h2-hero);
	line-height: 1;
	letter-spacing: -.03em;
	/* 15ch forced a wrap on top of the copy's own <br>, so claims broke
	   into three ragged lines. Wide enough now that the line breaks are
	   the ones the copy asks for. */
	max-width: 24ch;
	margin: 0 0 var(--hb-s3);
	color: inherit;
	transform-origin: left center;
	will-change: transform;
}
.hb-page2__scene p {
	font-size: var(--hb-text);
	line-height: var(--hb-text-lh);
	max-width: 58ch;
	margin: 0 0 1.4em;
	opacity: .92;
}
/* First paragraph carries the supporting point; anything after it is
   footnote-weight detail, not a second equal claim — the big h2 above
   should still be the only thing that reads as "the point" at a glance. */
.hb-page2__scene p ~ p {
	opacity: .68;
	max-width: 56ch;
}
.hb-page2__scene .hb-page2__cta { color: inherit; margin-top: var(--hb-s3); font-size: var(--hb-text); }
.hb-page2__scene .hb-page2__cta::after { background: currentColor; }
.hb-page2__scene .hb-page2__milestone-num { color: currentColor; opacity: .16; }

@media (max-width: 760px) {
	.hb-page2__scene { min-height: auto; overflow: hidden; }
	.hb-page2__scene h2 { max-width: 100%; }
}

/* ---- Contactos: details beside the form ----------------------------
   The page used to stack headline → lede → email → phone → form in one
   centre column, so the form began about a screen below the fold and
   the contact details read as a preamble to scroll past. Side by side,
   both ways of getting in touch are visible at once. ---- */
.hb-contact {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	gap: var(--hb-s6) var(--hb-s5);
	/* Top-aligned now that the heading lives INSIDE the aside. It used
	   to be centred because the details column held only a sentence and
	   an email address and would otherwise float near the top of a much
	   taller form — but that was solving a problem created by leaving
	   the title outside the grid. With the full block in the column, the
	   two columns are comparable in height and both should start on the
	   same line, which is what makes the page read as one layout. */
	align-items: start;
	width: 100%;
}
.hb-contact__aside { display: flex; flex-direction: column; align-items: flex-start; gap: var(--hb-s3); }
/* The headline sets its own rhythm inside the column, so it must not
   also inherit the aside's flex gap on both sides. */
.hb-contact__aside .hb-page2__eyebrow { margin-bottom: 0; }
.hb-contact__aside .hb-page2__headline { margin: 0; }
.hb-contact__lede {
	margin: 0;
	font-size: var(--hb-text);
	line-height: var(--hb-text-lh);
	max-width: 42ch;
	opacity: .9;
}
.hb-contact__direct { display: flex; flex-direction: column; gap: var(--hb-s2); align-items: flex-start; }
.hb-contact__email { font-size: var(--hb-h3); font-weight: 700; }
.hb-contact__phone-wrap { display: flex; flex-direction: column; }
.hb-contact__phone { font-size: var(--hb-text); opacity: .8; }
.hb-contact__phone:hover { opacity: 1; }
.hb-contact__phone-note { display: block; font-size: 12px; opacity: .55; }
@media (max-width: 900px) {
	.hb-contact { grid-template-columns: 1fr; gap: var(--hb-s5); }
}

/* ---- prose: running legal/reference text (Politica de Privacidade,
   Termos e Condicoes) ----------------------------------------------
   These pages are edited in WordPress, so the markup is whatever the
   editor emits — h2/h3/p/ul/ol/a with no classes. Everything here is
   element-scoped for that reason, and every size comes off the shared
   tokens so a legal page reads in the same voice as the rest of the
   site instead of falling back to browser defaults. ---- */
.hb-prose { max-width: 72ch; width: 100%; }
.hb-prose > * + * { margin-top: var(--hb-s3); }
.hb-prose h2 {
	font-size: var(--hb-h2);
	line-height: 1.1;
	letter-spacing: -.01em;
	color: var(--red);
	margin-top: var(--hb-s5);
}
.hb-prose h3 {
	font-size: var(--hb-h3);
	line-height: 1.2;
	color: var(--red);
	margin-top: var(--hb-s4);
}
.hb-prose p,
.hb-prose li { font-size: var(--hb-text); line-height: var(--hb-text-lh); }
.hb-prose ul, .hb-prose ol { padding-left: 1.4em; }
.hb-prose li + li { margin-top: var(--hb-s1); }
.hb-prose a {
	color: var(--red);
	border-bottom: 1px solid color-mix(in srgb, currentColor 45%, transparent);
	transition: border-color .25s ease;
}
.hb-prose a:hover,
.hb-prose a:focus-visible { border-bottom-color: currentColor; }
.hb-prose strong { font-weight: 700; }
.hb-prose__updated {
	margin-top: var(--hb-s5);
	padding-top: var(--hb-s3);
	border-top: 1px solid color-mix(in srgb, currentColor 20%, transparent);
	font-size: var(--hb-text-sm);
	opacity: .6;
}

/* ---- 404 ---- */
.hb-404 { min-height: 72vh; }
.hb-404__links {
	display: flex;
	flex-wrap: wrap;
	gap: var(--hb-s3) var(--hb-s4);
	margin-top: var(--hb-s5);
	position: relative;
	z-index: 2;
}

/* ---- forms, everywhere ------------------------------------------
   The site used to ask people to compose an email listing their own
   name, address, phone, NIF, level and schedule from memory. This is
   that, as a form. Two columns on anything wide enough, one on a
   phone, and every field a 44px target on touch (see the tap-target
   block further down).
   ---- */
.hb-form { width: 100%; max-width: 640px; }
.hb-form__title {
	margin: 0 0 var(--hb-s3);
	font-family: 'Amatry', Arial, sans-serif;
	font-weight: 400;
	font-size: var(--hb-h3);
	line-height: 1.15;
}
.hb-form__grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr));
	gap: var(--hb-s3) var(--hb-s4);
}
.hb-form__row { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.hb-form__row--wide { grid-column: 1 / -1; }
.hb-form__row label {
	font-family: 'Amatry', Arial, sans-serif;
	font-size: 11px;
	text-transform: uppercase;
	letter-spacing: .16em;
	opacity: .7;
}
.hb-form__row label span { text-transform: none; letter-spacing: 0; opacity: .7; }
.hb-form__row input,
.hb-form__row select,
.hb-form__row textarea {
	width: 100%;
	background: transparent;
	border: 0;
	border-bottom: 2px solid color-mix(in srgb, currentColor 28%, transparent);
	border-radius: 0;
	padding: 8px 0;
	font: inherit;
	font-size: var(--hb-text);
	color: inherit;
	transition: border-color .25s ease;
}
.hb-form__row textarea { resize: vertical; min-height: 96px; }
/* Every .hb-form lives inside .hb-page2__final (bordô background, gold
   text) — Contactos and every inner page's closing CTA. Placeholder
   text had no rule of its own here, so it fell back to the browser's
   default UA grey, unreadable on bordô. Measured (WCAG contrast against
   #A53047): gold/currentColor is 3.18:1 — under the 4.5:1 small-text
   minimum — cream at full opacity is 6.19:1, and this opacity (.9) still
   holds at 5.31:1, comfortably over the threshold while reading as
   placeholder text rather than a typed value. */
.hb-form__row input::placeholder,
.hb-form__row textarea::placeholder { color: var(--cream); opacity: .9; }
/* The native arrow is drawn in the OS colour and disappears on the dark
   grounds these forms sit on, so the control draws its own. */
.hb-form__row select {
	appearance: none;
	background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%);
	background-position: calc(100% - 12px) calc(50% + 2px), calc(100% - 7px) calc(50% + 2px);
	background-size: 5px 5px;
	background-repeat: no-repeat;
	padding-right: 26px;
}
.hb-form__row select option { color: var(--ink); background: var(--cream); }
.hb-form__row input:focus,
.hb-form__row select:focus,
.hb-form__row textarea:focus { outline: none; border-bottom-color: currentColor; }
.hb-form__row input:focus-visible,
.hb-form__row select:focus-visible,
.hb-form__row textarea:focus-visible { outline: 2px solid currentColor; outline-offset: 4px; }

.hb-form__submit {
	margin-top: var(--hb-s4);
	background: none;
	border: 0;
	padding: 0 0 8px;
	border-bottom: 2px solid currentColor;
	font-family: 'Franie', Arial;
	font-weight: 700;
	font-size: var(--hb-text);
	color: inherit;
	cursor: pointer;
	display: inline-flex;
	align-items: center;
}

.hb-form__note {
	grid-column: 1 / -1;
	margin: 0 0 var(--hb-s3);
	padding: var(--hb-s2) var(--hb-s3);
	border-left: 2px solid currentColor;
	font-size: var(--hb-text-sm);
	line-height: 1.5;
	background: color-mix(in srgb, currentColor 8%, transparent);
}
.hb-form__note--ok { border-left-color: var(--gold); }
.hb-form__note--erro { border-left-color: var(--red); }
.hb-page2__scene .hb-form__note--erro,
.hb-page2__final .hb-form__note--erro { border-left-color: var(--cream); }

/* ---- form success modal ----------------------------------------- */
body.hb-modal-open { overflow: hidden; }
.hb-form-modal {
	position: fixed;
	inset: 0;
	z-index: 10000;
	display: grid;
	place-items: center;
	padding: 20px;
	opacity: 0;
	visibility: hidden;
	transition: opacity .2s ease, visibility .2s ease;
}
.hb-form-modal.is-visible { opacity: 1; visibility: visible; }
.hb-form-modal.is-closing { opacity: 0; }
.hb-form-modal__backdrop {
	position: absolute;
	inset: 0;
	background: rgba(20, 17, 15, .48);
	backdrop-filter: blur(3px);
}
.hb-form-modal__dialog {
	position: relative;
	z-index: 1;
	width: min(100%, 430px);
	padding: 38px 36px 34px;
	border-radius: 14px;
	background: var(--cream);
	color: var(--ink);
	box-shadow: 0 24px 70px rgba(20, 17, 15, .24);
	text-align: center;
	transform: translateY(10px) scale(.99);
	transition: transform .25s ease;
}
.hb-form-modal.is-visible .hb-form-modal__dialog { transform: none; }
.hb-form-modal__close {
	position: absolute;
	top: 10px;
	right: 10px;
	width: 38px;
	height: 38px;
	border: 0;
	background: transparent;
	color: var(--red);
	font: 400 28px/1 Arial, sans-serif;
	cursor: pointer;
}
.hb-form-modal__icon {
	display: grid;
	place-items: center;
	width: 44px;
	height: 44px;
	margin: 0 auto 18px;
	border-radius: 50%;
	background: var(--red);
	color: var(--cream);
	font: 700 22px/1 Arial, sans-serif;
}
.hb-form-modal__dialog h2 {
	margin: 0 0 12px;
	color: var(--red);
	font-size: clamp(28px, 4vw, 36px);
	line-height: 1.05;
}
.hb-form-modal__dialog p {
	margin: 0 auto 24px;
	max-width: 34ch;
	font-size: 17px;
	line-height: 1.45;
}
.hb-form-modal__action {
	min-width: 112px;
	min-height: 44px;
	padding: 9px 20px;
	border: 0;
	border-radius: 999px;
	background: var(--red);
	color: var(--cream);
	font-family: 'Franie', Arial, sans-serif;
	font-size: 15px;
	font-weight: 700;
	cursor: pointer;
}
.hb-form-modal__close:focus-visible,
.hb-form-modal__action:focus-visible { outline: 3px solid var(--gold); outline-offset: 3px; }

@media (max-width: 600px) {
	.hb-form-modal { padding: 16px; }
	.hb-form-modal__dialog { padding: 34px 24px 28px; }
}

@media (prefers-reduced-motion: reduce) {
	.hb-form-modal,
	.hb-form-modal__dialog { transition: none; }
}

/* ---- direct contact: phone + WhatsApp -----------------------------
   Every call to action on this site was a mailto:. A form is the right
   answer for someone ready to enrol; for someone with one quick
   question it is still too much, and in Portugal that question is
   usually asked on WhatsApp. Renders only when the numbers are set. */
.hb-direct { margin-top: var(--hb-s4); }
.hb-direct__label {
	display: block;
	font-family: 'Amatry', Arial, sans-serif;
	font-size: 11px;
	text-transform: uppercase;
	letter-spacing: .16em;
	opacity: .6;
	margin-bottom: var(--hb-s2);
}
.hb-direct__links { display: flex; flex-wrap: wrap; align-items: center; gap: var(--hb-s3) var(--hb-s4); }
.hb-direct__wa, .hb-direct__tel {
	font-weight: 700;
	border-bottom: 2px solid currentColor;
	padding-bottom: 4px;
	display: inline-flex;
	align-items: flex-end;
}
.hb-direct__tel { font-variant-numeric: tabular-nums; }

/* A form standing on its own inside a content column (the level test on
   Cursos), rather than in the copy-left / action-right closing row. */
.hb-form-block {
	width: 100%;
	margin-top: var(--hb-s5);
	padding-top: var(--hb-s4);
	border-top: 1px solid color-mix(in srgb, currentColor 20%, transparent);
}
/* The closing row's action column was sized for a 170px round button.
   A form needs the room, so it takes the larger share and the copy
   stops being the wider of the two. */
.hb-cta-row__action--form { flex: 1 1 380px; min-width: 0; }

/* CLOSING SECTION WITH A FORM — two columns sharing one centre line.
   The heading used to sit outside .hb-cta-row, so the section stacked
   as [heading spanning the width] then [copy | form]. The form runs
   about twice the height of the copy beside it, which left the whole
   left half empty below a paragraph pinned to the top: two things near
   each other rather than one block.

   A first attempt did this with `display: contents` on the row, which
   put the heading and the copy in column one as SEPARATE grid items —
   and grid items stretch, so the heading inflated to 338px to fill its
   row. The heading and the copy are one block, so they are now one
   element, and the two sides simply centre against each other. */
.hb-final__split {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--hb-s4) var(--hb-s5);
	width: 100%;
}
/* The copy takes the larger share: the heading lives here and it is the
   longest line in the composition, while the form's own columns are
   fixed by its fields. */
.hb-final__copy { flex: 1.15 1 420px; min-width: 0; }
/* --hb-h2-hero is 74px at 1440, which in a 568px column broke "Pedir um
   orçamento sem compromisso?" across FOUR lines. A closing heading sits
   beside a form here, not alone across the page, so it gets its own step
   down — and the ch cap goes, because the column already limits it. */
.hb-final__copy > h2 {
	font-size: clamp(1.8rem, 4vw, 3.6rem);
	max-width: none;
	margin-bottom: var(--hb-s3);
}
.hb-final__copy .hb-cta-row__text { margin: 0; }
.hb-final__split > .hb-cta-row__action--form { flex: 1 1 420px; min-width: 0; }
/* ANEXO 7 — copy and form share a top line.
   The row is align-items:flex-start, but the heading above it carries a
   bottom margin while the form starts at its own first label, so the two
   columns began at different heights and the block read as unaligned.
   Zeroing the copy's own leading margin lines the first line of text up
   with the first field. */
.hb-cta-row:has(.hb-cta-row__action--form) { align-items: flex-start; gap: var(--hb-s4) var(--hb-s5); }
.hb-cta-row:has(.hb-cta-row__action--form) .hb-cta-row__text { flex: 1 1 300px; margin-top: 0; }
.hb-cta-row__action--form .hb-form { margin-top: 0; }
.hb-cta-row__action--form .hb-form__grid > .hb-form__row:first-child label { margin-top: 0; }
.hb-contact__social { display: flex; gap: var(--hb-s1); margin: var(--hb-s2) calc(var(--hb-s1) * -1) 0; }
.hb-contact__social a { display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; opacity: .8; transition: opacity .2s ease; }
.hb-contact__social a:hover { opacity: 1; }
.hb-contact__social svg { width: 20px; height: 20px; }

/* ---- contact form (Contactos) ---- */
.hb-page2__form { max-width: 460px; margin: 0; text-align: left; width: 100%; }
.hb-page2__form-row { margin-bottom: 3.4vh; }
.hb-page2__form label {
	display: block;
	font-family: 'Amatry', Arial, sans-serif;
	font-size: 12px;
	text-transform: uppercase;
	letter-spacing: .15em;
	opacity: .6;
	margin-bottom: 1.2vh;
}
.hb-page2__form input,
.hb-page2__form textarea {
	display: block;
	width: 100%;
	background: transparent;
	border: none;
	border-bottom: 2px solid currentColor;
	color: inherit;
	font: 400 18px/1.4 'Franie', Arial;
	padding: 8px 0;
	opacity: .95;
}
.hb-page2__form input::placeholder,
.hb-page2__form textarea::placeholder { color: currentColor; opacity: .4; }
.hb-page2__form input:focus,
.hb-page2__form textarea:focus { outline: none; border-bottom-color: var(--gold); }
.hb-page2__form textarea { resize: vertical; min-height: 90px; }
/* Anti-spam honeypot: must never be reachable by a human, because a
   visitor who fills it has their message silently discarded. This is
   declared through .hb-page2__form so it outranks
   `.hb-page2__form input { width: 100% }` — at the plain single-class
   specificity it had, only `left` survived the cascade and the field
   was still laid out at 335x18 with opacity .95, hidden by nothing but
   its off-canvas offset. Now every declaration holds, so the field
   stays hidden even if that offset is ever changed. */
.hb-page2__form .hb-page2__form-hp,
.hb-form .hb-page2__form-hp {
	position: absolute; left: -9999px;
	width: 1px; height: 1px; opacity: 0; pointer-events: none;
	/* The .hb-form selector is NOT optional. When the new form component
	   landed it reused this field but not the old wrapper class, so the
	   rule stopped matching and the honeypot rendered as a visible 147px
	   input in the middle of a real form. Anything typed into it is
	   treated as a bot and silently discarded — which would have thrown
	   away real enquiries without either side knowing. */
}
.hb-page2__form button {
	position: relative;
	display: inline-block;
	margin-top: 1vh;
	background: none;
	border: none;
	cursor: pointer;
	font-weight: 700;
	font-size: 19px;
	color: inherit;
	padding-bottom: 4px;
	transition: transform .3s ease;
}
.hb-page2__form button::after {
	content: "";
	position: absolute; left: 0; bottom: 0; width: 100%; height: 2px; background: currentColor;
}
.hb-page2__form button:hover { transform: translateX(6px); }
.hb-page2__form-note { margin-top: 2.5vh; font-size: 15px; }
.hb-page2__form-note--ok { color: var(--gold); font-weight: 700; }

/* ---- branded claims list (Traduções: "Como trabalhamos?") — the
   ¡ mark from the wordmark/menu stands in for a plain bullet. ---- */
.hb-page2__claims { list-style: none; margin: 4vh 0 1vh; padding: 0; display: grid; gap: 3.5vh; max-width: 680px; }
.hb-page2__claims li {
	position: relative;
	padding-left: 1.5em;
	font-family: 'Amatry', Arial, sans-serif;
	font-size: clamp(1.5rem, 2.8vw, 2.1rem);
	line-height: 1.15;
	letter-spacing: -.01em;
	color: var(--red);
}
.hb-page2__claims li::before {
	content: "¡";
	position: absolute;
	left: 0; top: -.08em;
	color: var(--gold);
	font-size: 1.1em;
}

/* ============================================================
   SHARED CONTENT COMPONENTS
   Built so a block of prose can become something scannable without
   losing a word of it. Each one is picked for a specific shape of
   content — see the note above each.
   ============================================================ */

/* NOTE: the .hb-flag act-break motif lives in site.css, not here —
   page.css only loads on the inner pages and the homepage needs it too. */

/* ---- CTA row -------------------------------------------------------
   Copy on the left, the action on the right, both sitting on the same
   baseline. Replaces the pattern where a round button was centred
   under a centred paragraph and read as an ornament floating loose in
   the band rather than the section's next step. ---- */
/* The row's height is set by the 170px round button, so ANY vertical
   alignment other than flex-start pushes the copy down away from the
   heading it belongs to: flex-end (the original) dropped it ~115px,
   and centring still left 87px. On every closing section on the site
   that read as a hole between the title and its sentence rather than
   as deliberate spacing. Top-aligning means the copy starts exactly one
   heading margin (--hb-s3) below the title, and the button sits beside
   it instead of dictating where it lands. */
.hb-cta-row {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: var(--hb-s5);
	flex-wrap: wrap;
	width: 100%;
}
.hb-cta-row__text {
	max-width: 46ch;
	margin: 0;
	font-size: var(--hb-text);
	line-height: var(--hb-text-lh);
	opacity: .9;
}
.hb-cta-row__action { flex-shrink: 0; }
/* The row owns the spacing between copy and action — any margin the CTA
   carries from its standalone use (including the .hb-page2__final
   round-button rule) would push it out of the baseline the row sets up.
   Specificity here has to clear `.hb-page2__final .hb-page2__cta--round`. */
.hb-page2__final .hb-cta-row .hb-page2__cta,
.hb-cta-row .hb-page2__cta { margin: 0; }
/* Two or more CTAs that belong together. They used to be dropped into
   .hb-cta-row, which is justify-content:space-between — built for one
   block of copy at the left and one action at the right. With two
   buttons and no copy, "space between" threw them to opposite ends of a
   1240px container and they read as unrelated. This groups them at
   their natural width instead. */
.hb-btn-group {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--hb-s3) var(--hb-s4);
	margin-top: var(--hb-s4);
}

@media (max-width: 760px) {
	.hb-btn-group { flex-direction: column; align-items: flex-start; gap: var(--hb-s3); }
	/* --hb-s4 (40px) between a sentence and the form it introduces read
	   as a break rather than a pairing — on a phone the two ended up
	   looking like separate sections. One step is enough to separate
	   them without disconnecting them. */
	.hb-cta-row { flex-direction: column; align-items: flex-start; gap: var(--hb-s3); }
	/* flex-basis applies to the MAIN axis, and the main axis here is
	   vertical. `flex: 1 1 300px` on the copy and `1 1 380px` on the form
	   were sizing the row for a horizontal layout; once it stacks, those
	   became HEIGHTS — the copy block was forced to 300px for ~60px of
	   text, leaving ~240px of measured nothing between the sentence and
	   the first field. Stacked, both blocks should simply be as tall as
	   their content. */
	/* Stacked. flex-basis applies to the MAIN axis, and the main axis is
	   vertical once this wraps to a column — so the bases above would
	   become heights and force each block far taller than its content.
	   That is the bug that put ~250px of nothing between a sentence and
	   the form it introduces. */
	.hb-final__split { flex-direction: column; align-items: stretch; gap: var(--hb-s3); }
	.hb-final__copy,
	.hb-final__split > .hb-cta-row__action--form,
	.hb-final__split > .hb-final__aside { flex: 0 0 auto; width: 100%; }

	/* Same :has() specificity as the desktop rule these override, or they
	   lose the cascade and the copy stays locked at its 300px basis. */
	.hb-cta-row:has(.hb-cta-row__action--form) .hb-cta-row__text,
	.hb-cta-row:has(.hb-cta-row__action--form) .hb-cta-row__action--form,
	.hb-cta-row > .hb-cta-row__text,
	.hb-cta-row > .hb-cta-row__action { flex: 0 0 auto; width: 100%; }
	.hb-cta-row__action { width: 100%; }
}

/* ---- Numbered steps ------------------------------------------------
   For a genuine sequence, where order carries meaning — Exames' "Como
   te inscreves" (reúne a documentação → transferência → comprovativo).
   The number is the scannable anchor: a reader can take the shape of
   the sequence from the page in a couple of seconds and only drop into
   the detail for the step that applies to them.

   This used to be the shared pattern for every such sequence, then got
   replaced everywhere by .hb-cardrail's horizontal cards — but for a
   plain "step + one paragraph" list with no price or date to organise,
   a card is a container seeking content, not content seeking a
   container. Kept as its own component for exactly that shape rather
   than routed back through the cardrail. ---- */
.hb-steps { display: grid; gap: 0; margin: var(--hb-s4) 0 0; }
.hb-step {
	display: grid;
	grid-template-columns: minmax(3.5ch, auto) minmax(0, 1fr);
	column-gap: var(--hb-s4);
	row-gap: var(--hb-s1);
	padding: var(--hb-s4) 0;
	border-top: 1px solid currentColor;
	border-color: color-mix(in srgb, currentColor 18%, transparent);
}
.hb-step:last-child { border-bottom: 1px solid color-mix(in srgb, currentColor 18%, transparent); }
.hb-step__num {
	grid-row: 1 / span 2;
	font-family: 'Amatry', Arial, sans-serif;
	font-size: clamp(1.6rem, 3vw, 2.4rem);
	line-height: 1;
	color: var(--gold);
	letter-spacing: -.02em;
}
.hb-step__title {
	margin: 0;
	font-size: var(--hb-h3);
	line-height: 1.25;
	color: var(--red);
	letter-spacing: -.01em;
}
.hb-step__body {
	margin: 0;
	font-size: var(--hb-text);
	line-height: var(--hb-text-lh);
	max-width: 62ch;
	opacity: .88;
}
.hb-page2__scene .hb-step__title { color: inherit; }
.hb-page2__scene .hb-step__num { color: var(--gold); }
@media (max-width: 640px) {
	.hb-step { grid-template-columns: 1fr; row-gap: var(--hb-s1); padding: var(--hb-s3) 0; }
	.hb-step__num { grid-row: auto; font-size: 1.4rem; }
}

/* ---- Card grid -----------------------------------------------------
   For peers — items with no inherent order that the reader compares
   rather than follows. Auto-fit means the same markup gives 3-up on
   desktop, 2-up on tablet and 1-up on a phone with no breakpoint of
   its own. ---- */
.hb-cardgrid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
	gap: var(--hb-s3);
	margin: var(--hb-s4) 0 0;
	width: 100%;
}
.hb-card2 {
	display: flex;
	flex-direction: column;
	gap: var(--hb-s2);
	padding: var(--hb-s4);
	background: color-mix(in srgb, var(--gold) 12%, transparent);
	border-radius: var(--hb-radius);
	border: 1px solid color-mix(in srgb, var(--red) 14%, transparent);
}
.hb-card2__label {
	font-family: 'Amatry', Arial, sans-serif;
	font-size: var(--hb-eyebrow);
	text-transform: uppercase;
	letter-spacing: .16em;
	opacity: .6;
}
.hb-card2__title {
	margin: 0;
	font-size: var(--hb-h3);
	line-height: 1.25;
	color: var(--ink);
}
.hb-card2__body {
	margin: 0;
	font-size: var(--hb-text);
	line-height: var(--hb-text-lh);
	opacity: .88;
}
.hb-page2__scene .hb-card2 {
	background: color-mix(in srgb, currentColor 8%, transparent);
	border-color: color-mix(in srgb, currentColor 20%, transparent);
}
.hb-page2__scene .hb-card2__title { color: inherit; }

/* Traduções — compact certification band. A single supporting service does
   not need a full-width card inside a full-height section. The editorial
   split gives the heading and explanation equal presence without leaving a
   large empty lower half. */
.hb-certification {
	padding-block: clamp(64px, 6.5vw, 96px);
	background: var(--paper);
	border-top: 6px solid var(--red);
	border-bottom: 1px solid color-mix(in srgb, var(--red) 20%, transparent);
}
.hb-page2__body.hb-certification__layout {
	display: grid;
	grid-template-columns: minmax(240px, .8fr) minmax(0, 1.35fr);
	gap: clamp(48px, 8vw, 128px);
	align-items: center;
	width: 100%;
}
.hb-certification__heading .hb-card2__label {
	display: block;
	margin-bottom: var(--hb-s2);
	color: var(--red);
}
.hb-certification__heading h2 {
	margin: 0;
	max-width: 10ch;
}
.hb-certification__content {
	padding: var(--hb-s2) 0 var(--hb-s2) clamp(28px, 4vw, 64px);
	border-left: 2px solid var(--gold);
}
.hb-certification__content h3 {
	margin: 0 0 var(--hb-s2);
	font-size: clamp(2rem, 3.2vw, 3.8rem);
	line-height: 1.05;
	color: var(--red);
}
.hb-certification__content p {
	max-width: 48ch;
	margin: 0;
	font-size: var(--hb-text);
	line-height: var(--hb-text-lh);
}
.hb-certification__content .hb-page2__cta { margin-top: var(--hb-s3); }

@media (max-width: 760px) {
	.hb-certification { padding-block: var(--hb-section-y); border-top-width: 4px; }
	.hb-page2__body.hb-certification__layout {
		grid-template-columns: 1fr;
		gap: var(--hb-s3);
	}
	.hb-certification__heading h2 { max-width: 12ch; }
	.hb-certification__content {
		padding: var(--hb-s3) 0 0;
		border-left: 0;
		border-top: 2px solid var(--gold);
	}
}

/* ---- Sector card rail (Empresas) --------------------------------------
   .hb-cardrail's plain drag/wheel/keyboard slider (page.css above,
   motion.js: initCardRail) — a NORMAL scroller, not the pinned/scroll-
   jacked .hb-deck stack or the .hb-timeline scroll-pin, on purpose: the
   client asked for something that scrolls through the sectors without
   being "like the other sliders" on the page. One card per sector,
   smaller photo than a full panel, and a solid dark caption band under
   it for contrast that doesn't depend on the photo underneath. */
/* .hb-cardrail__card.hb-cardrail__card--photo, not the bare modifier —
   .hb-cardrail__card's own base rule (further down, width/padding)
   carries the SAME specificity as a single-class modifier selector, so
   whichever is later in the file wins regardless of intent. Chaining
   both classes here (0,2,0) beats the base rule (0,1,0) outright. */
.hb-cardrail__card.hb-cardrail__card--photo {
	width: clamp(190px, 19vw, 230px);
	padding: 0;
	background: var(--night);
	color: var(--cream);
	gap: 0;
}
.hb-cardrail__card--photo .hb-cardrail__photo {
	width: 100%;
	aspect-ratio: 4 / 3;
	overflow: hidden;
}
.hb-cardrail__card--photo .hb-cardrail__photo img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}
.hb-cardrail__card--photo .hb-cardrail__caption {
	padding: var(--hb-s3);
	font-family: 'Amatry', Arial, sans-serif;
	font-weight: 400;
	font-size: clamp(1rem, 1.3vw, 1.2rem);
	line-height: 1.25;
}

/* ---- Brand line ----------------------------------------------------
   "Não precisas de falar perfeito. Só precisas de começar." is the
   emotional centre of the whole brand — it is the objection every
   hesitant learner is carrying, answered in nine words. It was living
   in the footer, at 16px, next to the sitemap.

   Given as a quiet moment immediately before a decision CTA: set in the
   display face, sized between body and headline so it reads as a spoken
   aside rather than another heading competing with the one above it. ---- */
.hb-page2__brandline {
	font-family: 'Amatry', Arial, sans-serif;
	font-size: clamp(1.3rem, 2.4vw, 2rem);
	line-height: 1.25;
	letter-spacing: -.01em;
	max-width: 20ch;
	margin: 0 0 var(--hb-s4);
	opacity: .85;
}
.hb-page2__brandline em { font-style: normal; color: var(--gold); }
.hb-page2__final .hb-page2__brandline em { color: var(--cream); }

/* ---- Accordion -----------------------------------------------------
   For reference content the reader consults rather than reads: exam
   rules, payment terms, cancellation policy. These were four long
   paragraphs of fine print that everyone scrolled past, and their
   length made the page feel heavier than its actual message.

   Built on native <details>/<summary>, deliberately: keyboard and
   screen-reader behaviour, find-in-page, and open/close all work with
   no JavaScript at all — nothing to load, nothing to hydrate, and it
   still works if the CDN scripts fail. The only JS-free compromise is
   that opening doesn't animate height, which is a fair trade.

   Closed by default: the point is that this content stops occupying
   the page until someone wants it. ---- */
.hb-accordion { margin: var(--hb-s4) 0 0; width: 100%; }
.hb-acc { border-top: 1px solid color-mix(in srgb, currentColor 18%, transparent); }
.hb-acc:last-of-type { border-bottom: 1px solid color-mix(in srgb, currentColor 18%, transparent); }
.hb-acc__head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--hb-s3);
	/* ~70px tall including the text — comfortably over the 44px a
	   finger needs, without a separate mobile rule. */
	padding: var(--hb-s3) 0;
	cursor: pointer;
	font-family: 'Amatry', Arial, sans-serif;
	font-size: var(--hb-h3);
	line-height: 1.25;
	color: var(--red);
	list-style: none;
	transition: opacity .25s ease;
}
/* Both are needed to drop the default disclosure triangle across
   engines — the pseudo-element for WebKit, list-style for the rest. */
.hb-acc__head::-webkit-details-marker { display: none; }
.hb-acc__head:hover { opacity: .72; }
.hb-acc__head::after {
	content: "+";
	flex: 0 0 auto;
	font-size: 1.4em;
	line-height: 1;
	color: var(--gold);
	transition: transform .3s cubic-bezier(.65,0,.35,1);
}
.hb-acc[open] .hb-acc__head::after { transform: rotate(45deg); }
.hb-acc__body { padding: 0 0 var(--hb-s4); max-width: 68ch; }
.hb-acc__body > :first-child { margin-top: 0; }
.hb-acc__body > :last-child { margin-bottom: 0; }
.hb-acc__body p {
	font-size: var(--hb-text);
	line-height: var(--hb-text-lh);
	margin: 0 0 1em;
}
@media (prefers-reduced-motion: reduce) {
	.hb-acc__head::after { transition: none; }
}

/* ---- Level chips ---------------------------------------------------
   A short closed set the reader scans rather than reads — the six DELE
   levels, which as a sentence ("A1, A2, B1, B2, C1 e C2") carried no
   more meaning than a comma list but took a paragraph to say. ---- */
.hb-levels {
	display: flex;
	flex-wrap: wrap;
	gap: var(--hb-s2);
	margin: var(--hb-s4) 0 0;
	padding: 0;
	list-style: none;
}
.hb-levels li {
	font-family: 'Amatry', Arial, sans-serif;
	font-size: clamp(1.1rem, 2vw, 1.5rem);
	line-height: 1;
	letter-spacing: -.01em;
	color: var(--red);
	background: color-mix(in srgb, var(--gold) 30%, transparent);
	border-radius: 999px;
	padding: .5em .9em;
}
.hb-page2__scene .hb-levels li { color: inherit; background: color-mix(in srgb, currentColor 14%, transparent); }
/* Inside .hb-timeline__chapter (Exames' new slider chapter 01) the base
   rule's gold-tint-on-dark read as a dull, low-contrast olive pill —
   solid cream instead, client's own "a branco" request. */
.hb-timeline__chapter .hb-levels li { color: var(--red); background: var(--cream); }

/* ---- Fact strip ----------------------------------------------------
   Turns credential prose ("more than 30 years", "first Portuguese
   institution to sign with the UNED") into something a reader takes in
   at a glance. The claim stays in full underneath; the strip is the
   headline version of it. ---- */
.hb-facts {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 190px), 1fr));
	gap: var(--hb-s4) var(--hb-s3);
	margin: var(--hb-s4) 0 0;
	width: 100%;
}
.hb-fact {
	display: flex;
	flex-direction: column;
	gap: var(--hb-s2);
}
.hb-fact__num {
	font-family: 'Amatry', Arial, sans-serif;
	font-size: clamp(2.6rem, 5vw, 4.2rem);
	line-height: .9;
	color: var(--gold);
	letter-spacing: -.03em;
	/* Digits keep their column while a counter animates through them,
	   so the label underneath never shifts. */
	font-variant-numeric: tabular-nums;
	font-feature-settings: "tnum";
}
/* A VALUE THAT IS A WORD, NOT A NUMBER.
   .hb-fact__num is sized for digits — clamp(2.6rem, 5vw, 4.2rem). Put a
   long word in it and it cannot break, so it simply runs out of its grid
   cell: "UNEDasiss" at 67px measured ~380px inside a 217px column on
   Estudar em Espanha and spilled sideways underneath the section's
   image. This keeps such values on the same scale as a term, which is
   what they are, and the overflow-wrap above is the safety net so no
   value can ever silently escape its column again. */
.hb-fact__num { overflow-wrap: anywhere; }

/* AS LINHAS TEM DE ATRAVESSAR AS COLUNAS.
   Cada .hb-fact empilhava o seu numero e a sua legenda por conta
   propria, por isso a legenda comecava onde o numero desse coluna
   acabasse. Com "+30" e "1.ª" a 67px e "UNEDasiss" a 21.6px -- a
   reducao logo abaixo, que existe para o nome nao transbordar da coluna
   -- as alturas eram 60px contra 25px, e o texto da terceira coluna
   arrancava 36px acima do das outras duas. Medido em Estudar em
   Espanha: os textos comecavam em 1146, 1146 e 1110.

   Subgrid resolve isto pela estrutura em vez de por um min-height a
   martelo: cada .hb-fact deixa de ter uma grelha propria e passa a usar
   as LINHAS da grelha mae, por isso a linha do numero tem uma so altura
   partilhada pelas tres colunas -- a do conteudo mais alto -- e as
   legendas assentam todas na mesma linha, seja qual for a copy que la
   entre no futuro.

   O row-gap declarado aqui e respeitado no primeiro intervalo (entre o
   numero e o proximo elemento), e nao o gap de 40px da mae — essa gap
   maior so serve para separar filas de factos quando estas mudam de
   linha em ecra estreito. (O segundo intervalo, quando existe um
   .hb-fact--divided, tem uma correcao propria mais abaixo — ver esse
   comentario.) */
@supports (grid-template-rows: subgrid) {
	.hb-fact {
		display: grid;
		grid-template-rows: subgrid;
		grid-row: span 2;
		row-gap: var(--hb-s2);
	}
	/* span 3 only where a third child (.hb-fact__divider, between value
	   and caption) actually exists, so a future 2-row fact (value/
	   caption only) keeps its own tight fit instead of reserving a dead
	   third row. Every current .hb-facts usage (Horários, Estudar em
	   Espanha, Traduções) is --divided now. */
	.hb-fact--divided { grid-row: span 3; }
	/* The row-gap above only takes on the FIRST internal gap (term to
	   divider) — measured live on Horários, Estudar em Espanha and
	   Traduções alike, the second (divider to label) still falls back
	   to .hb-facts' own 40px row-gap instead of this 16px one: 39px
	   where 16px was intended. Pulling the label up by the difference
	   rather than reworking how the gap cascades through the subgrid. */
	.hb-fact--divided .hb-fact__label { margin-top: calc(var(--hb-s2) - var(--hb-s4)); }
	/* O wordmark assenta no fundo da linha, nao no topo. As numerais tem
	   line-height .9 e a base delas fica junto ao fundo da caixa; alinhado
	   ao topo, "UNEDasiss" ficava 43px acima da base das numerais, com um
	   buraco por baixo. Assim ficam a 8px, que e a folga do descendente da
	   propria fonte -- le-se como a mesma linha. */
	.hb-fact__num--word { align-self: end; }
}

/* The client asked for the hairline to sit BETWEEN the value and its
   caption, not above the value — a plain block between them, sharing
   .hb-fact's own gap for spacing on both sides. */
.hb-fact__divider {
	display: block;
	width: 100%;
	height: 1px;
	background: color-mix(in srgb, currentColor 22%, transparent);
}

/* Sized to fit a long word ("Videoconferência", 16 letters) on ONE
   line at the fact grid's narrowest column (190px, minmax above) —
   var(--hb-h3) alone still wrapped it to two lines and threw the
   row's height out of line with its neighbours. white-space:nowrap
   is the actual guarantee; the vw-heavy clamp just keeps it as large
   as that guarantee allows at wider columns — raised again (client:
   "maior") now that removing the old top hairline freed up room. */
.hb-fact__num--word {
	font-size: clamp(1.2rem, 3.7vw, 1.85rem);
	line-height: 1.15;
	letter-spacing: 0;
	white-space: nowrap;
	overflow-wrap: normal;
}

/* "UNEDasiss" (Estudar em Espanha) has far more headroom than
   "Videoconferência" (16 characters, tuned to the tightest column
   above) — a shared size increase for both would overflow that one.
   Scoped bump, client: "mete a palavra 'UNEDasiss' maior também". */
.hb-fact__num--word-lg {
	font-size: clamp(1.35rem, 4.2vw, 2.1rem);
}

.hb-fact__num small {
	font-size: .42em;
	letter-spacing: 0;
	margin-left: .06em;
	vertical-align: baseline;
}
.hb-fact__label {
	font-size: var(--hb-text-sm);
	line-height: 1.5;
	opacity: .75;
	max-width: 26ch;
}
.hb-page2__section .hb-fact__num { color: var(--red); }

/* ---- points: claims that are NOT statistics ----------------------
   .hb-facts renders its value at clamp(2.6rem, 5vw, 4.2rem) because a
   number IS the content there ("14 alunos", "+30 anos"). Two sections
   were borrowing it for things that are not numbers, and both broke
   the page:

   - Exames, "Porque é que este diploma conta": the values are the
     words Porto / infinity / Cervantes. At 67px they rendered nearly
     twice the size of the h2 above them, so three supporting facts
     shouted over the heading they were supporting.
   - Traducoes, "O que traduzimos": all three values were the same
     decorative "!" glyph carrying no information at all — three
     identical red strokes reading as stray marks, while the actual
     claim sat underneath in 14px grey.

   Here the sentence is the content and the term is the marker, so the
   hierarchy runs heading > claim > term instead of the other way
   round. Rows are separated by hairlines, which also gives the block a
   shape at a glance without any element having to be big. ---- */
.hb-points {
	display: grid;
	width: 100%;
	margin: var(--hb-s4) 0 0;
	border-top: 1px solid color-mix(in srgb, currentColor 20%, transparent);
}
.hb-point {
	display: grid;
	grid-template-columns: minmax(0, 13ch) minmax(0, 1fr);
	gap: var(--hb-s2) var(--hb-s4);
	align-items: baseline;
	padding: var(--hb-s3) 0;
	border-bottom: 1px solid color-mix(in srgb, currentColor 20%, transparent);
}
.hb-point__term {
	font-family: 'Amatry', Arial, sans-serif;
	font-size: var(--hb-h3);
	line-height: 1.1;
	letter-spacing: -.01em;
	color: var(--gold);
}
.hb-point__body {
	font-size: var(--hb-text);
	line-height: var(--hb-text-lh);
	margin: 0;
	max-width: 52ch;
}
/* On the light editorial sections gold has too little contrast against
   cream, the same reason .hb-fact__num switches there. */
.hb-page2__section .hb-point__term { color: var(--red); }

/* No term to show — the claim is the whole content, so the marker is
   just the brand's own punctuation at label size, and the claim moves
   up into body type instead of sitting in 14px small print. */
.hb-points--claims .hb-point { grid-template-columns: auto minmax(0, 1fr); }
.hb-points--claims .hb-point__term { font-size: var(--hb-h3); opacity: .55; }

@media (max-width: 760px) {
	.hb-point { grid-template-columns: 1fr; gap: var(--hb-s1); }
	.hb-points--claims .hb-point { grid-template-columns: auto minmax(0, 1fr); }
}

/* ---- sector marquee (Empresas) — pure-CSS infinite scroll, no JS
   dependency, so it doesn't need the homepage's velocity-reactive
   GSAP marquee logic. ---- */
.hb-page2__marquee {
	/* Was rotated -1deg with a 102%/-1% bleed to cover the corners the
	   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.

	   Background was ink — the same colour as the scene right above it
	   AND the scene right below it, so the marquee read as one long dark
	   stretch instead of its own band. Gold breaks that up with an
	   actual colour change rather than a decorative line sitting next
	   to it, matching how the homepage's own hero orbs and card system
	   already use gold as the site's "warm" surface. */
	position: relative;
	overflow: hidden;
	background: var(--gold);
	color: var(--red);
	padding: 2.6vh 0;
	width: 100%;
}
.hb-page2__marquee-track {
	display: flex;
	width: max-content;
	animation: hb-page2-marquee 30s linear infinite;
}
.hb-page2__marquee-track span {
	font-family: 'Franie', Arial;
	font-weight: 700;
	font-size: 19px;
	white-space: nowrap;
	padding: 0 26px;
}
/* Ink, not gold — the dot used to separate itself from cream text by
   colour alone on a dark ground; on gold it needs to separate from RED
   text instead, and gold-on-gold would vanish outright. */
.hb-page2__marquee-track span b { color: var(--ink); margin-left: 26px; font-size: 11px; font-style: normal; }
@keyframes hb-page2-marquee { to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) { .hb-page2__marquee-track { animation: none; } }
@media (max-width: 760px) { .hb-page2__marquee-track span { font-size: 15px; } }

/* ---- numbered milestones (Estudar em Espanha: the 3-step UNEDasiss
   process) — a giant ghost numeral sits behind each step instead of
   the inline "1." the copy used to lead with. ---- */
.hb-page2__milestone { position: relative; margin: 7vh 0; padding-left: 13vw; }
.hb-page2__milestone-num {
	position: absolute;
	left: -2vw;
	top: -5vh;
	z-index: 0;
	font-family: 'Amatry', Arial, sans-serif;
	font-size: clamp(5rem, 11vw, 8.5rem);
	line-height: 1;
	color: var(--red);
	opacity: .13;
	pointer-events: none;
}
.hb-page2__milestone p { position: relative; z-index: 1; margin: 0; }

@media (max-width: 760px) {
	.hb-page2__milestone { padding-left: 0; padding-top: 9vh; margin: 6vh 0; }
	.hb-page2__milestone-num { left: -2vw; top: -1vh; font-size: 5rem; opacity: .15; }
}

/* ---- horizontal level path (Cursos: A1/A2 → C2, echoes the Sobre
   nós chapter timeline — one other deliberate use of that pinned
   horizontal-scroll pattern, here for the level/price journey
   instead of the 30-year story) ---- */
.hb-page2__path { height: 100vh; background: var(--night); overflow: hidden; }
.hb-page2__path-track { height: 100vh; display: flex; width: max-content; }
/* Width is the viewport MINUS the classic scrollbar (--hb-sbw, published
   by motion.js; 0 where scrollbars overlay). Plain 100vw includes the
   scrollbar, which made these panels wider than the visible area and
   pushed their content column ~7.5px right of every other section on
   the site. Same expression drives the padding, so a step's text now
   starts on exactly the same x as a .hb-page2__section's. */
.hb-page2__path-step {
	--hb-panel-w: calc(100vw - var(--hb-sbw, 0px));
	width: var(--hb-panel-w); height: 100vh; flex: 0 0 var(--hb-panel-w);
	padding-block: var(--hb-section-y);
	padding-inline: max(var(--hb-gutter), calc((100vw - var(--hb-sbw, 0px) - var(--hb-max)) / 2));
	display: flex;
	flex-direction: column;
	justify-content: center;
	position: relative;
	overflow: hidden;
	background: var(--night);
	color: var(--cream);
}
.hb-page2__path-step--accent { background: var(--gold); color: var(--ink); }
.hb-page2__path-step--accent h2 { color: var(--red); }
.hb-page2__path-step--dark { background: var(--red); color: var(--cream); }
.hb-page2__path-step--dark h2 { color: var(--gold); }
.hb-page2__path-step::before {
	content: "";
	position: absolute;
	z-index: 0;
	pointer-events: none;
	width: 40vw;
	height: 40vw;
	border-radius: 50%;
	filter: blur(90px);
	background: currentColor;
	opacity: .1;
	right: -10vw;
	bottom: -14vw;
}
.hb-page2__path-step > * { position: relative; z-index: 1; }
.hb-page2__path-tag {
	display: inline-block;
	font: italic 20px/1.4 'Franie', Arial;
	opacity: .8;
	margin-bottom: 2vh;
}
.hb-page2__path-num {
	display: block;
	font-family: 'Amatry', Arial, sans-serif;
	font-size: 13px;
	text-transform: uppercase;
	letter-spacing: .2em;
	opacity: .55;
	margin-bottom: 2vh;
}
.hb-page2__path-step h3 {
	/* Was up to 11rem, which left the panel looking mostly empty around a
	   two-character level name. */
	font-size: clamp(3.4rem, 9vw, 7rem);
	/* Cursos puts level codes here ("A1/A2", "C2") but Exames reuses the
	   same panel for words ("Inscrição", "Provas"). A word cannot break,
	   so at a size chosen for two characters it simply runs out of the
	   panel — measured 332px of text in a 250px column on a phone. */
	overflow-wrap: anywhere;
	line-height: .9;
	letter-spacing: -.02em;
	margin: 0 0 2vh;
}
.hb-page2__path-step h3 span { opacity: .35; font-weight: 400; padding: 0 .08em; }
.hb-page2__path-level {
	display: inline-block;
	font-family: 'Amatry', Arial, sans-serif;
	font-size: 15px;
	text-transform: uppercase;
	letter-spacing: .12em;
	opacity: .7;
	margin-bottom: 4vh;
}
/* Price and duration are what a reader is actually comparing between
   panels, so they carry real weight instead of sitting as small print
   under a giant level letter. */
/* flex-wrap: wrap, e nao nowrap. O cartao mede 344px em mobile e este
   par -- "410 €" grande mais "390 € pronto pagamento" -- pede 361px numa
   linha so. O cartao tem overflow: hidden, por isso o que sobrava era
   cortado: medido, 45px fora pela direita, o que na pratica dava
   "390 € pronto pagam". Com wrap, a segunda parte desce para a sua
   propria linha, onde cabe folgada (235px em 264 disponiveis). */
.hb-page2__path-price {
	display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--hb-s2);
	margin-bottom: var(--hb-s1);
	font-variant-numeric: tabular-nums;
}
/* "410 €" was breaking between the digits and the symbol, dropping a
   lone € onto its own line under the price. A price is one token. */
/* Sem white-space: nowrap em lado nenhum aqui. Estava nos dois, e era
   a minha correcao para "o simbolo do euro nao pode sofrer quebra de
   linha" -- so que travar a frase INTEIRA para proteger dois caracteres
   e o que a fazia sair do cartao. O euro esta agora colado ao seu numero
   por um espaco inquebravel no proprio texto (&nbsp;), que protege
   exatamente o que tem de ser protegido e deixa o resto quebrar. */
.hb-page2__path-price strong { font-family: 'Amatry', Arial, sans-serif; font-weight: 400; font-size: clamp(2.2rem, 4vw, 3.4rem); line-height: 1; }
.hb-page2__path-price span { font-size: var(--hb-text); opacity: .8; }
.hb-page2__path-duration {
	display: inline-block;
	font-family: 'Amatry', Arial, sans-serif;
	font-size: var(--hb-text);
	letter-spacing: .1em;
	text-transform: uppercase;
	opacity: .85;
	margin-top: var(--hb-s2);
	padding-top: var(--hb-s2);
	border-top: 1px solid color-mix(in srgb, currentColor 25%, transparent);
}

/* ============================================================
   CARD RAIL v3 — a shelf of compact cards for a short numbered
   sequence long enough to need moving sideways: Estudar em Espanha's
   UNEDasiss route, Cursos' five modules. (Exames' convocatória — just
   three dates — and "Como te inscreves" don't use this: see
   .hb-cardrow and .hb-steps below for those.)

   v1 pinned the rail (position:fixed + a spacer) to drive scroll-linked
   motion; on a rail shorter than the viewport — which every one of
   these is, by design, since the whole point is a compact card rather
   than a full-bleed panel — the spacer was ALSO shorter than the
   viewport, so later page content had already scrolled into view while
   the fixed rail still floated over it. v2 fixed the overlap by tying
   x to the rail's own scroll-through-the-viewport position instead of
   pinning — but that meant dragging a card ALSO moved the page's
   scroll position, and a drag gesture and the reader's own scroll
   reading as the same motion never stopped feeling like two things
   fighting for the same input.

   This version drops scroll out of it entirely. x is a plain local
   value initCardRail owns in motion.js — moved only by a direct mouse
   drag, a trackpad's horizontal wheel, or the arrow keys. Scrolling the
   page past the rail does nothing to it; nothing here needs a pin or a
   ScrollTrigger at all.

   Width comes in two flavours because the content does: a level code
   plus a price is a handful of short lines (.hb-cardrail__card, the
   default), a step's explanation is a real paragraph and reads badly
   squeezed into the same narrow column (.hb-cardrail__card--text,
   wider). Neither is sized to fill anything — cards are exactly as
   tall as their own content, and the row simply doesn't move at all on
   a screen wide enough to show every card already (initCardRail skips
   wiring the drag/wheel/keyboard handlers when there's nothing to
   overflow).
   ============================================================ */
.hb-cardrail {
	position: relative;
	overflow: hidden;
	width: 100%;
	margin-top: var(--hb-s4);

	/* THE EDGE FADE — the hint that there's more sideways than what's
	   showing, the same job a peeking neighbour panel does elsewhere.

	   Two things were wrong with the old version
	   (`transparent 0, #000 28px … #000 calc(100% - 28px), transparent`):

	   1. 28px is 2.5% of a 1137px rail, so the "fade" was really a hard
	      chop — and because a linear ramp in alpha is not perceptually
	      linear, the eye caught the exact pixel it began at. It read as
	      a smear over the card rather than the card receding.
	   2. It was painted on BOTH sides at ALL times, including at rest,
	      where nothing whatsoever is hidden to the left. It announced
	      content that was not there.

	   Now: wider, and eased on a smoothstep curve (.16/.50/.84 at the
	   quarter points) so there is no visible line where the fade starts.
	   Each side's width is multiplied by a 0..1 value that motion.js
	   sets from how much is genuinely hidden on that side — both
	   default to 0 here, so with no JS, or with a rail whose cards all
	   fit, there is no fade at all. */
	--hb-fade-w: clamp(48px, 7vw, 104px);
	--hb-fade-l: 0;
	--hb-fade-r: 0;
	--hb-fade-mask: linear-gradient(90deg,
		rgba(0, 0, 0, 0)    0,
		rgba(0, 0, 0, .16)  calc(var(--hb-fade-w) * var(--hb-fade-l) * .25),
		rgba(0, 0, 0, .50)  calc(var(--hb-fade-w) * var(--hb-fade-l) * .5),
		rgba(0, 0, 0, .84)  calc(var(--hb-fade-w) * var(--hb-fade-l) * .75),
		rgba(0, 0, 0, 1)    calc(var(--hb-fade-w) * var(--hb-fade-l)),
		rgba(0, 0, 0, 1)    calc(100% - var(--hb-fade-w) * var(--hb-fade-r)),
		rgba(0, 0, 0, .84)  calc(100% - var(--hb-fade-w) * var(--hb-fade-r) * .75),
		rgba(0, 0, 0, .50)  calc(100% - var(--hb-fade-w) * var(--hb-fade-r) * .5),
		rgba(0, 0, 0, .16)  calc(100% - var(--hb-fade-w) * var(--hb-fade-r) * .25),
		rgba(0, 0, 0, 0)    100%);
	-webkit-mask-image: var(--hb-fade-mask);
	mask-image: var(--hb-fade-mask);
}

/* Below canPin() (motion.js: min-width 901px AND a fine pointer) the
   drag/wheel/keyboard handlers are never wired — so without this the
   rail kept overflow:hidden and NOTHING could move it. On a phone that
   meant four of Cursos' five modules, prices included, were clipped
   and unreachable: 1315px of cards at 375px wide, 696px at 768px.
   Estudar em Espanha lost a whole step the same way.

   The condition is the exact inverse of canPin(), so behaviour and
   layout cannot disagree — the same pairing the homepage carousel and
   .hb-page2__path already use. */
@media (max-width: 900px), (pointer: coarse) {
	.hb-cardrail {
		overflow-x: auto;
		overflow-y: hidden;
		scroll-snap-type: x proximity;
		overscroll-behavior-x: contain;
		-webkit-overflow-scrolling: touch;
		scrollbar-width: none;
	}
	.hb-cardrail::-webkit-scrollbar { display: none; }
	.hb-cardrail__card { scroll-snap-align: start; }
	/* The negative side margins exist so the cards' drop shadow isn't
	   clipped by overflow:hidden. On a scroll container they'd instead
	   offset the scroll origin, so only the vertical pair is kept. */
	.hb-cardrail__track { padding-inline: 0; margin-inline: 0; }
}
.hb-cardrail__track {
	display: flex;
	/* Was flex-start with an alternating margin-top on the cards — a
	   staggered row read as uneven/broken rather than deliberate, and
	   reviewing it against a drag gesture made it worse: a card lifting
	   on :hover while the cursor slides across the row *during* a drag
	   made the whole rail look like it was bobbing up and down. Stretch
	   makes every card exactly as tall as the tallest one in the row —
	   genuinely uniform, not just visually close. */
	align-items: stretch;
	gap: var(--hb-s4);
	width: max-content;
	padding: 6px 6px 10px;
	margin: -6px -6px -10px;
	cursor: grab;
	touch-action: pan-y;
	-webkit-user-select: none;
	user-select: none;
}
.hb-cardrail__track.is-dragging { cursor: grabbing; }
.hb-cardrail__track:focus-visible {
	outline: none;
	box-shadow: inset 0 0 0 2px currentColor;
	border-radius: var(--hb-radius);
}

.hb-cardrail__card {
	position: relative;
	overflow: hidden;
	flex: 0 0 auto;
	width: clamp(240px, 22vw, 300px);
	display: flex;
	flex-direction: column;
	gap: var(--hb-s1);
	padding: var(--hb-s4);
	border-radius: var(--hb-radius);
	box-shadow: 0 16px 32px -20px rgba(26, 21, 18, .5);
}
/* The step number, small and faint, anchored to the TOP-right corner.
   First version of this sized it at 6rem and anchored it to the
   BOTTOM — same device as .hb-page2__milestone-num — but that page's
   giant numeral has a whole section of empty space to sit in, and a
   compact card doesn't: measured on the live page, it ran straight
   through "60 HORAS" and the second price line on any card whose
   content reached far enough down (Cursos' modules, Exames' "Passo 1"
   with two prices) — decoration colliding with real text, not depth.
   Top-right is safe regardless of how tall the content below grows,
   because nothing else in the card sits there: the tag/eyebrow at the
   top is short and left-aligned. Read from data-ghost so it never
   duplicates the visible "Etapa 01" text for a screen reader. */
.hb-cardrail__card::before {
	content: attr(data-ghost);
	position: absolute;
	z-index: 0;
	top: var(--hb-s2);
	right: var(--hb-s3);
	font-family: 'Amatry', Arial, sans-serif;
	font-size: 2.2rem;
	line-height: 1;
	color: currentColor;
	opacity: .3;
	pointer-events: none;
}
.hb-cardrail__card > * { position: relative; z-index: 1; }
/* Wider flavour for a card whose content is a paragraph, not a price —
   squeezed into the default width, Estudar em Espanha's PCE step wrapped
   to nine cramped lines; this gives it a normal reading measure instead. */
.hb-cardrail__card--text { width: clamp(280px, 32vw, 420px); }
.hb-cardrail__card--ink { background: var(--night); color: var(--cream); }
.hb-cardrail__card--gold { background: var(--gold); color: var(--ink); }
.hb-cardrail__card--gold .hb-cardrail__title,
.hb-cardrail__card--gold .hb-cardrail__price strong { color: var(--red); }
.hb-cardrail__card--red { background: var(--red); color: var(--cream); }
.hb-cardrail__tag {
	display: block;
	font-style: italic;
	font-size: 14px;
	opacity: .75;
}
.hb-cardrail__eyebrow {
	display: block;
	font-family: 'Amatry', Arial, sans-serif;
	font-size: 12px;
	text-transform: uppercase;
	letter-spacing: .15em;
	opacity: .65;
}
.hb-cardrail__title {
	margin: 18px 0 0;
	font-family: 'Amatry', Arial, sans-serif;
	font-weight: 400;
	font-size: clamp(1.3rem, 1.9vw, 1.7rem);
	line-height: 1.15;
	letter-spacing: -.01em;
}
.hb-cardrail__title span { opacity: .4; font-weight: 400; padding: 0 .05em; }
.hb-cardrail__meta {
	display: block;
	font-family: 'Amatry', Arial, sans-serif;
	font-size: 13px;
	text-transform: uppercase;
	letter-spacing: .1em;
	opacity: .7;
}
.hb-cardrail__text {
	margin: var(--hb-s1) 0 0;
	font-size: var(--hb-text-sm);
	line-height: 1.6;
	opacity: .92;
}
.hb-cardrail__price {
	display: flex;
	align-items: baseline;
	flex-wrap: wrap;
	gap: var(--hb-s1);
	margin-top: auto;
	padding-top: var(--hb-s2);
	font-variant-numeric: tabular-nums;
}
/* A card can carry more than one price (Exames' "Passo 1": A1 Escolar
   and A2/B1 Escolar both fall due on the same date) — the first one
   still anchors to the bottom via margin-top:auto above; any that
   follow stack directly under it without repeating that gap. */
.hb-cardrail__price + .hb-cardrail__price { margin-top: 0; padding-top: 0; }
/* color: currentColor, não herdado. .hb-page2__body strong {color:red}
   é uma regra geral para destaque em prosa, mas aqui colidia com um card
   de fundo escuro: bordô sobre ink dá 2,68:1, pior do que qualquer outra
   falha de contraste já identificada no site. currentColor iguala o
   preço à cor do próprio card — creme em --ink/--red (16,6:1 e 6,2:1),
   bordô em --gold (3,18:1, a mesma decisão pendente do resto do site,
   não uma nova). Encontrado ao auditar: só afeta o "Passo 1" da
   Convocatória em Exames, o único preço que resta no site depois de os
   preços terem saído dos cards de Cursos. */
.hb-cardrail__price strong { font-family: 'Amatry', Arial, sans-serif; font-weight: 400; font-size: clamp(1.5rem, 2.2vw, 1.9rem); line-height: 1; color: currentColor; }
.hb-cardrail__price span { font-size: 13px; opacity: .8; }
.hb-cardrail__duration {
	display: block;
	font-family: 'Amatry', Arial, sans-serif;
	font-size: 12px;
	letter-spacing: .08em;
	text-transform: uppercase;
	opacity: .8;
	margin-top: var(--hb-s1);
	padding-top: var(--hb-s1);
	border-top: 1px solid color-mix(in srgb, currentColor 25%, transparent);
}

/* Below canPin() (coarse pointer or under ~901px — motion.js skips the
   drag/wheel/keyboard wiring there entirely) and under reduced motion
   (motion.js's JS never runs at all), the track is a plain native
   horizontal scroller: real swipe, real momentum, no JS, keyboard
   support for free from the browser. Comfortably NOT "carousel-shaped"
   — no snap, no dots, several cards visible at once, exactly like the
   desktop shelf just driven by native scrolling instead of the pointer/
   wheel handlers. touch-action: pan-x here (overriding the pan-y
   default above) is what lets a horizontal swipe move the row without
   a vertical one being captured — the axis the browser doesn't own
   stays free for the page to scroll. */
@media (max-width: 900px), (pointer: coarse), (prefers-reduced-motion: reduce) {
	.hb-cardrail__track {
		overflow-x: auto;
		-webkit-overflow-scrolling: touch;
		scrollbar-width: none;
		cursor: auto;
		touch-action: pan-x;
		scroll-snap-type: x proximity;
	}
	.hb-cardrail__track::-webkit-scrollbar { display: none; }
	.hb-cardrail__card { scroll-snap-align: start; }
}
@media (max-width: 640px) {
	.hb-cardrail__card,
	.hb-cardrail__card--text { width: min(78vw, 320px); }
}

/* ---- Card row: the same cards, sitting still ------------------------
   For a set small enough to just show all at once — Exames'
   convocatória, three dates and nothing more. Reuses every
   .hb-cardrail__card/tag/eyebrow/title/meta/price/duration class for
   the same look, but wraps them in a plain flex row instead of
   .hb-cardrail's horizontal-scrolling track: no drag, no wheel
   handling, no keyboard nav, none of it wired in motion.js, because
   three cards this size already fit a normal content column at every
   width that matters — there's nothing to scroll TO. If the number of
   dates ever grows past what a row can hold, wrapping (not scrolling)
   is what happens next: the row simply becomes two lines. ---- */
.hb-cardrow {
	display: flex;
	flex-wrap: wrap;
	gap: var(--hb-s4);
	margin-top: var(--hb-s4);
}

/* Mobile: only the things the clamp()-based scale can't express on its
   own. Body copy is NOT re-declared here — it is 16px from the token,
   desktop and mobile alike, which is the whole point of the scale. */
@media (max-width: 760px) {
	.hb-page2__cover { min-height: 48vh; }
	.hb-page2__headline { max-width: 100%; }
	.hb-page2__section { min-height: auto; }
	.hb-page2__final { min-height: auto; }
	.hb-page2__cta--round { width: 116px; height: 116px; }
	/* 22vw was 82px at 375 — right for "C2", far too big for "Inscrição".
	   15vw fits the longest heading these panels carry and still leaves a
	   level code the biggest thing on its panel. */
	.hb-page2__path-step h3 { font-size: clamp(2.2rem, 15vw, 4rem); }

	/* Tap targets. These are underlined text links and a text-styled
	   submit button, so at their natural line height they came out
	   ~32px — under the ~44px a finger needs. min-height guarantees the
	   size regardless of font metrics (padding maths here depended on
	   the webfont's line box and landed a pixel short), and
	   align-items:flex-end keeps the text at the bottom of the box so
	   the underline still sits directly beneath it — the extra hit
	   area is added above the text, where it is invisible. */
}

/* Tap targets, on their own condition.
   These used to live inside the 760px block above, which meant a tablet
   at 768 — a finger, not a mouse — got none of them: the inner-page CTAs
   measured 26px there. Width OR a coarse pointer, so an iPad in
   landscape is covered too. */
@media (max-width: 900px), (pointer: coarse) {
	.hb-page2__form input:not([type="hidden"]):not(.hb-page2__form-hp),
	.hb-page2__form textarea { min-height: 44px; }
	.hb-page2__form button { min-height: 44px; }

	.hb-form__row input:not(.hb-page2__form-hp),
	.hb-form__row select { min-height: 44px; }
	.hb-form__submit { min-height: 44px; align-items: flex-end; }
	.hb-direct__wa, .hb-direct__tel { min-height: 44px; }
	/* One column: two 220px fields side by side on a 375px screen leaves
	   neither wide enough to read what you typed. */
	.hb-form__grid { grid-template-columns: minmax(0, 1fr); }

	/* align-items:flex-end keeps the text at the bottom of the taller
	   box, so the underline still sits directly beneath the words — the
	   extra hit area is added above the text, where it is invisible. */
	.hb-page2__cta:not(.hb-page2__cta--round) {
		min-height: 44px;
		align-items: flex-end;
	}
}

/* Below 900px the horizontal pin is off (see motion.js) — GSAP never
   measures or transforms the track, so it has to sit as a plain
   vertical stack here or the steps overlap instead of stepping
   through. Matches the prefers-reduced-motion fallback below. */
/* Mobile/reduced-motion layout for this carousel now comes from the
   shared [data-carousel] system in main.css — it stays HORIZONTAL with
   scroll-snap instead of collapsing to a vertical stack. Only the
   panel's own padding is set here. */
/* pointer:coarse as well as the width: an iPad in landscape is 1024px
   wide and would otherwise get the GSAP-pinned carousel, which is a
   mouse-scroll device driven off vertical scroll distance. Touch gets
   the native scroll-snap track, which is what a finger expects. */
@media (max-width: 900px), (pointer: coarse) {
	.hb-page2__path-step {
		padding-block: var(--hb-section-y);
		padding-inline: var(--hb-gutter);
		min-height: 0;
		justify-content: flex-start;
	}
}

@media (prefers-reduced-motion: reduce) {
	.hb-page2__path-step { padding-block: var(--hb-s5); padding-inline: var(--hb-s4); }
}

/* ============================================================
   BARALHO (.hb-deck) — a pilha de cards
   ============================================================
   Substitui o rail horizontal em Cursos e Estudar em Espanha.
   Aprovado na página de teste antes de vir para aqui.

   Porque não é o rail: o rail escondia conteúdo atrás de um gesto que
   metade dos visitantes não tinha. Abaixo dos 901px com rato o arrastar
   nunca ligava, e o rail ficava com overflow:hidden — medido, 1315px de
   cards inalcançáveis num telemóvel. A pilha não tem esse problema em
   lado nenhum: é vertical, move-se com o scroll normal da página, e
   todos os cards passam pelo ecrã sem ninguém ter de descobrir nada.

   Reutiliza .hb-cardrail__card e os seus filhos de propósito — é o mesmo
   card, noutro contentor. Assim a .hb-cardrow dos Exames, que também os
   usa, fica intacta, e não há duas definições do mesmo objeto.
   ============================================================ */
.hb-deck {
	display: flex;
	flex-direction: column;
	gap: 4vh;
	margin-top: var(--hb-s4);
	/* .hb-page2__body é um flex column com align-items:flex-start, ou
	   seja o eixo transversal é o horizontal e os filhos encolhem para a
	   largura do próprio conteúdo. Sem isto o baralho ficava com 668px
	   dentro de uma coluna de 1240 — medido — e os cards paravam a meio
	   do ecrã em vez de irem até ao limite do cabeçalho. É a mesma razão
	   pela qual .hb-cardrail já declarava width:100%. */
	align-self: stretch;
	width: 100%;
}
/* O sticky faz o prender; o motion.js só trata da escala. Cada item
   recebe um top ligeiramente maior que o anterior, o que deixa a margem
   do card de baixo à vista — é isso que dá a leitura de pilha em vez de
   substituição. */
.hb-deck__item {
	position: sticky;
	top: calc(14vh + var(--i, 0) * 26px);
	/* Origem no topo: o card encolhe para cima e não para o centro, por
	   isso o cabeçalho mantém-se alinhado enquanto recua. */
	transform-origin: 50% 0%;
	will-change: transform;
}

/* O card, agora à largura toda da coluna de conteúdo.
   Medido com Range sobre os nós de texto na página de teste: à largura
   inteira e com a coluna estreita do rail, o conteúdo real ocupava 207px
   num card de 1240px — 81% morto. Daí a composição horizontal. */
.hb-deck .hb-cardrail__card {
	width: auto;
	flex: 1 1 auto;
	display: grid;
	/* Três zonas: identidade do módulo | a frase | o que custa e dura.
	   A do meio é 1fr e as laterais dimensionam-se ao conteúdo, por isso
	   um card sem frase não deixa buraco — a coluna fecha-se e as duas
	   pontas mantêm-se onde estão. */
	grid-template-columns: minmax(0, auto) minmax(0, 1fr) minmax(0, auto);
	/* A terceira linha é 1fr para empurrar a duração para o fundo: é
	   isso que abre o intervalo entre o preço e o "60 horas". */
	grid-template-rows: auto auto auto 1fr;
	column-gap: clamp(28px, 4.5vw, 76px);
	row-gap: 4px;
	min-height: clamp(200px, 24vh, 260px);
	padding: clamp(24px, 2.6vw, 40px) clamp(28px, 3.2vw, 52px);
}
.hb-deck .hb-cardrail__card::before { font-size: clamp(1.5rem, 1.7vw, 2.1rem); }

/* A linha 1 é do __tag, que só o módulo 01 tem ("¿Cómo estás?", copy
   aprovada). Nos outros cards a linha fica vazia e colapsa a zero. */
.hb-deck .hb-cardrail__tag     { grid-column: 1; grid-row: 1; }
.hb-deck .hb-cardrail__eyebrow { grid-column: 1; grid-row: 2; align-self: end; }
/* margin-top: o sobrolho ("05 · MÓDULO") e o nível ("C2") estavam
   colados. O row-gap da grelha é de 4px e serve as outras linhas; este
   par precisa de mais ar do que as restantes, por isso leva-o aqui em
   vez de se abrir o gap todo. */
.hb-deck .hb-cardrail__title   { grid-column: 1; grid-row: 3; font-size: clamp(42px, 5.2vw, 82px); line-height: 1; margin: 24px 0 0; }
.hb-deck .hb-cardrail__meta    { grid-column: 1; grid-row: 4; align-self: start; margin-top: 6px; }

/* QUANDO A TURMA CORRE — a coluna do meio.
   Aqui esteve uma frase por módulo que eu tinha proposto, e saiu quando
   chegaram os horários reais: entre uma frase minha por aprovar e dados
   aprovados que respondem à pergunta que faz alguém inscrever-se ("posso
   ir a estas horas?"), a coluna é dos dados. */
.hb-deck .hb-cardrail__when {
	grid-column: 2; grid-row: 1 / span 4;
	align-self: center;
	display: flex;
	flex-direction: column;
	gap: 6px;
	max-width: 26ch;
}
.hb-deck .hb-cardrail__days {
	font-family: 'Amatry', Arial, sans-serif;
	font-size: clamp(18px, 1.8vw, 27px);
	line-height: 1.15;
	font-variant-numeric: tabular-nums;
}
.hb-deck .hb-cardrail__dates {
	font-size: clamp(13px, 1.05vw, 15px);
	line-height: 1.4;
	opacity: .72;
	font-variant-numeric: tabular-nums;
}


/* O preço empilha — em linha (o flex de base) o "390 € pronto
   pagamento" ficava ao lado do "410 €" em vez de por baixo dele.
   Segunda linha para um SEGUNDO preço quando existe: o "Passo 1" da
   convocatória dos Exames tem dois, e com uma célula só ficavam
   sobrepostos. */
.hb-deck .hb-cardrail__price {
	grid-column: 3; grid-row: 1;
	flex-direction: column;
	align-items: flex-end;
	gap: 2px;
	align-self: start;
	text-align: right;
	margin-top: 0;
	padding-top: 0;
}
.hb-deck .hb-cardrail__price + .hb-cardrail__price { grid-row: 2; margin-top: 6px; }
.hb-deck .hb-cardrail__duration {
	grid-column: 3; grid-row: 4;
	justify-self: end;
	align-self: end;
	text-align: right;
}

/* A variante de texto: com um parágrafo não há segunda zona a inventar,
   por isso a identidade fica à esquerda e o texto recebe a largura.
   Trava nos 62ch — passar disso é linha longa demais para se voltar a
   encontrar o início. */
.hb-deck .hb-cardrail__card--text {
	width: auto;
	grid-template-columns: minmax(0, 15rem) minmax(0, 1fr);
	/* Repor duas linhas: a base declara `auto auto 1fr` para empurrar a
	   duração para o fundo, e um card de texto não tem duração — a
	   terceira linha só abriria um vão vazio por baixo do parágrafo. */
	grid-template-rows: auto auto;
	row-gap: 8px;
	align-content: center;
}
.hb-deck .hb-cardrail__card--text .hb-cardrail__eyebrow { grid-column: 1; grid-row: 1; }
.hb-deck .hb-cardrail__card--text .hb-cardrail__title {
	grid-column: 1; grid-row: 2;
	align-self: start;
	font-size: clamp(24px, 2.3vw, 36px);
	line-height: 1.06;
	text-wrap: balance;
}
.hb-deck .hb-cardrail__card--text .hb-cardrail__text {
	grid-column: 2; grid-row: 1 / span 2;
	align-self: center;
	max-width: 62ch;
	margin: 0;
}

/* Entre 560 e 900 o card ainda é largo (795px a 900 de viewport) e uma
   coluna só deixava lá 42% morto — medido. As duas colunas aguentam-se
   até aos 560, só com o tipo mais contido. */
@media (max-width: 900px) and (min-width: 561px) {
	/* Tres colunas nao cabem num card de ~795px sem espremer a frase a
	   duas palavras por linha. Passa a duas: a frase desce para debaixo
	   do titulo, na coluna da identidade, e o preco fica onde estava. */
	.hb-deck .hb-cardrail__card {
		grid-template-columns: minmax(0, 1fr) minmax(0, auto);
		grid-template-rows: auto auto auto auto 1fr;
		column-gap: 26px;
	}
	.hb-deck .hb-cardrail__title { font-size: clamp(34px, 5vw, 44px); margin-top: 18px; }
	/* Linha 4, nao 3: a 3 e do titulo. Esta regra sobrou de quando a
	   grelha tinha uma linha a menos e punha os dois na mesma celula —
	   o titulo e o "Inicial" ficavam um por cima do outro. */
	.hb-deck .hb-cardrail__meta  { grid-row: 4; }
	.hb-deck .hb-cardrail__tag { grid-column: 1; grid-row: 1; font-size: 14px; }
	/* O horario desce para debaixo do nivel: tres colunas nao cabem num
	   card de ~795px sem espremer as datas a duas palavras por linha. */
	.hb-deck .hb-cardrail__when {
		grid-column: 1; grid-row: 5;
		align-self: start;
		margin-top: 14px;
		max-width: 34ch;
	}
	.hb-deck .hb-cardrail__days { font-size: 20px; }
	.hb-deck .hb-cardrail__duration { grid-column: 2; grid-row: 5; }
	.hb-deck .hb-cardrail__card--text { grid-template-columns: minmax(0, 11rem) minmax(0, 1fr); }
	.hb-deck .hb-cardrail__card--text .hb-cardrail__title { font-size: 24px; }
}

/* Abaixo dos 560 o card deixa mesmo de ser largo: a razão de ser da
   grelha desaparece e volta à coluna, que é o que serve um telemóvel. */
@media (max-width: 560px) {
	.hb-deck {
		flex-direction: column;
		align-items: stretch;
		gap: var(--hb-s4);
		overflow: visible;
		scroll-snap-type: none;
	}
	/* A card taller than the viewport must remain fully readable. On
	   phones the deck is therefore a normal document-flow list: no later
	   card can cover the end of the previous one, whatever its copy length. */
	.hb-deck__item {
		position: static;
		flex: 0 0 auto;
		display: flex;
		scroll-snap-align: none;
	}
	.hb-deck.is-stackable .hb-deck__item {
		position: sticky;
		top: calc(var(--hb-nav-h) + var(--hb-s2) + var(--i, 0) * 18px);
		transform-origin: 50% 0%;
	}
	.hb-deck__item > .hb-cardrail__card { width: 100%; height: 100%; }
	.hb-deck .hb-cardrail__card,
	.hb-deck .hb-cardrail__card--text {
		display: flex;
		flex-direction: column;
		gap: var(--hb-s1);
		min-height: 0;
		padding: var(--hb-s4);
	}
	.hb-deck .hb-cardrail__title { font-size: clamp(34px, 11vw, 46px); margin: 18px 0 0; }
	.hb-deck .hb-cardrail__card--text .hb-cardrail__title { font-size: 24px; }
	.hb-deck .hb-cardrail__tag { font-size: 15px; max-width: none; opacity: .85; }
	/* O card e flex aqui, por isso o horario flui na ordem do markup:
	   depois do nivel, antes da duracao. So o tamanho precisa de descer. */
	.hb-deck .hb-cardrail__when { max-width: none; margin-top: var(--hb-s2); }
	.hb-deck .hb-cardrail__days { font-size: 19px; }
	.hb-deck .hb-cardrail__dates { font-size: 14px; }
	.hb-deck .hb-cardrail__price { align-items: flex-start; text-align: left; margin-top: var(--hb-s2); }
	.hb-deck .hb-cardrail__duration { justify-self: auto; text-align: left; }
	.hb-deck .hb-cardrail__text { max-width: none; }
}

/* Touch tablets use the same readable document-flow deck even when
   their landscape width is above the phone breakpoint. */
@media (pointer: coarse) {
	.hb-deck { overflow: visible; scroll-snap-type: none; }
	.hb-deck__item { position: static; scroll-snap-align: none; }
	.hb-deck.is-stackable .hb-deck__item {
		position: sticky;
		top: calc(var(--hb-nav-h) + var(--hb-s2) + var(--i, 0) * 18px);
	}
}

/* Sem movimento: o sticky sai e a pilha passa a lista. Nada escondido,
   nada por desfazer — o motion.js também não corre. */
@media (prefers-reduced-motion: reduce) {
	.hb-deck__item { position: static; }
}

/* O baralho precisa que a secção NÃO seja um contentor de scroll.
   .hb-page2__section tem overflow:hidden para conter o círculo
   desfocado decorativo — mas overflow:hidden cria um scroll container,
   e um scroll container passa a ser o contentor do position:sticky lá
   dentro. Resultado medido em Cursos: a secção tem 1567px, o baralho
   1224px, e o sticky ficava sem praticamente nenhum curso para correr —
   o efeito simplesmente não acontecia.

   overflow:clip clipa exatamente da mesma maneira e NÃO cria scroll
   container, por isso o sticky volta a resolver contra a página. As
   duas declarações ficam por ordem de propósito: um browser sem clip
   (Safari < 16) mantém hidden e perde só o efeito, com o conteúdo todo
   na mesma legível. :has() já é usado noutros sítios do tema. */
.hb-page2__section:has(.hb-deck) {
	overflow: hidden;
	overflow: clip;
}

/* A tabela ganhou uma legenda e uma subetiqueta no nivel — nenhuma das
   duas existia quando .hb-page2__table foi escrita, porque a tabela
   nunca chegou a ser usada. */
.hb-page2__table-cap {
	caption-side: top;
	text-align: left;
	font-family: 'Amatry', Arial, sans-serif;
	font-size: 12px;
	letter-spacing: .14em;
	text-transform: uppercase;
	opacity: .55;
	padding-bottom: var(--hb-s2);
}
/* O nivel e a faixa na mesma celula: o codigo carrega a informacao e a
   faixa qualifica-o, por isso nao merece uma coluna sua — merece ser
   menor e ficar por baixo. */
.hb-page2__table th[scope="row"] {
	font-family: 'Amatry', Arial, sans-serif;
	font-size: clamp(17px, 1.5vw, 21px);
	text-transform: none;
	letter-spacing: 0;
	opacity: 1;
	white-space: nowrap;
}
.hb-page2__table th[scope="row"] span {
	display: block;
	font-family: 'Franie', Arial, sans-serif;
	font-size: 12px;
	letter-spacing: .12em;
	text-transform: uppercase;
	opacity: .6;
	margin-top: 2px;
}
/* Numeros de horas e datas alinham melhor com cifras de largura fixa. */
.hb-page2__table td { font-variant-numeric: tabular-nums; }
