/* EU Alternatives vertical. Generated by build-eu.mjs from src/eu/eu-theme.css
   — do not edit by hand. Every selector is scoped under .eu and every colour,
   radius, shadow and type size is a house token; both are gated at build. */
/* EU Alternatives vertical — the vertical's ONLY stylesheet.
   ===========================================================================
   Emitted by build-eu.mjs as dist/assets/css/eu-alternatives.css. Nothing else
   is concatenated into it: the Astro export's own sheet is no longer shipped.

   WHY THE EXPORT SHEET IS GONE
   The export was a dark-first glassmorphism site with its own token layer
   (--clr-*, --bg-*, --text-*, --radius-*, --shadow-*), its own type scale, its
   own button geometry and thirty hex values outside the Growack palette. Every
   one of those was a divergence that had to be over-painted rule by rule, and
   the over-paint could never win against the export's ~90 inline style
   attributes. Both are now removed at build time. What is left is this file.

   THE ONE RULE THIS FILE OBEYS
   It declares NO colour, NO radius, NO shadow and NO type size of its own. It
   consumes the house tokens on :root from styles.css / premium.css / v2.css:

     --color-bg --color-surface --color-surface-alt --color-border
     --color-text --color-text-muted --color-primary --color-primary-bright
     --color-primary-hover --color-primary-soft --color-teal --color-teal-soft
     --font-heading --font-body --fs-* --space-* --section-y --container
     --gutter --radius* --shadow-* --header-h --ease

   so a change to the house palette or rhythm reaches the vertical by
   construction and the two can never drift again. build-eu.mjs enforces this:
   a literal hex colour anywhere in this file FAILS THE BUILD.

   SCOPE
   Every selector begins `.eu` (or `.js .eu` / `.eu.is-…`). build-eu.mjs walks
   the emitted sheet and throws on any selector that does not, so the vertical
   cannot reach the 48 core pages and the core pages cannot be reached from it.
   Where a house component needed a vertical-only adjustment (the comparison
   marks, the tab panel's no-JS default) the override is written as
   `.eu .house-class`, which is scoped and never global.

   REUSE BEFORE INVENTION
   Cards, buttons, badges, chips, eyebrows, leads, sections, grids, tabs, the
   comparison columns, the arrow link and the container are the SAME classes
   the 48 core pages use — build-eu.mjs maps the export's class names onto them
   (see CLASS_MAP there). This file styles only what the main site has no
   component for: the directory shell, the category rail, the breadcrumb strip,
   the directory listing furniture, the company profile and the search.
   ========================================================================= */

/* ---- 1. scope root ------------------------------------------------------ */

.eu {
  /* Structural measurements only. No colour, no type, no radius: those are
     house tokens, read directly at the point of use. */
  --eu-rail: 248px;          /* category rail width inside the house column */
  --eu-rail-gap: var(--space-8);
  --eu-strip-y: var(--space-4);

  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
}

/* ---- 2. shell: the vertical sits INSIDE the house column ---------------- */
/* Before: a 280px rail outside the container pushed content to x=280 and the
   card to x=460, so nothing in the vertical lined up with the header above it
   or the footer below it. The layout is now the house .container: same
   max-width, same gutter, same edges as every other page on the site. */

.eu .eu-app-layout {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
  display: grid;
  grid-template-columns: var(--eu-rail) minmax(0, 1fr);
  gap: var(--eu-rail-gap);
  align-items: start;
}

/* The inset panel. ONE object next to the rail, not a stack of loose strips:
   a house surface, a hairline, the house large radius, and its own corners
   clipped so the bands inside end where the panel ends. The bands keep their
   tonal alternation and run edge to edge within it, which is what turns the
   pairing into furniture — a rail and a document panel — rather than a rail
   with page fragments floating beside it. */
.eu .eu-app-main {
  min-width: 0;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  overflow: clip;
}

/* A .container nested inside the already-constrained content column would
   double the gutter and re-narrow the copy: the shell above already set the
   measure, so it stops being a max-width here. It still owns the INNER
   gutter, because the panel itself carries no inline padding — that is what
   lets a band's tone reach the panel edge while its content stays inset. */
.eu .eu-app-main .container {
  max-width: none;
  padding-inline: clamp(var(--space-5), 2.6vw, var(--space-8));
}

/* ---- 3. section rhythm and banding -------------------------------------- */
/* The house drives every section from --section-y (100.8px at 1440, 56px at
   390). The vertical used ad hoc 24/32/40/48/80px and never read the token.
   build-eu.mjs now emits `section` on every export section, so the rhythm is
   inherited; these rules only handle the vertical's own first/last-child
   trims and its surface banding. */

.eu .eu-directory {
  background: var(--color-surface);
  border-radius: var(--radius-lg);
  border: 1px solid var(--color-border);
  padding-inline: clamp(var(--space-5), 3vw, var(--space-12));
  margin-block-end: var(--section-y);
}

/* The hero is the page's opening band, not a card. */
.eu .eu-hero {
  background: transparent;
  border: 0;
  padding-block: clamp(40px, 5vw, 72px) var(--section-y);
  text-align: start;
}
.eu .eu-hero .eu-hero-content {
  max-width: 720px;
  margin-inline: 0;
}
.eu .eu-hero .eyebrow {
  justify-content: flex-start;
}

.eu .eu-hero-cta {
  display: grid;
  justify-items: start;
  gap: var(--space-6);
  margin-top: var(--space-8);
}

/* The export drew an 800px blurred radial glow behind the hero. */
.eu .eu-hero-bg-glow {
  display: none;
}
.eu .eu-relative-wrapper {
  position: relative;
}

/* ---- 4. typography ------------------------------------------------------ */
/* Headings are the house scale and the house weights. The export ran h1 at
   700 with positive tracking and CSS-uppercased every company name, which
   restyled Sushil's product names into shouting; sentence case is restored
   and the copy itself is untouched. */

.eu h1,
.eu h2,
.eu h3,
.eu h4 {
  font-family: var(--font-heading);
  color: var(--color-text);
  text-transform: none;
}

.eu h1 {
  font-size: var(--fs-h1);
  font-weight: 800;
  line-height: 1.2;
  letter-spacing: -0.03em;
}
.eu h2 {
  font-size: var(--fs-h2);
  font-weight: 800;
  line-height: 1.22;
  letter-spacing: -0.035em;
}
.eu h3 {
  font-size: var(--fs-h4);
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -0.02em;
}

.eu p {
  font-size: var(--fs-body);
  line-height: 1.6;
  color: var(--color-text);
}
.eu .lead,
.eu .section-head p {
  color: var(--color-text-muted);
}
.eu .muted {
  color: var(--color-text-muted);
}

/* The section head is the house component; the vertical only asks it to keep
   the page-title variant left-aligned and to carry a hairline. */
.eu .section-head {
  margin-bottom: var(--space-8);
}
.eu .eu-page-head {
  border-bottom: 1px solid var(--color-border);
  padding-bottom: var(--space-5);
}

/* ---- 5. breadcrumb strip ------------------------------------------------ */
/* Genuinely new: the 48 core pages have no breadcrumb. Built from house
   tokens, sized above the 12px floor, AA on the surface it sits on. */

.eu .eu-breadcrumb-nav {
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
  margin-inline: calc(-1 * clamp(var(--space-5), 3vw, var(--space-12)));
  padding: var(--eu-strip-y) clamp(var(--space-5), 3vw, var(--space-12));
  margin-block-end: var(--space-8);
}
.eu .eu-breadcrumb-list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--fs-sm);
  text-transform: none;
  letter-spacing: 0;
}
.eu .eu-breadcrumb-item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
}
.eu .eu-breadcrumb-item + .eu-breadcrumb-item::before {
  content: "";
  width: 5px;
  height: 5px;
  flex: none;
  border-radius: 50%;
  background: var(--color-border);
}
.eu .eu-breadcrumb-link {
  color: var(--color-text-muted);
  font-weight: 500;
}
.eu .eu-breadcrumb-link:hover {
  color: var(--color-primary);
}
.eu .eu-breadcrumb-current {
  color: var(--color-text);
  font-weight: 600;
}

/* ---- 6. category rail --------------------------------------------------- */
/* The one place the vertical has to invent: 449 products across 62 categories
   need persistent navigation and the core pages have no rail pattern. It is
   built entirely from house tokens and it now lives INSIDE the house column,
   which is what put the content edges back on the header's line. */

.eu .eu-sidebar {
  position: sticky;
  top: calc(var(--header-h) + var(--space-4));
  max-height: calc(100vh - var(--header-h) - var(--space-8));
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--color-surface-alt);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
}

.eu .eu-sidebar-title {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--color-primary);
  margin-bottom: var(--space-4);
}
.eu .eu-sidebar-title::before {
  content: "";
  width: 22px;
  height: 1.5px;
  background: var(--color-primary);
  display: inline-block;
}

.eu .eu-sidebar-nav {
  display: grid;
  gap: 2px;
}
.eu .eu-sidebar-group {
  position: relative;
}
.eu .eu-sidebar-link,
.eu .eu-sidebar-sublink {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 9px 10px;
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
  font-weight: 500;
  line-height: 1.35;
  color: var(--color-text);
  text-transform: none;
  letter-spacing: 0;
}
/* The group link used to reserve --space-8 on the right for a collapse chevron
   that no longer exists, which left its count pill floating 32px short of the
   sublinks' pills below it. Same padding as the sublinks now, so every count
   in the rail lines up on one right edge whatever the sector name does. */
.eu .eu-sidebar-link { padding-right: 10px; }
.eu .eu-sidebar-link:hover,
.eu .eu-sidebar-sublink:hover {
  background: var(--color-surface);
  color: var(--color-primary);
  text-decoration: none;
}
.eu .eu-sidebar-link.is-active,
.eu .eu-sidebar-sublink.is-active,
.eu .eu-sidebar-link[aria-current="page"],
.eu .eu-sidebar-sublink[aria-current="page"] {
  background: var(--color-surface);
  border-left: 2px solid var(--color-primary);
  color: var(--color-primary);
  font-weight: 600;
}
.eu .eu-sidebar-link i,
.eu .eu-sidebar-sublink i {
  flex: none;
  font-size: 1.05rem;
  color: var(--color-teal);
}
.eu .eu-sidebar-link.is-active i,
.eu .eu-sidebar-link[aria-current="page"] i {
  color: var(--color-primary);
}
.eu .eu-grow {
  flex-grow: 1;
  min-width: 0;
}

.eu .eu-sidebar-count {
  flex: none;
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-xs);
  font-weight: 600;
  padding: 2px 8px;
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  color: var(--color-text-muted);
}
.eu .eu-sidebar-link.is-active .eu-sidebar-count,
.eu .eu-sidebar-sublink.is-active .eu-sidebar-count,
.eu .eu-sidebar-link[aria-current="page"] .eu-sidebar-count,
.eu .eu-sidebar-sublink[aria-current="page"] .eu-sidebar-count {
  background: var(--color-teal-soft);
  border-color: var(--color-teal-soft);
  color: var(--color-teal);
}

.eu .eu-sidebar-subnav {
  display: grid;
  gap: 1px;
  margin: 2px 0 var(--space-3) var(--space-4);
  padding-left: var(--space-3);
  border-left: 1px solid var(--color-border);
}
/* ---- 6b. the rail's TOOLS block ----------------------------------------
   /compare/ and /suggest/ are DESTINATIONS, not a 63rd category, and the rail
   has to say so without inventing a second visual language for a link. So the
   link itself is .eu-sidebar-link unchanged — identical type, padding, radius,
   icon size, hover, focus and active state as the eight sector links, which is
   the whole point: they are peers of the sectors, not a lesser row. Three
   things separate them, and all three are absences or containers rather than
   restyles:
     · a hairline and a gap above, so the eye reads a break;
     · their own label, so the group is named rather than merely spaced;
     · NO count pill, because a tool has nothing to count. That gap on the
       right is the clearest signal in the block that these two are a different
       kind of thing, and it costs no ink.
   The label is a .eu-sidebar-title one step down: same uppercase micro-caps
   and tracking, but muted rather than orange and with no leading rule, so it
   sits under "DIRECTORY" in the hierarchy instead of beside it. */
/* STICKY TO THE FOOT OF THE RAIL, and this is the one property the block does
   not share with a sector link. Measured: on a Hosting & Infrastructure page
   the rail's own content is 1456px inside a 796px scrollport, so a block in
   normal flow at the end of it sits 600px below the fold and the reader has to
   scroll a sidebar to find out the page exists — which is the problem this
   change was made to fix, reproduced one level down. Pinned to the foot it is
   on screen on all 523 pages at every scroll position, in source order after
   the sectors, and nothing is permanently hidden behind it: scroll the rail to
   its end and the block is simply in its natural place. */
.eu .eu-sidebar-sect {
  position: sticky;
  /* NOT `bottom: 0`. Measured: a scroll container constrains a sticky child to
     its CONTENT box, not its padding box, so `bottom: 0` parked the block 21px
     short of the rail's inner edge and left a strip of the sector nav visibly
     scrolling underneath it — the one thing a pinned footer must not do. One
     rail padding lower puts its border box on the rail's padding box, flush
     inside the hairline. */
  bottom: calc(-1 * var(--space-5));
  margin-top: var(--space-4);
  /* Its own bottom padding fills the rail's, pulled up by the negative margin,
     so the pinned block reaches the rail's inner edge instead of floating one
     gutter above it with a strip of scrolling nav showing underneath. Vertical
     only — a horizontal bleed would put the block wider than the scrollport
     and can cost a 1px horizontal scrollbar inside the rail. */
  padding: var(--space-4) 0 var(--space-5);
  margin-bottom: calc(-1 * var(--space-5));
  border-top: 1px solid var(--color-border);
  background: var(--color-surface-alt);
}
.eu .eu-sidebar-subtitle {
  display: block;
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--color-text-muted);
  margin-bottom: var(--space-2);
}
/* NO rule for the tool link itself, deliberately. It is .eu-sidebar-link with
   nothing added and nothing taken away — the moment this block starts carrying
   its own padding, weight or colour, a tool stops being the same object as a
   sector and the rail has two link styles to keep in step forever. */

/* (.eu-collapse-toggle-btn / .eu-collapse-icon / .eu-sidebar-group.eu-collapsed
   are gone. The chevron that collapsed the open sector's subnav measured 8x8
   with a zero-size glyph — an invisible control that was still a tab stop on
   519 pages. It is not restyled, it is removed: what it hid was the branch the
   reader is standing in. Every element left in the rail is a destination.) */

/* ---- 7. directory listing ----------------------------------------------- */
/* The cards themselves are the house .card.card--tile — surface, hairline,
   18px radius, the two-stop lift and the alternating orange/teal top rule all
   come from the main site's own component. What is left here is the furniture
   inside a directory card, which the main site has no equivalent for. */

.eu .eu-category-grid,
.eu .eu-bento-grid {
  display: grid;
  gap: var(--space-6);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr));
}

.eu .eu-product-card,
.eu .eu-bento-card,
.eu .eu-feature-card {
  gap: var(--space-3);
}
.eu .eu-product-card[onclick],
.eu .eu-bento-card[onclick] {
  cursor: pointer;
}
.eu .eu-product-card > p,
.eu .eu-feature-card > p {
  color: var(--color-text-muted);
  font-size: var(--fs-sm);
  line-height: 1.6;
}

.eu .eu-product-header,
.eu .eu-bento-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  flex-wrap: wrap;
}
.eu .eu-tag-row,
.eu .eu-bento-tags {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.eu .eu-bento-tags {
  margin-bottom: var(--space-4);
}

/* Icons. The export sized every glyph inline (3rem on a company page, 1.25rem
   in a list); the sizes now live here so a glyph cannot out-specify the sheet. */
.eu .eu-product-icon {
  font-size: 1.5rem;
  color: var(--color-teal);
  line-height: 1;
}
.eu .eu-company-list-icon {
  font-size: 1.15rem;
  color: var(--color-text-muted);
  line-height: 1;
}
.eu .eu-lg-icon {
  font-size: 2rem;
  color: var(--color-teal);
  line-height: 1;
}
.eu .eu-icon-box,
.eu .eu-bento-icon-wrapper {
  display: inline-grid;
  place-items: center;
  flex: none;
  width: 44px;
  height: 44px;
  border-radius: var(--radius);
  background: var(--color-primary-soft);
  color: var(--color-primary);
  font-size: 1.35rem;
}
.eu .eu-bento-icon-wrapper--lg {
  width: 64px;
  height: 64px;
  font-size: 2rem;
  border-radius: var(--radius-lg);
  margin-bottom: var(--space-5);
}

/* A card's closing rule and forward link. */
.eu .eu-card-foot {
  margin-top: auto;
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}
.eu .eu-card-foot .link-arrow {
  width: 100%;
  justify-content: space-between;
}

/* The group page's 3-product preview list. */
.eu .eu-company-list {
  display: grid;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
  flex-grow: 1;
}
.eu .eu-company-list-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: var(--color-surface-alt);
  border: 1px solid transparent;
}
.eu .eu-company-list-item:hover {
  background: var(--color-teal-soft);
  border-color: var(--color-teal-soft);
  text-decoration: none;
}
.eu .eu-company-list-label {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--color-text);
  text-transform: none;
  min-width: 0;
}

/* Empty listing (spelling-grammar ships zero products). */
.eu .eu-empty {
  grid-column: 1 / -1;
  text-align: center;
  padding: var(--space-12) var(--space-6);
  background: var(--color-surface-alt);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
}

/* ---- 8. company profile ------------------------------------------------- */

.eu .eu-company-detail-card {
  max-width: 820px;
  margin-inline: auto;
}
.eu .eu-company-detail-card .eu-product-header {
  display: block;
  padding-bottom: var(--space-6);
  margin-bottom: var(--space-6);
  border-bottom: 1px solid var(--color-border);
}
.eu .eu-company-detail-card .eu-product-icon {
  display: block;
  font-size: 2.25rem;
  margin-bottom: var(--space-4);
}
.eu .eu-company-detail-card h1 {
  margin-bottom: var(--space-4);
}
.eu .eu-company-content {
  color: var(--color-text);
}
.eu .eu-company-content p + p {
  margin-top: var(--space-5);
}
.eu .eu-company-cta {
  margin-top: var(--space-8);
}

/* ---- 8b. the editorial page head (/compare, /blog, /suggest) ------------ */
/* The three editorial pages arrived as one undifferentiated panel: the page's
   real title was an h2 inside the content card, there was no eyebrow, and the
   whole page was a single surface. The transform lifts the title out into this
   band — the house .page-hero shape, on the page field, above the white
   .eu-directory card — so each page reads as a head and a body, which is how
   every one of the 48 core pages reads.

   Left-aligned, unlike .eu-hero on the index: that one is a marketing front
   door and is centred; these are documents. */

.eu .eu-page-hero {
  background: transparent;
  border: 0;
}
/* (The `.eu .eu-app-main .eu-page-hero` trim that used to live here is gone.
   It compensated for a breadcrumb that bled across the top of the content
   column with no band of its own, so it doubled the head's top step. The panel
   now holds a `.eu-bands` stack in which the breadcrumb IS a band with its own
   padding and its own closing hairline, so the house .page-hero step applies
   unaltered and the h1 sits on a core page's baseline whether the rail is
   there or not. Reinstating the rail changed the FRAME, not the page.) */
.eu .eu-page-hero .lead {
  margin-top: var(--space-5);
}

/* ---- 9. comparison ------------------------------------------------------ */
/* ONE comparison panel, not two floating cards.
   The export shipped two detached lists whose only distinguishing marks were
   green #166534 and red #B91C1C, both outside the fixed palette, and whose
   active tab computed identically to the resting tabs, so a reader could not
   tell which panel was showing OR which column was which.

   The columns, the lists and the circular marks are still the house .compare
   component — every rule below either unifies the two halves into a single
   bordered surface (.eu-vs) or swaps a colour for a house token:
   (a) teal for the favoured side, neutral grey for the other, which is the
       pattern the core pages already use;
   (b) the house .tab-panel is display:none by default, which would leave the
       page blank without JS. All three panels render; JS then shows one.

   What this does NOT do is align the two lists into shared rows. That would
   assert that item n on the left is answered by item n on the right, and his
   data does not carry it: on Drive Storage "Basic encryption" is answered by
   the FIRST item on the EU side, not the fourth. The pairing is not in the
   export, so it is not drawn. */

.eu .eu-comparison-section,
.eu .eu-features,
.eu .eu-submit-section {
  /* Section wrappers. The rhythm and the band come from the house .section and
     .eu-directory the transform emits alongside these markers; the marker
     itself exists so an archetype can target one section without a new class. */
  position: relative;
}
.eu .eu-comparison-content {
  display: block;
}

/* The widget is a plain wrapper now: each panel carries its own bordered
   surface, and a card inside a card inside the .eu-directory card was three
   nested boxes for one comparison. */
.eu .eu-comparison-widget {
  background: transparent;
  border: 0;
  padding: 0;
}
.eu .tabs-head {
  margin-bottom: var(--space-8);
}
/* The tab strip scrolls rather than wraps. The house .tabs-head wraps, and the
   three labels do not fit on one line below about 430px: the strip then ran two
   rows, and the active tab's underline is drawn at the BOTTOM of the button, so
   on the first row it floated in mid-air well above the strip's own rule. One
   line that scrolls keeps the underline on the rule at every width. The 1px
   pad is what stops overflow clipping that underline, which sits at -1px. */
.eu .eu-vs-tabs {
  flex-wrap: nowrap;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  padding-bottom: 1px;
  /* No scrollbar: it painted a grey track directly over the strip's own rule
     and over the active tab's underline, which is the one mark that says which
     panel is showing. The clipped third label at the edge is the affordance,
     and arrow-key navigation scrolls the focused tab into view. */
  scrollbar-width: none;
}
.eu .eu-vs-tabs::-webkit-scrollbar {
  display: none;
}
/* The tab controls are anchors, not buttons, so that without JS they are jump
   links to panels that are all on the page. The house .tab-btn is styled for a
   <button>; these are the only differences an anchor in a scroller needs. */
.eu .eu-vs-tabs .tab-btn {
  flex: 0 0 auto;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
}
.eu .eu-vs-tabs .tab-btn:hover {
  text-decoration: none;
}

.eu .eu-vs-title {
  margin-bottom: var(--space-6);
}
/* With JS one panel shows at a time and the active tab already names it, so the
   heading would say the same word twice. It stays in the document for the
   outline and for anyone reading without JS. */
.js .eu .eu-vs-title {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.eu .eu-vs {
  gap: 0;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.eu .eu-vs .compare-col {
  display: flex;
  flex-direction: column;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: var(--color-surface);
  box-shadow: none;
}
.eu .eu-vs .compare-col + .compare-col {
  border-left: 1px solid var(--color-border);
}
/* The house 4px rule caps the favoured column. Teal, not the house orange:
   orange is the vertical's own accent everywhere else and would stop reading as
   "this is the side being recommended". */
.eu .eu-vs .compare-col--good::before {
  background: var(--color-teal);
}

.eu .eu-vs__head {
  padding: var(--space-5) var(--space-6);
  border-bottom: 1px solid var(--color-border);
  background: var(--color-surface-alt);
}
.eu .eu-vs .compare-col--good .eu-vs__head {
  background: var(--color-teal-soft);
  border-bottom-color: var(--color-teal);
}
.eu .eu-vs__head h3 {
  margin: var(--space-3) 0 0;
}
.eu .eu-vs .compare-col--good .eu-vs__tag {
  background: var(--color-teal-soft);
  border-color: var(--color-teal);
  color: var(--color-teal);
}
.eu .eu-vs__head a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
.eu .eu-vs__head a:hover {
  color: var(--color-teal);
}
.eu .eu-vs .compare-list {
  padding: var(--space-6);
  align-content: start;
  flex: 1 1 auto;
}
.eu .compare-col--good .ci {
  background: var(--color-teal-soft);
  color: var(--color-teal);
}
.eu .compare-col--bad .ci {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  color: var(--color-text-muted);
}

/* The two head bands MUST end on the same line, or the first claim on one side
   sits a line lower than the first claim on the other and the panel stops
   reading as one object. They are independent columns, so nothing aligns them
   by default: the moment a vendor name wraps to two lines on one side only
   (narrow viewports, or a longer name in a future export) the seam breaks.
   Subgrid puts both heads in the same parent row. Where subgrid is not
   supported the columns stay flex and behave exactly as they do today, which
   is the current, acceptable state — so this is additive, never a regression. */
@supports (grid-template-rows: subgrid) {
  .eu .eu-vs {
    grid-template-rows: auto 1fr;
  }
  .eu .eu-vs .compare-col {
    display: grid;
    grid-template-rows: subgrid;
    grid-row: span 2;
  }
}

/* The house .compare drops to one column at 760px. The divider has to turn
   with it or the two halves run together, and the shared head row has to be
   released or two items each spanning two rows over-run a one-column grid. */
@media (max-width: 760px) {
  .eu .eu-vs {
    grid-template-rows: none;
  }
  .eu .eu-vs .compare-col {
    display: flex;
    grid-row: auto;
  }
  .eu .eu-vs .compare-col + .compare-col {
    border-left: 0;
    border-top: 1px solid var(--color-border);
  }
}

.eu .tab-panel {
  display: block;
}
.eu .tab-panel + .tab-panel {
  margin-top: var(--space-12);
}
.js .eu .tab-panel {
  display: none;
  margin-top: 0;
}
.js .eu .tab-panel.is-active {
  display: block;
}

/* ---- 9b. /blog ---------------------------------------------------------- */
/* Four value propositions that arrived as four floating cards with a webfont
   glyph each. A list becomes a diagram: the house .figgrid, one bounded object
   with 1px seams. It carries no role="img" here because unlike the core pages'
   figures this grid IS the page's content rather than a restatement of prose
   beside it, so its text has to stay in the accessibility tree. */

.eu .figgrid {
  margin-block: 0;
}
.eu .eu-blog-cta {
  margin-top: var(--space-12);
}

/* ---- 10. search --------------------------------------------------------- */
/* A JS enhancement: hidden without JS rather than left as a dead end, which is
   the same .js convention the core pages use. */

.eu .eu-hero-search {
  display: none;
}
.js .eu .eu-hero-search {
  display: block;
  position: relative;
  width: 100%;
  max-width: 560px;
  margin-inline: auto;
}
.eu .eu-search-icon {
  position: absolute;
  left: 18px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 1.15rem;
  color: var(--color-text-muted);
  pointer-events: none;
}
.eu .eu-search-input {
  width: 100%;
  padding: 14px 18px 14px 48px;
  font-family: var(--font-body);
  font-size: var(--fs-body);
  color: var(--color-text);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-xs);
  outline: none;
}
.eu .eu-search-input::placeholder {
  color: var(--color-text-muted);
}
.eu .eu-search-input:focus {
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px var(--color-primary-soft);
}

.eu .eu-search-results {
  position: absolute;
  top: calc(100% + var(--space-2));
  left: 0;
  right: 0;
  z-index: 50;
  margin: 0;
  padding: 0;
  list-style: none;
  text-align: left;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
  overflow: hidden;
}
.eu .eu-search-results a {
  display: block;
  padding: 10px 16px;
  border-bottom: 1px solid var(--color-border);
  color: var(--color-text);
}
.eu .eu-search-results li:last-child a {
  border-bottom: 0;
}
.eu .eu-search-results a:hover {
  background: var(--color-surface-alt);
  text-decoration: none;
}
.eu .eu-search-results__title {
  display: block;
  font-weight: 600;
  font-size: var(--fs-sm);
}
.eu .eu-search-results__meta {
  display: block;
  font-size: var(--fs-xs);
  color: var(--color-text-muted);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* ---- 11. /suggest form -------------------------------------------------- */

/* Two things changed here and both were layout, not skin.
   1. The form used to sit in a white bordered card INSIDE the white
      .eu-directory card — two identical surfaces nested, which reads as a
      rendering fault rather than a hierarchy. The form panel is now tinted:
      the house .form-card is white and is always placed on a grey band, and
      there is no grey band available inside the directory panel.
   2. His eligibility list used to be the left half of a two-up beside the
      form, which left most of that half empty at every width above 860px. It
      is now in the page head, which is where the core pages put a .check-list. */
.eu .eu-page-hero .check-list {
  margin-top: var(--space-8);
}
.eu .eu-submit-form-container {
  min-width: 0;
  /* Three short fields do not want the full 780px of the panel: at that width
     the inputs read as a mile of empty box. Held to a form measure and centred,
     which is the one place the vertical is not left-aligned and is the same
     shape the house form cards use. */
  max-width: 560px;
  margin-inline: auto;
  background: var(--color-surface-alt);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: clamp(var(--space-5), 3vw, var(--space-8));
}
/* The form is the HOUSE form: .form-grid / .field / .input / .select, the same
   primitives /contact/ uses. The vertical's own .eu-form-group geometry is gone
   — it was a second, slightly different copy of the same control (11px/14px
   padding, --radius-sm, an orange focus ring) that had to be kept in step with
   the house one by hand. Only the two rules the layout genuinely needs stay. */
.eu form .form-grid {
  gap: var(--space-5);
}
.eu form .btn {
  margin-top: var(--space-8);
}
.eu .eu-success-message {
  background: var(--color-teal-soft);
  border: 1px solid var(--color-teal);
  border-radius: var(--radius);
  padding: var(--space-8);
  text-align: center;
}
.eu .eu-success-mark {
  width: var(--space-12);
  height: var(--space-12);
  margin: 0 auto var(--space-4);
}
.eu .eu-success-mark svg {
  width: var(--space-6);
  height: var(--space-6);
}
.eu .eu-success-message h2 {
  font-size: var(--fs-h3);
}
.eu .eu-success-message p {
  margin-bottom: var(--space-6);
}
.eu .eu-hidden {
  display: none;
}

/* ---- 12. mobile: drawer, and the same content edge as the core pages ----- */

.eu .eu-drawer-toggle {
  display: none;
}

@media (max-width: 992px) {
  /* No JS: the rail sits above the content and works as a plain nav. */
  .eu .eu-app-layout {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-6);
  }
  .eu .eu-sidebar {
    position: static;
    max-height: none;
    overflow: visible;
  }
  /* With the rail in the flow and no scrollport of its own, there is nothing
     for the tools block to stick INSIDE: sticky would fall through to the
     viewport and pin a footer bar to the bottom of the screen for as long as
     any part of the rail is on it. Nothing to pin to, so nothing pinned — the
     whole rail is visible here anyway, which is the condition sticky exists to
     recover. */
  .eu .eu-sidebar-sect {
    position: static;
  }

  /* With JS: a real off-canvas drawer opened by the toggle the shell emits,
     because the button that used to open it lived in the export's deleted
     header. The toggle is the panel's first child and the panel carries no
     inline padding of its own, so it takes the same inner gutter the bands'
     .container takes — it has to line up with the h1 under it, not with the
     panel edge. */
  .js .eu .eu-drawer-toggle {
    display: inline-flex;
    margin: clamp(var(--space-5), 2.6vw, var(--space-8));
    margin-bottom: 0;
  }
  .js .eu .eu-sidebar {
    position: fixed;
    top: var(--header-h);
    left: 0;
    z-index: 90;
    width: min(300px, 86vw);
    height: calc(100vh - var(--header-h));
    max-height: none;
    overflow-y: auto;
    border-radius: 0;
    border-inline-start: 0;
    box-shadow: var(--shadow-lg);
    transform: translateX(-100%);
    transition: transform 0.25s var(--ease);
  }
  .js .eu.is-drawer-open .eu-sidebar {
    transform: translateX(0);
  }
  /* The drawer IS a scrollport (fixed, full height, overflow-y:auto), so the
     tools block pins again inside it — the same behaviour, and the same
     reason, as the desktop rail. */
  .js .eu .eu-sidebar-sect {
    position: sticky;
  }
}

@media (max-width: 640px) {
  .eu .eu-directory {
    border-inline: 0;
    border-radius: 0;
    margin-inline: calc(-1 * var(--gutter));
    padding-inline: var(--gutter);
  }
  .eu .eu-breadcrumb-nav {
    margin-inline: calc(-1 * var(--gutter));
    padding-inline: var(--gutter);
  }
  .eu .eu-company-detail-card,
  .eu .card {
    padding: var(--space-5);
  }
}

/* ---- 13. focus and motion ----------------------------------------------- */
/* The house ring: 2px --color-primary-bright at 3px offset. */

.eu a:focus-visible,
.eu button:focus-visible,
.eu input:focus-visible,
.eu select:focus-visible,
.eu [tabindex]:focus-visible {
  outline: 2px solid var(--color-primary-bright);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}

@media (prefers-reduced-motion: reduce) {
  .eu,
  .eu * {
    transition: none !important;
    animation: none !important;
    scroll-behavior: auto !important;
  }
  .eu *:hover {
    transform: none !important;
  }
}

/* ---- 14. company archetype (449 pages) ---------------------------------- */
/* Rendered by src/eu/archetype-company.mjs. The page runs two .eu-directory
   bands on the page field, the second .eu-band--soft, which is the same
   three-surface structure as a category page. Almost everything on it is a
   component that already exists — house (.section, .section-head, .eyebrow,
   .split, .card, .btn, .cta-row, .stack-entry, .se-title, .se-meta, .se-more,
   .article-body) or vertical (.eu-directory, .eu-band--soft, .eu-page-head,
   .eu-breadcrumb-nav, .eu-listing-head, .eu-row, .eu-origin). What is left
   below is only what a product profile genuinely needs and nothing else on
   the site has: the record-plus-panel layout and the facts panel itself.
   No colour, no type size and no radius is invented; the build fails on a
   literal colour anywhere in this file. */

/* The record. .split is 1fr 1fr and vertically centred, which is right for a
   hero pairing and wrong for a document beside a facts panel: the panel is
   short, so centring floated it against the middle of a nine-line paragraph. */
.eu .eu-company-split {
  grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
  align-items: start;
  gap: clamp(var(--space-8), 4vw, var(--space-12));
}
.eu .eu-company-head {
  margin-bottom: var(--space-8);
}
.eu .eu-company-head h1 {
  margin: 0;
}
.eu .eu-company-main {
  min-width: 0;
}

/* The description. .article-body already caps the measure at 38em; the column
   is narrower than that, so the cap never binds and the copy reads at the
   house 16/1.6 in the house ink. */
.eu .eu-company-content > p + p {
  margin-top: var(--space-5);
}

/* Primary action. The button is the house .btn--primary.btn--lg; the note is
   the destination, which is a fact the page already holds and which tells a
   reader where the button goes before they press it. Omitted, with the button,
   on the 37 pages whose export record carries href="#". */
.eu .eu-company-cta {
  margin-top: var(--space-8);
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-4);
}
.eu .eu-cta-note {
  font-size: var(--fs-sm);
  color: var(--color-text-muted);
  overflow-wrap: anywhere;
}

/* The facts panel. Sticky under the header so the record stays addressable
   while a long description scrolls. */
.eu .eu-facts {
  position: sticky;
  top: calc(var(--header-h) + var(--space-6));
  /* The house .card is --radius (12px) and .card--tile is --radius-lg (18px).
     The band around this panel and the sibling cards beside it are both 18px,
     and two radii on one page reads as two systems. .card--tile itself is not
     the answer: it carries a lift on hover, and nothing in this panel is a
     click target. */
  border-radius: var(--radius-lg);
}
.eu .eu-facts-h {
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--color-primary);
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0 0 var(--space-4);
}
.eu .eu-facts-h::before {
  content: "";
  width: 22px;
  height: 1.5px;
  background: var(--color-primary);
  display: inline-block;
}
.eu .eu-facts-list {
  margin: 0;
}
.eu .eu-fact {
  display: grid;
  gap: var(--space-1);
  padding-block: var(--space-4);
}
.eu .eu-fact:first-child { padding-block-start: 0; }
.eu .eu-fact:last-child  { padding-block-end: 0; }
.eu .eu-fact + .eu-fact {
  border-top: 1px solid var(--color-border);
}
.eu .eu-fact-k {
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}
.eu .eu-fact-v {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--fs-body);
  font-weight: 600;
  line-height: 1.4;
  color: var(--color-text);
}
.eu .eu-fact-v a {
  color: var(--color-text);
}
.eu .eu-fact-v a:hover {
  color: var(--color-primary);
}
.eu .eu-fact-note {
  font-weight: 400;
  font-size: var(--fs-sm);
  color: var(--color-text-muted);
}

/* Country of origin. The flag is the export's own asset (33 SVGs it shipped
   and never referenced) and it is CONTENT, in the same class as the client
   logos the core pages render in their own colours — the vertical's palette is
   unchanged. It is a mark, never the only carrier: the country name is always
   printed beside it, so nothing depends on reading a 20px flag. */
.eu .eu-flag {
  width: 20px;
  height: 15px;
  flex: none;
  box-sizing: border-box;
  border: 1px solid var(--color-border);
  object-fit: cover;
}
.eu .eu-origin {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

/* The relationship block needs nothing of its own. It is the SAME components
   the category listing uses — .section.eu-directory.eu-band--soft, the
   .eu-listing-head, and .stack-entry.eu-row rows with .eu-origin — so a
   profile and the category page that links to it read as one system. The only
   rule here is the spacing under the button that states the true total. */
.eu .eu-related-cta {
  margin-top: var(--space-8);
}

@media (max-width: 900px) {
  /* One column, and the panel stops being sticky: stacked, it would pin a
     facts card over the copy it belongs to. */
  .eu .eu-company-split {
    grid-template-columns: minmax(0, 1fr);
  }
  .eu .eu-facts {
    position: static;
  }
}

/* ===========================================================================
   14. LISTING ARCHETYPES — the index, the 62 categories, the 8 groups
   ---------------------------------------------------------------------------
   Rendered by build-eu-listing.mjs from the directory model. Everything below
   obeys the file's one rule: no colour, no radius, no shadow and no type size
   of its own — every value is a house token, so a palette or rhythm change
   reaches the vertical by construction. Positional data (a treemap cell's
   rectangle, a bar's length) is the one thing written inline on the element,
   because it IS the data and belongs with the datum, not in a stylesheet.
   ========================================================================= */

/* ---- 14.1 banding ------------------------------------------------------- */
/* The audit's finding was that the whole vertical was one flat #F8FAFC field.
   Each listing page now runs at least three surfaces down the page: the page
   field, the white content band, and this tinted one. */

.eu .eu-band--soft {
  background: var(--color-surface-alt);
}

/* ---- 14.2 the four counts ----------------------------------------------- */
/* The house .stat-grid / .stat / .stat-num / .stat-label, unchanged. The
   vertical only asks for the rule under it and the two-up mobile step, which
   the house grid already does at 760px. */

.eu .eu-stats .stat {
  border-left: 2px solid var(--color-border);
  padding-left: var(--space-4);
}
.eu .eu-stats .stat:first-child {
  border-left-color: var(--color-primary-bright);
}

/* ---- 14.3 the proportion bar (FIG 1 and FIG 4) -------------------------- */
/* preserveAspectRatio="none" is deliberate and load-bearing: x distorts to
   fill the container, which is exactly the encoding, while the CSS height pins
   y. There is no text, no stroke and no radius inside to distort with it, so
   the figure stays exact at every width and no glyph is ever scaled below the
   12px floor — the labels are all real HTML outside the SVG. */

.eu .eu-bar {
  display: block;
  width: 100%;
  height: 10px;
  border-radius: var(--radius-pill);
  overflow: hidden;
  background: var(--color-surface-alt);
}
.eu .eu-bar--wide {
  height: 14px;
}

/* ---- 14.4 FIG 1: sector coverage ---------------------------------------- */

.eu .eu-cov {
  display: grid;
}
.eu .eu-cov__row {
  display: grid;
  grid-template-columns: minmax(0, 17rem) minmax(0, 1fr) 3.5rem;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--color-border);
}
.eu .eu-cov__row:last-child {
  border-bottom: 0;
}
.eu .eu-cov__lab {
  min-width: 0;
}
.eu .eu-cov__lab a {
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: var(--fs-sm);
  line-height: 1.3;
  color: var(--color-text);
}
.eu .eu-cov__lab a:hover {
  color: var(--color-primary);
  text-decoration: none;
}
.eu .eu-cov__sub {
  display: block;
  margin-top: 2px;
  font-size: var(--fs-xs);
  line-height: 1.35;
  color: var(--color-text-muted);
}
.eu .eu-cov__track {
  min-width: 0;
}
.eu .eu-cov__val {
  text-align: right;
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
  color: var(--color-primary);
}
.eu .eu-cov__key {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-5);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-border);
  font-size: var(--fs-xs);
  color: var(--color-text-muted);
}
/* The key's swatches are the house .sh-sw, so a legend entry cannot drift from
   the segment it explains: both read the same --chart-shade-N token. The second
   entry is four swatches in ramp order rather than one, because "every other
   category" stopped being one colour the moment the shade started tracking the
   value. */
.eu .eu-cov__key .sh-sw + .sh-sw {
  margin-left: 2px;
}
.eu .eu-cov__ramp {
  display: inline-flex;
  align-items: center;
  margin-left: var(--space-4);
}

@media (max-width: 640px) {
  .eu .eu-cov__row {
    grid-template-columns: minmax(0, 1fr) 3.5rem;
    row-gap: var(--space-2);
  }
  .eu .eu-cov__lab {
    grid-column: 1 / -1;
  }
}

/* ---- 14.5 FIG 2: origin treemap ----------------------------------------- */
/* Cells are real HTML positioned in percentages, not glyphs inside a scaling
   viewBox, so every label is live text at a real size at 1440 and at 390. The
   two cream cells are the three origins above a tenth of the directory; every
   other cell is neutral and AREA does the arguing. */

.eu .eu-tree {
  position: relative;
  width: 100%;
  aspect-ratio: 1000 / 460;
}
.eu .eu-tree__cell {
  position: absolute;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 2px;
  overflow: hidden;
  padding: var(--space-2);
  background: var(--color-surface-alt);
  border: 1px solid var(--color-surface);
  /* The value ramp rides the bottom edge, where a solid 3px mark can be as
     dark as the ranking needs without touching the contrast of the country
     name and count sitting inside the cell. */
  border-bottom: 3px solid var(--shade, var(--chart-shade-3));
  border-radius: var(--radius-sm);
}
.eu .eu-tree__cell--lead {
  background: var(--color-primary-soft);
}
.eu .eu-tree__cell--rest {
  background: var(--color-surface);
  border: 1px dashed var(--color-border);
}
.eu .eu-tree__flag {
  margin-bottom: auto;
}
.eu .eu-tree__name {
  font-size: var(--fs-xs);
  font-weight: 600;
  line-height: 1.2;
  color: var(--color-text);
}
.eu .eu-tree__n {
  font-family: var(--font-heading);
  font-size: var(--fs-sm);
  font-weight: 700;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--color-primary);
}
.eu .eu-tree__cell--rest .eu-tree__n {
  color: var(--color-text-muted);
}

@media (max-width: 900px) {
  .eu .eu-tree {
    aspect-ratio: 1000 / 720;
  }
}
@media (max-width: 560px) {
  .eu .eu-tree {
    aspect-ratio: 1000 / 1180;
  }
}

/* ---- 14.6 FIG 4: the category origin strip ------------------------------ */

.eu .eu-fig--flush {
  margin-top: 0;
}
.eu .eu-strip__key {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  margin-top: var(--space-4);
  font-size: var(--fs-xs);
}
.eu .eu-key {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--color-text-muted);
}
/* The strip's key uses the house .sh-sw too. Every entry keeps its own count
   and now carries its own step, so Germany 5, France 2 and Finland 1 are three
   different marks in the key exactly as they are three different marks in the
   bar. */
.eu .eu-key .sh-sw {
  width: 10px;
}

/* ---- 14.7 icons --------------------------------------------------------- */
/* Inline SVG on currentColor. The listing pages and the rail draw no icon
   webfont at all: build-eu.mjs emits the unpkg <script> only for a page that
   still contains a ph-* class, so the dependency disappears by itself. */

.eu .eu-ic {
  width: 20px;
  height: 20px;
  flex: none;
}
.eu .eu-ic--lg {
  width: 24px;
  height: 24px;
}
.eu .eu-ic--xl {
  width: 30px;
  height: 30px;
}
.eu .eu-icon-box--lg {
  width: 60px;
  height: 60px;
  border-radius: var(--radius-lg);
}

/* ---- 14.8 index: the eight sector cards --------------------------------- */

.eu .eu-group-card__head {
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
  margin-bottom: var(--space-5);
}
.eu .eu-group-card__head h3 a {
  color: var(--color-text);
}
.eu .eu-group-card__head h3 a:hover {
  color: var(--color-primary);
  text-decoration: none;
}
.eu .eu-group-card__meta {
  margin-top: 4px;
  font-size: var(--fs-sm);
  color: var(--color-text-muted);
}
.eu .eu-chip-n {
  margin-left: 6px;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  color: var(--color-text-muted);
}
.eu .stack-chip:hover .eu-chip-n {
  color: var(--color-primary);
}

/* ---- 14.9 group: the category cards ------------------------------------- */

.eu .eu-group-head {
  display: flex;
    flex-direction: column;
  align-items: flex-start;
  gap: var(--space-5);
}
.eu .eu-cat-card__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}
.eu .eu-cat-card__head h3 a {
  color: var(--color-text);
}
.eu .eu-cat-card__head h3 a:hover {
  color: var(--color-primary);
  text-decoration: none;
}
.eu .eu-cat-card__none {
  flex-grow: 1;
  font-size: var(--fs-sm);
  color: var(--color-text-muted);
}

/* ---- 14.10 category: the listing rows ----------------------------------- */
/* The house .stack-entry, which is what /resources/blogs/ already runs, so a
   directory listing and the site's own archive read as one component. The
   right-hand cell the component reserves for a visual carries the country
   instead: real signal, never a motif, at 449 rows. */

.eu .eu-listing-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-5);
}
.eu .eu-listing-head__note {
  font-size: var(--fs-sm);
  color: var(--color-text-muted);
}
.eu .eu-filter {
  display: none;
}
.js .eu .eu-filter {
  display: flex;
}
.eu .eu-rows {
  gap: var(--space-4);
}
.eu .eu-row {
  grid-template-columns: minmax(0, 1fr) minmax(0, 13rem);
  align-items: center;
}
.eu .eu-row .se-title {
  margin-top: 0;
  font-size: var(--fs-h4);
}
.eu .eu-row__blurb {
  display: block;
  color: var(--color-text-muted);
}
.eu .eu-row__side {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-4);
}
.eu .eu-row__side .eu-origin {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--color-text);
  text-align: right;
}
.eu .eu-row__side .se-more {
  margin-top: 0;
  flex: none;
}
.eu .eu-row:hover .se-more {
  border-color: var(--color-primary);
  color: var(--color-primary);
}
.eu .eu-row.eu-hidden {
  display: none;
}
/* The connector hairline the house component draws between entries assumes a
   24px gutter; this list runs at 16px and the rows are shorter, so it is
   dropped rather than left half-length. */
.eu .eu-rows .stack-entry + .stack-entry::before {
  display: none;
}

@media (max-width: 720px) {
  .eu .eu-row {
    grid-template-columns: minmax(0, 1fr);
  }
  .eu .eu-row__side {
    justify-content: space-between;
  }
}

/* ---- 14.11 rail, empty state, and the eyebrow as a link ----------------- */

.eu .eu-sidebar-lede {
  margin: calc(-1 * var(--space-2)) 0 var(--space-4);
  font-size: var(--fs-xs);
  color: var(--color-text-muted);
}
.eu .eu-empty__act {
  margin-top: var(--space-4);
}
/* `.eu p` is (0,1,1) and the house `.lead` is (0,1,0), so every standfirst in
   the vertical was silently rendering at body size. Measured 16px where the
   core pages give 18.4px. Same token, correct specificity. */
.eu p.lead {
  font-size: var(--fs-lead);
}
/* A category page's eyebrow is its sector, and it links there. It is the house
   eyebrow in every other respect. */
.eu a.eyebrow:hover {
  color: var(--color-primary-hover);
  text-decoration: none;
}

/* ---- 14.12 the two listing card variants, and two label spans ----------- */
/* Both are the house .card.card--tile; these rules only set the internal
   rhythm a directory card needs and the flex behaviour that lets the footer
   link sit on the baseline across a row of uneven cards. */

.eu .eu-group-card,
.eu .eu-cat-card {
  gap: var(--space-3);
}
.eu .eu-group-card .eu-bento-tags {
  margin-bottom: var(--space-5);
  flex-grow: 1;
  align-content: flex-start;
}
.eu .eu-origin__n {
  min-width: 0;
}
.eu .eu-key__n {
  font-variant-numeric: tabular-nums;
}
/* A cell narrow enough to take a name but not the longest name must clip
   gracefully rather than push its own count out of the box. */
.eu .eu-tree__name {
  overflow-wrap: anywhere;
}

/* (.eu-crumbed retired with the panel. It cancelled the record band's top pad
   because the breadcrumb strip bled to the card's edges as the band's first
   child. On a railless page the breadcrumb is a band in its own right, so
   there is no pad to cancel and nothing emits the class. See section 17.) */

/* The house .figx carries a 48px block margin for an article flow. As the last
   thing in a banded section it stacked on the section's own --section-y and
   left ~150px of empty surface under the plot. */
.eu .section > .figx:last-child,
.eu .eu-directory > .figx:last-child {
  margin-bottom: 0;
}
.eu .section > .figx:first-child {
  margin-top: 0;
}
/* The count inside an ACTIVE filter chip: the chip fill turns orange and its
   label turns white, but the count kept the muted grey and measured 1.07:1 on
   the fill. A number that rides inside a control must take the control's ink. */
.eu .filter-btn.is-active .eu-chip-n {
  color: inherit;
}

/* ---- 14.13 FIG 2 on a phone: the same data as a ranked list ------------- */
/* A treemap needs width to label itself; at 390 the plot is 312px across and
   every cell but the largest falls under the ~90px a country name needs. The
   list carries the identical derived values and the two swap at 560px, so
   neither is ever a second, drifting source. */

.eu .eu-tree-list {
  display: none;
  margin: 0;
  padding: 0;
  list-style: none;
}
.eu .eu-tl {
  display: grid;
  grid-template-columns: minmax(0, 10.5rem) minmax(0, 1fr) 2.25rem;
  align-items: center;
  gap: var(--space-3);
  padding: 7px 0;
  border-bottom: 1px solid var(--color-border);
}
.eu .eu-tl:last-child {
  border-bottom: 0;
}
.eu .eu-tl__k {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--color-text);
}
.eu .eu-tl__k span {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.eu .eu-tl--rest .eu-tl__k {
  color: var(--color-text-muted);
  font-weight: 400;
}
.eu .eu-tl__track {
  display: block;
  height: 8px;
  border-radius: var(--radius-pill);
  background: var(--color-surface-alt);
  overflow: hidden;
}
.eu .eu-tl__fill {
  display: block;
  height: 100%;
  border-radius: var(--radius-pill);
  background: var(--shade, var(--chart-shade-3));
}
.eu .eu-tl__n {
  text-align: right;
  font-family: var(--font-heading);
  font-size: var(--fs-sm);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--color-primary);
}

@media (max-width: 560px) {
  .eu .eu-tree {
    display: none;
  }
  .eu .eu-tree-list {
    display: block;
  }
}
/* 20 of the 449 products record an origin that is not a place, so they carry
   no flag. In a stacked list that pulled their label 28px left of every other
   row; the slot is held open and left empty rather than filled. */
.eu .eu-flag--none {
  display: inline-block;
  border-color: transparent;
  background: transparent;
}

/* ---- 15. the rail's replacements: sector bar and category bar ------------ */
/* The 248px rail is what makes the vertical read as an app: it insets every
   page into an 872px panel at x=424, where every band on the 48 core pages is
   full-bleed at viewport width and holds a 1200px .container with its content
   at x=144. These two components carry the rail's navigation in that core
   architecture instead — full-bleed bands, house .container, house chips.

   Neither is sticky, neither is off-canvas, neither needs opening: they are in
   the reading order, which is why the rail's two JS controls (collapse the
   subnav, open the drawer) have nothing to replace them. */

/* ---- 15.1 sector bar: the directory's section nav, 522 pages ------------- */
/* A rule-bounded strip rather than a panel: white band, a hairline top and
   bottom, and the chips WRAP on the house .container's own measure so nothing
   is ever scrolled out of sight or hidden behind a control. Eight sector names
   need eight rows at 390px, which is why the strip follows the page head on a
   listing page and closes the page everywhere else — the h1 leads at every
   width, and the strip is a section index, never a barrier before the title. */

.eu .eu-sectorbar {
  display: block;
  background: var(--color-surface);
  border-block: 1px solid var(--color-border);
  padding-block: var(--space-6);
}
.eu .eu-sectorbar__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2) var(--space-4);
  margin-bottom: var(--space-4);
}
.eu .eu-sectorbar__lede {
  margin: 0;
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
  color: var(--color-text-muted);
}
.eu .eu-sectorbar__list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* ---- 15.2 category bar: the sector's categories, at the foot ------------- */
/* Emitted on the 62 category and 449 company pages — the pages where the
   rail's open subnav was the only one-click path to the sibling categories. A
   group page gets none: its .eu-category-grid already lists all of them. */

.eu .eu-catbar {
  background: var(--color-surface);
  border-top: 1px solid var(--color-border);
}
.eu .eu-catbar__head {
  margin-bottom: var(--space-6);
}
.eu .eu-catbar__head h2 a {
  color: inherit;
}
.eu .eu-catbar__head h2 a:hover {
  color: var(--color-primary);
  text-decoration: none;
}
.eu .eu-catbar__list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* ---- 15.3 the nav chip, shared by both bars ----------------------------- */
/* The house a.stack-chip, which the index already uses for exactly this job.
   These rules only add the count's spacing, the icon slot and the current-page
   state; the chip's own type, radius, fill, border and hover stay the house
   component's, so a chip in the sector bar and a chip on the index are the
   same object. */

.eu .eu-navchip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--color-text);
}
.eu .eu-navchip__l {
  min-width: 0;
}
.eu .eu-navchip .eu-chip-n {
  font-variant-numeric: tabular-nums;
}
/* Current page. The chip keeps its geometry and takes the house primary fill,
   the same treatment .filter-btn.is-active already carries, so "where I am" is
   one mark across the site. */
.eu a.stack-chip.eu-navchip.is-active,
.eu a.stack-chip.eu-navchip.is-active:hover {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-surface);
}
.eu .eu-navchip.is-active .eu-chip-n {
  color: inherit;
}
.eu .eu-ic--sm {
  width: 16px;
  height: 16px;
}

/* ---- 16. the railless page: the core pages' own band architecture -------- */
/* THE LAST DIVERGENCE, and it was never a component — every component in the
   vertical already measures byte-for-byte against the 48 core pages. It was
   the PAGE:

     core      section width 1440 at x=0, a 1200px .container inside it,
               content at x=144, bands alternating down the page.
     vertical  a 248px rail on the left of all 523 pages, the content inset
               into an 872px panel at x=424, and that panel drawn as a card
               with an 18px radius and a 1px border.

   One reads as a site, the other as an app with a sidebar. `.eu-bands` is the
   railless page: build-eu.mjs drops the rail and the two wrapper divs, and the
   page's own sections become top-level bands. They already carry a house
   .container each — the rail's panel was the only thing making those
   containers pass-through — so no band here restates a width, a gutter or a
   max-width. It only UNDOES the panel: the card border, the card radius, the
   card's own inline padding and the gap the card left below itself. */

.eu .eu-bands {
  display: block;
}

/* The breadcrumb strip. Inside the panel it bled to the panel's edges on
   negative inline margins; as a band it is full-bleed already and the
   .container build-eu.mjs wraps its list in supplies the measure. */
.eu .eu-bands > .eu-breadcrumb-nav {
  margin-inline: 0;
  padding-inline: 0;
  margin-block-end: 0;
}

/* The content band. Same surface as before, minus the card: the 1px border,
   the 18px radius, the panel's inline padding (the .container inside owns the
   gutter now) and the block margin that separated one card from the next (the
   house .section's own padding-block owns the rhythm). Specificity beats both
   the base rule and the 640px one, so the phone width inherits the band. */
.eu .eu-bands > .eu-directory {
  border: 0;
  border-radius: 0;
  margin-inline: 0;
  padding-inline: 0;
  margin-block-end: 0;
}

/* The page head needs NO rule here. Its panel-only trim now lives under
   `.eu .eu-app-main` (section 8b), so on a band page the house .page-hero step
   applies unchanged and this h1 sits on a core page's own baseline. */

/* ---- 17. the listing surfaces as core bands ----------------------------- */
/* THE INDEX, THE 62 CATEGORY PAGES AND THE 8 GROUP PAGES.
   These three are rendered from the model by build-eu-listing.mjs, so unlike
   the export's own pages they never had a wrapper to unpick: the renderers
   simply emit the core page shape directly:

       <section class="section sec-*"><div class="container"> … </div></section>

   full-bleed at viewport width, house 1200px .container inside, content at the
   core pages' own x. The tone classes are the CORE's own .sec-paper,
   .sec-white and .sec-gray, not a parallel set, and that is what makes the
   seam work: the three light neutrals sit ~2% apart and the core already
   folds every junction between them with a measured hairline. A private
   vocabulary would have had to re-derive that matrix and would have drifted
   from it.

   So there is almost nothing to declare here. Everything below is a TRIM: a
   margin that made sense inside the 872px card and reads as a hole now that
   the card is a band. */

/* The house .figx carries a 48px block margin for an article flow. Sections 8b
   and 14 already trim it where the figure is a direct child of the band; on a
   listing page the .container sits between them, so the same trim has to
   reach one level further in. Without this a figure opening a band stacks its
   own margin on the band's --section-y and leaves ~100px of empty surface
   above the plot. */
.eu .container > .figx:first-child {
  margin-top: 0;
}
.eu .container > .figx:last-child {
  margin-bottom: 0;
}

/* The page head closing a .page-hero band. Inside the card the rule under the
   standfirst separated the head from the figure below it; as the last thing in
   a hero band it is a rule with nothing under it, and the core's own heroes
   carry none. The band's closing padding owns the gap. */
.eu .page-hero .container > .eu-page-head:last-child {
  border-bottom: 0;
  padding-bottom: 0;
  margin-bottom: 0;
}
