/*
  Catalogue stylesheet.

  Deliberately small and self-contained. These pages are read by crawlers first
  and people second, and a render-blocking stylesheet on the critical path is a
  Core Web Vitals problem. The whole file is under 4 KB and loads in one request.

  It mirrors the React design system's tokens so a visitor who lands here from
  search and then navigates into the app does not see two different products.
*/

:root {
  --page: #fbfaf9;
  --panel: #fff;
  --sunken: #f4f3f1;
  --border: #e4e2df;
  --ink: #1c1b1a;
  --ink-2: #5f5d59;
  /* WCAG AA on every ground this sits on, measured rather than judged:
     the old #8a8782 gave 3.23-3.58:1 against the page, panel and sunken
     backgrounds where 4.5 is required, and it was the sole cause of every
     contrast failure on the site. These are the LIGHTEST values that pass —
     tertiary text is meant to recede, so the darkest safe grey is the wrong
     answer too. */
  --ink-3: #706d68;
  --accent: #00734a;
  --accent-soft: #eaf5f0;
  --radius: 10px;
  --wrap: 68rem;
}

/* Three states, not two — the same model the React app uses.

   `system` is the default and follows the OS. An explicit choice writes a
   cookie, the server stamps `light`/`dark` on <html>, and that wins over the
   OS in both directions. The `:not(.light)` guard is what makes the light
   choice stick on a machine set to dark; without it the media query would
   quietly override the visitor's own decision.

   The dark values are duplicated rather than shared because a CSS custom
   property cannot be conditionally aliased, and a preprocessor for one 4 KB
   file is a worse trade than nine repeated lines. */
@media (prefers-color-scheme: dark) {
  :root:not(.light) {
    --page: #111110;
    --panel: #1a1a19;
    --sunken: #201f1e;
    --border: #302f2d;
    --ink: #f2f1ef;
    --ink-2: #a8a5a0;
    --ink-3: #8a8782;
    --accent: #4ac48d;
    --accent-soft: #16281f;
  }
}

:root.dark {
  --page: #111110;
  --panel: #1a1a19;
  --sunken: #201f1e;
  --border: #302f2d;
  --ink: #f2f1ef;
  --ink-2: #a8a5a0;
  --ink-3: #8a8782;
  --accent: #4ac48d;
  --accent-soft: #16281f;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--page);
  color: var(--ink);
  font: 400 16px/1.6 "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
}

.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 1.25rem; }

/* The skip link is the first tab stop, and invisible until focused. */
.skip {
  position: absolute; left: -9999px;
  background: var(--accent); color: #fff;
  padding: .6rem 1rem; border-radius: var(--radius); z-index: 10;
}
.skip:focus { left: 1rem; top: 1rem; }

/* Present for a screen reader, absent for everyone else. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.site-header { border-bottom: 1px solid var(--border); background: var(--panel); }
.site-header .wrap { display: flex; align-items: center; gap: 1.5rem; height: 3.5rem; }
.brand { display: flex; align-items: center; gap: .6rem; font-weight: 600; text-decoration: none; color: var(--ink); }
.brand b { color: var(--accent); font-weight: 600; }
.site-header nav { margin-left: auto; display: flex; gap: 1.25rem; }
.site-header nav a { color: var(--ink-2); text-decoration: none; font-size: .9rem; }
.site-header nav a:hover { color: var(--accent); }

.breadcrumbs { padding-top: 1rem; }
.breadcrumbs ol { list-style: none; display: flex; flex-wrap: wrap; gap: .4rem; margin: 0; padding: 0; font-size: .8rem; color: var(--ink-3); }
.breadcrumbs li + li::before { content: "/"; margin-right: .4rem; color: var(--border); }
.breadcrumbs a { color: var(--ink-2); text-decoration: none; }
.breadcrumbs a:hover { color: var(--accent); text-decoration: underline; }

main { padding: 1.5rem 0 4rem; }
h1 { font-size: clamp(1.6rem, 3.5vw, 2.25rem); line-height: 1.2; letter-spacing: -.02em; margin: .5rem 0 .75rem; }
h2 { font-size: 1.2rem; letter-spacing: -.01em; margin: 2.5rem 0 .75rem; }
h3 { font-size: 1rem; margin: 0 0 .35rem; }
a { color: var(--accent); }

.lede { font-size: 1.05rem; color: var(--ink-2); max-width: 46rem; margin: 0 0 1.5rem; }
.note { font-size: .85rem; color: var(--ink-3); max-width: 46rem; }
.meta { font-size: .8rem; color: var(--ink-3); margin: .25rem 0 0; }

/* Definition grids — the workhorse of every detail panel. */
/* The separators are outlines on the cells, not the container's background
   showing through 1px gaps. With auto-fit, a row that does not fill left a
   grey rectangle where a cell would have been — an empty box that reads as
   missing data. Outlines take no layout space, so a short last row simply
   ends. */
.facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); gap: 1px; background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; margin: 0 0 1.5rem; }
.facts > div { background: var(--panel); padding: .75rem .9rem; outline: 1px solid var(--border); }
.facts dt { font-size: .7rem; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-3); margin-bottom: .2rem; }
.facts dd { margin: 0; font-weight: 500; }

table { width: 100%; border-collapse: collapse; font-size: .9rem; margin-bottom: 1rem; }
/* Tabular figures: a column of prices is unscannable without them. */
th, td { font-variant-numeric: tabular-nums; text-align: left; padding: .6rem .75rem; border-bottom: 1px solid var(--border); }
th { font-size: .7rem; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-3); font-weight: 600; }
tbody tr:hover { background: var(--sunken); }

.cards { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr)); gap: .75rem; }
.cards li { background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius); padding: .9rem 1rem; }
.cards h2, .cards h3 { font-size: .95rem; margin: 0; }
.cards h2 a, .cards h3 a { text-decoration: none; }
.cards h2 a:hover, .cards h3 a:hover { text-decoration: underline; }
.cards p { margin: .25rem 0 0; font-size: .875rem; color: var(--ink-2); }

.links { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: .5rem; }
.links li { background: var(--panel); border: 1px solid var(--border); border-radius: 999px; padding: .3rem .8rem; font-size: .85rem; }
.links a { text-decoration: none; color: var(--ink); }
.links a:hover { color: var(--accent); }
.links .meta { display: inline; margin-left: .35rem; }

.tag { display: inline-block; background: var(--accent-soft); color: var(--accent); border-radius: 999px; padding: .05rem .5rem; font-size: .7rem; margin-right: .35rem; }

.sources { list-style: none; margin: 0; padding: 0; }
.sources li { padding: .6rem 0; border-bottom: 1px solid var(--border); }
.sources .meta { display: block; }

.article-body p { max-width: 38rem; }

.faq dt { margin-top: 1.25rem; }
.faq dt h3 { margin: 0; }
.faq dd { margin: .35rem 0 0; color: var(--ink-2); }

.related { margin-top: 3rem; padding-top: 1.5rem; border-top: 1px solid var(--border); }

.site-footer { border-top: 1px solid var(--border); background: var(--panel); padding: 2rem 0; margin-top: 3rem; font-size: .85rem; color: var(--ink-2); }
.site-footer nav { display: flex; flex-wrap: wrap; gap: 1.25rem; margin: .75rem 0; }
.site-footer a { color: var(--ink-2); text-decoration: none; }
.site-footer a:hover { color: var(--accent); }
.fine { color: var(--ink-3); font-size: .78rem; }

@media (max-width: 640px) {
  .site-header nav { display: none; }
  table { display: block; overflow-x: auto; white-space: nowrap; }
}

/* -- The rail --------------------------------------------------------------
   One column below 60rem: the rail is dropped rather than stacked, because
   four summary cards between the content and the footer is a scroll tax on a
   phone and every link in it is already in the nav. */
.layout { display: block; }
.layout > main { min-width: 0; }

@media (min-width: 64rem) {
  .layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 17rem;
    gap: 2.5rem;
    align-items: start;
  }
  .rail { position: sticky; top: 1.5rem; }
}

.rail { display: none; }
@media (min-width: 64rem) { .rail { display: block; } }

.rail-card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: .9rem 1rem;
  margin-bottom: .75rem;
}
.rail-card h2 {
  font-size: .7rem; text-transform: uppercase; letter-spacing: .04em;
  color: var(--ink-2); margin: 0 0 .6rem;
}
.rail-figure { font-size: 1.25rem; font-weight: 600; margin: 0; }
.rail-note {
  font-size: .7rem; line-height: 1.5; color: var(--ink-2); margin: .5rem 0 0;
}

.rail-rows { list-style: none; margin: .5rem 0 0; padding: 0; }
.rail-rows li {
  display: flex; justify-content: space-between; gap: .6rem;
  font-size: .78rem; padding: .3rem 0;
}
.rail-rows li + li { border-top: 1px solid var(--border); }
.rail-rows em { display: block; font-style: normal; font-size: .68rem; color: var(--ink-2); }

.rail-links { list-style: none; margin: 0; padding: 0; }
.rail-links li { padding: .22rem 0; }
.rail-links a { font-size: .78rem; text-decoration: none; }
.rail-links a:hover { text-decoration: underline; }

.rail-link {
  display: inline-block; margin-top: .6rem; font-size: .75rem; text-decoration: none;
}
.rail-link:hover { text-decoration: underline; }

/* Direction is carried by the glyph beside the number, so the colour is
   reinforcement rather than the message — the same rule the app follows. */
.delta { white-space: nowrap; font-variant-numeric: tabular-nums; }
.delta--gain { color: #0a7d6f; }
.delta--loss { color: #c23b34; }
.delta--flat { color: var(--ink-2); }

/* -- Header parity ---------------------------------------------------------
   The catalogue and the app render the same URLs, so their headers have to
   look like one product. Same nav, same search affordance, same theme
   control. */
.site-header .wrap { gap: 1.25rem; }

.header-search { flex: 1 1 auto; max-width: 26rem; }
.header-search form { display: flex; }
.header-search input {
  flex: 1;
  min-width: 0;
  font: inherit;
  font-size: .85rem;
  padding: .45rem .75rem;
  color: var(--ink);
  background: var(--sunken);
  border: 1px solid var(--border);
  border-radius: 999px 0 0 999px;
  border-right: 0;
}
.header-search input::placeholder { color: var(--ink-3); }
.header-search input:focus {
  outline: none;
  border-color: var(--accent);
}
.header-search button {
  font: inherit;
  font-size: .8rem;
  padding: .45rem .9rem;
  cursor: pointer;
  color: #fff;
  background: var(--accent);
  border: 1px solid var(--accent);
  border-radius: 0 999px 999px 0;
}

/* The theme control is a link, not a button, because these pages carry no
   JavaScript at all — a CSP of `script-src 'none'` is the point of them. It
   round-trips through /theme, which sets a cookie and sends the reader back
   to where they were. */
.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--ink-2);
  text-decoration: none;
  font-size: .9rem;
  line-height: 1;
}
.theme-toggle:hover { background: var(--sunken); color: var(--ink); }

@media (max-width: 52rem) {
  /* Wrap, never hide. This used to hide BOTH the nav and the search below
     52rem, leaving a phone visitor a logo, a theme toggle, and no way to go
     anywhere — on the device most Nigerians browse on. The header now wraps
     to three rows: brand line, full-width search, scrollable nav. */
  .site-header .wrap { flex-wrap: wrap; row-gap: .5rem; }
  .header-search { flex-basis: 100%; max-width: none; order: 3; }
  .site-header nav {
    order: 4; flex-basis: 100%;
    display: flex; gap: 1rem;
    overflow-x: auto; -webkit-overflow-scrolling: touch;
    white-space: nowrap; padding-bottom: .25rem;
  }
}

/* A company's own copy about itself. Set apart so it never reads as the
   catalogue's own description of them. */
blockquote {
  margin: .75rem 0 0;
  padding: .1rem 0 .1rem 1rem;
  border-left: 2px solid var(--border);
  color: var(--ink-2);
  font-style: italic;
}

/* Where a business appears off its own domain. Laid out inline because the
   set is small and reads as a row of destinations, not a list of documents. */
.social-list { list-style: none; padding: 0; margin: 0 0 .6rem;
  display: flex; flex-wrap: wrap; gap: .5rem; }
.social-list li { margin: 0; }
.social-list a { display: inline-block; padding: .3rem .6rem;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--sunken); font-size: .9rem; text-decoration: none; }
.social-list a:hover { border-color: var(--accent); }

/* The supplier's product photo. Bounded so a marketplace's 1600px original
   cannot dominate a page that is mostly a price table. */
.product-photo { margin: 0 0 1rem; }
.product-photo img { max-width: 14rem; max-height: 14rem; object-fit: contain;
  background: #fff; border: 1px solid var(--border); border-radius: var(--radius); }

/* Long tokens must wrap, not widen the page. Source URLs run to 150
   characters, and an email address is one unbreakable word. */
.sources a, .facts dd { overflow-wrap: anywhere; }
.facts > div { min-width: 0; }

/* The photo plate stays white — product shots are white-filled — but padding
   makes it read as a deliberate frame rather than a hole in the dark theme. */
.product-photo img { padding: .375rem; }

/* The product gallery. One bounded slide per supplier photo; scroll-snap does
   the sliding, because these pages carry no script. Larger than the single
   photo's 14rem box — a gallery is the point of the page section, not an
   aside — and the plate stays white for the same reason that one's does. */
.product-gallery-track { display: flex; gap: .5rem; overflow-x: auto;
  scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch;
  scrollbar-width: thin; }
.product-gallery-track a { flex: 0 0 auto; scroll-snap-align: center; }
.product-gallery .product-gallery-track img { max-width: min(28rem, 80vw);
  max-height: 18rem; }
