/* Chiesi — component styles. Tokens live in tokens.css. */

/* ---------- Base ---------- */

html { -webkit-text-size-adjust: 100%; }
body { text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; }

/* Anchored one-page navigation needs breathing room under the sticky header. */
:target,
[id] { scroll-margin-top: 6rem; }

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; }
}

:where(a, button, input, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--ct-accent);
  outline-offset: 3px;
  border-radius: 4px;
}

::selection { background: var(--ct-accent); color: var(--ct-base); }

img, svg, video { max-width: 100%; height: auto; }

/* ---------- Ambient glow ---------- */

/*
 * Two soft radial blooms behind the top of every page, tinted from the two accent
 * hues. Sits on a pseudo-element at z-index -1 with `isolation` on the parent, so
 * it paints behind the content but still above the page background. The sticky
 * header's backdrop blur picks it up, which is the point.
 */
.wp-site-blocks {
  position: relative;
  isolation: isolate;
}

.wp-site-blocks::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  block-size: min(620px, 70vh);
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(60% 60% at 18% 0%, color-mix(in srgb, var(--ct-accent) 26%, transparent), transparent 70%),
    radial-gradient(50% 55% at 90% 8%, color-mix(in srgb, var(--ct-accent-2) 20%, transparent), transparent 70%);
  filter: blur(10px);
}

/* Nothing to show if the browser cannot mix the colours. */
@supports not (background: color-mix(in srgb, red 50%, transparent)) {
  .wp-site-blocks::before { display: none; }
}

/* ---------- Utility text ---------- */

.ct-eyebrow {
  font-family: var(--wp--preset--font-family--mono);
  font-size: var(--wp--preset--font-size--xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ct-muted);
  margin: 0 0 0.75rem;
}

.ct-lead { font-size: var(--wp--preset--font-size--lg); color: var(--ct-muted); line-height: 1.55; }

/* ---------- Header ---------- */

/*
 * The sticky element has to be the template-part wrapper, not .ct-header itself:
 * the wrapper is .ct-header's containing block and hugs it exactly, so a sticky
 * header inside it has no range to travel and never sticks.
 */
.ct-header-sticky,
.wp-site-blocks > .wp-block-template-part:first-child,
.wp-site-blocks > .wp-block-template-part:has(> .ct-header) {
  position: sticky;
  top: 0;
  z-index: 100;
  /* A hairline via box-shadow rather than a border: no layout shift, and it
     paints over the section below instead of adding to the header's height. */
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0);
  transition: box-shadow var(--wp--custom--transition);
}

/* Specificity has to clear the base rule above, whose :has() selector counts as
   three classes — hence the redundant-looking chain. */
.wp-site-blocks > .wp-block-template-part.ct-header-sticky.is-stuck,
.wp-site-blocks > .wp-block-template-part.is-stuck:has(> .ct-header) {
  box-shadow: 0 1px 0 var(--ct-border);
}

/* Logged-in views have the fixed admin bar above; sit below it. */
body.admin-bar .ct-header-sticky,
body.admin-bar .wp-site-blocks > .wp-block-template-part:first-child,
body.admin-bar .wp-site-blocks > .wp-block-template-part:has(> .ct-header) {
  top: var(--wp-admin--admin-bar--height, 32px);
}

.ct-header {
  /* Positioned so ::before (the blur layer) resolves against it. */
  position: relative;
}

/*
 * The translucent blur lives on a pseudo-element, not on .ct-header itself.
 * backdrop-filter makes an element a containing block for fixed-position
 * descendants, which would trap the mobile navigation overlay inside the header
 * instead of letting it cover the viewport.
 */
.ct-header::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  /* Opaque first, so browsers without color-mix() still get a readable header. */
  background: var(--ct-base);
  background: color-mix(in srgb, var(--ct-base) 82%, transparent);
  backdrop-filter: saturate(160%) blur(14px);
  -webkit-backdrop-filter: saturate(160%) blur(14px);
}

@supports not (backdrop-filter: blur(1px)) {
  .ct-header::before { background: var(--ct-base); }
}

.ct-header .wp-block-navigation {
  font-size: var(--wp--preset--font-size--sm);
  font-weight: 520;
}
.ct-header .wp-block-navigation a { color: var(--ct-muted); }
.ct-header .wp-block-navigation a:hover,
.ct-header .wp-block-navigation .current-menu-item > a { color: var(--ct-contrast); text-decoration: none; }

.ct-header .wp-block-navigation .wp-block-navigation-item__content {
  position: relative;
  padding-block: 0.25rem;
}
.ct-header .wp-block-navigation a::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -2px;
  height: 1.5px;
  background: var(--ct-accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--wp--custom--transition);
}
.ct-header .wp-block-navigation a:hover::after,
.ct-header .wp-block-navigation a[aria-current="true"]::after { transform: scaleX(1); }

/* Mobile overlay: full-bleed, opaque, and large enough to tap.
   The colours have to be set through core's own selectors. Core ships
   `.wp-block-navigation:not(.has-background) …​.is-menu-open { background-color: #fff }`
   (and `#000` for the text) at specificity 0,5,0, so a plain
   `.wp-block-navigation__responsive-container.is-menu-open` rule loses and the overlay
   comes out white with near-white links in dark mode. */
.wp-block-navigation:not(.has-background)
  .wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay) {
  background-color: var(--ct-base);
}
.wp-block-navigation:not(.has-text-color)
  .wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay) {
  color: var(--ct-contrast);
}
.wp-block-navigation__responsive-container.is-menu-open {
  padding-top: 5.5rem;
}
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item__content {
  color: var(--ct-contrast);
  font-size: var(--wp--preset--font-size--xl);
  font-weight: 600;
  padding-block: 0.35rem;
}
.wp-block-navigation__responsive-container.is-menu-open a::after { display: none; }
.wp-block-navigation__responsive-container-close { color: var(--ct-contrast); }

.ct-header .wp-block-site-title a { color: var(--ct-contrast); }

/* ---------- Brand mark ---------- */

.ct-brand {
  display: inline-flex;
  align-items: center;
  color: var(--ct-accent);
}
.ct-brand svg { inline-size: 1.75rem; block-size: 1.75rem; display: block; }
.ct-brand__tile { fill: currentColor; stroke: none; }
.ct-brand__glyph { stroke: var(--ct-base); }

/* Give it a gentle lift on hover of the whole title group. */
.ct-header__brand { transition: transform var(--wp--custom--transition); }
.ct-header__brand:hover .ct-brand svg { transform: rotate(-6deg) scale(1.04); }
.ct-brand svg { transition: transform 260ms cubic-bezier(0.2, 0, 0.2, 1); }

/* ---------- Theme toggle ---------- */

.ct-theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 2.375rem;
  block-size: 2.375rem;
  padding: 0;
  border: 1px solid var(--ct-border);
  border-radius: var(--wp--custom--radius--pill);
  background: transparent;
  color: var(--ct-muted);
  cursor: pointer;
  transition: color var(--wp--custom--transition), border-color var(--wp--custom--transition),
              background var(--wp--custom--transition);
}
.ct-theme-toggle:hover { color: var(--ct-contrast); border-color: var(--ct-contrast); background: var(--ct-surface); }
.ct-theme-toggle svg { inline-size: 1.125rem; block-size: 1.125rem; display: block; }

/* Show the icon for the mode you would switch *to*. */
.ct-theme-toggle .ct-icon-moon { display: none; }
:root[data-theme="dark"] .ct-theme-toggle .ct-icon-moon { display: block; }
:root[data-theme="dark"] .ct-theme-toggle .ct-icon-sun { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .ct-theme-toggle .ct-icon-moon { display: block; }
  :root:not([data-theme="light"]) .ct-theme-toggle .ct-icon-sun { display: none; }
}

/* ---------- Hero ---------- */

.ct-hero { padding-block: clamp(4rem, 12vh, 9rem) clamp(3rem, 8vh, 6rem); }

.ct-hero__name {
  margin: 0;
  font-size: var(--wp--preset--font-size--display);
  font-weight: 680;
  letter-spacing: -0.035em;
  line-height: 1.02;
}
.ct-hero__role {
  margin: 0.75rem 0 0;
  font-size: var(--wp--preset--font-size--xl);
  font-weight: 450;
  color: var(--ct-muted);
  letter-spacing: -0.02em;
}
.ct-hero__role .ct-sep { color: var(--ct-border); padding-inline: 0.35em; }

/* Rotating phrase. Every phrase is in the DOM; inactive ones are taken out of
   flow so the line never reflows as they swap. */
.ct-rotate {
  position: relative;
  display: inline-block;
  vertical-align: top;
  color: var(--ct-contrast);
  font-weight: 560;
}
/* Only the active phrase is in flow; every other one is taken out of it and
   stacked in the same spot, so phrases cross-fade without ever sitting side by
   side and without shifting the rest of the line. */
.ct-rotate__word {
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: 0;
  display: inline-block;
  white-space: nowrap;
  opacity: 0;
  transform: translateY(0.45em);
  pointer-events: none;
  transition: opacity 420ms cubic-bezier(0.2, 0, 0.2, 1), transform 420ms cubic-bezier(0.2, 0, 0.2, 1);
}
.ct-rotate__word.is-active {
  position: relative;
  opacity: 1;
  transform: none;
  pointer-events: auto;
}
.ct-rotate__word.is-leaving {
  opacity: 0;
  transform: translateY(-0.45em);
}

@media (prefers-reduced-motion: reduce) {
  .ct-rotate__word { transition: none; }
}

/* The portrait is a plain core/image block; all the styling hangs off the figure
   so the saved markup stays exactly what core's save() produces. */
.ct-avatar {
  margin: 0 0 0 auto;
  inline-size: fit-content;
}
.ct-avatar img {
  display: block;
  inline-size: clamp(200px, 26vw, 320px);
  block-size: clamp(200px, 26vw, 320px);
  border-radius: var(--wp--custom--radius--pill);
  object-fit: cover;
  border: 1px solid var(--ct-border);
  box-shadow: var(--ct-shadow-md);
}

/* Once the hero columns stack, lead with the portrait instead of leaving it
   stranded under the buttons. */
@media (max-width: 781px) {
  .ct-hero { padding-block: clamp(2.5rem, 7vh, 4rem) clamp(2.5rem, 6vh, 4rem); }

  .ct-hero .wp-block-columns { flex-direction: column-reverse; }

  /* Centred, not flush left: stacked above left-aligned text, a portrait pushed to
     one edge reads as a layout mistake rather than a choice. */
  .ct-hero .ct-avatar { margin-inline: auto; margin-block-end: 1.25rem; }
}

.ct-status {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: var(--wp--preset--font-size--xs);
  color: var(--ct-muted);
  border: 1px solid var(--ct-border);
  border-radius: var(--wp--custom--radius--pill);
  padding: 0.3rem 0.75rem 0.3rem 0.6rem;
  background: var(--ct-surface);
}
.ct-status::before {
  content: "";
  inline-size: 7px; block-size: 7px;
  border-radius: 50%;
  background: #22c55e;
  box-shadow: 0 0 0 3px color-mix(in srgb, #22c55e 22%, transparent);
}

/* ---------- Sections ---------- */

.ct-section { padding-block: clamp(3.5rem, 9vh, 6.5rem); }
.ct-section--surface { background: var(--ct-surface); }

.ct-section__title { margin: 0 0 0.5rem; }

/* Keep prose at a readable measure while its container still lines up with the
   section grid: the wrapper keeps core's centring, the text inside is capped. */
.ct-measure > * { max-width: 68ch; }
.ct-section__intro { color: var(--ct-muted); margin: 0 0 2.5rem; max-width: 60ch; }

/* ---------- Numbers strip ---------- */

.ct-section--tight { padding-block: clamp(2.5rem, 6vh, 4rem); }

.ct-metrics {
  display: grid;
  /* 140px keeps two columns on a 375px phone; wider screens fit all five. */
  gap: 1.5rem 1.25rem;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  align-items: start;
  margin-block-start: 2rem;
}

/* The flow layout gives every child but the first a block-gap margin, which a
 * grid honours as an offset. Gap already handles the spacing here. */
.ct-metrics > * {
  margin-block: 0;
}

@media (min-width: 600px) {
  .ct-metrics {
    gap: 1.25rem 2rem;
  }
}

.ct-metric { display: flex; flex-direction: column; gap: 0.15rem; }

.ct-metric__value {
  margin: 0;
  font-size: var(--wp--preset--font-size--xxl);
  font-weight: 680;
  letter-spacing: -0.03em;
  line-height: 1;
  color: var(--ct-contrast);
  /* The one place the second accent earns its keep outside the glow. */
  background: linear-gradient(135deg, var(--ct-accent), var(--ct-accent-2));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* If the gradient text is not supported, fall back to a solid colour. */
@supports not ((background-clip: text) or (-webkit-background-clip: text)) {
  .ct-metric__value { color: var(--ct-accent); background: none; }
}

.ct-metric__label {
  margin: 0;
  font-size: var(--wp--preset--font-size--sm);
  font-weight: 600;
  color: var(--ct-contrast);
}
.ct-metric__note {
  margin: 0;
  font-size: var(--wp--preset--font-size--xs);
  line-height: 1.45;
  color: var(--ct-muted);
}

/* ---------- Cards ---------- */

.ct-card {
  background: var(--ct-base);
  border: 1px solid var(--ct-border);
  border-radius: var(--wp--custom--radius--md);
  padding: 1.5rem;
  box-shadow: var(--ct-shadow-sm);
  transition: border-color var(--wp--custom--transition), transform var(--wp--custom--transition),
              box-shadow var(--wp--custom--transition);
  /* No block-size:100% here — see the scoped rule below. */
}

/* A card inside a columns block has to be told to fill its column: the column
   is a stretched flex item, but the card in it is a flow block sized by its own
   content, so without this the three "What I do" cards end up ragged.
   Deliberately NOT applied to every .ct-card: on a *grid* child the percentage
   makes the row track measure short of its own children, which painted the
   Certificates heading over the Education cards on /resume/. */
.wp-block-column > .ct-card { block-size: 100%; }
.ct-card:hover { border-color: color-mix(in srgb, var(--ct-accent) 45%, var(--ct-border)); }

.ct-card__title { margin: 0 0 0.4rem; font-size: var(--wp--preset--font-size--lg); }
.ct-card__text { margin: 0; color: var(--ct-muted); font-size: var(--wp--preset--font-size--sm); }
/* Feature-card icons are drawn by the theme and tinted with the accent colour,
   so they follow light/dark without any markup in the page content. */
.ct-card--icon::before {
  content: "";
  display: block;
  inline-size: 1.625rem;
  block-size: 1.625rem;
  margin-block-end: 1rem;
  background-color: var(--ct-accent);
  -webkit-mask: var(--ct-card-icon) center / contain no-repeat;
  mask: var(--ct-card-icon) center / contain no-repeat;
}
.ct-card--layers   { --ct-card-icon: var(--ct-icon-layers); }
.ct-card--users    { --ct-card-icon: var(--ct-icon-users); }
.ct-card--network  { --ct-card-icon: var(--ct-icon-network); }
.ct-card--mail     { --ct-card-icon: var(--ct-icon-mail); }
.ct-card--pin      { --ct-card-icon: var(--ct-icon-pin); }
.ct-card--building { --ct-card-icon: var(--ct-icon-building); }

/* Contact cards put the icon beside the label rather than above it. */
.ct-contact-card.ct-card--icon::before { margin-block-end: 0.85rem; inline-size: 1.375rem; block-size: 1.375rem; }

.ct-grid { display: grid; gap: 1.25rem; }
.ct-grid--3 { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.ct-grid--2 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }

/* ---------- Timeline (experience & education) ---------- */

.ct-timeline {
  list-style: none;
  margin: 0;
  padding: 0;
  /* Keep resume prose at a comfortable line length even in a wide section. */
  max-width: 60rem;
}

.ct-timeline__item {
  position: relative;
  padding-inline-start: 2rem;
  padding-block-end: 2.25rem;
}
.ct-timeline__item:last-child { padding-block-end: 0; }

.ct-timeline__item::before {
  content: "";
  position: absolute;
  inset-inline-start: 5px;
  inset-block: 0.65rem 0;
  inline-size: 1px;
  background: var(--ct-border);
}
.ct-timeline__item:last-child::before { display: none; }

.ct-timeline__item::after {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: 0.42rem;
  inline-size: 11px; block-size: 11px;
  border-radius: 50%;
  background: var(--ct-base);
  border: 2px solid var(--ct-border);
  transition: border-color var(--wp--custom--transition);
}
.ct-timeline__item.is-current::after { border-color: var(--ct-accent); background: var(--ct-accent); }

.ct-timeline__meta {
  font-family: var(--wp--preset--font-family--mono);
  font-size: var(--wp--preset--font-size--xs);
  color: var(--ct-muted);
  letter-spacing: 0.02em;
  display: block;
  margin-block-end: 0.3rem;
}
.ct-timeline__role { margin: 0; font-size: var(--wp--preset--font-size--lg); font-weight: 620; }
.ct-timeline__org {
  margin: 0.1rem 0 0.7rem;
  font-size: var(--wp--preset--font-size--sm);
  color: var(--ct-muted);
  font-weight: 500;
}
.ct-timeline__org a { color: inherit; text-decoration: underline; text-decoration-color: var(--ct-border); }
.ct-timeline__org a:hover { color: var(--ct-accent); text-decoration-color: currentColor; }
.ct-timeline__org .ct-loc::before { content: " · "; color: var(--ct-border); }

.ct-timeline__body { color: var(--ct-muted); font-size: var(--wp--preset--font-size--sm); }
.ct-timeline__body > :first-child { margin-block-start: 0; }
.ct-timeline__body > :last-child { margin-block-end: 0; }
.ct-timeline__body ul { padding-inline-start: 1.1rem; }
.ct-timeline__body li { margin-block: 0.3rem; }

/* Grouped employer entries: one company, several roles nested beneath it. */

.ct-timeline__company {
  margin: 0 0 0.2rem;
  font-size: var(--wp--preset--font-size--lg);
  font-weight: 620;
}
.ct-timeline__company a { color: inherit; text-decoration: none; }
.ct-timeline__company a:hover { color: var(--ct-accent); }

.ct-roles {
  list-style: none;
  margin: 1rem 0 0;
  padding: 0;
}

.ct-role {
  position: relative;
  padding-inline-start: 1.5rem;
  padding-block-end: 1.4rem;
}
.ct-role:last-child { padding-block-end: 0; }

/* A lighter second-level rail, so roles read as children of the company. */
.ct-role::before {
  content: "";
  position: absolute;
  inset-inline-start: 3px;
  inset-block: 0.6rem 0;
  inline-size: 1px;
  background: var(--ct-border);
}
.ct-role:last-child::before { display: none; }

.ct-role::after {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: 0.42rem;
  inline-size: 7px;
  block-size: 7px;
  border-radius: 50%;
  background: var(--ct-border);
}
.ct-role.is-current::after { background: var(--ct-accent); }

/* A company with a single role needs no second-level marker — the company's own
   dot and date already cover it. */
.ct-roles--single .ct-role { padding-inline-start: 0; padding-block-end: 0; }
.ct-roles--single .ct-role::before,
.ct-roles--single .ct-role::after { display: none; }

.ct-role__title {
  margin: 0;
  font-size: var(--wp--preset--font-size--md);
  font-weight: 600;
}
.ct-role__meta {
  display: block;
  margin-block: 0.1rem 0.55rem;
  font-family: var(--wp--preset--font-family--mono);
  font-size: var(--wp--preset--font-size--xs);
  color: var(--ct-muted);
}

/* Education variant */
.ct-edu { display: grid; gap: 1.25rem; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
.ct-edu__logo {
  display: block;
  inline-size: 44px; block-size: 44px;
  object-fit: contain;
  border-radius: var(--wp--custom--radius--sm);
  background: #fff;
  border: 1px solid var(--ct-border);
  padding: 4px;
  margin-block-end: 0.85rem;
}
/* The logo sits on its own line above the title so the title, the meta line and
   the body all start at the card's padding edge. An entry with no logo still
   renders an invisible 44px box, which keeps titles across the row level. */
.ct-edu__head { margin-block-end: 0.85rem; }
.ct-edu__logo--empty { visibility: hidden; }
.ct-edu__grade {
  display: inline-block;
  font-family: var(--wp--preset--font-family--mono);
  font-size: var(--wp--preset--font-size--xs);
  color: var(--ct-accent);
  background: var(--ct-accent-soft);
  border-radius: var(--wp--custom--radius--pill);
  padding: 0.15rem 0.6rem;
  margin-block-start: 0.6rem;
}

/* Global styles print `:root :where(h3){margin-block-start:…}` *after* this file
   at the same specificity, so a plain `.ct-card__title{margin:0}` loses on source
   order. Markup written in the editor carries an inline `margin-top:0` and never
   noticed; the plugin's server-rendered blocks have no inline style, which pushed
   the education title 40px below its logo and the certificate name 28px below the
   top of its own row. One selector deeper is enough. */
.ct-edu .ct-card__title,
.ct-edu .ct-timeline__org,
.ct-cert .ct-cert__name { margin-block-start: 0; }

/* ---------- Certificates ---------- */

.ct-certs { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); list-style: none; margin: 0; padding: 0; }
.ct-cert { display: flex; gap: 0.9rem; align-items: flex-start; }
.ct-cert__logo {
  inline-size: 38px; block-size: 38px;
  object-fit: contain;
  border-radius: var(--wp--custom--radius--sm);
  background: #fff;
  border: 1px solid var(--ct-border);
  padding: 3px;
  flex: 0 0 auto;
}
.ct-cert__name { margin: 0; font-size: var(--wp--preset--font-size--sm); font-weight: 600; line-height: 1.4; }
.ct-cert__meta { margin: 0.2rem 0 0; font-size: var(--wp--preset--font-size--xs); color: var(--ct-muted); font-family: var(--wp--preset--font-family--mono); }

/* Inline sub-label inside a contact card. The card body is ~180px wide, which is
   a few pixels short of "PEC: " plus the address — rather than let the label wrap
   away from its value, give it its own line in the card-label style. */
.ct-contact__sub {
  display: block;
  margin-block-start: 0.55rem;
  font-family: var(--wp--preset--font-family--mono);
  font-size: var(--wp--preset--font-size--xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ct-muted);
}

/* ---------- Posts ---------- */

.ct-posts { display: grid; gap: 1rem; }

/* Post listings: thumbnail beside the text on desktop, stacked on small screens.
   Laid out here rather than with nested column blocks so the query template stays
   simple and each item collapses cleanly when a post has no featured image. */
.wp-block-post-template > li {
  display: grid;
  grid-template-columns: 190px minmax(0, 1fr);
  gap: 1.5rem;
  align-items: start;
}
.wp-block-post-template > li:not(:has(.wp-block-post-featured-image)) {
  grid-template-columns: minmax(0, 1fr);
}
.wp-block-post-template .wp-block-post-featured-image {
  margin: 0;
  overflow: hidden;
  /* Several featured images are event logos on a transparent background with dark
     artwork. Without a light plate behind them they vanish in dark mode, so the
     plate is a fixed light value rather than a theme token. */
  background: #f4f5f7;
  border: 1px solid var(--ct-border);
  border-radius: 10px;
}
.wp-block-post-template .wp-block-post-featured-image img {
  inline-size: 100%;
  block-size: auto;
  transition: transform 420ms cubic-bezier(0.22, 1, 0.36, 1);
}
.wp-block-post-template > li:hover .wp-block-post-featured-image img { transform: scale(1.04); }

/* Never crop a listing thumbnail. Most featured images here are cards and banners with
   text set into them — a WordCamp logo, a hackathon project card, an interview banner —
   and `cover` cut the wording off. Their ratios run from 0.71 to 2.13 with a median of
   exactly 16/9, which is what the block asks for, so most of them fill the tile edge to
   edge with no padding and nothing lost. `!important` is required twice over: the block
   prints `object-fit:cover` as an inline style. Every tile is the same 16/9 box: the few
   images that are nowhere near that ratio simply get more space around them, which is a
   fair trade for a consistent grid. */
.wp-block-post-template .wp-block-post-featured-image img {
  object-fit: contain !important;
}

.ct-post-body > :first-child { margin-block-start: 0; }

/* One post runs into the next once the thumbnail sits above the text, so small screens
   get a rule and more air between entries. */
@media (max-width: 600px) {
  .wp-block-post-template { gap: 0 !important; }
  .wp-block-post-template > li { grid-template-columns: minmax(0, 1fr); gap: 0.9rem; }
  .wp-block-post-template > li + li {
    margin-block-start: 2rem;
    padding-block-start: 2rem;
    border-block-start: 1px solid var(--ct-border);
  }
  .wp-block-post-template .wp-block-post-featured-image img { max-block-size: 220px; }
}

/* Footer legal line: one line on desktop, wrapping naturally when it has to. */
.ct-sep-dot { opacity: 0.45; padding-inline: 0.15em; }
.ct-footer__legal { max-width: 60ch; }

/* Stack the footer on small screens: the legal line wraps to two lines beside the icons
   and the two rows end up fighting for the same space. */
@media (max-width: 600px) {
  .ct-footer { padding-block: 2rem; text-align: center; }
  .ct-footer > .wp-block-group {
    flex-direction: column-reverse;
    align-items: center;
    gap: 1.5rem;
  }
  .ct-footer__legal { max-width: none; line-height: 1.7; }
  /* Break before the VAT number instead of letting it wrap mid-phrase; the
     separator dot only reads as one on a single line. */
  .ct-footer__legal .ct-sep-dot {
    display: block;
    height: 0;
    overflow: hidden;
  }
  .ct-footer .wp-block-social-links { gap: 1.1rem !important; }
  .ct-footer .wp-block-social-links .wp-social-link { padding: 0.25rem; }
}
.ct-post-card { display: block; padding: 1.4rem 1.5rem; text-decoration: none; color: inherit; }
.ct-post-card:hover { text-decoration: none; }
.ct-post-card__date {
  font-family: var(--wp--preset--font-family--mono);
  font-size: var(--wp--preset--font-size--xs);
  color: var(--ct-muted);
}
.ct-post-card__title { margin: 0.35rem 0 0.5rem; font-size: var(--wp--preset--font-size--lg); }
.ct-post-card:hover .ct-post-card__title { color: var(--ct-accent); }
.ct-post-card__excerpt { margin: 0; color: var(--ct-muted); font-size: var(--wp--preset--font-size--sm); }

.wp-block-post-title a { color: var(--ct-contrast); }
.wp-block-post-title a:hover { color: var(--ct-accent); text-decoration: none; }

/* Team portraits, in place of a group photo. */
.ct-team {
  display: flex;
  flex-wrap: wrap;
  gap: 1.1rem 1.25rem;
  margin-block: 1.75rem;
}
.ct-team .wp-block-image {
  margin: 0;
  inline-size: 84px;
  text-align: center;
}
.ct-team .wp-block-image img {
  inline-size: 72px;
  block-size: 72px;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid var(--ct-border);
  background: var(--ct-surface);
  transition: transform 260ms cubic-bezier(0.22, 1, 0.36, 1);
}
.ct-team .wp-block-image:hover img { transform: scale(1.06); }
.ct-team figcaption {
  margin-block-start: 0.5rem;
  font-size: var(--wp--preset--font-size--xs);
  line-height: 1.3;
  color: var(--ct-muted);
}

/* Single-post reading rhythm */
.ct-entry > * { margin-block: 1.1em; }
.ct-entry h2 { margin-block-start: 2.4em; margin-block-end: 1em; }
.ct-entry h3 { margin-block-start: 1.9em; margin-block-end: 0.8em; }
.ct-entry figure img { border-radius: var(--wp--custom--radius--md); }

/* Wide figures inside an article. The post content sits in a constrained group,
 * so a nested constrained layout caps .alignwide at the 720px prose column —
 * break out and re-centre on the viewport instead. Used by screenshots that are
 * unreadable at column width. */
/* Core's constrained layout applies `margin-left/right: auto !important` to
 * everything that is not alignleft/right/full — .alignwide included — so the
 * breakout has to match that !important to win. Auto margins resolve to 0 once
 * the element is wider than its container, which is why it sat flush left. */
.ct-entry .wp-block-post-content > .alignwide {
  width: min(var(--wp--style--global--wide-size), calc(100vw - 3rem));
  max-width: none;
  margin-inline: 50% 0 !important;
  transform: translateX(-50%);
}

.ct-entry .alignwide img {
  inline-size: 100%;
  height: auto;
}

.ct-entry figure.wp-block-image {
  /* A screenshot on a white canvas needs an edge in dark mode. */
  margin-block: 2em;
}

.ct-entry figure.wp-block-image img {
  border: 1px solid var(--ct-border);
}

.ct-entry figcaption.wp-element-caption {
  color: var(--ct-muted);
  font-size: var(--wp--preset--font-size--sm);
  margin-block-start: 0.7em;
  text-align: left;
}

/* The post header image may be a wide banner or a square event logo, so it is
   contained on a light plate rather than cropped to fill. It sits as a direct
   child of <main> in single.html, which keeps this scoped away from listings. */
main > .wp-block-post-featured-image {
  background: #f4f5f7;
  border: 1px solid var(--ct-border);
  border-radius: var(--wp--custom--radius--md);
  overflow: hidden;
}
main > .wp-block-post-featured-image img {
  /* The block prints object-fit:cover inline from its aspect-ratio setting. */
  object-fit: contain !important;
  max-block-size: 420px;
}
.ct-entry blockquote {
  padding-inline-start: 1.25rem;
  color: var(--ct-muted);
  font-style: italic;
}

/* Core ships no visual treatment for the code block, and a bare <pre> spills
   out of the measure on anything longer than the column. Give it the card
   surface and let long lines scroll rather than overflow. */
.ct-entry .wp-block-code {
  margin-block: 1.6em;
  padding: 1.1rem 1.25rem;
  background: var(--ct-surface);
  border: 1px solid var(--ct-border);
  border-radius: var(--wp--custom--radius--md);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.ct-entry .wp-block-code code {
  display: block;
  font-family: var(--wp--preset--font-family--mono);
  font-size: var(--wp--preset--font-size--xs);
  line-height: 1.7;
  color: var(--ct-contrast);
  white-space: pre;
  tab-size: 2;
}

/* ---------- Category pills ---------- */

.ct-cats { margin-block-start: 1.6rem; }

.ct-cats__list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  list-style: none;
  margin: 0;
  padding: 0;
}

.ct-cat {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.4rem 0.9rem;
  border: 1px solid var(--ct-border);
  border-radius: var(--wp--custom--radius--pill);
  font-size: var(--wp--preset--font-size--sm);
  font-weight: 520;
  color: var(--ct-muted);
  text-decoration: none;
  transition: border-color var(--wp--custom--transition), color var(--wp--custom--transition),
              background var(--wp--custom--transition);
}
.ct-cat:hover {
  border-color: var(--ct-accent);
  color: var(--ct-accent);
  background: var(--ct-accent-soft);
  text-decoration: none;
}

.ct-cat.is-active {
  background: var(--ct-contrast);
  border-color: var(--ct-contrast);
  color: var(--ct-base);
}
.ct-cat.is-active:hover {
  background: var(--ct-contrast);
  border-color: var(--ct-contrast);
  color: var(--ct-base);
}

.ct-cat__count {
  font-family: var(--wp--preset--font-family--mono);
  font-size: var(--wp--preset--font-size--xs);
  opacity: 0.65;
}

/* Category links in a post header. */
.ct-post-cats { display: inline-flex; flex-wrap: wrap; gap: 0.4rem; }
.ct-post-cats a {
  font-family: var(--wp--preset--font-family--mono);
  font-size: var(--wp--preset--font-size--xs);
  text-transform: lowercase;
  letter-spacing: 0.02em;
  color: var(--ct-accent);
  text-decoration: none;
  padding: 0.1rem 0.5rem;
  border: 1px solid var(--ct-border);
  border-radius: var(--wp--custom--radius--pill);
  transition: border-color var(--wp--custom--transition);
}
.ct-post-cats a:hover { border-color: var(--ct-accent); text-decoration: none; }
.ct-post-cats .wp-block-post-terms__separator { display: none; }

/* ---------- Pagination ---------- */

.wp-block-query-pagination {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  padding-block-start: var(--wp--preset--spacing--50);
  border-block-start: 1px solid var(--ct-border);
}

/* Previous / next read as buttons; the numbers sit between them. */
.wp-block-query-pagination-previous,
.wp-block-query-pagination-next {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.5rem 1rem;
  border: 1px solid var(--ct-border);
  border-radius: var(--wp--custom--radius--pill);
  font-size: var(--wp--preset--font-size--sm);
  font-weight: 560;
  color: var(--ct-contrast);
  text-decoration: none;
  transition: border-color var(--wp--custom--transition), background var(--wp--custom--transition),
              color var(--wp--custom--transition);
}
.wp-block-query-pagination-previous:hover,
.wp-block-query-pagination-next:hover {
  border-color: var(--ct-accent);
  color: var(--ct-accent);
  background: var(--ct-accent-soft);
  text-decoration: none;
}
.wp-block-query-pagination-next { margin-inline-start: auto; }

.wp-block-query-pagination-numbers {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  font-family: var(--wp--preset--font-family--mono);
  font-size: var(--wp--preset--font-size--xs);
}

.wp-block-query-pagination-numbers .page-numbers {
  display: grid;
  place-items: center;
  min-inline-size: 2rem;
  block-size: 2rem;
  padding-inline: 0.4rem;
  border-radius: var(--wp--custom--radius--sm);
  color: var(--ct-muted);
  text-decoration: none;
  transition: background var(--wp--custom--transition), color var(--wp--custom--transition);
}
.wp-block-query-pagination-numbers a.page-numbers:hover {
  background: var(--ct-surface);
  color: var(--ct-contrast);
  text-decoration: none;
}
.wp-block-query-pagination-numbers .page-numbers.current {
  background: var(--ct-accent);
  color: var(--ct-base);
  font-weight: 600;
}
.wp-block-query-pagination-numbers .page-numbers.dots {
  background: none;
  color: var(--ct-border);
  min-inline-size: 1rem;
}

@media (max-width: 600px) {
  .wp-block-query-pagination { gap: 0.4rem; }
  .wp-block-query-pagination-previous span,
  .wp-block-query-pagination-next span { display: none; }
}

/* ---------- Contact ---------- */

.ct-contact { display: grid; gap: 1.25rem; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); }
.ct-contact__label {
  font-family: var(--wp--preset--font-family--mono);
  font-size: var(--wp--preset--font-size--xs);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ct-muted);
  margin: 0 0 0.6rem;
}
.ct-contact__body { margin: 0; font-size: var(--wp--preset--font-size--sm); line-height: 1.75; }
.ct-contact__body a { text-decoration: underline; text-decoration-color: var(--ct-border); }
.ct-contact__body a:hover { text-decoration-color: currentColor; }

/* ---------- Footer ---------- */

.ct-footer {
  border-top: 1px solid var(--ct-border);
  padding-block: 2.5rem;
  font-size: var(--wp--preset--font-size--sm);
  color: var(--ct-muted);
}
.ct-footer a { color: var(--ct-muted); text-decoration: underline; text-decoration-color: var(--ct-border); }
.ct-footer a:hover { color: var(--ct-contrast); }

/* Core social links, toned down to match */
.wp-block-social-links.is-style-logos-only .wp-social-link { color: var(--ct-muted); }
.wp-block-social-links.is-style-logos-only .wp-social-link:hover { color: var(--ct-accent); transform: none; }

/* ---------- Motion ---------- */

/* Scroll reveal. JS adds .is-visible when the element first enters the viewport
   and sets --ct-reveal-i so siblings stagger rather than all landing at once. */
.ct-reveal {
  opacity: 0;
  transform: translateY(16px);
}
.ct-reveal.is-visible {
  opacity: 1;
  transform: none;
  transition:
    opacity 620ms cubic-bezier(0.22, 1, 0.36, 1) calc(var(--ct-reveal-i, 0) * 70ms),
    transform 620ms cubic-bezier(0.22, 1, 0.36, 1) calc(var(--ct-reveal-i, 0) * 70ms);
}

/* The hero is above the fold, so it animates on load instead of on scroll. */
@keyframes ct-rise {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: no-preference) {
  .ct-hero .ct-status,
  .ct-hero .ct-hero__name,
  .ct-hero .ct-hero__role,
  .ct-hero .ct-lead,
  .ct-hero .wp-block-buttons,
  .ct-hero .ct-avatar {
    animation: ct-rise 760ms cubic-bezier(0.22, 1, 0.36, 1) backwards;
  }

  .ct-hero .ct-status        { animation-delay: 60ms; }
  .ct-hero .ct-hero__name    { animation-delay: 140ms; }
  .ct-hero .ct-hero__role    { animation-delay: 220ms; }
  .ct-hero .ct-lead          { animation-delay: 300ms; }
  .ct-hero .wp-block-buttons { animation-delay: 380ms; }
  .ct-hero .ct-avatar        { animation-delay: 180ms; }
}

/* Section headings get a slightly longer travel for a calmer feel. */
.ct-reveal.ct-section__title,
.ct-reveal.ct-eyebrow { transform: translateY(20px); }

@media (prefers-reduced-motion: reduce) {
  .ct-reveal { opacity: 1; transform: none; }
  .ct-reveal.is-visible { transition: none; }
}

/* Cards lift very slightly toward the pointer. */
@media (prefers-reduced-motion: no-preference) and (hover: hover) {
  .ct-card { transition: border-color var(--wp--custom--transition), transform 260ms cubic-bezier(0.22, 1, 0.36, 1), box-shadow 260ms ease; }
  .ct-card:hover { transform: translateY(-3px); box-shadow: var(--ct-shadow-md); }
}

/* ---------- Empty-state hint (editor/admin aid) ---------- */

.ct-empty {
  border: 1px dashed var(--ct-border);
  border-radius: var(--wp--custom--radius--md);
  padding: 1.25rem;
  color: var(--ct-muted);
  font-size: var(--wp--preset--font-size--sm);
  margin: 0;
}

/* ---------- Core skip link ---------- */

.skip-link.screen-reader-text:focus {
  background: var(--ct-contrast);
  color: var(--ct-base);
  border-radius: 0 0 var(--wp--custom--radius--sm) 0;
  padding: 0.75rem 1.25rem;
  z-index: 999;
}
