/* Portfolio index — full structural rebuild (explicit direction: not a
   superficial refresh) reusing the exact split/typography/card system
   already proven on /blogs/ and /ai-hub/ (see css/components/blog.css/
   ai-hub.css and pages/blogs.njk/ai-hub.njk for the reference
   composition), not a new visual language. Tokens below are
   intentionally byte-identical to blog.css's/ai-hub.css's own --li-*
   recipe (same values, same names) rather than a shared file, matching
   how this codebase already handles this exact situation (ai-hub.css's
   own header comment). Scoped to .portfolio-hero/.portfolio-feed so
   nothing here leaks onto any other page. */
.portfolio-hero,
.portfolio-feed {
  --li-card-bg: rgba(38, 32, 56, 0.55);
  --li-card-blur: blur(24px);
  --li-border: rgba(255, 255, 255, 0.08);
  --li-border-hover: rgba(88, 130, 246, 0.4);
  --li-shadow: 0 4px 24px rgba(0, 0, 0, 0.35);
  --li-shadow-hover: 0 10px 32px rgba(63, 123, 248, 0.16), 0 4px 16px rgba(184, 107, 248, 0.12);
  --li-radius: 16px;
  --li-text: rgba(255, 255, 255, 0.92);
  --li-text-secondary: rgba(255, 255, 255, 0.6);
  --li-media-bg: rgba(10, 8, 16, 0.6);
}

/* Same wide 1560px matrix as /blogs/ and /ai-hub/ (not page-split's
   1180px default), same fixed 390px intro column, same 56px gap — audit
   requirement: Portfolio, Blog and Hub IA must share one matrix, not
   each invent an approximate one. */
.portfolio-hero .section__inner {
  max-width: 1560px;
}

@media (min-width: 1024px) {
  .page-split--portfolio {
    max-width: 1560px;
    --page-split-intro: 390px;
    --page-split-gap: 56px;
  }
}

/* Left column stays LEFT-aligned (explicit direction for this page's H1
   specifically) — Blog/Hub both override page-split.css's shared default
   to centered for their own intro column, but Portfolio does not: no
   override rule here at all, so the plain page-split.css default
   (text-align: left at >=1024px) applies untouched. */

.portfolio-hero__inner {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

/* Vertically centered within its own sticky box on desktop (explicit
   direction: "descend un peu pour que ça soit bien centré en hauteur") —
   a capped min-height (not raw 100vh, so a very tall viewport doesn't
   push this absurdly tall) plus justify-content: center nudges the
   content down from the top of the sticky box instead of sitting flush
   against it. */
@media (min-width: 1024px) {
  .portfolio-hero__inner {
    justify-content: center;
    min-height: min(calc(100vh - 240px), 700px);
  }
}

.portfolio-hero__inner .page-title,
.portfolio-hero__inner .page-subtitle {
  margin: 0;
}

.portfolio-subtitle {
  max-width: 42ch;
}

.portfolio-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;
}

/* ---- Expertise filter chips -- moved into the left column, below the
   subtitle (explicit direction, simplified down from an earlier pass
   that also had a search bar, a separate nature-of-project filter and a
   recommendation card here, plus a second uniform-gradient-pill
   expertise row above the grid on the right). Same per-topic colored-
   chip language as /blogs/'s .blog-filtergroup: default = colored border
   only, hover = temporary colored fill, selected = persistent colored
   fill (--theme-color set inline per button, see pages/portfolio.njk).
   Wraps onto multiple lines in the narrow fixed-width column — no
   horizontal scroll container needed here. Still a real ARIA radiogroup
   (single selection, roving tabindex, keyboard nav in
   js/portfolio-filter.js). ---- */
.portfolio-expertisegroup {
  display: flex;
  flex-wrap: wrap;
  gap: 9px;
  margin-top: 4px;
}

/* Centered on mobile/tablet (explicit direction) — matches the H1/
   subtitle's own centered treatment at this breakpoint (page-split.css's
   shared default for .page-split__intro below 1024px); left-aligned
   again once the split kicks in, alongside the left-aligned H1. */
@media (max-width: 1023px) {
  .portfolio-expertisegroup {
    justify-content: center;
  }
}

/* Même recette que .blog-filtergroup__btn (blog.css) : réduits et arrondis
   en pilule ("trop gros" -> "plus mignons"), et teintés au repos avec leur
   propre --theme-color (transparent, pas plein) plutôt qu'un fond
   totalement transparent, pour que chaque chip se lise déjà coloré avant
   même le survol/la sélection. */
.portfolio-expertisegroup__btn {
  appearance: none;
  background: color-mix(in srgb, var(--theme-color, rgba(255, 255, 255, 0.4)) 16%, transparent);
  border: 1.5px solid var(--theme-color, rgba(255, 255, 255, 0.4));
  font-family: var(--font-satoshi);
  font-size: 12px;
  font-weight: 600;
  color: #fff;
  padding: 6px 14px;
  min-height: 32px;
  border-radius: 999px;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.18s ease, color 0.18s ease, box-shadow 0.18s ease;
}

.portfolio-expertisegroup__btn:hover {
  background: var(--theme-color, rgba(255, 255, 255, 0.4));
}

.portfolio-expertisegroup__btn[aria-checked="true"] {
  background: var(--theme-color, rgba(255, 255, 255, 0.55));
  box-shadow: 0 4px 16px color-mix(in srgb, var(--theme-color, #fff) 45%, transparent);
}

.portfolio-expertisegroup__btn:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
}

/* =====================================================================
   Right column -- results count, grid, cards, load more, empty state.
   ===================================================================== */
.portfolio-results-count {
  margin: 0 0 16px;
  font-family: var(--font-satoshi);
  font-size: 13px;
  color: var(--li-text-secondary);
}

.portfolio-results-count[hidden] {
  display: none;
}

/* Container query, not a viewport breakpoint (explicit direction) -- the
   grid reflows against the right column's own rendered width. Thresholds
   per spec: >=~1040px -> 3 col, ~680-1039px -> 2 col, <680px -> 1 col. */
.portfolio-feed {
  container-type: inline-size;
}

.portfolio-grid {
  display: grid;
  grid-template-columns: 1fr;
  grid-auto-rows: 1fr;
  align-items: stretch;
  gap: 24px;
  transition: opacity 0.18s ease;
}

@container (min-width: 680px) {
  .portfolio-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@container (min-width: 1040px) {
  .portfolio-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (prefers-reduced-motion: reduce) {
  .portfolio-grid,
  .portfolio-card {
    transition: none;
  }
}

/* ---- Card -- same dark-glass family as .blog-card/.ai-hub-card, taken
   one notch further (explicit direction: "reprendre la qualité visuelle
   des cartes du Hub IA, avec une identité propre au Portfolio") with the
   masked-gradient-border-crossfade technique already proven on
   /services/'s .service-module (services-cards.css) -- a resting dim
   ring and a hover-only brighter ring, pure opacity cross-fade, zero
   gradient-interpolation artifacts. <article>, not <a> (a project has AT
   MOST one action, rendered as its own real link — some cards have none
   at all and stay non-interactive, so the whole card can't be the link
   target). Every hover effect below is transform/opacity/color only --
   no box-shadow animation, no blur animation, no mousemove, no 3D/tilt,
   no extra library. */
.portfolio-card {
  position: relative;
  isolation: isolate;
  display: flex;
  flex-direction: column;
  height: 100%;
  background: var(--li-card-bg);
  backdrop-filter: var(--li-card-blur);
  -webkit-backdrop-filter: var(--li-card-blur);
  border-radius: var(--li-radius);
  box-shadow: var(--li-shadow);
  overflow: hidden;
  transition: transform 0.2s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.portfolio-card:hover,
.portfolio-card:focus-within {
  transform: translateY(-3px);
}

.portfolio-card::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  padding: 1px;
  border-radius: inherit;
  background: linear-gradient(135deg, rgba(63, 123, 248, 0.35), rgba(184, 107, 248, 0.25), rgba(63, 123, 248, 0.1));
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  pointer-events: none;
}

.portfolio-card::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  padding: 1px;
  border-radius: inherit;
  background: linear-gradient(135deg, rgba(63, 123, 248, 0.8), rgba(184, 107, 248, 0.6), rgba(63, 123, 248, 0.28));
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.portfolio-card:hover::after,
.portfolio-card:focus-within::after {
  opacity: 1;
}

/* Fixed halo -- always faintly present in one corner, intensifies on
   hover (opacity only, never pointer-following). */
.portfolio-card__cover::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: radial-gradient(60% 80% at 100% 0%, rgba(99, 102, 241, 0.22), transparent 60%);
  opacity: 0.6;
  transition: opacity 0.2s ease;
  pointer-events: none;
}

.portfolio-card:hover .portfolio-card__cover::before,
.portfolio-card:focus-within .portfolio-card__cover::before {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .portfolio-card,
  .portfolio-card::after,
  .portfolio-card__cover::before {
    transition: none;
  }

  .portfolio-card:hover,
  .portfolio-card:focus-within {
    transform: none;
  }
}

/* [hidden] set directly by js/portfolio-filter.js -- author `display:
   flex` above always wins over the UA [hidden] default regardless of
   specificity (same fix already applied once for .blog-card[hidden]). */
.portfolio-card[hidden] {
  display: none;
}

/* ---- Cover -- same 16:9 ratio on every card, real screenshot/render
   when one exists, a CSS-only fallback otherwise (never a fake
   screenshot). ---- */
.portfolio-card__cover {
  position: relative;
  isolation: isolate;
  width: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--li-media-bg);
  flex-shrink: 0;
}

.portfolio-card__cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.3s ease;
}

.portfolio-card:hover .portfolio-card__cover img,
.portfolio-card:focus-within .portfolio-card__cover img {
  transform: scale(1.02);
}

@media (prefers-reduced-motion: reduce) {
  .portfolio-card__cover img {
    transition: none;
  }

  .portfolio-card:hover .portfolio-card__cover img,
  .portfolio-card:focus-within .portfolio-card__cover img {
    transform: none;
  }
}

/* ---- Fallback cover -- ONE shared template (dark surface + fixed
   blue-violet halo + a faint node/line pattern + the project's own
   expertise icon and label), only ever varied by which icon/label it
   shows. Never a fake screenshot, never a per-category color scheme. ---- */
.portfolio-card__fallback {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  background: linear-gradient(160deg, rgba(63, 123, 248, 0.1), rgba(184, 107, 248, 0.06) 55%, transparent);
}

.portfolio-card__fallback-halo {
  position: absolute;
  inset: 0;
  background: radial-gradient(55% 65% at 50% 30%, rgba(99, 102, 241, 0.28), transparent 70%);
}

/* A handful of faint technical nodes/lines -- purely decorative, low
   opacity, never claims to be a real diagram of anything. */
.portfolio-card__fallback-nodes {
  position: absolute;
  inset: 0;
  opacity: 0.5;
  background-image:
    radial-gradient(circle 2.5px at 18% 25%, rgba(255, 255, 255, 0.35), transparent 70%),
    radial-gradient(circle 2px at 82% 22%, rgba(255, 255, 255, 0.3), transparent 70%),
    radial-gradient(circle 2px at 30% 78%, rgba(255, 255, 255, 0.28), transparent 70%),
    radial-gradient(circle 2.5px at 74% 72%, rgba(255, 255, 255, 0.3), transparent 70%),
    linear-gradient(115deg, transparent 46%, rgba(255, 255, 255, 0.06) 50%, transparent 54%);
}

.portfolio-card__fallback-icon {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: rgba(139, 92, 246, 0.16);
  border: 1px solid rgba(139, 92, 246, 0.38);
  color: #cdd8ff;
}

.portfolio-card__fallback-icon svg {
  width: 24px;
  height: 24px;
}

.portfolio-card__fallback-label {
  position: relative;
  font-family: var(--font-satoshi);
  font-weight: 700;
  font-size: 11.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.75);
  text-align: center;
  padding: 0 20px;
}

/* ---- Body ---- */
.portfolio-card__body {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: 16px 18px 18px;
}

.portfolio-card__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.portfolio-card__nature,
.portfolio-card__status {
  display: inline-flex;
  font-family: var(--font-satoshi);
  font-weight: 600;
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
}

.portfolio-card__nature {
  color: var(--li-text-secondary);
}

/* Not conveyed by color alone (accessibility requirement) -- a dot glyph
   in front of the text, not just a tinted background. */
.portfolio-card__status {
  color: #8fe3b8;
  align-items: center;
  gap: 5px;
}

.portfolio-card__status::before {
  content: "";
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: currentColor;
}

/* Reserved 2-line height regardless of actual title length -- keeps
   every card's title block the same height (same convention as
   .blog-card__title's own line-clamp). */
.portfolio-card__title {
  margin: 8px 0 0;
  font-family: var(--font-satoshi);
  font-weight: 700;
  font-size: 17px;
  line-height: 1.35;
  color: #fff;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: calc(1.35em * 2);
}

.portfolio-card__summary {
  margin: 8px 0 0;
  font-family: var(--font-satoshi);
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--li-text);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: calc(1.5em * 3);
}

/* ---- Result band -- a compact strip, not a second button. ---- */
.portfolio-card__result {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: 12px 0 0;
  padding: 8px 12px;
  background: rgba(52, 211, 153, 0.08);
  border: 1px solid rgba(52, 211, 153, 0.2);
  border-radius: 9px;
}

.portfolio-card__result-label {
  font-family: var(--font-satoshi);
  font-weight: 700;
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #8fe3b8;
}

.portfolio-card__result-value {
  font-family: var(--font-satoshi);
  font-weight: 600;
  font-size: 13px;
  line-height: 1.4;
  color: #fff;
}

/* ---- Technologies -- max 3 shown, identical style, no per-item
   brightness difference; a 4th+ collapses into a plain "+N". ---- */
.portfolio-card__tech {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 12px 0 0;
  padding: 0;
  list-style: none;
}

.portfolio-card__tech li {
  display: inline-flex;
  padding: 3px 10px;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 9999px;
  font-family: var(--font-satoshi);
  font-size: 11px;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.85);
  white-space: nowrap;
}

.portfolio-card__tech--more {
  color: rgba(255, 255, 255, 0.45) !important;
}

/* ---- Action -- at most one per card, arrow nudges on hover. No button
   at all when a project has no real destination (see pages/portfolio.njk
   -- the {% if p.action %} guard). ---- */
.portfolio-card__action {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: auto;
  padding: 14px 18px;
  border-top: 1px solid rgba(255, 255, 255, 0.06);
  font-family: var(--font-satoshi);
  font-size: 13px;
  font-weight: 600;
  color: #9fb8ff;
  text-decoration: none;
  transition: color 0.15s ease;
}

.portfolio-card__action svg {
  transition: transform 0.15s ease;
}

.portfolio-card:hover .portfolio-card__action,
.portfolio-card:focus-within .portfolio-card__action {
  color: #c3d4ff;
}

.portfolio-card:hover .portfolio-card__action svg,
.portfolio-card:focus-within .portfolio-card__action svg {
  transform: translateX(3px);
}

.portfolio-card__action:focus-visible {
  outline: 2px solid var(--li-border-hover);
  outline-offset: -2px;
}

@media (prefers-reduced-motion: reduce) {
  .portfolio-card__action svg {
    transition: none;
  }

  .portfolio-card:hover .portfolio-card__action svg,
  .portfolio-card:focus-within .portfolio-card__action svg {
    transform: none;
  }
}

/* Cards without an action still need the body to reach the card's own
   bottom edge (equal card heights across a row) -- flex-1 on .body
   already handles that; nothing extra needed here. */

/* ---- Load more / empty state -- same recipe as .blog-loadmore/
   .blog-empty. ---- */
.portfolio-loadmore[hidden],
.portfolio-empty[hidden] {
  display: none;
}

.portfolio-loadmore {
  display: flex;
  justify-content: center;
  margin-top: 36px;
}

.portfolio-loadmore button {
  width: auto;
  padding: 0 28px;
}

.portfolio-empty {
  text-align: center;
  padding: 48px 16px;
}

.portfolio-empty p {
  font-family: var(--font-satoshi);
  color: var(--color-muted-foreground, #9898a6);
  margin: 0 0 12px;
}

.portfolio-empty__reset {
  appearance: none;
  border: none;
  background: transparent;
  font-family: var(--font-satoshi);
  font-size: 14px;
  font-weight: 600;
  color: #9fb8ff;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
  min-height: 44px;
  padding: 0 8px;
}

.portfolio-empty__reset:hover {
  color: #c3d4ff;
}

.portfolio-empty__reset:focus-visible {
  outline: 2px solid var(--li-border-hover);
  outline-offset: 2px;
}
