/* ------------------------------------------------------------------
   faldy.id overrides on top of the base template.
   Everything here either replaces template branding with our own, or
   teaches the template how to style Markdown output from Astro.
   Values reuse the template's own custom properties so themes stay in sync.
------------------------------------------------------------------- */

/* --- Footer wordmark ------------------------------------------- */
/* The template ships the studio name as traced letterforms. We render live
   text in the template's accent face instead. */
.fd-footer__wordmark {
  width: 100%;
  height: auto;
}
.fd-footer__wordmark text {
  font-family: var(--_font-accent);
  font-size: 72px;
  font-weight: var(--fw-bold);
  fill: currentColor;
  letter-spacing: -0.03em;
}

/* --- Hero headline --------------------------------------------- */
/* The hero keeps its h1 for screen readers only (absolute, opacity 0)
   and lets the marquee carry the statement. The headline here is the whole
   pitch, so it gets shown — same place in the flow, above the marquee. */
.hero-06-headline__title {
  position: static;
  opacity: 1;
  visibility: visible;
  white-space: normal;
  max-width: 20ch;
  padding: 0 3rem;
  margin: 0 0 2.4rem;
  font: normal var(--fw-medium) 3.6rem/1.1 var(--_font-accent);
  letter-spacing: -0.02em;
  color: var(--t-bright);
}
@media only screen and (min-width: 768px) {
  .hero-06-headline__title {
    padding: 0 6rem;
    font-size: 5.6rem;
  }
}
@media only screen and (min-width: 1200px) {
  /* From 1200px up the headline sits over the dark backdrop, so it takes the
     same permanently-light colour the template gives the intro line there. */
  .hero-06-headline__title {
    font-size: 7.2rem;
    margin-bottom: 3.2rem;
    color: var(--pt-t-light-bright);
  }
}

/* --- Hero backdrop --------------------------------------------- */
/* The freelancer hero is built around a looping video. We use a still
   so the page stays light. */
.fd-hero-06__video .hero-still {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* --- Card cover images ------------------------------------------ */
/* Covers used to be CSS background-images. They are real <img> tags now — the
   variant the template itself ships commented out inside
   .fd-blog-preview__image — which gets them intrinsic dimensions, async
   decoding and a loading attribute for the Astro audit.

   One caveat worth knowing: .parallax-img-small hands each image to Ukiyo,
   which reads naturalWidth during init. Whether that forces a lazy image to
   download early was not confirmed — it could not be measured here, because
   headless Chrome ignores lazy-load deferral and fetches everything. If the
   card covers ever look like they are all loading upfront (953 KB on /blog,
   477 KB on the homepage, 410 KB on /case-studies), check this first in a real
   browser's network panel.

   The blog preview already had a matching img rule; the project item did not. */
.fd-project-item__preview img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* --- Page transitions ------------------------------------------- */
/* The template got its between-page feel from the preloader curtain plus a
   GSAP stagger, both gated on imagesLoaded and costing 3.2s. This is the same
   idea in CSS for a fraction of the time, with no dependency on app.min.js —
   if that file fails, pages still render.

   Only #fd-page-content moves. The header, nav and footer are identical on
   every page, so holding them still while the content swaps makes navigation
   read as a transition rather than a reload. Note that the template puts
   .loading__fade on the header logo, the header controls and the nav as well
   as on article images, so that class cannot be animated globally — doing so
   fades the chrome in on every page load.

   Everything is scoped to :root.js-nav, a class set by an inline script before
   first paint. Without JS the class never lands, so content is simply visible
   rather than stuck at opacity 0. */
@keyframes page-enter {
  from { opacity: 0; transform: translate3d(0, 2.4rem, 0); }
  to   { opacity: 1; transform: none; }
}

@keyframes page-enter-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}

:root.js-nav .fd-page-content {
  animation: page-enter 0.45s cubic-bezier(0.22, 1, 0.36, 1) both;
}

/* The image at the top of an article arrives just behind the words. Scoped
   inside the content so it never touches the header or nav. */
:root.js-nav .fd-page-content .loading__fade {
  animation: page-enter-fade 0.5s ease 0.18s both;
}

/* Leaving. This has to be an animation rather than a transition: the entrance
   above uses animation-fill-mode: both, which keeps its final opacity applied
   indefinitely, and a filling animation outranks a transition on the same
   property. A transition here was silently ignored and the conflict showed up
   as a flicker. Replacing the animation outright avoids that.

   Short, because navigation is held for this long on every click. */
@keyframes page-leave {
  to { opacity: 0; }
}

:root.js-nav.is-leaving .fd-page-content {
  animation: page-leave 0.16s ease-out both;
}

@media (prefers-reduced-motion: reduce) {
  :root.js-nav .fd-page-content,
  :root.js-nav .fd-page-content .loading__fade {
    animation: none;
  }
  :root.js-nav.is-leaving .fd-page-content {
    animation: none;
  }
}

/* --- Tag groups in content columns ------------------------------ */
/* .fd-article__tags is centred, which is right for the centred header of
   an article but wrong everywhere else. In a left-aligned content column —
   the toolbox on the homepage and on /work — a centred row of chips floats
   away from the label above it and from everything below. */
.fd-pinned-universal__scroll .fd-article__tags,
.fd-block__content .fd-article__tags {
  justify-content: flex-start;
}

/* Consecutive labelled groups sit 1.3rem apart by default, which is tighter
   than the gap *inside* a group, so the labels read as belonging to the rows
   above them rather than below. */
.fd-pinned-universal__scroll .fd-block__paragraph + .fd-block__paragraph,
.fd-pinned-universal__scroll .fd-res-list + .fd-block__paragraph {
  margin-top: 4.8rem;
}

/* --- Animated button captions ----------------------------------- */
/* app.min.js rewrites every `.btn-anim .btn-caption` into one inline-block
   span per letter, then stacks two copies of the result for the hover roll.
   The caption is a fixed height with overflow:hidden, so the second copy is
   hidden until hover — that part is the intended mechanic.

   The problem is that per-letter spans let the browser break a line *mid-word*,
   and a wrapped line lands in the hidden half. The label does not look
   wrapped, it looks truncated: "Case studies" renders as "Case st" and
   "Read the writing" as "Read the writin". The template never hits this
   because the labels it ships are short enough to always fit on one line. */
.btn-anim__block {
  white-space: nowrap;
}

/* --- Footer navigation ------------------------------------------ */
/* The template pins the footer nav to 4.4rem from 768px up, which is wider
   than a three-column footer leaves for a label like "Case studies" — at
   1200px the column is 236px and the label wants 268px. Scale it with the
   viewport instead so the longest label always fits its column. */
@media only screen and (min-width: 768px) {
  .footer-nav__link {
    font-size: clamp(3rem, 3.1vw, 4.4rem);
  }
  /* Tracks the font size, so the two stacked copies of the caption stay
     exactly one line apart the way the template's fixed 5.3rem does at 4.4rem. */
  .footer-nav__link .btn-caption {
    height: 1.2em;
  }
}

/* --- Headline decorations --------------------------------------- */
/* The template ships these as headline-img-NN pointing into img/illustrations.
   Same pill geometry, our own art. */
.inner-headline__title.headline-decor-case-studies::before {
  background-image: url(../images/decor/hdl-case-studies.webp);
}

.inner-headline__title.headline-decor-writing::before {
  background-image: url(../images/decor/hdl-writing.webp);
}

/* --- Markdown article body ------------------------------------- */
/* Astro renders Markdown as bare elements. The template styles hand-authored
   .fd-article__block markup. These rules bridge the two. */
.markdown-body {
  display: flex;
  flex-direction: column;
  gap: 3rem;
  width: 100%;
  text-align: left;
}

.markdown-body > :first-child {
  margin-top: 0;
}

.markdown-body h2 {
  font: normal var(--fw-medium) 3.2rem/1.2 var(--_font-accent);
  color: var(--t-bright);
  margin: 3rem 0 0;
}

.markdown-body h3 {
  font: normal var(--fw-medium) 2.6rem/1.2 var(--_font-accent);
  color: var(--t-bright);
  margin: 2rem 0 0;
}

.markdown-body h4 {
  font: normal var(--fw-medium) 2.2rem/1.2 var(--_font-accent);
  color: var(--t-bright);
  margin: 1rem 0 0;
}

@media only screen and (min-width: 768px) {
  .markdown-body h2 { font-size: 4rem; }
  .markdown-body h3 { font-size: 3rem; }
  .markdown-body h4 { font-size: 2.4rem; }
}

.markdown-body p,
.markdown-body li {
  color: var(--t-medium);
}

.markdown-body a {
  color: var(--t-bright);
  text-decoration: underline;
  text-underline-offset: 0.3em;
  text-decoration-thickness: 1px;
  transition: color 0.3s ease;
}
.markdown-body a:hover {
  color: var(--accent);
}

.markdown-body ul,
.markdown-body ol {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding-left: 2.4rem;
}
.markdown-body ul { list-style: disc; }
.markdown-body ol { list-style: decimal; }
.markdown-body li::marker { color: var(--t-muted-extra); }

.markdown-body blockquote {
  margin: 0;
  padding: 3rem 0;
  border-top: 1px solid var(--st-muted);
  border-bottom: 1px solid var(--st-muted);
}
.markdown-body blockquote p {
  font: normal var(--fw-medium) 2.4rem/1.35 var(--_font-accent);
  color: var(--t-bright);
  margin: 0;
}

.markdown-body img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--_radius-m);
}

.markdown-body hr {
  width: 100%;
  height: 1px;
  border: 0;
  background-color: var(--st-muted);
  margin: 0;
}

/* Inline code and Shiki blocks. Shiki emits both a light and a dark
   .astro-code; we show whichever matches the active scheme. */
.markdown-body :not(pre) > code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.9em;
  background-color: var(--base-tint);
  border: 1px solid var(--st-muted);
  border-radius: 0.6rem;
  padding: 0.2em 0.45em;
  color: var(--t-bright);
}

.markdown-body pre {
  overflow-x: auto;
  padding: 2.4rem;
  border-radius: var(--_radius-m);
  border: 1px solid var(--st-muted);
  font-size: 1.4rem;
  line-height: 1.6;
  margin: 0;
}
.markdown-body pre code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  background: none;
  border: 0;
  padding: 0;
}

/* Shiki dual-theme switching, driven by the template's colour-scheme
   attribute rather than the media query, so the toggle works. */
:root[color-scheme="dark"] .astro-code,
:root[color-scheme="dark"] .astro-code span {
  color: var(--shiki-dark) !important;
  background-color: var(--shiki-dark-bg) !important;
  font-style: var(--shiki-dark-font-style) !important;
  font-weight: var(--shiki-dark-font-weight) !important;
  text-decoration: var(--shiki-dark-text-decoration) !important;
}

/* --- Table of contents ----------------------------------------- */
.fd-article__block.block-table-of-contents .table-of-contents__nav {
  display: flex;
  flex-direction: column;
  gap: 0.8rem;
  padding: 0;
  list-style: none;
}
.fd-article__block.block-table-of-contents .table-of-contents__nav a {
  color: var(--t-medium);
  transition: color 0.3s ease;
}
.fd-article__block.block-table-of-contents .table-of-contents__nav a:hover {
  color: var(--t-bright);
}
.table-of-contents__nav .toc-depth-3 {
  padding-left: 1.6rem;
}

/* --- Case study body ------------------------------------------- */
.case-study__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 1.2rem 2.4rem;
}
/* Selectors are qualified because the template's own .fd-article__content ol
   rule is more specific than a bare class, and would re-add decimal markers
   on top of our counter. */
.case-study__steps,
.fd-article__content ol.case-study__steps,
.fd-article__content ul.case-study__steps {
  counter-reset: step;
  display: flex;
  flex-direction: column;
  gap: 2.4rem;
  padding: 0;
  list-style: none;
}
.case-study__steps li,
.fd-article__content ol.case-study__steps li,
.fd-article__content ul.case-study__steps li {
  position: relative;
  padding-left: 4.4rem;
  color: var(--t-medium);
  list-style: none;
}
.case-study__steps li::before,
.fd-article__content ol.case-study__steps li::before,
.fd-article__content ul.case-study__steps li::before {
  counter-increment: step;
  content: counter(step, decimal-leading-zero);
  position: absolute;
  left: 0;
  top: 0.1em;
  font: normal var(--fw-medium) 1.4rem/1 var(--_font-accent);
  color: var(--t-muted-extra);
}

/* --- Stat cards ------------------------------------------------- */
/* The template fixes these cards tall enough for a decorative illustration
   in the lower half. Ours carry only a figure and a label, so the reserved
   space is dead weight. */
.fd-stats-cards__item {
  height: 300px;
}
@media only screen and (min-width: 768px) {
  .fd-stats-cards__item {
    height: 260px;
  }
}
@media only screen and (min-width: 1600px) {
  .fd-stats-cards__item {
    height: 300px;
  }
}

/* --- Button rows ------------------------------------------------ */
/* The template's control rows hold one or two buttons and never wrap.
   Where we put three side by side, narrow screens clip the labels. */
.fd-section-title__controls {
  flex-wrap: wrap;
  gap: 1rem;
}
