:root {
  --ink-900: #14171A;
  --ink-700: #2E3338;
  --grey-600: #5C6266;
  --grey-400: #9AA0A4;
  --grey-200: #D8DAD8;
  --grey-100: #EDEDEA;
  --paper: #FAF9F6;

  --petrol-800: #0B403C;
  --petrol-600: #12615A;
  --petrol-400: #3E8A82;
  --petrol-100: #DCE9E6;

  --ochre-600: #A2570F;
  --ochre-400: #D08A2E;
  --ochre-100: #F5E7D2;

  --text: var(--ink-900);
  --text-muted: var(--grey-600);
  --bg: var(--paper);
  --bg-raised: #FFFFFF;
  --border: var(--grey-200);
  --border-strong: var(--grey-400);

  --link: var(--petrol-600);
  --cta-bg: var(--petrol-800);
  --cta-text: var(--paper);

  /* Task 6 (fonts): Archivo, single family per the Placa Esmaltada ruling in
     .impeccable/surfaces/site-src-pages-home-svelte.md -- real plates use one
     condensed grotesque at varying sizes and weights, not a display/body pair.
     Components read this token; the @font-face declaring the actual family is in
     base.css, next to the font file it points at. */
  --font-sans: 'Archivo', system-ui, sans-serif;

  /* A monotonic value ladder, lightest to darkest, so the roles stay tellable apart
     when Part A is printed in black and white:
       gap       petrol-100  L=0.792
       today     grey-400    L=0.347
       critical  ochre-600   L=0.145
       target    petrol-800  L=0.041
     Worst pair 2.03:1, up from 1.15:1. grey-400 is a *fill* here, which does not
     contradict the "borders and hairlines only, never text" rule in the usage
     notes below.
     Known gap, not fixed here: these four separate from each OTHER, but not from
     the page. chart-gap on paper measures 1.18:1, so a gap fill is near-invisible
     on an unbordered chart. Widening that touches the Part A/B templates too, so
     it is D's call rather than a silent token change. */
  --chart-today:    var(--grey-400);
  --chart-gap:      var(--petrol-100);
  --chart-target:   var(--petrol-800);
  --chart-critical: var(--ochre-600);
}

/* Usage rules

   Base carries ~90% of any surface. Petrol appears on links, the CTA button,
   and the reachable-state fill in charts. Ochre marks bottlenecks and single
   points of failure only — if more than about three elements on a page are
   ochre, it has stopped meaning anything.

   The logo is never coloured. Ink on paper, paper on ink, nothing else.

   Grey 400 is 2.5:1 against paper. Borders and hairlines only, never text.

   Reports get printed in black and white. Every chart pairing must differ in
   value as well as hue — check by desaturating before you ship a template.

   Do not add a second accent later. The moment there are two, colour stops
   carrying meaning in the reports, which is the only place it earns its keep.
*/

/* Reset, focus, motion, the type family — and, from Task 6b, the type scale, the
   spacing rhythm and the page's own classes.

   The scale was deliberately absent until the Home page existed, because it is an
   output of the build rather than an input to it. It is here now, derived from the
   committed direction in .impeccable/surfaces/site-src-pages-home-svelte.md
   (Placa Esmaltada, seed 04a058c7): Portuguese vitreous-enamel utility signage,
   petrol carrying whole plate fields with paper as the mount between them, ochre
   spent only on the action, and near-zero motion because a mounted plate does not
   move. Every colour is a token or a color-mix() of tokens — no literal hex below
   this comment. */

/* Archivo, self-hosted, one variable-font file covers weight 100-900 and width
   62-125 -- the surface brief's single-family ruling (real plates use one condensed
   grotesque at varying sizes and weights, not a display/body pair). No Google Fonts
   <link>: the site ships no cookie banner and makes no external request until a
   visitor clicks to load the Cal.com booker on /contacto (see entry-client.js and
   src/content/pt.js's privacy.sections[2]) -- so the font file must be same-origin
   regardless, rather than depend on when or whether that click happens. Regenerate
   with tools/build_fonts.sh; do not hand-edit.
   File: static/fonts/archivo.woff2 (~74 KB), licensed OFL -- static/fonts/OFL.txt
   travels with it, as OFL requires. */
@font-face {
  font-family: 'Archivo';
  src: url('/fonts/archivo.woff2') format('woff2');
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-style: normal;
  /* font-display: block, not swap or optional, and the choice is load-bearing here.
     The direction's memorable moment is the first viewport's hook in stencilled
     caps, and the direction bars motion -- "no scroll reveals, no parallax, no
     draw-on. State changes only." A font swap that reflows that hook after paint is
     exactly the kind of movement the direction refuses, even though it is a browser
     default nobody would call "an animation". The memory test in the surface brief
     -- "a visitor who left after one viewport would describe 'the sign', not 'a
     website'" -- fails outright if the hook silently renders in system-ui instead
     of the condensed stencilled caps that make it the sign.
     swap guarantees a flash on every cold load: fallback text paints immediately,
     then jumps to Archivo (condensed, different metrics from any system fallback)
     whenever it arrives -- reflow on essentially every visit.
     block and optional both start with an invisible-text period, then diverge on
     what happens if the font isn't ready yet. block's period is ~3s (current
     Chrome/Firefox/Safari behaviour): if Archivo lands within it -- the normal
     case, not the exception -- the browser paints once, already in the real font:
     zero flash, zero reflow. Only past that ~3s does it fall back and swap later.
     optional's period is much shorter, ~100ms by spec recommendation, and once it
     elapses the browser commits to the fallback for that entire page view with no
     later swap -- so a miss there isn't a brief flash, it's the wrong typeface,
     silently, for the whole visit.
     Given rel="preload" in html.js, this 74KB same-origin file is fetched at high
     priority before CSS parse finishes, on the connection already fetching the
     HTML -- on the audience's stated worst case, a phone mid-workday, that
     routinely clears 100ms (cellular RTT alone can exceed it) but is very unlikely
     to approach 3s. block therefore trades a rare, brief invisible-text pause
     (only when the fetch is unusually slow) for near-certain correct-font-only
     rendering, instead of optional's real risk of "silently wrong font for the
     whole visit" on exactly the network the ICP actually uses. The brief invisible
     period is judged the smaller cost against a direction whose entire memorable
     moment is what the hook is set in. */
  font-display: block;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body,
h1,
h2,
h3,
h4,
p,
figure,
blockquote,
dl,
dd,
ul,
ol {
  margin: 0;
  padding: 0;
}

ul,
ol {
  list-style: none;
}

html {
  -webkit-text-size-adjust: 100%;
}

img,
picture,
svg,
video {
  display: block;
  max-width: 100%;
}

input,
button,
textarea,
select {
  font: inherit;
  color: inherit;
}

/* Links carry a permanent underline, not colour alone. petrol-600 measures 6.92:1
   against paper -- correct as text -- but only 1.75:1 against .lede's ink-700 and
   1.18:1 against --text-muted, and WCAG 1.4.1 wants >=3:1 between link text and the
   prose around it whenever colour is the only thing telling them apart. Lightening
   petrol-600 is not the fix: it is a committed brand token. The underline is, and it
   removes the "colour is the only cue" condition outright rather than trading it for
   a marginal ratio. Thickening on hover is the same state change .plate-link and
   .banner a already use -- those two underlined from the start, so this rule brings
   the bare <a> onto the site's existing behaviour rather than inventing one.
   Every link that is not prose (.btn, .navlink, .masthead__brand, .skip:focus) sets
   text-decoration: none on its own class and outranks this. */
a {
  color: var(--link);
  text-decoration: underline;
  text-underline-offset: 0.18em;
  text-decoration-thickness: 1px;
  transition: text-decoration-thickness var(--state);
}

a:hover {
  text-decoration-thickness: 2px;
}

/* ---------------------------------------------------------------------------
   Scale

   Type: fluid steps, no step within 20% of its neighbour so the jumps are legible
   as jumps. The display step tops out at 5.25rem (84px), under the 6rem ceiling.

   Width comes from Archivo's wdth axis via font-stretch, and it is a ladder with one
   rung per role -- not a per-element setting. That axis is why a single family is
   enough: condensed is native to the face, not a synthesised squeeze.

     74%  the hook, and only the hook          .hero__hook
     80%  section titles                       .section-title
     84%  sub-titles at --fs-lg                .register q, .step__title,
                                               .service__name, .notfit__title
     88%  controls and table lettering         .btn, .grid__name, .faq__q
     92%  labels, meta and standing captions   .navlink, .step__meta, .service__meta,
                                               .sectors li, .site-foot__tagline,
                                               .about__ask, .hero__micro
     100% reading text (the body default)

   Anything off this ladder is a bug unless the line carries a comment saying why.
   --fs-lg previously ran at both 84% and 86% and there was no reason for the split;
   .about__ask (94%) and .hero__micro (96%) were singletons. All four now sit on a
   rung. .step__no keeps 84% deliberately: it is a tabular numeral in a 2.75rem tag,
   sized to fit the tag rather than to match a text role.

   Space: a 4px-based ladder plus two composite rhythms -- --gutter for the page's
   side margins and --band-y for the vertical air between sections.
   --------------------------------------------------------------------------- */
:root {
  --fs-xs: 0.8125rem;
  --fs-sm: 0.9375rem;
  --fs-base: clamp(1rem, 0.97rem + 0.16vw, 1.0625rem);
  --fs-md: clamp(1.0625rem, 0.99rem + 0.36vw, 1.25rem);
  --fs-lg: clamp(1.25rem, 1.1rem + 0.75vw, 1.625rem);
  --fs-xl: clamp(1.625rem, 1.35rem + 1.35vw, 2.25rem);
  --fs-2xl: clamp(2rem, 1.5rem + 2.4vw, 3rem);
  --fs-display: clamp(2.5rem, 1.4rem + 5.6vw, 5.25rem);

  --sp-1: 0.25rem;
  --sp-2: 0.5rem;
  --sp-3: 0.75rem;
  --sp-4: 1rem;
  --sp-5: 1.5rem;
  --sp-6: 2rem;
  --sp-7: 3rem;
  --sp-8: 4rem;
  --sp-9: 6rem;

  --gutter: clamp(1.25rem, 4.5vw, 3.5rem);
  --band-y: clamp(3.5rem, 8vw, 6.5rem);
  --wrap: 68rem;
  --measure: 64ch;

  /* Plate hardware. --plate-inset is where the cast rule runs; --hole-pos is how far
     the drilled mounting holes sit inside that rule. */
  --plate-inset: clamp(0.5rem, 1.4vw, 1.125rem);
  --hole-pos: 1.375rem;

  /* Rubric grid: width of one score column and of the empty box inside it. */
  --score-col: 1.5rem;
  --score-box: 1rem;

  /* Rules. Measured against the surface they sit on -- all four are hairlines and
     fills, never text, so the 3:1 non-text floor is the relevant one and each clears
     it or is deliberately below it as a soft separator inside an already-framed field.
       --rule-mount       #9AAFAC on paper       2.19:1
       --rule-mount-faint #B2C1BE on paper       1.77:1
       --rule-plate       petrol-400 on petrol-800 2.85:1
       --rule-plate-soft  #315E5B on petrol-800  1.59:1 */
  --rule-mount: color-mix(in srgb, var(--petrol-800) 40%, var(--paper));
  --rule-mount-faint: color-mix(in srgb, var(--petrol-800) 30%, var(--paper));
  --rule-plate: var(--petrol-400);
  --rule-plate-soft: color-mix(in srgb, var(--petrol-100) 18%, var(--petrol-800));

  --hole-ring: color-mix(in srgb, var(--ink-900) 40%, transparent);
  --shadow-mount: 0 6px 18px color-mix(in srgb, var(--ink-900) 16%, transparent);
  --shadow-key: 0 2px 6px color-mix(in srgb, var(--ink-900) 28%, transparent);
  --shadow-key-down: 0 1px 3px color-mix(in srgb, var(--ink-900) 24%, transparent);

  /* The one duration on the site. Motion is state-change only: hover, focus, and the
     switch-like press on the booking control. */
  --state: 90ms linear;
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

p {
  max-width: var(--measure);
  text-wrap: pretty;
}

h1,
h2,
h3 {
  text-wrap: balance;
  line-height: 1.05;
  font-weight: 700;
}

/* A visible focus ring is the keyboard user's only cursor. :focus-visible rather than
   :focus so it does not fire on mouse clicks. Offset keeps it off the glyphs. */
:focus-visible {
  outline: 2px solid var(--petrol-600);
  outline-offset: 2px;
}

/* On the petrol fields a petrol ring is invisible, so the ring inverts to paper there.
   paper on petrol-800 is 11.00:1, far above the 3:1 a focus indicator needs. */
.plate :focus-visible,
.masthead :focus-visible,
.site-foot :focus-visible {
  outline-color: var(--paper);
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------------------------------------------------------------------------
   Layout primitives
   --------------------------------------------------------------------------- */
.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.band {
  padding-block: var(--band-y);
}

.mount {
  background: var(--bg);
  color: var(--text);
}

/* A plate: a whole petrol field with a cast rule set in from its edges and a drilled
   mounting hole at each corner of that rule. The holes are paper, because a real hole
   shows the surface the plate is screwed to -- here, the paper mount. */
.plate {
  position: relative;
  background: var(--petrol-800);
  color: var(--paper);
}

.plate > .wrap {
  position: relative;
  z-index: 1;
  padding-inline: max(var(--gutter), calc(var(--plate-inset) + 1.5rem));
}

.plate::before,
.plate::after {
  content: '';
  position: absolute;
  inset: var(--plate-inset);
  z-index: 0;
  pointer-events: none;
}

.plate::before {
  border: 1px solid var(--rule-plate);
}

.plate::after {
  background-image:
    radial-gradient(circle at var(--hole-pos) var(--hole-pos),
      var(--paper) 0 5px, var(--hole-ring) 5px 6.5px, transparent 6.5px),
    radial-gradient(circle at calc(100% - var(--hole-pos)) var(--hole-pos),
      var(--paper) 0 5px, var(--hole-ring) 5px 6.5px, transparent 6.5px),
    radial-gradient(circle at var(--hole-pos) calc(100% - var(--hole-pos)),
      var(--paper) 0 5px, var(--hole-ring) 5px 6.5px, transparent 6.5px),
    radial-gradient(circle at calc(100% - var(--hole-pos)) calc(100% - var(--hole-pos)),
      var(--paper) 0 5px, var(--hole-ring) 5px 6.5px, transparent 6.5px);
}

/* The skip link must stay in the accessibility tree, so it is clipped rather than
   display:none -- a hidden-by-display link cannot be focused, which defeats it. */
.skip {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip:focus {
  position: fixed;
  top: var(--sp-3);
  left: var(--sp-3);
  z-index: 20;
  width: auto;
  height: auto;
  margin: 0;
  padding: var(--sp-3) var(--sp-4);
  overflow: visible;
  clip-path: none;
  background: var(--paper);
  color: var(--petrol-800);
  font-weight: 700;
  text-decoration: none;
  box-shadow: var(--shadow-mount);
}

main:focus {
  outline: none;
}

/* ---------------------------------------------------------------------------
   Plate lettering and reading text
   --------------------------------------------------------------------------- */

/* Stencilled caps: the wdth axis, not a second family. 'case' switches punctuation --
   the guillemets in «grau de digitalização» especially -- to their cap-height forms,
   which is the whole reason that feature is in the subset. */
.section-title {
  font-size: var(--fs-xl);
  font-stretch: 80%;
  font-weight: 800;
  letter-spacing: 0.012em;
  text-transform: uppercase;
  font-feature-settings: 'case' 1;
  color: var(--petrol-800);
  margin-bottom: var(--sp-6);
}

.section-title--plate {
  color: var(--paper);
}

.lede {
  font-size: var(--fs-md);
  color: var(--ink-700);
  margin-top: var(--sp-5);
}

.plate-lede {
  font-size: var(--fs-md);
  color: var(--petrol-100);
  margin-top: var(--sp-6);
}

.plate-link {
  color: var(--paper);
  text-decoration: underline;
  text-underline-offset: 0.18em;
  text-decoration-thickness: 1px;
  transition: text-decoration-thickness var(--state);
}

.plate-link:hover {
  text-decoration-thickness: 2px;
}

/* ---------------------------------------------------------------------------
   Controls

   Two kinds only. .btn--action is the booking switch: ochre-400 fill (4.06:1 against
   the petrol field, above the 3:1 non-text floor) with an ink-900 label at 6.30:1, an
   inset bevel along its lower edge, and a real offset-plus-blur shadow. Pressing it
   travels 2px and the shadow collapses -- the switch bottoming out. The bevel is
   inset, so nothing about the press changes layout.
   .btn--plate is the same control without the accent, for the masthead.
   --------------------------------------------------------------------------- */
.btn {
  display: inline-block;
  font-size: var(--fs-sm);
  font-stretch: 88%;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  font-feature-settings: 'case' 1;
  text-decoration: none;
  padding: 0.875rem 1.5rem 0.9375rem;
  border: 0;
  border-radius: 2px;
}

.btn--lg {
  font-size: var(--fs-base);
  padding: 1rem 2rem 1.0625rem;
}

.btn--action {
  background: var(--ochre-400);
  color: var(--ink-900);
  box-shadow: inset 0 -4px 0 var(--ochre-600), var(--shadow-key);
  transition: background-color var(--state), transform var(--state), box-shadow var(--state);
}

/* Hover fill is ochre-400 lightened toward paper: #D69B4C. Label contrast rises to
   7.41:1, and the fill still reads 4.77:1 against the petrol field. */
.btn--action:hover {
  background: color-mix(in srgb, var(--ochre-400) 85%, var(--paper));
}

.btn--action:active {
  transform: translateY(2px);
  box-shadow: inset 0 -1px 0 var(--ochre-600), var(--shadow-key-down);
}

.btn--plate {
  background: transparent;
  color: var(--paper);
  box-shadow: inset 0 0 0 2px var(--paper);
  transition: background-color var(--state), color var(--state);
}

.btn--plate:hover {
  background: var(--paper);
  color: var(--petrol-800);
}

/* ---------------------------------------------------------------------------
   Masthead — the plate's top rail. Not sticky: the banner island mounts above it at
   runtime, and a fixed rail would need a hardcoded offset that is wrong whenever the
   banner's height is not what was assumed.
   --------------------------------------------------------------------------- */
.masthead {
  background: var(--petrol-800);
  color: var(--paper);
  padding-block: var(--sp-5);
}

.masthead__inner {
  display: grid;
  grid-template-columns: auto auto;
  align-items: center;
  gap: var(--sp-4) var(--sp-5);
}

.masthead__brand {
  display: block;
  color: var(--paper);
  text-decoration: none;
}

/* The inlined SVG is display:block from the reset. Its wrapper has to be a block too,
   or an anonymous block box forms inside an inline box and drags stray leading into
   the masthead row. */
.lockup,
.mark {
  display: block;
}

.lockup svg,
.mark svg {
  height: 1.75rem;
  width: auto;
}

.masthead__nav {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-5);
}

.masthead__cta {
  justify-self: end;
  font-size: var(--fs-xs);
  padding: 0.5625rem 0.875rem 0.625rem;
}

.navlink {
  color: var(--petrol-100);
  font-size: var(--fs-sm);
  font-stretch: 92%;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-decoration: none;
  padding-block: var(--sp-1);
  border-bottom: 2px solid transparent;
  transition: color var(--state), border-color var(--state);
}

.navlink:hover {
  color: var(--paper);
  border-bottom-color: var(--paper);
}

/* Task 9: language switcher. Same control as .navlink -- it is navigation, not a
   distinct affordance -- set apart only by a plate-rule divider, so it reads as
   "one more thing in this row" rather than a second nav bar. Never carries
   aria-current: the switcher's target is by definition never the current page. */
.navlink--lang {
  border-left: 1px solid var(--petrol-600);
  padding-left: var(--sp-4);
}

.navlink[aria-current='page'] {
  color: var(--paper);
  border-bottom-color: var(--rule-plate);
}

@media (min-width: 52rem) {
  .masthead__inner {
    grid-template-columns: auto 1fr auto;
  }

  .masthead__nav {
    grid-column: auto;
    justify-content: flex-end;
    gap: var(--sp-6);
  }

  .lockup svg {
    height: 2.125rem;
  }

  .masthead__cta {
    font-size: var(--fs-sm);
    padding: 0.6875rem 1.125rem 0.75rem;
  }
}

/* ---------------------------------------------------------------------------
   Hero — the memorable moment. One petrol field, the hook in stencilled caps, and
   the only warm field on the page under it.
   --------------------------------------------------------------------------- */
.hero {
  padding-block: clamp(3rem, 9vw, 6rem) clamp(3.5rem, 10vw, 7rem);
}

.hero__hook {
  font-size: var(--fs-display);
  font-stretch: 74%;
  font-weight: 800;
  /* 0.98, not tighter. The hook wraps to about three lines of uppercase Portuguese and
     carries a tilde on NÃO; below ~0.95 the accent on a lower line starts closing on
     the baseline above it, and this is the one heading on the page that cannot afford
     to look wrong. Uppercase has no descenders to speak of, so 0.98 still reads as
     signage-tight. */
  line-height: 0.98;
  letter-spacing: 0.006em;
  text-transform: uppercase;
  font-feature-settings: 'case' 1;
  color: var(--paper);
  max-width: 22ch;
}

.hero__sub {
  margin-top: var(--sp-6);
  max-width: 54ch;
  font-size: var(--fs-md);
  color: var(--petrol-100);
}

.hero__act {
  margin-top: var(--sp-7);
}

/* ochre-100 on petrol-800 is 9.51:1. It is the one warm text on the page and it is
   tied to the action directly above it -- what the booking actually costs and
   returns. */
.hero__micro {
  margin-top: var(--sp-4);
  font-size: var(--fs-sm);
  font-stretch: 92%;
  letter-spacing: 0.02em;
  color: var(--ochre-100);
}

/* ---------------------------------------------------------------------------
   The six overheard sentences — engraved register lines on the paper mount. Each
   line carries a hairline rule and a short cast tick, the way an inspection register
   is ruled off.
   --------------------------------------------------------------------------- */
.register {
  margin-top: var(--sp-7);
  border-bottom: 1px solid var(--rule-mount);
}

.register__line {
  position: relative;
  border-top: 1px solid var(--rule-mount);
  padding-block: var(--sp-5);
}

.register__line::before {
  content: '';
  position: absolute;
  top: -2px;
  left: 0;
  width: 2.5rem;
  height: 3px;
  background: var(--petrol-800);
}

.register q {
  display: block;
  quotes: '«' '»';
  font-size: var(--fs-lg);
  font-stretch: 84%;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: 0.004em;
  color: var(--ink-900);
  max-width: 34ch;
}

.register__closing {
  margin-top: var(--sp-7);
}

/* ---------------------------------------------------------------------------
   How it works — four steps whose order is the information, so they are numbered.
   The numeral sits in a petrol tag, the way a valve or circuit is tagged.
   --------------------------------------------------------------------------- */
.steps {
  counter-reset: step;
  margin-top: var(--sp-8);
  display: grid;
  gap: var(--sp-7);
}

.step {
  counter-increment: step;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--sp-5);
  align-items: start;
  padding-top: var(--sp-5);
  border-top: 1px solid var(--rule-mount-faint);
}

.step__no {
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  background: var(--petrol-800);
  color: var(--paper);
  font-size: var(--fs-md);
  font-stretch: 84%;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  border-radius: 2px;
}

.step__no::before {
  content: counter(step);
}

/* min-width: 0 so a long unbroken word in the step body cannot force the 1fr track
   wider than the grid and push the whole row into horizontal overflow. */
.step__text {
  min-width: 0;
}

.step__title {
  font-size: var(--fs-lg);
  font-stretch: 84%;
  font-weight: 700;
  letter-spacing: 0.01em;
  color: var(--petrol-800);
}

.step__meta {
  margin-top: var(--sp-2);
  font-size: var(--fs-sm);
  font-stretch: 92%;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  font-feature-settings: 'case' 1;
  font-variant-numeric: tabular-nums;
  color: var(--petrol-600);
}

.step__body {
  margin-top: var(--sp-4);
  color: var(--ink-700);
}

/* A drawn marker, not a glyph: a short cast dash on the same axis as the register
   ticks above. */
.ticks {
  margin-top: var(--sp-4);
  display: grid;
  gap: var(--sp-3);
  max-width: var(--measure);
}

.ticks li {
  position: relative;
  padding-left: var(--sp-6);
  color: var(--ink-700);
}

.ticks li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.7em;
  width: 1rem;
  height: 2px;
  background: var(--petrol-600);
}

.notfit .ticks li::before {
  background: var(--petrol-800);
}

/* ---------------------------------------------------------------------------
   The rubric — the published instrument, blank. Seven dimensions by a 0-4 scale, on
   its own plate because it is the strongest real proof this page has.
   --------------------------------------------------------------------------- */
.grid-wrap {
  margin-top: var(--sp-7);
  overflow-x: auto;
}

.grid {
  width: 100%;
  border-collapse: collapse;
  text-align: left;
}

.grid__caption {
  caption-side: top;
  text-align: left;
  font-size: var(--fs-md);
  color: var(--petrol-100);
  max-width: var(--measure);
  padding-bottom: var(--sp-6);
}

/* The second caption sentence: why every box is empty. Set a step down from the intro
   so it reads as a note on the instrument rather than a second claim, still petrol-100
   on petrol-800 at 9.29:1. */
.grid__caption-note {
  display: block;
  margin-top: var(--sp-3);
  font-size: var(--fs-sm);
}

.grid__corner {
  width: auto;
}

.grid thead th {
  border-bottom: 2px solid var(--rule-plate);
  padding-bottom: var(--sp-3);
}

/* The five score columns are sized by token so the dimension column keeps a readable
   share on a phone. At a 360px viewport the plate's inner width is ~296px; five 24px
   columns leave ~160px for the dimension name and its description, which wrap rather
   than scroll. The columns widen twice as room appears. */
.grid__score {
  width: var(--score-col);
  text-align: center;
  font-size: var(--fs-sm);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--petrol-100);
}

.grid__dim {
  padding: var(--sp-4) var(--sp-3) var(--sp-4) 0;
  border-bottom: 1px solid var(--rule-plate-soft);
  font-weight: 400;
  hyphens: auto;
  overflow-wrap: break-word;
}

.grid__name {
  display: block;
  font-size: var(--fs-base);
  font-stretch: 88%;
  font-weight: 700;
  line-height: 1.2;
  color: var(--paper);
}

.grid__desc {
  display: block;
  margin-top: var(--sp-1);
  font-size: var(--fs-sm);
  color: var(--petrol-100);
  line-height: 1.35;
}

.grid__cell {
  border-bottom: 1px solid var(--rule-plate-soft);
  padding: var(--sp-4) 0;
  text-align: center;
}

/* An unticked box. The grid ships empty on purpose: no real Part A report exists yet,
   so filling it would mean inventing a client's scores. */
.grid__box {
  display: block;
  width: var(--score-box);
  height: var(--score-box);
  margin-inline: auto;
  border: 1px solid var(--rule-plate);
  border-radius: 1px;
}

@media (min-width: 30rem) {
  :root {
    --score-col: 2rem;
    --score-box: 1.125rem;
  }
}

@media (min-width: 40rem) {
  :root {
    --score-col: 3rem;
    --score-box: 1.375rem;
  }

  .grid__dim {
    padding-right: var(--sp-5);
  }
}

/* ---------------------------------------------------------------------------
   Catálogo — the service list. Unlike .steps, order does not carry information
   (each service stands on its own, not in a fixed sequence), so no counter tag:
   just the rule-topped card the FAQ items already use, with the step's title/meta/
   body sizes reused verbatim since a service name, duration and scope play exactly
   the roles a step's title, meta and body already play.
   --------------------------------------------------------------------------- */
.services {
  margin-top: var(--sp-7);
  display: grid;
  gap: var(--sp-7);
}

.service {
  padding-top: var(--sp-5);
  border-top: 1px solid var(--rule-mount-faint);
}

.service__name {
  font-size: var(--fs-lg);
  font-stretch: 84%;
  font-weight: 700;
  letter-spacing: 0.01em;
  color: var(--petrol-800);
}

.service__meta {
  margin-top: var(--sp-2);
  font-size: var(--fs-sm);
  font-stretch: 92%;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  font-feature-settings: 'case' 1;
  font-variant-numeric: tabular-nums;
  color: var(--petrol-600);
}

.service__scope {
  margin-top: var(--sp-4);
  color: var(--ink-700);
}

/* S0 on the steel — the same service block, re-inked for the petrol field. No new
   geometry and no new tokens: only the four colours that would otherwise be ink or
   petrol-800 on petrol-800. Measured against petrol-800:
     paper name          11.00:1
     petrol-100 meta      9.29:1
     petrol-100 instances 9.29:1
     petrol-400 tick dash  2.85:1 — a 2px drawn marker, the same --rule-plate value
       the plate's own cast rule and the grid's borders already run at.
   No border-top on the name here: the plate's cast rule is already the frame, and a
   second rule inside it would be the list's separator doing a job nothing needs. */
.service-plate .service__name {
  color: var(--paper);
}

.service-plate .service__meta {
  color: var(--petrol-100);
}

.service-plate .ticks li {
  color: var(--petrol-100);
}

.service-plate .ticks li::before {
  background: var(--rule-plate);
}

.service-plate__act {
  margin-top: var(--sp-7);
}

/* ---------------------------------------------------------------------------
   Who it is for
   --------------------------------------------------------------------------- */
.sectors {
  margin-top: var(--sp-6);
  display: grid;
  gap: 0;
  grid-template-columns: 1fr;
  border-bottom: 1px solid var(--rule-mount-faint);
}

.sectors li {
  position: relative;
  padding: var(--sp-4) 0 var(--sp-4) var(--sp-6);
  border-top: 1px solid var(--rule-mount-faint);
  font-size: var(--fs-md);
  font-stretch: 92%;
  font-weight: 600;
  color: var(--petrol-800);
}

.sectors li::before {
  content: '';
  position: absolute;
  left: 0;
  top: calc(var(--sp-4) + 0.55em);
  width: 1rem;
  height: 2px;
  background: var(--petrol-600);
}

@media (min-width: 44rem) {
  .sectors {
    grid-template-columns: 1fr 1fr;
    column-gap: var(--sp-7);
  }
}

.notfit {
  margin-top: var(--sp-8);
  background: var(--petrol-100);
  border-top: 3px solid var(--petrol-800);
  padding: var(--sp-6);
}

/* petrol-800 on petrol-100 is 9.29:1. */
.notfit__title {
  font-size: var(--fs-lg);
  font-stretch: 84%;
  font-weight: 700;
  letter-spacing: 0.01em;
  color: var(--petrol-800);
}

.notfit .ticks li {
  color: var(--petrol-800);
}

/* ---------------------------------------------------------------------------
   About — D is the product, so the photograph is not an afterthought.
   --------------------------------------------------------------------------- */
.about {
  margin-top: var(--sp-6);
  display: grid;
  gap: var(--sp-7);
  align-items: start;
}

.about__figure {
  max-width: 20rem;
}

.about__photo {
  width: 100%;
  height: auto;
  border: 3px solid var(--petrol-800);
  box-shadow: var(--shadow-mount);
}

.about__text > * + * {
  margin-top: var(--sp-4);
}

.about__ask {
  margin-top: var(--sp-6);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--rule-mount);
  font-size: var(--fs-md);
  font-stretch: 92%;
  font-weight: 600;
  color: var(--petrol-800);
}

@media (min-width: 52rem) {
  .about {
    grid-template-columns: 20rem 1fr;
    gap: var(--sp-8);
  }
}

/* ---------------------------------------------------------------------------
   FAQ — every answer on the plate, nothing folded away.
   --------------------------------------------------------------------------- */
.faq {
  margin-top: var(--sp-6);
  display: grid;
  gap: var(--sp-6);
}

.faq__item {
  padding-top: var(--sp-5);
  border-top: 1px solid var(--rule-mount-faint);
}

.faq__q {
  font-size: var(--fs-md);
  font-stretch: 88%;
  font-weight: 700;
  line-height: 1.2;
  color: var(--petrol-800);
}

.faq__a {
  margin-top: var(--sp-3);
  max-width: var(--measure);
  color: var(--ink-700);
}

@media (min-width: 56rem) {
  .faq {
    grid-template-columns: 1fr 1fr;
    column-gap: var(--sp-8);
  }
}

/* ---------------------------------------------------------------------------
   Closing plate and the footer rail beneath it
   --------------------------------------------------------------------------- */
.close__title {
  font-size: var(--fs-2xl);
  max-width: 18ch;
}

.close__act {
  margin-top: var(--sp-7);
}

.close__alt {
  margin-top: var(--sp-5);
  font-size: var(--fs-sm);
  color: var(--petrol-100);
}

.plate--close {
  padding-bottom: clamp(3rem, 8vw, 5rem);
}

/* The closing plate and the footer are one piece of steel, and the frame now says so.
   Before this, .plate--close drew the full four-sided cast rule with a drilled hole at
   each corner -- and then .site-foot continued the same petrol *below* the bottom pair
   of holes. A plate that carries on past its own bottom screws is not a plate; it is a
   decorative border, which is the one thing the whole direction is built to avoid.
   So the frame is drawn open-bottomed here and closed by the footer: the section's
   ::before loses its bottom border and runs to the section's own bottom edge, the
   footer's picks up at its top edge, and because both are full-bleed sections inset by
   the same --plate-inset the two vertical rules meet with nothing between them. The
   four holes then sit at the four corners of one object, the maker's name is inside
   the frame the way it is on real signage, and .site-foot__inner's existing rule reads
   as a division within the plate rather than the seam between two of them.
   Alternative considered and rejected: putting the footer on the paper mount. It
   closes the same hole but spends petrol the direction commits to. */
.plate--close::before {
  inset: var(--plate-inset) var(--plate-inset) 0;
  border-bottom: 0;
}

/* Top two holes only -- the bottom pair now belongs to the footer. */
.plate--close::after {
  inset: var(--plate-inset) var(--plate-inset) 0;
  background-image:
    radial-gradient(circle at var(--hole-pos) var(--hole-pos),
      var(--paper) 0 5px, var(--hole-ring) 5px 6.5px, transparent 6.5px),
    radial-gradient(circle at calc(100% - var(--hole-pos)) var(--hole-pos),
      var(--paper) 0 5px, var(--hole-ring) 5px 6.5px, transparent 6.5px);
}

.site-foot {
  background: var(--petrol-800);
  color: var(--petrol-100);
  padding-block: var(--sp-6) var(--sp-7);
}

/* :has(), not a class on the footer, because the condition is genuinely about what
   precedes it: only a footer that follows a closing plate is inside that plate's
   frame. /contacto ends on a paper mount, so its footer stays the plain petrol rail
   it should be -- there is no frame above it being violated. */
main:has(> .plate--close) + .site-foot {
  position: relative;
}

main:has(> .plate--close) + .site-foot::before,
main:has(> .plate--close) + .site-foot::after {
  content: '';
  position: absolute;
  inset: 0 var(--plate-inset) var(--plate-inset);
  z-index: 0;
  pointer-events: none;
}

main:has(> .plate--close) + .site-foot::before {
  border: 1px solid var(--rule-plate);
  border-top: 0;
}

main:has(> .plate--close) + .site-foot::after {
  background-image:
    radial-gradient(circle at var(--hole-pos) calc(100% - var(--hole-pos)),
      var(--paper) 0 5px, var(--hole-ring) 5px 6.5px, transparent 6.5px),
    radial-gradient(circle at calc(100% - var(--hole-pos)) calc(100% - var(--hole-pos)),
      var(--paper) 0 5px, var(--hole-ring) 5px 6.5px, transparent 6.5px);
}

/* Same clearance the plate gives its own content, for the same reason: inside the
   frame, not under it. */
main:has(> .plate--close) + .site-foot > .wrap {
  position: relative;
  z-index: 1;
  padding-inline: max(var(--gutter), calc(var(--plate-inset) + 1.5rem));
}

.site-foot__inner {
  display: grid;
  gap: var(--sp-5);
  padding-top: var(--sp-6);
  border-top: 1px solid var(--rule-plate);
}

.site-foot__brand {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  max-width: none;
  color: var(--paper);
}

.mark svg {
  height: 1.625rem;
}

.site-foot__tagline {
  font-size: var(--fs-sm);
  font-stretch: 92%;
  font-weight: 600;
  letter-spacing: 0.01em;
}

.site-foot__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-5);
  font-size: var(--fs-sm);
}

@media (min-width: 52rem) {
  .site-foot__inner {
    grid-template-columns: auto 1fr;
    align-items: center;
  }

  .site-foot__meta {
    justify-content: flex-end;
  }
}

/* ---------------------------------------------------------------------------
   Contacto — the Cal.com booker (Task 8). #cal-inline is empty in the prerendered
   HTML; entry-client.js mounts CalEmbed.svelte into it, which loads app.cal.com's
   own script and lets Cal.com size and style the iframe itself, so no height or
   background is claimed here that a since-resized iframe would immediately
   contradict. No skeleton, no spinner: the direction bars motion, so the empty
   frame is just empty, and the always-visible mailto paragraph directly above it
   (plain .lede, reusing content.cta.alt/cta.email) is the honest placeholder for
   both "hasn't loaded yet" and "never loads" -- see task-8-report.md. */
.cal-embed {
  margin-top: var(--sp-6);
}

/* Framed, because Cal.com's booker is the one thing on this site that is not ours to
   draw. Its type is Inter, its cards are rounded, and neither is configurable -- only
   its colours are (CalEmbed.svelte pins cal-brand/bg/text to petrol-800 and paper). So
   the fix is not to restyle Cal's internals, which cannot be done honestly; it is to
   mount it. The frame is the same hardware the rest of the site is built from: a 3px
   petrol-800 edge and a real offset-plus-blur shadow (exactly what .about__photo does
   with the one other rectangle on the site that arrived from outside), a hairline cast
   rule set in from that edge, and a drilled fixing at each corner of the rule -- the
   plate's own idiom at instrument scale. What was a bare third-party iframe now reads
   as a panel screwed onto the mount, on the page whose only job is the booking.
   Measured: petrol-800 edge and fixings on paper 11.00:1; --rule-mount hairline on
   paper 2.19:1, the value that token is already documented at. All three are drawn
   marks, not text.
   The chrome is dropped while the frame is :empty -- which is exactly how it ships in
   the prerendered HTML, and how it stays for a visitor whose browser never runs
   entry-client.js or blocks app.cal.com. An empty bordered panel would be a broken
   instrument; nothing is the honest state, and the mailto paragraph directly above it
   is already the no-JS path. :empty, not display:none, so the container keeps its
   layout width for Cal to measure at init. */
.cal-embed__frame {
  /* Fixing centre and radius, set so the fixings clear the iframe: the rule sits 6px
     in, a fixing spans 1px-9px from the frame edge, and the iframe starts at 16px. */
  --frame-rule: 6px;
  --frame-screw: 5px;
  --frame-screw-r: 4px;

  position: relative;
  margin-top: var(--sp-7);
  width: 100%;
  padding: var(--sp-4);
  background: var(--paper);
  border: 3px solid var(--petrol-800);
  box-shadow: var(--shadow-mount);
}

.cal-embed__frame::before,
.cal-embed__frame::after {
  content: '';
  position: absolute;
  inset: var(--frame-rule);
  pointer-events: none;
}

.cal-embed__frame::before {
  border: 1px solid var(--rule-mount);
}

.cal-embed__frame::after {
  background-image:
    radial-gradient(circle at var(--frame-screw) var(--frame-screw),
      var(--petrol-800) 0 var(--frame-screw-r), transparent var(--frame-screw-r)),
    radial-gradient(circle at calc(100% - var(--frame-screw)) var(--frame-screw),
      var(--petrol-800) 0 var(--frame-screw-r), transparent var(--frame-screw-r)),
    radial-gradient(circle at var(--frame-screw) calc(100% - var(--frame-screw)),
      var(--petrol-800) 0 var(--frame-screw-r), transparent var(--frame-screw-r)),
    radial-gradient(circle at calc(100% - var(--frame-screw)) calc(100% - var(--frame-screw)),
      var(--petrol-800) 0 var(--frame-screw-r), transparent var(--frame-screw-r));
}

.cal-embed__frame:empty {
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
}

.cal-embed__frame:empty::before,
.cal-embed__frame:empty::after {
  display: none;
}

/* Task 5: the banner island (src/components/Banner.svelte). No transitions here --
   the site's binding direction is near-zero motion; state changes (hover, focus)
   only. Measured contrast: petrol-800 on petrol-100 is 9.29:1; ochre-600 on
   ochre-100 is 4.41:1, AA-large only. WCAG "large text" is 14pt bold (18.66px) or
   18pt regular (24px) -- bold alone at the inherited 16px is still normal-size text
   and needs 4.5:1, which 4.41:1 misses. .banner--warning therefore sets both
   font-size and font-weight, inherited by its <p> and <a> children. The literal
   1.1875rem is an accessibility-forced value on one variant and predates the scale
   above; it stays literal because the floor it clears is a WCAG number, not a step
   on this page's ladder. */
.banner {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  padding: 0.75rem 1rem;
  text-align: center;
}

.banner p {
  margin: 0;
}

.banner a {
  color: inherit;
  text-decoration: underline;
}

.banner--promo {
  background: var(--petrol-100);
  color: var(--petrol-800);
}

.banner--info {
  background: var(--grey-100);
  color: var(--ink-900);
}

.banner--warning {
  background: var(--ochre-100);
  color: var(--ochre-600);
  font-size: 1.1875rem; /* 19px, clears the 18.66px WCAG large-text floor */
  font-weight: 700;
}
