/*
Theme Name: Stories of Inclusion
Theme URI: https://storiesofinclusion.org
Author: Nexa Sparks
Author URI: https://nexasparks.com
Description: Bilingual (Bangla/English), accessibility-first theme for Stories of Inclusion. Standalone — no parent theme, so the site carries no dependency on a third-party theme author.
Version: 0.1.0
Requires at least: 6.5
Requires PHP: 8.0
License: Proprietary — delivered to Stories of Inclusion
Text Domain: soi
Tags: accessibility-ready, translation-ready, education
*/

/* ==========================================================================
   DESIGN TOKENS
   Every colour pair used for text is contrast-checked against WCAG AA.
   See docs/design-system.md for the measured ratios — do not change a
   colour here without re-running that check.
   ========================================================================== */

:root {
  /* --- Brand ---------------------------------------------------------- */
  /* Provisional palette. The client has not supplied brand colours
     (Requirements V3.0 Section 14, item 3). Chosen for contrast first:
     deep teal reads as trustworthy and calm; amber carries the youth-led
     energy without shouting. Replace on receipt of brand assets, but
     re-check every ratio if you do. */
  --soi-primary:        #0a4f5c;  /* deep teal   */
  --soi-primary-dark:   #06333c;
  --soi-primary-light:  #e6f2f4;
  --soi-accent:         #b4530a;  /* warm amber, darkened for AA on white */
  --soi-accent-light:   #fdf1e6;

  /* --- Neutrals ------------------------------------------------------- */
  --soi-ink:            #16191c;  /* body text            */
  --soi-ink-soft:       #4a5157;  /* secondary text       */
  /* Two border tokens, deliberately.
     --soi-line is decorative only (dividers, card edges). WCAG 1.4.11 does
     not apply to it because it carries no information.
     --soi-line-strong is for anything that identifies an interactive
     control — input borders, checkbox outlines, select edges — where 3:1
     against the background IS required. Using --soi-line on a form field
     is an accessibility defect, not a style choice. */
  --soi-line:           #d9dee1;  /* decorative rules only */
  --soi-line-strong:    #767e84;  /* interactive borders   */
  --soi-bg:             #ffffff;
  --soi-bg-alt:         #f6f8f9;

  /* --- Status --------------------------------------------------------- */
  --soi-success:        #1c6b3f;
  --soi-warning:        #8a5a00;
  --soi-error:          #a3221c;

  /* --- Typography ----------------------------------------------------- */
  /* Bangla and English are set separately. Bangla needs a slightly larger
     size and looser line-height to stay legible at the same optical weight. */
  --soi-font-en:  "Inter", "Segoe UI", system-ui, -apple-system, sans-serif;
  --soi-font-bn:  "Hind Siliguri", "Noto Sans Bengali", "Nirmala UI", sans-serif;
  --soi-font-bn-serif: "Noto Serif Bengali", "Hind Siliguri", serif;

  --soi-text-xs:   0.8125rem;
  --soi-text-sm:   0.9375rem;
  --soi-text-base: 1.0625rem;
  --soi-text-lg:   1.1875rem;
  --soi-text-xl:   1.4375rem;
  --soi-text-2xl:  1.8125rem;
  --soi-text-3xl:  2.25rem;
  --soi-text-4xl:  2.875rem;

  --soi-leading-tight: 1.25;
  --soi-leading-base:  1.65;
  --soi-leading-loose: 1.8;   /* Bangla body copy */

  /* --- Space (4px base) ----------------------------------------------- */
  --soi-space-1:  0.25rem;
  --soi-space-2:  0.5rem;
  --soi-space-3:  0.75rem;
  --soi-space-4:  1rem;
  --soi-space-5:  1.25rem;
  --soi-space-6:  1.5rem;
  --soi-space-10: 2.5rem;
  --soi-space-8:  2rem;
  --soi-space-12: 3rem;
  --soi-space-16: 4rem;
  --soi-space-24: 6rem;

  /* --- Layout --------------------------------------------------------- */
  --soi-width-content: 42rem;   /* long-form reading measure */
  --soi-width-wide:    72rem;   /* page container            */
  --soi-radius:        6px;
  --soi-radius-lg:     12px;

  /* --- Elevation ------------------------------------------------------ */
  --soi-shadow-sm: 0 1px 2px rgba(6, 51, 60, 0.08);
  --soi-shadow-md: 0 4px 12px rgba(6, 51, 60, 0.10);

  /* --- Motion --------------------------------------------------------- */
  --soi-transition: 160ms ease;
}

/* Bangla reading context. Polylang sets lang="bn" on <html>; every Bangla
   string elsewhere carries lang="bn" on its own element, so both are covered. */
:root:lang(bn),
[lang="bn"] {
  --soi-font-en: var(--soi-font-bn);
  --soi-leading-base: var(--soi-leading-loose);
}

/* ==========================================================================
   RESET
   ========================================================================== */

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

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

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

body {
  font-family: var(--soi-font-en);
  font-size: var(--soi-text-base);
  line-height: var(--soi-leading-base);
  color: var(--soi-ink);
  background: var(--soi-bg);
  -webkit-font-smoothing: antialiased;
}

img, picture, video, canvas, svg { display: block; max-width: 100%; height: auto; }
input, button, textarea, select { font: inherit; color: inherit; }

/* ==========================================================================
   ACCESSIBILITY PRIMITIVES
   These are load-bearing. Requirements V3.0 Section 4 commits to every one
   of them — treat this block as specification, not decoration.
   ========================================================================== */

/* Visible focus on every interactive element. Never remove without an
   equally visible replacement. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 3px solid var(--soi-accent);
  outline-offset: 2px;
  border-radius: 2px;
}

/* Skip link — first thing in the tab order, visible once focused. */
.soi-skip-link {
  position: absolute;
  left: var(--soi-space-4);
  top: -100%;
  z-index: 999;
  padding: var(--soi-space-3) var(--soi-space-4);
  background: var(--soi-primary);
  color: #fff;
  font-weight: 600;
  border-radius: 0 0 var(--soi-radius) var(--soi-radius);
  transition: top var(--soi-transition);
}
.soi-skip-link:focus { top: 0; }

/* Screen-reader-only text that remains focusable. */
.screen-reader-text {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Honour the visitor's motion preference. Requirements V3.0 Section 4. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* Respect a raised contrast preference rather than overriding it. */
@media (prefers-contrast: more) {
  :root {
    --soi-ink-soft: var(--soi-ink);
    --soi-line: var(--soi-ink-soft);
  }
}

/* ==========================================================================
   TYPOGRAPHY
   ========================================================================== */

h1, h2, h3, h4, h5, h6 {
  line-height: var(--soi-leading-tight);
  font-weight: 700;
  color: var(--soi-primary-dark);
  text-wrap: balance;
}

h1 { font-size: var(--soi-text-4xl); }
h2 { font-size: var(--soi-text-3xl); }
h3 { font-size: var(--soi-text-2xl); }
h4 { font-size: var(--soi-text-xl); }

p { text-wrap: pretty; }

a {
  color: var(--soi-primary);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}
a:hover { color: var(--soi-accent); }

/* Never signal meaning with colour alone — links inside body copy stay
   underlined so they are distinguishable without colour vision. */
.soi-prose a { text-decoration: underline; }

.soi-prose {
  max-width: var(--soi-width-content);
}
.soi-prose > * + * { margin-top: var(--soi-space-4); }
.soi-prose h2 { margin-top: var(--soi-space-12); }
.soi-prose h3 { margin-top: var(--soi-space-8); }

/* ==========================================================================
   LAYOUT
   ========================================================================== */

.soi-container {
  width: 100%;
  max-width: var(--soi-width-wide);
  margin-inline: auto;
  padding-inline: var(--soi-space-4);
}

@media (min-width: 48rem) {
  .soi-container { padding-inline: var(--soi-space-8); }
}

/* Fluid, so the page does not carry desktop-sized gaps down onto a phone.
   The old fixed 4rem read as dead space on a sparse page and as cramped on a
   full one. */
.soi-section { padding-block: clamp( var(--soi-space-12), 7vw, var(--soi-space-16) ); }
.soi-section--alt { background: var(--soi-bg-alt); }

/* ==========================================================================
   TRANSLATION FALLBACK NOTICE
   Requirements V3.0 Section 6: content may exist in one language only. The
   visitor is told, rather than shown a blank page.
   ========================================================================== */

.soi-translation-notice {
  display: flex;
  gap: var(--soi-space-3);
  align-items: flex-start;
  padding: var(--soi-space-3) var(--soi-space-4);
  margin-bottom: var(--soi-space-6);
  background: var(--soi-accent-light);
  border-inline-start: 4px solid var(--soi-accent);
  border-radius: var(--soi-radius);
  font-size: var(--soi-text-sm);
  color: var(--soi-ink);
}

/* ==========================================================================
   BUTTONS
   Minimum target 44x44 including padding — this site is used on cheap phones
   by people who are not its designers.
   ========================================================================== */

.soi-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--soi-space-2);
  min-height: 44px;
  padding: var(--soi-space-3) var(--soi-space-6);
  border: 2px solid transparent;
  border-radius: var(--soi-radius);
  font-size: var(--soi-text-base);
  font-weight: 600;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--soi-transition), border-color var(--soi-transition), color var(--soi-transition);
}

.soi-btn--primary {
  background: var(--soi-primary);
  border-color: var(--soi-primary);
  color: #fff;
}
.soi-btn--primary:hover { background: var(--soi-primary-dark); border-color: var(--soi-primary-dark); color: #fff; }

.soi-btn--accent {
  background: var(--soi-accent);
  border-color: var(--soi-accent);
  color: #fff;
}
.soi-btn--accent:hover { background: #8f4208; border-color: #8f4208; color: #fff; }

.soi-btn--outline {
  background: transparent;
  border-color: var(--soi-primary);
  color: var(--soi-primary);
}
.soi-btn--outline:hover { background: var(--soi-primary-light); color: var(--soi-primary-dark); }

/* On a dark or photographic ground. */
.soi-btn--inverse {
  background: #fff;
  border-color: #fff;
  color: var(--soi-primary-dark);
}
.soi-btn--inverse:hover { background: var(--soi-primary-light); color: var(--soi-primary-dark); }

.soi-btn--small { min-height: 36px; padding: var(--soi-space-2) var(--soi-space-4); font-size: var(--soi-text-sm); }
.soi-btn--block { display: flex; width: 100%; }

/* ==========================================================================
   FILTER BAR
   The audiobook "browse by class / subject" chips (V3.0 §5.1) — shared by
   the post type archive and the term archives those chips link to, so a
   visitor never loses the filters once they click one. A tinted panel gives
   the two chip rows one visible boundary instead of floating loose between
   the title and the grid.
   ========================================================================== */

.soi-filter-bar {
  display: flex;
  flex-direction: column;
  gap: var(--soi-space-3);
  padding: var(--soi-space-5) var(--soi-space-6);
  margin-bottom: var(--soi-space-8);
  background: var(--soi-primary-light);
  border-radius: var(--soi-radius-lg);
}

.soi-filter-bar__label {
  flex-basis: 100%;
  font-size: var(--soi-text-sm);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--soi-primary-dark);
}
:lang(bn) .soi-filter-bar__label { letter-spacing: 0; text-transform: none; }

/* ==========================================================================
   SITE HEADER
   ========================================================================== */

.soi-header {
  background: var(--soi-bg);
  border-bottom: 1px solid var(--soi-line);
  position: relative;
  z-index: 10;
}

.soi-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--soi-space-4);
  min-height: 72px;
  flex-wrap: wrap;
}

.soi-header__brand {
  font-size: var(--soi-text-lg);
  font-weight: 700;
  line-height: 1.2;
}
.soi-header__brand a { color: var(--soi-primary-dark); text-decoration: none; }
.soi-header__brand img { max-height: 48px; width: auto; }

.soi-header__tools {
  display: flex;
  align-items: center;
  gap: var(--soi-space-3);
}

/* --- Primary navigation ---------------------------------------------- */

.soi-nav__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--soi-space-1);
  margin: 0;
  padding: 0;
  list-style: none;
}

.soi-nav__list a {
  display: block;
  padding: var(--soi-space-2) var(--soi-space-3);
  border-radius: var(--soi-radius);
  color: var(--soi-ink);
  font-weight: 500;
  text-decoration: none;
}
.soi-nav__list a:hover { background: var(--soi-primary-light); color: var(--soi-primary-dark); }

/* Current page is marked with weight and a rule, never colour alone. */
.soi-nav__list .current-menu-item > a,
.soi-nav__list .current_page_item > a {
  font-weight: 700;
  color: var(--soi-primary-dark);
  box-shadow: inset 0 -3px 0 var(--soi-accent);
}

/* --- Mobile disclosure ------------------------------------------------ */

.soi-nav-toggle { display: none; }

@media (max-width: 60rem) {
  .soi-nav-toggle {
    display: inline-flex;
    align-items: center;
    gap: var(--soi-space-2);
    min-height: 44px;
    padding: var(--soi-space-2) var(--soi-space-3);
    background: transparent;
    border: 2px solid var(--soi-line-strong);
    border-radius: var(--soi-radius);
    font-weight: 600;
    cursor: pointer;
  }

  /* The collapsed state is driven by [hidden] on the panel, so the markup
     stays meaningful with CSS off and aria-expanded stays truthful. */
  .soi-nav {
    flex-basis: 100%;
    order: 10;
  }
  .soi-nav__list {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding-block: var(--soi-space-2);
    border-top: 1px solid var(--soi-line);
  }
  .soi-nav__list a { padding: var(--soi-space-3); }
}

/* --- Language switcher ------------------------------------------------ */

.soi-lang {
  display: flex;
  align-items: center;
  gap: 0;
  border: 2px solid var(--soi-line-strong);
  border-radius: var(--soi-radius);
  overflow: hidden;
}

.soi-lang__item {
  display: block;
  min-height: 40px;
  padding: var(--soi-space-2) var(--soi-space-3);
  color: var(--soi-ink);
  font-size: var(--soi-text-sm);
  font-weight: 600;
  text-decoration: none;
  line-height: 24px;
}
.soi-lang__item:hover { background: var(--soi-primary-light); color: var(--soi-primary-dark); }

/* The active language is announced by aria-current; the styling repeats that
   visually rather than replacing it. */
.soi-lang__item[aria-current] {
  background: var(--soi-primary);
  color: #fff;
}
.soi-lang__item[aria-current]:hover { background: var(--soi-primary-dark); color: #fff; }

/* --- Account (Ultimate Member) ----------------------------------------- */

.soi-account {
  display: flex;
  align-items: center;
  gap: var(--soi-space-2);
}

.soi-account__item {
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  padding: var(--soi-space-2) var(--soi-space-3);
  border-radius: var(--soi-radius);
  color: var(--soi-ink);
  font-size: var(--soi-text-sm);
  font-weight: 600;
  text-decoration: none;
}
.soi-account__item:hover { background: var(--soi-primary-light); color: var(--soi-primary-dark); }

/* Sign Up carries the same weight as a primary button — it is the one link
   in the header meant to convert a first-time visitor, not just navigate. */
.soi-account__item--primary {
  background: var(--soi-primary);
  color: #fff;
}
.soi-account__item--primary:hover { background: var(--soi-primary-dark); color: #fff; }

/* ==========================================================================
   FOOTER
   ========================================================================== */

.soi-footer {
  margin-top: var(--soi-space-24);
  padding-block: var(--soi-space-16) var(--soi-space-8);
  background: var(--soi-primary-dark);
  color: #e8eef0;
}
.soi-footer a { color: #fff; }
.soi-footer h2, .soi-footer h3 { color: #fff; font-size: var(--soi-text-lg); }

.soi-footer__grid {
  display: grid;
  gap: var(--soi-space-8);
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  margin-bottom: var(--soi-space-12);
}

.soi-footer__legal {
  padding-top: var(--soi-space-6);
  border-top: 1px solid rgba(255, 255, 255, 0.2);
  font-size: var(--soi-text-sm);
}

.soi-social {
  display: flex;
  flex-wrap: wrap;
  gap: var(--soi-space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}
.soi-social a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: 50%;
}
.soi-social svg { width: 20px; height: 20px; fill: currentColor; }

/* ==========================================================================
   SECTION HEADINGS
   ========================================================================== */

.soi-section__head {
  max-width: var(--soi-width-content);
  margin-bottom: var(--soi-space-8);
}

/* A short amber rule above each section heading. The palette carries a warm
   accent that was doing almost nothing on the page, and this is where it earns
   its place: it marks where a section starts, which on a long homepage of
   stacked strips is the thing the eye was missing. Decorative, so it is drawn
   rather than marked up, and it is skipped where the heading is only there for
   a screen reader. */
.soi-section__head > h2:first-child::before,
.soi-section__head > h1:first-child::before {
  content: "";
  display: block;
  width: 2.5rem;
  height: 4px;
  margin-bottom: var(--soi-space-4);
  background: var(--soi-accent);
  border-radius: 2px;
}

.soi-section__head h2 {
  font-size: clamp( var(--soi-text-2xl), 3.5vw, var(--soi-text-3xl) );
  letter-spacing: -0.015em;
}
:lang(bn) .soi-section__head h2 { letter-spacing: 0; }
.soi-section__head p {
  margin-top: var(--soi-space-3);
  color: var(--soi-ink-soft);
  font-size: var(--soi-text-lg);
}

/* ==========================================================================
   CARDS AND GRIDS
   ========================================================================== */

/* These three are layout containers that are sometimes marked up as a list —
   the awards grid, the social links, the contact buttons on a book. A <ul> is
   the right element when the content is a list of things, but the marker and
   its indent are not wanted, and forgetting this leaves bullets sitting beside
   cards. Reset here, once, rather than at each call site. */
.soi-grid,
.soi-cluster,
.soi-stack {
  list-style: none;
}
ul.soi-grid,
ul.soi-cluster,
ul.soi-stack,
ol.soi-stack {
  margin: 0;
  padding: 0;
}

.soi-grid {
  display: grid;
  gap: var(--soi-space-6);
  grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr));
}
.soi-grid--wide { grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr)); }

.soi-card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--soi-bg);
  border: 1px solid var(--soi-line);
  border-radius: var(--soi-radius-lg);
  overflow: hidden;
  box-shadow: 0 1px 2px rgba(6, 51, 60, 0.04);
  transition:
    box-shadow var(--soi-transition),
    border-color var(--soi-transition),
    transform var(--soi-transition);
}
.soi-card:hover {
  box-shadow: var(--soi-shadow-md);
  border-color: var(--soi-primary-light);
  transform: translateY(-2px);
}

/* An amber edge that grows along the top on hover. It gives the tile something
   to do under the cursor beyond a shadow, and it uses the accent colour that
   the rest of the page had left idle. */
.soi-card::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: 0;
  height: 3px;
  background: var(--soi-accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--soi-transition);
}
.soi-card:hover::after,
.soi-card:focus-within::after { transform: scaleX(1); }

/* A card with no picture — the normal state for a blog post or an award while
   the client is still filling the site — was a bordered box with a line of
   text in it. Tinting the head of the body gives it a shape of its own so a
   grid of them reads as a set of cards rather than as a table with borders.
   :has() is not universal; where it is missing the card simply stays plain. */
@supports selector(:has(*)) {
  .soi-card:not(:has(.soi-card__media)) .soi-card__body {
    background: linear-gradient( 180deg, var(--soi-primary-light) 0%, rgba(230, 242, 244, 0) 5.5rem );
  }
}

/* Motion is a preference, not a default. */
@media (prefers-reduced-motion: reduce) {
  .soi-card { transition: box-shadow var(--soi-transition), border-color var(--soi-transition); }
  .soi-card:hover { transform: none; }
  .soi-card::after { transition: none; }
}

.soi-card__media { position: relative; background: var(--soi-primary-light); aspect-ratio: 16 / 9; }
.soi-card__media img { width: 100%; height: 100%; object-fit: cover; }

.soi-card__body { display: flex; flex-direction: column; gap: var(--soi-space-2); padding: var(--soi-space-6); flex: 1; }
.soi-card__title { font-size: var(--soi-text-xl); line-height: 1.3; letter-spacing: -0.01em; }
:lang(bn) .soi-card__title { letter-spacing: 0; }
.soi-card__title a { color: var(--soi-primary-dark); text-decoration: none; }
.soi-card:hover .soi-card__title a { color: var(--soi-primary); }


/* The whole card is clickable, but only the title is a link — so the
   accessible name stays the title and keyboard focus lands in one place. */
.soi-card__title a::after { content: ""; position: absolute; inset: 0; }

.soi-card__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--soi-space-2) var(--soi-space-4);
  color: var(--soi-ink-soft);
  font-size: var(--soi-text-sm);
}
.soi-card__excerpt { color: var(--soi-ink-soft); font-size: var(--soi-text-sm); }

/* ==========================================================================
   BADGES
   ========================================================================== */

.soi-badge {
  display: inline-block;
  padding: 2px var(--soi-space-2);
  background: var(--soi-primary-light);
  border-radius: 999px;
  color: var(--soi-primary-dark);
  font-size: var(--soi-text-xs);
  font-weight: 600;
}
.soi-badge--accent { background: var(--soi-accent-light); color: #7a3806; }

/* ==========================================================================
   VIDEO FACADE
   Requirements V3.0 Section 4: the real player loads only on press, so a page
   listing ten audiobooks does not load ten players.
   ========================================================================== */

.soi-video {
  position: relative;
  aspect-ratio: 16 / 9;
  background: var(--soi-primary-dark);
  border-radius: var(--soi-radius-lg);
  overflow: hidden;
}
.soi-video img, .soi-video iframe { width: 100%; height: 100%; object-fit: cover; border: 0; }

.soi-video__play {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  background: transparent;
  border: 0;
  cursor: pointer;
}
.soi-video__play::before {
  content: "";
  width: 72px;
  height: 72px;
  background: var(--soi-accent) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23ffffff'%3E%3Cpath d='M8 5v14l11-7z'/%3E%3C/svg%3E") no-repeat center / 40%;
  border-radius: 50%;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.4);
  transition: transform var(--soi-transition);
}
.soi-video__play:hover::before { transform: scale(1.08); }
.soi-video__play:focus-visible { outline-offset: -4px; }

/* ==========================================================================
   OUR JOURNEY TIMELINE
   Requirements V3.0 Section 5.4.
   ========================================================================== */

.soi-timeline { position: relative; margin: 0; padding: 0; list-style: none; }

/* The connecting line. Decorative, so it is drawn rather than marked up. */
.soi-timeline::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: 27px;
  width: 2px;
  background: var(--soi-line);
}

.soi-timeline__item {
  position: relative;
  padding-inline-start: 76px;
  padding-bottom: var(--soi-space-12);
}
.soi-timeline__item:last-child { padding-bottom: 0; }

.soi-timeline__year {
  position: absolute;
  inset-inline-start: 0;
  top: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  background: var(--soi-primary);
  border-radius: 50%;
  color: #fff;
  font-size: var(--soi-text-sm);
  font-weight: 700;
}

.soi-timeline__title { font-size: var(--soi-text-xl); margin-bottom: var(--soi-space-2); }
.soi-timeline__body { color: var(--soi-ink-soft); }
.soi-timeline__image { margin-top: var(--soi-space-4); border-radius: var(--soi-radius); }

/* The gentle reveal promised in Section 5.4, and its opt-out. */
@media (prefers-reduced-motion: no-preference) {
  .soi-timeline__item {
    opacity: 0;
    transform: translateY(16px);
    transition: opacity 500ms ease, transform 500ms ease;
  }
  .soi-timeline__item.is-visible { opacity: 1; transform: none; }
}

/* ==========================================================================
   IMPACT STATISTICS
   ========================================================================== */

.soi-stats {
  display: grid;
  gap: var(--soi-space-6);
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  margin: 0;
  padding: 0;
  list-style: none;
}
/* Each figure gets a panel of its own. Four numbers floating on a tinted band
   read as a row of loose text; boxed, they read as the achievement they are —
   and this is the client's proudest section, the one the portfolio PDF leads
   with. */
.soi-stat {
  position: relative;
  padding: var(--soi-space-8) var(--soi-space-4);
  background: var(--soi-bg);
  border: 1px solid var(--soi-line);
  border-radius: var(--soi-radius-lg);
  text-align: center;
}

/* Amber cap, echoing the rule on the section headings. */
.soi-stat::before {
  content: "";
  position: absolute;
  inset-inline: 35%;
  top: 0;
  height: 4px;
  background: var(--soi-accent);
  border-radius: 0 0 3px 3px;
}

.soi-stat__value {
  display: block;
  color: var(--soi-primary);
  font-size: clamp( var(--soi-text-3xl), 5vw, var(--soi-text-4xl) );
  font-weight: 700;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}
/* Bangla numerals are not tabular in most faces and the negative tracking
   closes up the matras. */
:lang(bn) .soi-stat__value { letter-spacing: 0; font-variant-numeric: normal; }

.soi-stat__label {
  display: block;
  margin-top: var(--soi-space-3);
  color: var(--soi-ink-soft);
  font-size: var(--soi-text-sm);
  font-weight: 500;
}

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

.soi-hero {
  position: relative;
  display: flex;
  align-items: center;
  min-height: clamp(24rem, 60vh, 34rem);
  padding-block: var(--soi-space-16);
  color: #fff;
  overflow: hidden;

  /* Three layers rather than a flat fill. The client may never supply a hero
     image — they are a nine-person volunteer team — so the no-image state has
     to be the good one, not the fallback. A diagonal shift through the two
     teals plus a warm off-centre glow gives the band depth and a direction to
     read in; a single background-color gives a dark rectangle. */
  background:
    radial-gradient( 60% 80% at 85% 15%, rgba(180, 83, 10, 0.30) 0%, rgba(180, 83, 10, 0) 60% ),
    radial-gradient( 50% 70% at 10% 90%, rgba(10, 79, 92, 0.65) 0%, rgba(10, 79, 92, 0) 70% ),
    linear-gradient( 145deg, #06333c 0%, #0a4f5c 55%, #08404b 100% );
}

/* A faint grid, one step above invisible. It catches the light on a large
   screen where flat colour looks like a missing image, and is imperceptible on
   a phone. Decorative only, so it is drawn rather than marked up. */
.soi-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient( rgba(255, 255, 255, 0.04) 1px, transparent 1px ),
    linear-gradient( 90deg, rgba(255, 255, 255, 0.04) 1px, transparent 1px );
  background-size: 64px 64px;
  mask-image: radial-gradient( 80% 80% at 50% 40%, #000 0%, transparent 100% );
  pointer-events: none;
}
.soi-hero__bg { position: absolute; inset: 0; }
.soi-hero__bg img { width: 100%; height: 100%; object-fit: cover; }

/* Text over an image needs a guaranteed floor for contrast, because the image
   is chosen by the client and cannot be relied on. */
.soi-hero__bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, rgba(6, 51, 60, 0.92) 0%, rgba(6, 51, 60, 0.72) 100%);
}
.soi-hero__inner { position: relative; z-index: 1; max-width: 46rem; }

/* Fluid rather than a fixed step, because this one line has to work at 320px
   and at 1600px and the token scale tops out well below what a hero wants. */
.soi-hero h1 {
  color: #fff;
  font-size: clamp( var(--soi-text-3xl), 5.5vw, 4rem );
  line-height: 1.1;
  letter-spacing: -0.02em;
  text-wrap: balance;
}
.soi-hero p {
  max-width: 38rem;
  margin-top: var(--soi-space-5);
  color: #cfe0e3;
  font-size: clamp( var(--soi-text-lg), 2.2vw, var(--soi-text-xl) );
  line-height: 1.55;
}
.soi-hero__actions { display: flex; flex-wrap: wrap; gap: var(--soi-space-3); margin-top: var(--soi-space-8); }

/* Bangla sits optically smaller than Latin at the same point size and its
   ascenders and matras need the extra room. */
:lang(bn) .soi-hero h1 { line-height: 1.28; letter-spacing: 0; }

/* ==========================================================================
   FORMS
   Every control gets --soi-line-strong, never --soi-line: an input border
   carries information and must clear 3:1.
   ========================================================================== */

.soi-field { margin-bottom: var(--soi-space-5); }
.soi-field label { display: block; margin-bottom: var(--soi-space-2); font-weight: 600; }
.soi-field__hint { display: block; margin-bottom: var(--soi-space-2); color: var(--soi-ink-soft); font-size: var(--soi-text-sm); }

.soi-input, .soi-select, .soi-textarea,
input[type="text"], input[type="email"], input[type="tel"], input[type="url"],
input[type="password"], input[type="search"], input[type="number"], input[type="date"],
select, textarea {
  width: 100%;
  min-height: 44px;
  padding: var(--soi-space-3);
  background: var(--soi-bg);
  border: 2px solid var(--soi-line-strong);
  border-radius: var(--soi-radius);
  color: var(--soi-ink);
}
textarea { min-height: 8rem; resize: vertical; }

/* Required is stated in the label text as well; this is reinforcement. */
.soi-field--required label::after { content: " *"; color: var(--soi-error); }

.soi-field__error {
  display: block;
  margin-top: var(--soi-space-2);
  color: var(--soi-error);
  font-size: var(--soi-text-sm);
  font-weight: 600;
}
.soi-field--invalid input, .soi-field--invalid textarea, .soi-field--invalid select {
  border-color: var(--soi-error);
}

/* ==========================================================================
   NOTICES
   ========================================================================== */

.soi-notice {
  padding: var(--soi-space-4);
  border-inline-start: 4px solid var(--soi-primary);
  border-radius: var(--soi-radius);
  background: var(--soi-primary-light);
  margin-bottom: var(--soi-space-6);
}
.soi-notice--success { background: #e7f3ec; border-color: var(--soi-success); }
.soi-notice--error { background: #fbeae9; border-color: var(--soi-error); }

/* ==========================================================================
   PROGRESS
   Requirements V3.0 Section 5.5 — the figure is always in text as well, never
   only in the width of a bar.
   ========================================================================== */

.soi-progress {
  height: 10px;
  background: var(--soi-primary-light);
  border-radius: 999px;
  overflow: hidden;
}
.soi-progress__bar { height: 100%; background: var(--soi-success); }

/* ==========================================================================
   PAGINATION
   ========================================================================== */

.soi-pagination { margin-top: var(--soi-space-12); }
.soi-pagination .nav-links { display: flex; flex-wrap: wrap; gap: var(--soi-space-2); }
.soi-pagination .page-numbers {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0 var(--soi-space-2);
  border: 1px solid var(--soi-line-strong);
  border-radius: var(--soi-radius);
  text-decoration: none;
}
.soi-pagination .page-numbers.current {
  background: var(--soi-primary);
  border-color: var(--soi-primary);
  color: #fff;
  font-weight: 700;
}

/* ==========================================================================
   TABLES
   ========================================================================== */

.soi-table { width: 100%; border-collapse: collapse; }
.soi-table caption { margin-bottom: var(--soi-space-3); color: var(--soi-ink-soft); text-align: start; }
.soi-table th, .soi-table td { padding: var(--soi-space-3); border-bottom: 1px solid var(--soi-line); text-align: start; }
.soi-table th { font-weight: 700; color: var(--soi-primary-dark); }

/* Wide content scrolls inside its own box; the page never scrolls sideways. */
.soi-scroll-x { overflow-x: auto; }

/* ==========================================================================
   GALLERY
   ========================================================================== */

.soi-gallery {
  display: grid;
  gap: var(--soi-space-3);
  grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
  margin: 0;
  padding: 0;
  list-style: none;
}
.soi-gallery button { display: block; width: 100%; padding: 0; background: none; border: 0; cursor: pointer; }
.soi-gallery img { aspect-ratio: 1; object-fit: cover; border-radius: var(--soi-radius); }

/* ==========================================================================
   UTILITIES
   ========================================================================== */

.soi-stack > * + * { margin-top: var(--soi-space-4); }
.soi-stack--lg > * + * { margin-top: var(--soi-space-8); }
.soi-cluster { display: flex; flex-wrap: wrap; gap: var(--soi-space-3); align-items: center; }

/* The "All posts" link that closes a homepage strip. Without this it sits
   almost touching the cards it belongs under. */
.soi-grid + .soi-center { margin-top: var(--soi-space-12); }
.soi-center { text-align: center; }
.soi-measure { max-width: var(--soi-width-content); }

/* ==========================================================================
   MAGAZINE READER
   Requirements V3.0 Section 5.4.
   ========================================================================== */

/* Tall rather than a fixed aspect ratio: a magazine page is portrait, and a
   16/9 box would show a strip of one page. The viewport unit keeps it usable
   on a phone without running past the screen. */
.soi-reader {
  display: block;
  width: 100%;
  height: min(80vh, 900px);
  background: var(--soi-primary-light);
  border: 1px solid var(--soi-line);
  border-radius: var(--soi-radius-lg);
}

/* The fallback shown when the browser cannot render a PDF inline. */
.soi-reader p { padding: var(--soi-space-6); }

/* Images placed at the head of a page or a profile. */
.soi-page__image { border-radius: var(--soi-radius-lg); }

/* ==========================================================================
   Site search (Section 4.10)
   ==========================================================================
   Lives inside the primary nav so that on a narrow screen it opens with the
   menu instead of needing a disclosure control of its own. Its border uses
   --soi-line-strong, not --soi-line: this identifies a control, and a control
   boundary has to clear 3:1 (WCAG 1.4.11). Using the decorative token here
   would be an accessibility defect, not a style choice.
   ========================================================================== */

.soi-search {
  display: flex;
  gap: var(--soi-space-2);
  align-items: center;
}

.soi-search__field {
  min-width: 0;
  flex: 1 1 auto;
  min-height: 44px;
  padding: var(--soi-space-2) var(--soi-space-3);
  font: inherit;
  color: var(--soi-ink);
  background: var(--soi-bg);
  border: 1px solid var(--soi-line-strong);
  border-radius: var(--soi-radius);
}

.soi-search__submit {
  min-height: 44px;
  min-width: 44px;
  padding: var(--soi-space-2) var(--soi-space-4);
  font: inherit;
  font-weight: 600;
  color: #fff;
  cursor: pointer;
  background: var(--soi-primary);
  border: 1px solid var(--soi-primary);
  border-radius: var(--soi-radius);
}

.soi-search__submit:hover { background: var(--soi-primary-dark); }

@media (min-width: 60.0625rem) {
  /* On a wide screen the nav is a row, and the search sits at its end rather
     than stretching across it. */
  .soi-search { flex: 0 1 18rem; margin-inline-start: auto; }
}

/* ==========================================================================
   Share links (Section 4.2)
   ==========================================================================
   Plain links to each network's share address — no third-party script, so the
   page costs nothing for a control most visitors never press.
   ========================================================================== */

.soi-share {
  padding-block-start: var(--soi-space-5);
  border-block-start: 1px solid var(--soi-line);
}

.soi-share__heading {
  margin: 0 0 var(--soi-space-3);
  font-size: var(--soi-text-sm);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--soi-ink-soft);
}

.soi-share__list { list-style: none; padding: 0; margin: 0; }

/* ==========================================================================
   Location map (Section 4.11)
   ==========================================================================
   A facade until somebody asks for the map — see inc/location-map.php. The
   placeholder has to be the same height as the map that replaces it, or the
   page jumps when it loads, which is a scored defect.
   ========================================================================== */

.soi-map { display: grid; gap: var(--soi-space-4); }

.soi-map__address {
  margin: 0;
  font-size: var(--soi-text-lg);
  line-height: var(--soi-leading-base);
}

.soi-map__facade {
  display: grid;
  place-items: center;
  width: 100%;
  height: min(60vh, 420px);
  overflow: hidden;
  background:
    linear-gradient(135deg, var(--soi-primary-light), var(--soi-bg-alt));
  border: 1px solid var(--soi-line);
  border-radius: var(--soi-radius-lg);
}

/* The iframe the script swaps in fills the box it replaced. */
.soi-map__facade iframe {
  width: 100%;
  height: 100%;
  border: 0;
}
