/**
 * Page-level composition.
 * Grid spans follow the approved template specifications.
 */

/* ================================================== COPY-COLUMN RHYTHM */

/*
 * ONE vertical-rhythm contract for every copy column in the system.
 *
 * Headings ship with margin:0 from the reset and the display steps use a
 * sub-1 line-height, so any column that stacks a kicker, a heading and a lede
 * will collide unless something re-establishes the rhythm. This was
 * originally fixed per component, which meant every new copy column shipped
 * the bug again — the CTA band and the homepage section headers both did.
 * Listing the columns here keeps the rule in one place; a new column joins
 * the list rather than inventing its own margins.
 */
.hero__copy > * + *,
.case-hero__copy > * + *,
.section-head__copy > * + *,
.cta-band__copy > * + *,
.next-project__copy > * + *,
.article-hero__copy > * + *,
.product-feature__copy > * + *,
.index-hero__copy > * + *,
.error-404 > * + *,
.split__intro > * + * { margin-block-start: var(--space-3); }

/* A button group is a change of intent, not another paragraph. */
.hero__copy > .button-group,
.case-hero__copy > .button-group { margin-block-start: var(--space-5); }

/* ================================================================ HERO */

.hero { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--space-6); align-items: center; }
.hero__copy { grid-column: span 7; }
.hero__proof { grid-column: span 5; }

/* Labels the card as evidence rather than as decoration. */
.hero__proof-label { margin-block-end: var(--space-2); color: var(--color-text-muted); }

/* ===================================================== WORK INDEX OPENING */

/*
 * Five columns of argument, seven of evidence.
 *
 * The work index has one job on its first screen — show the work — and it was
 * spending that screen on a heading, a paragraph and two numbers. The showcase
 * is a fixed three-tile composition: one dominant landscape crop with two
 * stacked beside it, so the eye gets a hierarchy rather than three equal
 * thumbnails, and the tiles keep their ratios instead of stretching to the
 * height of the copy.
 */
.index-hero { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--grid-gap); align-items: center; }
.index-hero__copy { grid-column: span 5; }
.index-hero__showcase { grid-column: 6 / -1; display: grid; grid-template-columns: 2fr 1fr; grid-template-rows: 1fr 1fr; gap: var(--space-2); }

/* No projects with images yet: the copy widens rather than sitting beside a hole. */
.index-hero--text-only .index-hero__copy { grid-column: span 9; }

.showcase-tile { margin: 0; overflow: hidden; border-radius: var(--radius-md); background-color: var(--color-surface-sunken); }
.showcase-tile--1 { grid-row: span 2; }
.showcase-tile img { inline-size: 100%; block-size: 100%; object-fit: cover; display: block; }

/*
 * Only the dominant tile declares a ratio; the two beside it take their height
 * from the rows it defines. Landscape, because the work being shown is
 * landscape — a portrait crop cut the laptop in half — and because a portrait
 * dominant tile made the opening 600px tall and pushed the filters, and with
 * them the actual index, off the first screen.
 */
.showcase-tile--1 { aspect-ratio: 4 / 3; }

@media (max-width: 1199px) {
  .index-hero__copy,
  .index-hero__showcase,
  .index-hero--text-only .index-hero__copy { grid-column: 1 / -1; }
  .index-hero__showcase { margin-block-start: var(--space-5); }
}

@media (max-width: 600px) {
  /* Three tiles at phone width become three postage stamps. Lead with one. */
  .index-hero__showcase { grid-template-columns: 1fr; grid-template-rows: auto; }
  .showcase-tile--1 { grid-row: auto; aspect-ratio: 16 / 10; }
  .showcase-tile--2,
  .showcase-tile--3 { display: none; }
}

/*
 * A hero with no proof to show.
 *
 * The 7/5 split assumes columns 8-12 carry evidence. On routes that have none
 * — a service with no matching case study, a contact page with no published
 * response time — the grid was reserving five empty columns, which reads as an
 * unfinished layout rather than as restraint. The rule is conditional: with
 * proof, 7/5; without it, a wider text column and less bottom air, so the
 * first substantive section arrives sooner.
 *
 * The columns are never filled with decoration to justify the grid.
 */
.hero--text-only .hero__copy { grid-column: span 9; }
.section--hero:has(.hero--text-only) { padding-block-end: var(--space-8); }

/*
 * The same rule, derived rather than declared.
 *
 * A PHP template can add `hero--text-only` after checking whether the proof
 * column has anything to show. A converted page cannot: the proof column is a
 * block that renders nothing when its setting is empty, and by then the parent
 * class is already written into the post content. Someone filling in the
 * response time on the settings screen would get the stat back but keep a hero
 * still laid out for nine columns of copy — a mismatch nobody would connect to
 * the setting they had just changed.
 *
 * `:has()` asks the question at render time instead, so the layout follows the
 * content with nothing to keep in sync by hand.
 *
 * The padding half of this pair was written as
 * `.section--hero:has(.hero:not(:has(.hero__proof)))` and did nothing at all:
 * `:has()` may not appear inside another `:has()`, so the whole selector was
 * invalid and dropped, silently. The column rule above is a single `:has()`
 * and was always fine, which is why the hero WAS nine columns wide while still
 * carrying the full 96px bottom — the two halves of one intent disagreed and
 * nothing said so. Measured on /contact-us/: 96px of hero padding meeting the
 * next section's 96px left 192px of empty canvas between the booking link and
 * «Στείλτε μας μήνυμα».
 *
 * Two sibling `:has()` at the same level is legal; only nesting is not.
 */
.hero:not(:has(.hero__proof)) .hero__copy { grid-column: span 9; }
.section--hero:has(.hero):not(:has(.hero__proof)) { padding-block-end: var(--space-6); }            /* 48 */
.section--hero:has(.hero):not(:has(.hero__proof)) + .section { padding-block-start: var(--space-6); } /* 48 */

@media (max-width: 768px) {
  .section--hero:has(.hero):not(:has(.hero__proof)) { padding-block-end: var(--space-4); }            /* 32 */
  .section--hero:has(.hero):not(:has(.hero__proof)) + .section { padding-block-start: var(--space-5); } /* 40 */
}

@media (max-width: 1199px) {
  .hero { grid-template-columns: repeat(8, minmax(0, 1fr)); gap: var(--space-5); }
  .hero__copy, .hero__proof { grid-column: 1 / -1; }
}

@media (max-width: 768px) {
  .hero { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-4); }
}

/* ====================================================== SECTION HEADERS */

.section-head { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--grid-gap); align-items: end; margin-block-end: var(--space-5); }
.section-head__copy { grid-column: span 7; }
.section-head__aside { grid-column: 10 / -1; display: flex; justify-content: flex-end; }
.section-head__kicker { margin-block-end: var(--space-1); }

@media (max-width: 1199px) {
  .section-head { grid-template-columns: 1fr; }
  .section-head__copy, .section-head__aside { grid-column: 1 / -1; justify-content: flex-start; }
}

/* ================================================================== BLOG */

/*
 * Masthead and lead article as one opening.
 *
 * Four columns of identity beside eight of article. The masthead is aligned to
 * the top rather than centred: it is a label for the page, and centring it
 * against a tall article card left it floating in the middle of nothing.
 */
.blog-hero { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--grid-gap); align-items: start; }
.blog-hero__masthead { grid-column: span 4; }
.blog-hero__lead { grid-column: 5 / -1; }

/* Category archives and page two have no lead article. */
.blog-hero--no-lead .blog-hero__masthead { grid-column: 1 / -1; }

.blog-hero__masthead > * + * { margin-block-start: var(--space-3); }
.blog-hero__categories ul { display: flex; flex-wrap: wrap; gap: var(--space-2); margin: 0; padding: 0; list-style: none; }
.blog-hero__categories { margin-block-start: var(--space-5); }

/*
 * The lead article stacks: image across the full eight columns, then metadata
 * and headline beneath it. The side-by-side composition it replaces put the
 * headline halfway down the picture and cropped the image to half the width it
 * had available.
 */
.blog-hero__lead .card--post-lead { display: block; }
.blog-hero__lead .card--post-lead .card__media { aspect-ratio: 16 / 9; }
.blog-hero__lead .card--post-lead .card__body { padding-block-start: var(--space-3); }

@media (max-width: 1199px) {
  .blog-hero__masthead,
  .blog-hero__lead { grid-column: 1 / -1; }
}

/* ================================================================ GRIDS */

.grid-cards { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-4) var(--space-3); }
.grid-cards--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid-cards--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
/* A card grid that follows body copy rather than a section header. */
.grid-cards--offset { margin-block-start: var(--space-5); }

@media (max-width: 1199px) { .grid-cards, .grid-cards--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 768px) { .grid-cards, .grid-cards--2, .grid-cards--4 { grid-template-columns: 1fr; gap: var(--space-4); } }

/* Featured work: one project carries visual priority. */
.work-feature { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--grid-gap); }
.work-feature__primary { grid-column: span 8; }
.work-feature__secondary { grid-column: span 4; }

@media (max-width: 1199px) { .work-feature__primary, .work-feature__secondary { grid-column: 1 / -1; } }

/* ======================================================== CAPABILITIES */

/*
 * The hash's 2×2 logic used as information grouping, not as decoration.
 */
.capability-matrix { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1px; background-color: var(--color-border-subtle); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-md); overflow: hidden; }
.capability-matrix__item { padding: var(--space-4); background-color: var(--color-surface-raised); }
.capability-matrix__title { margin-block-end: var(--space-1); }

@media (max-width: 768px) { .capability-matrix { grid-template-columns: 1fr; } }

.split { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--space-6); align-items: start; }
.split__intro { grid-column: span 5; }
.split__body { grid-column: 7 / -1; }

/*
 * Collapsing to one track is part of stacking, not a nicety.
 *
 * A `1 / -1` item spans the twelve tracks AND the eleven gaps between them, so
 * its width is only equal to the container while the gaps still fit. These
 * three grids use the fixed `--space-6` (48px) rather than the responsive
 * `--grid-gap`, so at 390px the eleven column gaps alone came to 528px in a
 * 348px container: the tracks were squeezed to 0 and the stacked item was
 * 528px wide, giving /contact-us/ 164px of horizontal scroll on the page that
 * takes enquiries. Measured on the live site, not inferred.
 *
 * One track has no column gaps to accumulate, so the arithmetic cannot come
 * back whatever any spacing token is later changed to.
 */
@media (max-width: 1199px) {
  .split { grid-template-columns: minmax(0, 1fr); gap: var(--space-4); }
  .split__intro, .split__body { grid-column: 1 / -1; }
}

/* ============================================================= PROCESS */

.process { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-3); margin-block-start: var(--space-5); counter-reset: step; }
.process__step { padding-block-start: var(--space-3); border-block-start: 2px solid var(--color-border-subtle); }
.process__number { display: block; margin-block-end: var(--space-1); color: var(--color-accent-text); font-family: var(--font-display); font-weight: 700; }
.process__body { margin-block-start: var(--space-1); color: var(--color-text-secondary); font-size: var(--type-body-sm); }

/* ======================================================== SERVICE RANGE */

/*
 * The supporting service catalogue: grouped names only. It must read as
 * breadth behind the tailor-made offer, never as twelve competing cards, so
 * there is no card chrome here at all — one rule per column and nothing else.
 */
.service-range { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-4) var(--space-3); }
.service-range__group { padding-block-start: var(--space-3); border-block-start: 2px solid var(--color-border-subtle); }

/* The lead group is the positioning. It gets the accent rule; the rest do not. */
.service-range__group--lead { border-block-start-color: var(--color-accent); }

.service-range__title { margin-block-end: var(--space-2); }
.service-range__list { list-style: none; margin: 0; padding: 0; color: var(--color-text-secondary); font-size: var(--type-body-sm); }
.service-range__list li + li { margin-block-start: var(--space-1); }

@media (max-width: 1199px) { .service-range { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-4); } }
@media (max-width: 768px) { .service-range { grid-template-columns: 1fr; } }

@media (max-width: 1199px) { .process { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-4); } }
@media (max-width: 768px) { .process { grid-template-columns: 1fr; } }

/* ======================================================== CASE STUDY */

/*
 * Case-study hero: copy on five columns, the work on seven.
 *
 * The image is the reason the page exists, so it gets the larger share and sits
 * on the first screen. `align-items: center` keeps a short title from leaving
 * the picture stranded low in the band.
 */
.case-hero { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--grid-gap); align-items: center; }
.case-hero__copy { grid-column: span 5; }
.case-hero__media { grid-column: 6 / -1; }

/* Nothing to show beside the copy: widen it rather than leave seven empty columns. */
.case-hero--no-media .case-hero__copy { grid-column: span 9; }

.case-hero__media img {
  inline-size: 100%;
  block-size: auto;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  border-radius: var(--radius-md);
}

/*
 * The specification, as a band rather than a rail.
 *
 * Set on the navy surface: these are the facts a reader checks rather than
 * reads, and giving them their own information surface stops them competing
 * with the project for the opening.
 */
.case-facts-band .facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: var(--space-4) var(--space-5);
}

/*
 * The scope of work is not the same shape as the other facts.
 *
 * Type, client, delivery date and domain are two or three words each. What was
 * delivered runs to about forty. In equal columns that one cell wrapped to ten
 * lines and set the height of the whole band, leaving four columns of empty
 * navy beside a wall of text.
 *
 * It gets its own full-width row underneath instead, where the same text sets
 * in two comfortable lines. Reading order is unchanged — the short facts are
 * scanned, then the scope is read.
 */
.case-facts-band .facts__item--scope {
  grid-column: 1 / -1;
  padding-block-start: var(--space-3);
  border-block-start: 1px solid var(--color-border-inverse);
}

.case-facts-band .facts__item--scope .facts__value { max-inline-size: var(--measure-lead); }

.facts { display: flex; flex-direction: column; gap: var(--space-3); }
.facts__item { display: flex; flex-direction: column; gap: var(--space-1); }
.facts__label { color: var(--color-text-secondary); font-size: var(--type-caption); font-weight: 650; letter-spacing: 0.035em; text-transform: uppercase; }
.facts__value { font-size: 0.9375rem; }

/*
 * "δεν είναι πλέον ενεργό" beside a domain that is no longer a link. Set at the
 * label's weight and colour so it reads as metadata about the row rather than as
 * a warning — the project is still work worth showing.
 */
.facts__note {
  display: block;
  margin-block-start: var(--space-1);
  color: var(--color-text-muted);
  font-size: var(--type-caption);
}

@media (max-width: 1199px) {
  .case-hero__copy, .case-hero__media, .case-hero--no-media .case-hero__copy { grid-column: 1 / -1; }
  /* The facts rail becomes a horizontal grid below the introduction. */
  .facts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-3); }
}

@media (max-width: 768px) { .facts, .case-facts-band .facts { grid-template-columns: 1fr; } }

.case-section { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--grid-gap); }
.case-section__heading { grid-column: span 4; }
.case-section__body { grid-column: 5 / 11; max-inline-size: var(--measure-body); }
.case-section__aside { grid-column: 11 / -1; }

@media (max-width: 1199px) {
  .case-section__heading, .case-section__body, .case-section__aside { grid-column: 1 / -1; }
}

.metrics { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-3); }
.metric { padding: var(--space-3); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-md); }
.metric__value { font-family: var(--font-display); font-size: 2.5rem; font-weight: 700; line-height: 1; }
.metric__label { margin-block-start: var(--space-1); font-weight: 600; }
/* A number without its measurement context is meaningless — the context slot
   is part of the component, not optional decoration. */
.metric__context { margin-block-start: var(--space-1); color: var(--color-text-secondary); font-size: var(--type-body-sm); }

@media (max-width: 1199px) { .metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .metrics { grid-template-columns: 1fr; } }

.screens { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--grid-gap); }
.screens__key { grid-column: 1 / -1; }
.screens__support { grid-column: span 6; }
.screens__minor { grid-column: span 4; }

@media (max-width: 768px) { .screens__support, .screens__minor { grid-column: 1 / -1; } }

.next-project { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--grid-gap); align-items: center; }
.next-project__media { grid-column: span 5; }
.next-project__copy { grid-column: span 7; }

@media (max-width: 768px) {
  .next-project__media, .next-project__copy { grid-column: 1 / -1; }
  /* Mobile order: image → label/title. */
  .next-project__media { order: -1; }
}

/* ========================================================== READING */

/*
 * Service body: the same 7 / 5 as the hero above it, not a centred column.
 *
 * The body used to sit in a centred `.container` under a `.container--wide`
 * hero, so it started 260px right of the H1 and aligned with nothing on the
 * page. Measured on /services/φιλοξενία-ιστοσελίδων/ at 1440: a 622px column
 * of 4,090 characters, 5,567px tall, floating in the middle of the canvas.
 *
 * The line length was never the problem — 622px is about 68 Greek characters,
 * which is right. The problem was that the column had no relationship to
 * anything and no navigation once the hero scrolled away. So it now starts
 * where the H1 starts, and the jump list rides beside it instead of
 * disappearing with the hero.
 */
.service-layout {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  /* 48px, the same gutter every other 7 / 5 split on the site uses. */
  gap: var(--space-6);
  align-items: start;
}

.service-layout__body { grid-column: span 7; max-inline-size: none; margin-inline: 0; }

/*
 * A right-hand rail, so its rule is the mirror of `.article-toc`, not a reuse
 * of it. The first attempt put both classes on the nav; `.article-toc` is
 * declared later in this file at the same specificity, so it won — the rail
 * jumped back to column 1 and brought its left-rail border with it, on the
 * wrong side. The list styling is shared; the side is not.
 */
/*
 * The jump list is a panel, not a hairline rail.
 *
 * It was a navy panel when it lived in the hero; moving it beside the body
 * turned it into a left border and a column of grey links, which is a weaker
 * thing on a page whose whole right side is otherwise empty. The panel is
 * also what makes it read as one object while it travels down the page.
 *
 * `surface-panel` on the element itself supplies the navy and every inverse
 * text colour — heading, micro-label, links, link hover — so nothing here
 * restates a colour, and the palette stays editable in one place.
 */
.service-layout__toc {
  grid-column: 8 / -1;
  position: sticky;
  inset-block-start: calc(var(--header-height) + var(--space-3));
  padding: var(--space-3);
  border-radius: var(--radius-md);
}

.service-layout__toc .article-toc__list { margin-block-start: var(--space-2); }

/* One column below the breakpoint the rest of the site collapses at. */
@media (max-width: 1199px) {
  .service-layout { grid-template-columns: minmax(0, 1fr); }
  .service-layout__body { grid-column: 1 / -1; }
  /* Below the breakpoint it stops being a rail, but stays a panel. */
  .service-layout__toc { grid-column: 1 / -1; position: static; margin-block-start: var(--space-6); }
}

.reading { max-inline-size: var(--container-reading); margin-inline: auto; }
.reading > * + * { margin-block-start: 1.25em; }
.reading h2 { margin-block: 3.5rem 1.25rem; }
.reading h3 { margin-block: 2.5rem 1rem; }
.reading h4 { margin-block: var(--space-4) 0.75rem; }
.reading img { border-radius: var(--radius-sm); }
.reading > figure { margin-block: var(--space-4); }
/* A deliberate breakout for an exceptional screenshot. */
.reading > figure.is-wide { max-inline-size: 70rem; margin-inline: calc(50% - 35rem); }

@media (max-width: 1200px) { .reading > figure.is-wide { max-inline-size: 100%; margin-inline: 0; } }

/* Legal pages run slightly wider than editorial text — clauses get dense. */
.reading--legal { max-inline-size: 72ch; }

/* ============================================================ ARTICLE */

/*
 * ARTICLE — a reading template, not a page with an article in it.
 *
 * Masthead is 7 / 5: copy beside the lead image rather than above it. The image
 * used to span all twelve columns underneath the title, which pushed the opening
 * sentence off the first screen and left the copy stranded on the left of an
 * empty row. Beside the title it does the job it is there for — telling the
 * reader what the piece is about before they commit to it.
 */
.article-hero { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--grid-gap); align-items: start; }
.article-hero__copy { grid-column: 1 / 8; }
.article-hero__media { grid-column: 9 / -1; }

.article-hero__media img { inline-size: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: var(--radius-xs); }

/* A long Greek title running to three lines beats shrinking the type. */
.article-title { max-inline-size: 45rem; }

.article-standfirst {
  margin-block-start: var(--space-3);
  max-inline-size: 41rem;
  color: var(--color-text-secondary);
  font-size: 1.25rem;
  line-height: 1.55;
}

/*
 * The information rail: one ruled line between the masthead and the reading.
 * It answers "how long is this?" before the reader has to guess, and it names
 * the publisher rather than inventing an author.
 */
.article-rail-band { border-block: 1px solid var(--color-border-subtle); }

.article-rail {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-6);
  margin: 0;
}

.article-rail__item { display: flex; flex-direction: column; gap: 2px; }
.article-rail__label { color: var(--color-text-secondary); font-size: var(--type-caption); font-weight: 600; letter-spacing: 0.035em; text-transform: uppercase; }
.article-rail__value { margin: 0; font-size: 0.9375rem; }

/*
 * Body: a jump-list rail, the article, and room to breathe.
 *
 * The article column lands near 40rem, which is where continuous Greek prose
 * stops being tiring. The rail is only rendered from three sections up — below
 * that a table of contents is longer than the navigation it saves.
 */
.article-layout {
  display: grid;
  grid-template-columns: 3fr 7fr 2fr;
  gap: var(--grid-gap);
  align-items: start;
}

.article-layout > .article-body { grid-column: 2; }
.article-layout--tail > * { grid-column: 2; }

/* No rail: the article keeps its column rather than sliding left. */
.article-layout:not(:has(.article-toc)) > .article-body { grid-column: 2; }

/*
 * The article rail is a panel, for the same reason the service rail is.
 *
 * These two jump lists do the same job on the same kind of page, so they
 * should not be two different objects — one a navy panel and the other a
 * hairline. `surface-panel` on the element supplies the navy and every
 * inverse text colour, so nothing here restates a colour.
 */
.article-toc {
  grid-column: 1;
  position: sticky;
  inset-block-start: calc(var(--header-height) + var(--space-3));
  padding: var(--space-3);
  border-radius: var(--radius-md);
}

.article-toc__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin-block-start: var(--space-2);
  padding: 0;
  list-style: none;
  counter-reset: shellit-toc;
}

.article-toc__list a {
  display: block;
  padding-block: var(--space-1);
  color: var(--color-text-secondary);
  font-size: 0.875rem;
  line-height: 1.35;
  text-decoration: none;
}

.article-toc__list a:hover { color: var(--color-link); text-decoration: underline; }

@media (max-width: 1199px) {
  .article-hero__copy, .article-hero__media { grid-column: 1 / -1; }
  .article-hero__media { margin-block-start: var(--space-4); }

  /*
   * The rail stops being a rail. A sticky column beside a single-column
   * article on a tablet is a column of nothing, so the jump list becomes an
   * ordinary block above the text and stops sticking.
   */
  .article-layout { grid-template-columns: 1fr; }
  .article-layout > .article-body,
  .article-layout--tail > * { grid-column: 1; }

  /* Below the breakpoint it stops being a rail, but stays a panel. */
  .article-toc {
    grid-column: 1;
    position: static;
    margin-block-end: var(--space-5);
  }
}
.article-meta { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-2); align-items: center; margin-block-start: var(--space-3); color: var(--color-text-secondary); font-size: var(--type-body-sm); }


.share { display: flex; flex-wrap: wrap; gap: var(--space-1); align-items: center; margin-block-start: var(--space-6); padding-block-start: var(--space-3); border-block-start: 1px solid var(--color-border-subtle); }

/* ============================================================= CONTACT */

.contact-layout { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--space-6); align-items: start; }
/*
 * 7 / 5, the same split and the same 48px gutter as every hero on the site.
 *
 * The rail used to start at line 9, which skipped column 8 and made the space
 * between the form and the rail 159px — while the identical "text left, panel
 * right" relationship in every hero measured 48px. One page reading three
 * times wider than the rest is the kind of inconsistency that has no reason
 * anyone can name, and it also cost the rail a whole column of width.
 */
.contact-layout__form { grid-column: span 7; }
.contact-layout__rail { grid-column: 8 / -1; }

/*
 * The rail travels with the form instead of stopping a third of the way down
 * it.
 *
 * Measured at 1440: the rail ends after the booking card while the form runs on
 * for roughly another 650px, so the right half of the page goes empty exactly
 * where someone is deciding whether to finish the form or just phone. The fix
 * is not to invent something to put there — it is to keep what is already
 * there, which is the phone number and the booking card, in view while they
 * decide.
 *
 * `align-items: start` above is what makes this possible: a stretched grid
 * item is as tall as its row, and a sticky element cannot move inside a box
 * that is already the full height of its container.
 */
@media (min-width: 1200px) {
  .contact-layout__rail {
    position: sticky;
    /* Clear of the sticky header, which the site sets in the same variable. */
    inset-block-start: calc(var(--header-height) + var(--space-3));
  }
}

@media (max-width: 1199px) {
  .contact-layout { grid-template-columns: minmax(0, 1fr); }
  .contact-layout__form, .contact-layout__rail { grid-column: 1 / -1; }
}

.contact-rail__item { padding-block: var(--space-2); border-block-end: 1px solid var(--color-border-subtle); }
.contact-rail__label { color: var(--color-text-secondary); font-size: var(--type-caption); font-weight: 650; letter-spacing: 0.035em; text-transform: uppercase; }

/* ============================================================ SEARCH */

.search-results { list-style: none; margin: 0; padding: 0; }
.search-result { padding-block: 1.75rem; border-block-end: 1px solid var(--color-border-subtle); }
.search-result__type { margin-block-end: var(--space-1); }

/* ================================================================ 404 */

.error-404 { max-inline-size: 45rem; margin-inline: auto; padding-block: var(--space-12); text-align: start; }

@media (max-width: 768px) { .error-404 { padding-block: var(--space-8); } }

/* ========================================================== PRODUCTS */

.product-status { display: inline-flex; align-items: center; gap: var(--space-1); font-weight: 700; }
/* Status is always textual — the marker only reinforces it. */
.product-status__marker { font-size: 1.1em; line-height: 1; }
.product-status--shipped { color: var(--color-success); }
.product-status--beta { color: var(--color-info); }
.product-status--development { color: var(--color-text-secondary); }

.product-feature { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--space-6); align-items: center; }
.product-feature__copy { grid-column: span 5; }
.product-feature__media { grid-column: 6 / -1; }

@media (max-width: 1199px) {
  .product-feature { grid-template-columns: minmax(0, 1fr); }
  .product-feature__copy, .product-feature__media { grid-column: 1 / -1; }
}

.roadmap { list-style: none; margin: 0; padding: 0; }
.roadmap__item { display: grid; grid-template-columns: 10rem 1fr; gap: var(--space-2); padding-block: var(--space-2); border-block-end: 1px solid var(--color-border-subtle); }
.roadmap__phase { color: var(--color-text-secondary); font-weight: 650; }

@media (max-width: 560px) { .roadmap__item { grid-template-columns: 1fr; gap: var(--space-0-5); } }

/* A button pair or standalone link that follows a matrix or a card row. */
.button-group--offset,
.split__action { margin-block-start: var(--space-5); }
