/* Cyber+ academy — one stylesheet, mobile first, from 320 px.

   The page is set in one family, Montserrat: 700 announces, 400/500 reads.
   Google's latin-ext range for it carries U+0259, so ə and the rest of the
   azerbaijani letters come from the same file as the cyrillic.

   Besides white, black and grey the page carries the two colours of the logo,
   the way the academy's own Instagram uses them: blue for the headings and for
   every action, crimson for the one accent line under a heading and for the
   number 100+. Crimson is never a button and never body text: #f8004c on white
   is 4.12:1, enough for large type (≥24 px) and for nothing smaller. A broken
   field on the light ground is #b0003a (7.22:1); on the dark ground it is the
   lifted #ff2e63 (4.83:1 on #101a2b) because #b0003a sinks there to 2.41:1.

   Three grounds: the tinted paper #f6f7f9 with two soft washes of the logo's
   own colours in its corners, the white header, and the blued earth #101a2b
   under the first screen and under the closing plate that holds the form and
   the footer. On that earth the blue button turns over — light plate, blue
   letters, #1a3fb8 on #f2f3f0, 7.70:1 — because blue on it reads at 2.03:1.

   Pairs the page paints, measured (WCAG 2.1, two decimals):
     #ffffff on #1a3fb8   8.58:1  white on the action blue — every solid button
     #ffffff on #14308c  11.47:1  the same button, pressed
     #1a3fb8 on #ffffff   8.58:1  blue as text on the white header
     #1a3fb8 on #f6f7f9   8.05:1  blue headings on the tinted paper
     #1a3fb8 on #f2f3f0   7.70:1  the turned-over button on a dark ground
     #f8004c on #f6f7f9   3.89:1  the crimson 100+ — large type only
     #ff2e63 on #101a2b   4.83:1  the crimson line of a heading on the earth
     #f2f3f0 on #101a2b  15.65:1  light ink on the earth
     #9ba19f on #101a2b   6.63:1  muted light ink on the earth
     #6880d0 on #101a2b   4.64:1  the lifted blue — a focused field's line
     #15181a on #f6f7f9  16.55:1  ink on the paper
     #565c60 on #f6f7f9   6.36:1  muted ink on the paper
     #565c60 on #ffffff   6.78:1  muted ink on the white band */

:root {
  --bg: #f6f7f9;           /* tinted paper */
  --bg-soft: #ffffff;      /* the white band inside it */
  --ink: #15181a;
  --ink-soft: #565c60;
  --line: #e1e4ea;
  --line-strong: #c6cbd4;

  --brand: #1a3fb8;        /* the action blue */
  --brand-strong: #14308c; /* the same blue, pressed — 24% towards black */
  --brand-lift: #6880d0;   /* the same blue, lifted to clear 4.5:1 on both dark grounds */
  --mark: #f8004c;         /* logo crimson — identity only */
  --mark-plus: var(--mark); /* the plus inside the drawn shield */
  --alert: #b0003a;        /* the same crimson, darkened to hold text on white */

  --head: #ffffff;         /* the header's ground: white, the logo in its own colours */
  --dark: #101a2b;         /* hero and footer: the same earth with blue in it */
  --mark-lift: #ff2e63;    /* the same crimson, lifted to 4.83:1 on --dark */
  --dark-ink: #f2f3f0;     /* light ink, 16.01:1 on --head, 15.65:1 on --dark */
  --dark-soft: #9ba19f;    /* muted light ink, 6.79:1 on --head, 6.63:1 on --dark */
  --dark-line: #31363a;    /* the hairline on either dark ground */

  --wrap: 68rem;
  --pad: 1.25rem;
  --r: 8px;
  --t: 180ms;

  /* How tall the travelling header stands. Three rows here, two from 48rem,
     one from 54rem — the same thresholds the header itself rebuilds on. An
     anchor stops this far short of its heading, so the heading lands under
     the header and not behind it. Measured, not guessed. */
  --head-h: 10.7rem;

  /* One family, two jobs. The fallbacks are honest: every family named after
     it ships the azerbaijani letters and cyrillic on the platform it belongs
     to, so a failed font request changes the letterform and nothing else. */
  --font: "Montserrat", "Segoe UI", system-ui, -apple-system, "Noto Sans",
          "Helvetica Neue", Arial, sans-serif;
  --font-head: var(--font);
}

*, *::before, *::after { box-sizing: border-box; }

/* The scroll the owner picked runs in three parts, and the first two are here:
   an anchor travels instead of jumping, and the bar beside the page is the
   page's own blue on the page's own tint rather than the system grey. The
   third part, a section lifting into place, is further down with the sections
   themselves. */
html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: var(--head-h);
  scrollbar-width: thin;
  scrollbar-color: var(--brand) var(--bg-soft);
}
html::-webkit-scrollbar { width: 10px; height: 10px; }
html::-webkit-scrollbar-track { background: var(--bg-soft); }
html::-webkit-scrollbar-thumb { background: var(--brand); border-radius: var(--r); }

body {
  margin: 0;
  /* The academy's own Instagram ground: grey paper with a blue wash in one
     corner and a crimson wash in the other. Both are faint enough to leave
     the ink at 16:1, and they sit behind the whole page rather than behind
     each block, so no block gets a gradient of its own. */
  background:
    radial-gradient(60% 45% at 0% 0%, rgba(26, 63, 184, 0.18), transparent 70%),
    radial-gradient(55% 45% at 100% 100%, rgba(248, 0, 76, 0.15), transparent 70%),
    var(--bg);
  background-attachment: fixed, fixed, scroll;
  color: var(--ink);
  font-family: var(--font);
  font-size: 1rem;
  line-height: 1.6;
  font-weight: 400;
  /* No overflow-x:hidden here on purpose. Nothing on the page may stick out
     sideways in the first place, and a hidden overflow would hide a regression
     instead of failing the 320 px check. */
  overflow-wrap: break-word;
  -webkit-font-smoothing: antialiased;
}

/* Someone who asked the system for no animation gets a still page: no travel
   on an anchor, no lift on a section, and every transition down to a tick.
   This is not one of the settings — it overrules them. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { transition-duration: 1ms !important; }
  html.reveal main .section,
  html.reveal .site-footer {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
}

h1, h2, p, dl, dd, figure { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
img, svg { max-width: 100%; }

a { color: inherit; }

:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
  border-radius: 2px;
}
/* The same blue sinks into either dark ground (2.08:1 on the header, 2.03:1
   below), so on all three dark bands the ring takes the lifted shade instead:
   #6880d0, 4.75:1 on the header and 4.64:1 on the hero and the footer. */
.hero :focus-visible,
.site-header :focus-visible,
.site-footer :focus-visible { outline-color: var(--brand-lift); }

/* The icon sprite is markup, not picture: it takes no room. */
.sprite {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

.ico {
  width: 1.125rem;
  height: 1.125rem;
  flex: none;
}

.icon-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.375rem;
  height: 2.375rem;
  border-radius: var(--r);
  color: var(--ink-soft);
  text-decoration: none;
  transition: color var(--t) ease;
}
.icon-link:hover { color: var(--ink); }

/* ---------- skip link ---------- */

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 10;
}
/* White on #1a3fb8, 8.58:1. It is the page's first action, so it is blue. */
.skip:focus-within,
.skip:focus {
  left: 0;
  padding: 0.65rem 1rem;
  background: var(--brand);
  color: #ffffff;
  text-decoration: none;
}

/* ---------- header: one line, four groups ---------- */

/* The header stands on the near black the page writes its text in. That makes
   it the third dark band, and it takes the treatment the hero and the footer
   already have rather than a second one of its own: the light ink and the
   muted light ink change hands here once, at the top, and every anchor, word
   and icon inside picks them up by inheritance. */
/* The header travels with the page instead of scrolling away: the anchors and
   the button that starts the form stay a thumb away wherever the reader is.
   It sits under the skip link (z-index 10) and over everything else. White,
   so the logo file stands in its own blue and crimson, and every action in it
   takes the blue straight: #1a3fb8 on #ffffff, 8.58:1. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--head);
}
/* The one line under the header runs from the blue to the crimson: the two
   colours together, the way the owner showed them on the key. */
.site-header::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: linear-gradient(90deg, var(--brand) 0%, var(--mark) 100%);
}

/* Three layouts, one for each amount of room.

   From 54rem the four groups share one row: logo, anchors, AZ/RU/EN, then
   Instagram and the button. From 48rem to 54rem the anchors take a line of
   their own and the switch stays up on the first one, beside the button.
   Below 48rem the first line holds the logo and the button, the anchors take
   the full width of the second, and the switch gets the third.

   The switch is never below the fold and the anchors are never removed: the
   page does not read the browser language, so a russian or english reader who
   cannot see AZ/RU/EN on the first screen simply leaves, and the phone is
   where the page is longest and the anchors matter most. The anchor track is
   minmax(0,1fr) in every layout, so a long word cannot push the row wider than
   the screen. */
.site-header__inner {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0.7rem var(--pad);
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas:
    "brand actions"
    "nav   nav"
    "lang  lang";
  align-items: center;
  column-gap: 0.75rem;
  row-gap: 0.45rem;
}

/* Pinned to its own width in every layout: stretched to the track, the anchor
   would make the empty paper beside the logo click through to #main. */
.brand { grid-area: brand; justify-self: start; }
.site-nav { grid-area: nav; min-width: 0; }
.lang { grid-area: lang; justify-self: start; }
.site-header__actions { grid-area: actions; }

.site-nav__list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.15rem 1.05rem;
  min-width: 0;
}

.site-nav__list a {
  display: inline-block;
  padding: 0.2rem 0;
  font-size: 0.8125rem;
  color: var(--ink-soft);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color var(--t) ease, border-color var(--t) ease;
}
/* An anchor is an action, so it answers in the blue every action uses. The
   header stands on the dark ground, so the shade it answers in is the lifted
   one, set a few rules above: #6880d0 on #15181a, 4.75:1. */
.site-nav__list a:hover,
.site-nav__list a:focus-visible {
  color: var(--brand);
  border-bottom-color: var(--brand);
}

.site-header__actions {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  flex: none;
}

/* Measured in Chrome with the fonts loaded and swept width by width, not
   guessed. The single row first holds at 770 px of viewport in azerbaijani,
   786 in english and 835 in russian — russian carries the longest words.
   Added up as boxes the four groups read 780, 796 and 846 instead: the switch
   measures 86.3 wide but gives 11.2 of that back through its own negative side
   margins. Either way 768 px no longer holds even azerbaijani, so the single
   row starts at 54rem (864 px), where russian still has 29 px to spare; the
   gaps stay narrow until 64rem. */
@media (min-width: 48rem) {
  :root { --head-h: 6.5rem; }
  .site-header__inner {
    grid-template-columns: minmax(0, 1fr) auto auto;
    grid-template-areas:
      "brand lang actions"
      "nav   nav  nav";
    column-gap: 1rem;
    padding-top: 0.8rem;
    padding-bottom: 0.8rem;
  }
  .lang { justify-self: end; margin-top: 0; }
  .site-nav__list {
    justify-content: center;
    column-gap: 0.85rem;
  }
}

@media (min-width: 54rem) {
  :root { --head-h: 4.6rem; }
  .site-header__inner {
    grid-template-columns: auto minmax(0, 1fr) auto auto;
    grid-template-areas: "brand nav lang actions";
  }
}

@media (min-width: 64rem) {
  .site-header__inner { column-gap: 1.5rem; }
  .site-nav__list { column-gap: 1.05rem; }
}

/* 320 px is the narrowest screen the page answers for, and there the logo, the
   icon and the button have to share 280 px of paper. The header buys the room
   back from its own gutter instead of from the logo. */
@media (max-width: 23.4375rem) {
  .site-header__inner {
    padding-left: 1rem;
    padding-right: 1rem;
    column-gap: 0.5rem;
  }
  .site-header__actions { gap: 0.15rem; }
}

/* Header: the logo file itself, flattened to white by the rule above because
   the ground under it is dark. Height is fixed and the width follows, so the
   picture cannot squash. 1.75rem before, 2.75rem now — 28 px to 44 px. */
.brand {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
  flex: none;
}
.brand__logo {
  display: block;
  height: 2.75rem;
  width: auto;
}

/* Footer: the ground is the blued earth, so the logo file would sit there as a
   white patch. The mark is redrawn from the sprite in light ink instead, and the
   name is set in type — same two colours, no rectangle. */
.brand--footer {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  font-family: var(--font-head);
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: -0.015em;
  white-space: nowrap;
  --mark-plus: var(--mark-lift);
}
.brand__mark {
  width: 1.6rem;
  height: 1.6rem;
  flex: none;
}
.brand__b { color: var(--mark-lift); }

/* ---------- language switch: one on the page, in the header ---------- */

/* Three plain words, no box: a control that has to be noticed but must not
   compete with the one button in the header. The language in use is an action
   already taken, so it wears the action blue — lifted for the dark header,
   #6880d0 on #15181a, 4.75:1. The other two sit in the quiet grey the anchors
   use, #9ba19f on #15181a, 6.79:1, and lighten to the light ink on hover. */
.lang {
  display: flex;
  align-items: center;
  gap: 0.1rem;
  flex: none;
  /* the first and last button's own padding, given back — the words line up
     with the anchors on the left and with the button's edge on the right.
     The extra top margin is for the phone, where the switch sits on a line of
     its own under the anchors and must not read as one more of them. */
  margin: 0.3rem -0.35rem 0;
}

.lang__btn {
  appearance: none;
  background: none;
  border: 0;
  border-bottom: 1px solid transparent;
  padding: 0.25rem 0.35rem;
  font: inherit;
  font-size: 0.8125rem;
  line-height: 1.4;
  color: var(--ink-soft);
  cursor: pointer;
  transition: color var(--t) ease, border-color var(--t) ease;
}
.lang__btn:hover { color: var(--ink); }
.lang__btn.is-on {
  color: var(--brand);
  border-bottom-color: var(--brand);
  font-weight: 500;
}

/* ---------- buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: 2.875rem;
  padding: 0.6rem 1.15rem;
  border: 1px solid transparent;
  border-radius: var(--r);
  font: inherit;
  font-size: 0.9375rem;
  font-weight: 500;
  line-height: 1.3;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--t) ease, border-color var(--t) ease, color var(--t) ease;
}

.btn--sm {
  min-height: 2.375rem;
  padding: 0.4rem 0.85rem;
  font-size: 0.875rem;
}

/* White on #1a3fb8 measures 8.58:1, and 11.47:1 once pressed. */
.btn--solid {
  background: var(--brand);
  color: #ffffff;
}
.btn--solid:hover { background: var(--brand-strong); }
.btn--solid:disabled {
  background: var(--line);
  color: var(--ink-soft);
  cursor: default;
}

/* On the dark earth the blue fill would sink into it (2.03:1), so the button
   turns over instead of being lightened: light plate, blue lettering —
   #1a3fb8 on #f2f3f0, 7.70:1. The first screen and the closing plate carry it
   the same way. */
.hero .btn--solid,
.close .btn--solid {
  background: var(--dark-ink);
  color: var(--brand);
}
.hero .btn--solid:hover,
.close .btn--solid:hover { background: #ffffff; }

.btn--line {
  background: transparent;
  border-color: var(--line-strong);
  color: var(--ink);
}
.btn--line:hover { border-color: var(--brand); color: var(--brand); }

.btn--on-dark {
  border-color: var(--dark-line);
  color: var(--dark-ink);
}
.btn--on-dark:hover { border-color: var(--dark-soft); }

/* ---------- hero ---------- */

/* The first screen is built the way the owner's NEO Estate opens: one picture
   blurred behind a dark veil, and on it, down the middle, the logo, the line,
   the paragraph and the button. The picture is the instructor, already
   blurred in the file (sigma 12 at 1920 px) — a live blur would cost the
   phone a repaint per frame and leaves a light fringe at the edges.

   The studio in the picture is nearly white, so the veil is heavy, and it is
   not one colour: the owner asked for the two brand colours together, as on
   the key he showed, so the veil runs from the blue on the left through the
   earth in the middle to the crimson on the right. All three are dark enough:
   under the lightest patch of the picture the light ink reads at 6.7:1 on the
   blue end, 7.0:1 on the earth and 5.9:1 on the crimson end. The words stand
   in the middle third, on the earth.

   The middle axis is the owner's choice for this screen and this screen only;
   everything below it sets from the left. */
.hero {
  position: relative;
  isolation: isolate;
  background: var(--dark);
  color: var(--dark-ink);
  text-align: center;
}

.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image:
    linear-gradient(180deg, rgba(16, 26, 43, 0) 55%, rgba(16, 26, 43, 0.55) 100%),
    linear-gradient(105deg,
      rgba(20, 45, 150, 0.84) 0%,
      rgba(16, 26, 43, 0.78) 36%,
      rgba(16, 26, 43, 0.78) 62%,
      rgba(150, 0, 60, 0.82) 100%),
    image-set(url("../assets/hero-1920.webp") type("image/webp"),
              url("../assets/hero-1920.jpg") type("image/jpeg"));
  background-size: cover, cover, cover;
  background-position: center, center, center 30%;
  background-repeat: no-repeat, no-repeat, no-repeat;
}

/* The narrow screen: the words take the whole width, so the two colours meet
   top to bottom instead of left to right, and the veil closes harder. */
@media (max-width: 53.99rem) {
  .hero::before {
    background-image:
      linear-gradient(170deg,
        rgba(20, 45, 150, 0.86) 0%,
        rgba(16, 26, 43, 0.84) 40%,
        rgba(16, 26, 43, 0.84) 60%,
        rgba(150, 0, 60, 0.86) 100%),
      image-set(url("../assets/hero-960.webp") type("image/webp"),
                url("../assets/hero-960.jpg") type("image/jpeg"));
    background-size: cover, cover;
    background-position: center, center 30%;
    background-repeat: no-repeat, no-repeat;
  }
}

.hero__inner {
  max-width: 54rem;
  margin: 0 auto;
  padding: 4rem var(--pad) 4.5rem;
  display: grid;
  justify-items: center;
  gap: 1.25rem;
}

@media (min-width: 54rem) {
  .hero__inner { padding: 6rem var(--pad) 6.5rem; }
}

/* The logo file, flattened to the light ink: on this ground its blue would
   sink to 2:1. It is the same silhouette the header carried while the header
   was dark, only larger — the size NEO gives its own mark on this screen. */
.hero__logo {
  width: min(20rem, 68vw);
  height: auto;
  filter: brightness(0) invert(1);
  margin-bottom: 0.5rem;
}

/* Two lines, the second one crimson — the way the academy sets its own
   headlines on Instagram. The break between them is real: the second line is
   its own block, so no language gets a dangling word. */
.hero__title {
  font-family: var(--font-head);
  font-size: clamp(1.45rem, 5vw, 3rem);
  font-weight: 700;
  line-height: 1.12;
  letter-spacing: -0.025em;
  max-width: 24ch;
}
.hero__title > span { display: block; text-wrap: balance; }
/* The accent line carries both colours at once, lifted for the dark ground:
   #6880d0 into #ff2e63, both above 4.5:1 on the earth. fit-content keeps the
   gradient the width of the words, not of the screen. */
.hero__title-tail,
.close .section__title-tail {
  width: fit-content;
  color: var(--mark-lift);
  background: linear-gradient(90deg, var(--brand-lift) 0%, var(--mark-lift) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
.hero__title-tail { margin-inline: auto; }

/* The narrowest screens: "Kibertəhlükəsizliyi" and "кибербезопасности" set in
   Montserrat 700 need the step below 344 px to stay one word. */
@media (max-width: 21.5rem) {
  .hero__title { font-size: 1.3rem; }
}

.hero__lead {
  max-width: 58ch;
  color: #d6d9d5;
  font-size: 1.0625rem;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.65rem;
  margin-top: 1rem;
}

/* ---------- sections ---------- */

.section {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 2.75rem var(--pad);
  display: grid;
  gap: 1rem;
}

/* The third part of the scroll: a section and the footer lift ten pixels into
   place as they come into the screen. 200 ms, opacity and ten pixels of
   travel, and nothing grows — the rule allows 150 to 250 ms and forbids a
   bounce or any scale above 1.05.

   The whole thing hangs off a class the page's own script puts on <html>, and
   the script puts it there only after it has made sure it can take it off
   again. A page whose script never ran carries no class, so it shows every
   section instead of hiding them all. */
html.reveal main .section,
html.reveal .site-footer {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 200ms ease-out, transform 200ms ease-out;
}
html.reveal main .section.is-seen,
html.reveal .site-footer.is-seen {
  opacity: 1;
  transform: none;
}

/* Full-width tinted strip. The section inside keeps the usual grid. */
.band {
  background: var(--bg-soft);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

/* A heading is set the way the academy sets its own: Montserrat 700 in the
   blue, tight. #1a3fb8 on the tinted paper, 8.05:1. Where a heading has a
   second line, that line is the crimson accent — large type only. */
.section__title {
  font-family: var(--font-head);
  font-size: clamp(1.375rem, 2.6vw, 1.875rem);
  font-weight: 700;
  line-height: 1.18;
  letter-spacing: -0.02em;
  color: var(--brand);
  max-width: 22ch;
  min-width: 0;
}
.section__title > span { display: block; text-wrap: balance; }
.section__title-tail {
  width: fit-content;
  color: var(--mark);
  background: linear-gradient(90deg, var(--brand) 0%, var(--mark) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* A section that stacks its heading over its content instead of beside it. */
.section--stack { grid-template-columns: minmax(0, 1fr) !important; }
.section--stack .section__title { max-width: 26ch; }
.section--stack .lead { max-width: 56ch; font-size: 1.0625rem; }

.section__body { min-width: 0; }

.lead {
  max-width: 62ch;
  color: var(--ink-soft);
}

.note {
  margin-top: 0.75rem;
  font-size: 0.9375rem;
  color: var(--ink-soft);
}

/* ---------- labs: the photo, the number, the ladder ---------- */

/* The one place on the page a photograph earns its room: the student at a lab
   is what the paragraph above is about. A plate of the paper bites into the
   photo's lower left corner and carries the number 100+ — the one fact no
   competitor has — in the crimson, large enough to hold 3:1 on the paper.
   Beside it the three points step down a ladder: each hairline starts at its
   own indent, so the lines shorten step by step and the list reads as a path,
   labs, then project, then portfolio. Nothing here is a link, so nothing
   answers the cursor. */
.labs {
  margin-top: 2.5rem;
  display: grid;
  gap: 3rem;
  align-items: start;
}
@media (min-width: 54rem) {
  .labs {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    column-gap: 4rem;
  }
}

.labs__photo {
  position: relative;
  margin: 0 0 2rem 0.75rem;
}
@media (min-width: 54rem) {
  .labs__photo { margin: 0 0 1.5rem 1.5rem; }
}
.labs__img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--r);
}
.labs__num {
  position: absolute;
  left: -0.75rem;
  bottom: -0.75rem;
  padding: 0.5rem 0.9rem 0 0;
  background: var(--bg);
  border-radius: 0 var(--r) 0 0;
  font-family: var(--font-head);
  font-size: 3.5rem;
  font-weight: 700;
  line-height: 0.9;
  letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums;
}
/* The plate is paper, the number on it is the two colours in one word. */
.labs__num > span {
  color: var(--mark);
  background: linear-gradient(100deg, var(--brand) 0%, var(--mark) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
@media (min-width: 54rem) {
  .labs__num {
    left: -1.5rem;
    bottom: -1.5rem;
    padding: 0.75rem 1.25rem 0 0;
    font-size: 5.5rem;
  }
}

.labs__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
}
.labs__item {
  display: grid;
  grid-template-columns: 2rem minmax(0, 1fr);
  column-gap: 0.9rem;
  padding: 1.25rem 0;
  border-top: 1px solid var(--line-strong);
}
.labs__item:nth-child(2) { margin-left: 0.75rem; }
.labs__item:nth-child(3) { margin-left: 1.5rem; }
@media (min-width: 54rem) {
  .labs__item {
    grid-template-columns: 2.5rem minmax(0, 1fr);
    column-gap: 1rem;
    padding: 1.5rem 0;
  }
  .labs__item:nth-child(2) { margin-left: 2.5rem; }
  .labs__item:nth-child(3) { margin-left: 5rem; }
}
.labs__ico {
  width: 1.5rem;
  height: 1.5rem;
  margin-top: 0.15rem;
  color: var(--brand);
}
.labs__name {
  font-weight: 600;
  font-size: 1.125rem;
  line-height: 1.3;
}
.labs__text {
  margin-top: 0.3rem;
  color: var(--ink-soft);
  font-size: 0.9375rem;
  max-width: 38ch;
}

/* The heading holds the left column, the content the right one.
   Deliberately off-centre: the page never centres a block of text. */
@media (min-width: 54rem) {
  .section {
    grid-template-columns: minmax(0, 17rem) minmax(0, 1fr);
    column-gap: 3.5rem;
    padding-top: 3.5rem;
    padding-bottom: 3.5rem;
  }
}

/* ---------- rows ---------- */

.rows {
  margin-top: 1.75rem;
  border-top: 1px solid var(--line);
}

.row {
  padding: 1rem 0;
  border-bottom: 1px solid var(--line);
  display: grid;
  gap: 0.2rem;
}

.row__title { font-weight: 500; }
.row__text { color: var(--ink-soft); font-size: 0.9375rem; }

@media (min-width: 40rem) {
  .row {
    grid-template-columns: minmax(0, 13rem) minmax(0, 1fr);
    column-gap: 1.5rem;
    align-items: baseline;
  }
}

.plain {
  margin-top: 1.5rem;
  display: grid;
  gap: 0.5rem;
}
.plain li {
  padding-left: 1.1rem;
  position: relative;
  color: var(--ink);
}
.plain li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.85em;
  width: 0.5rem;
  height: 1px;
  background: var(--line-strong);
}

/* ---------- facts ---------- */

.facts {
  margin-top: 1.75rem;
  max-width: 32rem;
  border-top: 1px solid var(--line);
}
.facts__row {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.25rem 1rem;
  padding: 0.7rem 0;
  border-bottom: 1px solid var(--line);
}
.facts dt { color: var(--ink-soft); font-size: 0.9375rem; }
.facts dd { margin: 0; font-weight: 500; }

/* ---------- faq ---------- */

.faq {
  margin-top: 0.25rem;
  border-top: 1px solid var(--line-strong);
  max-width: 46rem;
}

.faq__item { border-bottom: 1px solid var(--line-strong); }

.faq__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.95rem 0;
  font-weight: 500;
  cursor: pointer;
  list-style: none;
}
.faq__q::-webkit-details-marker { display: none; }

/* Plus when shut, minus when open. Two sprite icons stacked, crossfaded —
   no spin, no bounce. */
/* The mark is the control: pressing the row opens it. That makes it an action,
   so it takes the action blue — #1a3fb8 on the band's #f4f5f2, 7.84:1. */
.faq__mark {
  position: relative;
  width: 1.125rem;
  height: 1.125rem;
  flex: none;
  color: var(--brand);
}
.faq__mark .ico {
  position: absolute;
  inset: 0;
  transition: opacity var(--t) ease;
}
.faq__mark-minus { opacity: 0; }
.faq__item[open] .faq__mark-plus { opacity: 0; }
.faq__item[open] .faq__mark-minus { opacity: 1; }

.faq__a {
  padding: 0 0 1rem;
  max-width: 58ch;
  color: var(--ink-soft);
}

/* ---------- the closing plate: form and footer on one earth ---------- */

/* The page closes the way it opened — on the blued earth. The form is the
   upper part of that plate and the footer its foot, so the request is the
   last thing on the page and not a box before the end. Fields are lines, not
   frames: a hairline of light under each one, and the lifted blue #6880d0
   (4.64:1 on this ground) when the field is being written in. */
.close {
  background:
    radial-gradient(70% 60% at 0% 0%, rgba(26, 63, 184, 0.55), transparent 70%),
    radial-gradient(55% 70% at 100% 40%, rgba(248, 0, 76, 0.30), transparent 70%),
    var(--dark);
  color: var(--dark-ink);
  --ink: var(--dark-ink);
  --ink-soft: var(--dark-soft);
  --line: var(--dark-line);
  --line-strong: rgba(255, 255, 255, 0.35);
}
.close .section { padding-top: 4rem; padding-bottom: 3.5rem; }
@media (min-width: 54rem) {
  .close .section {
    grid-template-columns: minmax(0, 22rem) minmax(0, 1fr);
    padding-top: 6rem;
    padding-bottom: 4.5rem;
  }
}
.close .section__title {
  color: var(--dark-ink);
  font-size: clamp(1.75rem, 3.2vw, 2.5rem);
  max-width: 14ch;
}
.close .section__title-tail { color: var(--mark-lift); }
.close .lead { color: var(--dark-soft); }

.form {
  margin-top: 2.25rem;
  max-width: 32.5rem;
  display: grid;
  gap: 1.75rem;
}

.field { display: grid; gap: 0.2rem; }

/* The label and, for the contact field, its hint share one line: "Contact"
   on the left, "email or phone" on the right, so the hint costs no row. */
.field__head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  font-size: 0.8125rem;
}
.field__label { font-weight: 500; color: var(--dark-soft); transition: color var(--t) ease; }
.field__hint { color: var(--dark-soft); }
.field:focus-within .field__label { color: var(--dark-ink); }

.field__input {
  width: 100%;
  min-width: 0;
  padding: 0.55rem 0 0.65rem;
  border: 0;
  border-bottom: 1px solid var(--line-strong);
  border-radius: 0;
  background: transparent;
  color: var(--dark-ink);
  font: inherit;
  font-size: 1.125rem;
  line-height: 1.4;
  transition: border-color var(--t) ease, box-shadow var(--t) ease;
}
.field__input:hover { border-bottom-color: rgba(255, 255, 255, 0.6); }
.field__input:focus {
  outline: none;
  border-bottom-color: var(--brand-lift);
  box-shadow: inset 0 -1px 0 var(--brand-lift);
}
.field__input--area {
  resize: vertical;
  min-height: 5.5rem;
}
.field__input.is-bad {
  border-bottom-color: var(--mark-lift);
  box-shadow: inset 0 -1px 0 var(--mark-lift);
}

.field__err {
  font-size: 0.875rem;
  line-height: 1.45;
  color: var(--mark-lift);
  margin-top: 0.35rem;
}

.form__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.65rem;
  margin-top: 0.25rem;
}

.hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.form__status {
  font-size: 0.9375rem;
  color: var(--dark-soft);
}
.form__status.is-bad { color: var(--mark-lift); }

.form__fallback {
  display: grid;
  gap: 0.75rem;
  padding: 1rem 0 0;
  border-top: 1px solid var(--dark-line);
}
.form__fallback-text { font-size: 0.9375rem; color: var(--dark-soft); }
.form__fallback-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

/* The receipt: type alone, no colour. The contact the person typed is read
   back to them — that echo is the confirmation. */
.done {
  margin-top: 2.25rem;
  max-width: 32.5rem;
  display: grid;
  gap: 0.75rem;
}
.done:focus { outline: none; }
.done__title {
  font-family: var(--font-head);
  font-size: 1.5rem;
  font-weight: 600;
  line-height: 1.25;
}
.done__text { color: var(--dark-soft); }
.done__echo { color: var(--dark-ink); font-weight: 500; word-break: break-all; }

/* ---------- footer ---------- */

/* The foot of the closing plate: the same earth as the form above it, and a
   hairline between the two. */
.site-footer {
  background: var(--dark);
  color: var(--dark-ink);
  border-top: 1px solid var(--dark-line);
}

/* The footer is the one place on the page that centres, and it does so because
   the owner asked for it: the mark with the name and the line under it stand in
   the middle of the band. Everything else on the page still sets from the left. */
.site-footer__inner {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 2.5rem var(--pad);
  display: grid;
  justify-items: center;
  gap: 0.75rem;
  text-align: center;
}

.site-footer__tagline {
  color: var(--dark-soft);
  font-size: 0.9375rem;
  max-width: 40ch;
}

.site-footer__links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem 1.5rem;
  margin-top: 0.75rem;
  font-size: 0.9375rem;
}
/* Every channel in this list is still null in content.js, so every item in it
   is hidden and the list is a box with nothing in it — which would still take
   its own top margin and the footer's row gap and leave a hole under the name.
   It stands down until one of the items has something to say. */
.site-footer__links:not(:has(> li:not([hidden]))) { display: none; }
.site-footer__links li {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}
.site-footer__links a {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  text-decoration: none;
  border-bottom: 1px solid var(--dark-line);
  padding-bottom: 1px;
  transition: border-color var(--t) ease;
}
.site-footer__links a:hover { border-bottom-color: var(--brand-lift); }
.site-footer__label { color: var(--dark-soft); }

[hidden] { display: none !important; }
