/* Khushy Digital — WordPress-only additions.
   Loads LAST, after the generated design layer. Nothing here restates a rule
   the demo already made; this file only covers what WordPress adds that the
   static demo never had.

   Playbook §8.2: this file wins over the design's media queries at equal
   specificity, so every size-dependent addition is scoped inside its own
   min-width query and the mobile design is left alone. */

/* ------------------------------------------------------------------ *
 * 1. Images
 * ------------------------------------------------------------------ */

/* base.css sets max-width:100% on images. WordPress emits real width/height
   attributes, and without height:auto any image whose attributes differ from
   its rendered box is distorted (playbook §8.7). The attributes stay — they
   are what prevents CLS — and this pairs with them. */
img, svg, video { height: auto; }

/* An image inside a fixed-ratio frame is the exception: it must fill the box. */
.bc .m img,
.phead-media img,
.frame img { height: 100%; }

/* ------------------------------------------------------------------ *
 * 2. Section modifiers the widget base emits
 * ------------------------------------------------------------------ */

.sec-tight { padding-block: 52px; }
.sec-topline { border-top: 1px solid var(--line); }
.sec-dark.sec-topline { border-top-color: var(--d3); }

/* --- Fix: step numerals render as solid blue blocks on a dark section ---

   A defect in the demo's own stylesheet, not in the port. Two rules disagree:

     .sec-dark .steps .st .n { background: var(--blue) }        (0,4,0)
     .steps .st .n           { background-clip: text; … }       (0,3,0)

   The first is the `background` SHORTHAND, so it also sets background-clip
   back to border-box — and at higher specificity it wins. The gradient then
   paints the whole box instead of being clipped to the glyph, and
   -webkit-text-fill-color:transparent hides the numeral inside it. The result
   is a filled rectangle where a large gradient numeral should be.

   Light sections are unaffected: no .sec-dark rule applies there, so the
   clip survives. Only the dark case needs restating.

   This cannot be fixed in components.css — that file is generated, and the
   next `php bin/build-css.php` would overwrite it. It belongs here. */
.sec-dark .steps .st .n {
  background-color: transparent;
  -webkit-background-clip: text;
  background-clip: text;
}

/* ------------------------------------------------------------------ *
 * 3. Site logo
 * ------------------------------------------------------------------ */

/* The demo's lockup is a coloured square plus text, so there is no image
   treatment to inherit — this is a real addition.

   Sized by HEIGHT with width:auto: a wordmark and a square mark share no
   aspect ratio, and height is what the 76px header row actually constrains.
   The heights come from the Customizer via --logo-h / --logo-h-footer. */

.logo .logo-img {
  height: var(--logo-h, 38px);
  width: auto;
  max-width: 240px;
  object-fit: contain;
  display: block;
}

/* An image logo replaces the whole lockup, so the flex gap meant for
   mark + text would otherwise show as a dangling space. The class is set
   server-side rather than relying on :has(), so it works the same wherever
   the markup is rendered. */
.logo.has-logo-img { gap: 0; }

.fx-top .logo .logo-img,
.logo.on-dark .logo-img { height: var(--logo-h-footer, 42px); }

/* The header bar is the brand blue, so it carries the reversed logo too -
   but at the header height, not the footer's. Same in the drawer head. */
header#site-header .logo.on-dark .logo-img,
.dhead .logo.on-dark .logo-img { height: var(--logo-h, 38px); }

/* Never let the logo squeeze the nav or overflow a phone. */
@media (max-width: 760px) {
  .logo .logo-img { max-width: 170px; }
}

/* ------------------------------------------------------------------ *
 * 4. Page hero heading levels
 * ------------------------------------------------------------------ */

/* The hero's H1 is the EYEBROW — the small blue label — so the main keyword
   sits in the page's one H1. The large display line is an H2.

   That swap needs CSS, because the demo styles the hero by TAG:

     .phero h1 { font-size: clamp(31px, 4.1vw, 56px); … }   (0,1,1)
     .eyebrow  { font-size: 13px; … }                       (0,1,0)

   `.phero h1` is the more specific of the two, so an <h1 class="eyebrow">
   would render the label at 56px. These two rules put the appearance back
   where the design had it, independent of which tag carries which role. */

.phero h1.eyebrow {
  font-size: 13px;
  line-height: 1.5;
  letter-spacing: .78px;
  margin: 0;
}

/* The display line, now an H2, takes the treatment .phero h1 used to give it.
   Values copied from the demo, not invented — see components.css `.phero h1`. */
.phero h2 {
  font-size: clamp(31px, 4.1vw, 56px);
  line-height: 1.08;
  letter-spacing: -1.5px;
  margin: 16px 0 18px;
}

/* ------------------------------------------------------------------ *
 * 5. Trust strip logos
 * ------------------------------------------------------------------ */

/* The demo's trust strip only ever held text wordmarks (.lrow b), so there is
   no image treatment to inherit — this is a real addition, not a restatement.

   Client logos arrive at every conceivable size and aspect ratio, so each is
   sized to one shared height and left to find its own width. That is what
   keeps a tall roundel and a wide wordmark sitting on the same line. */

.lrow .lg {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.lrow .lg img {
  /* Overrides the blanket img{height:auto} in section 1 — here the height is
     the point, and the width is what follows from it. */
  height: var(--lg-h, 34px);
  width: auto;
  max-width: 150px;
  object-fit: contain;
}

/* The wordmarks are muted grey and warm up on hover. Logos get the equivalent:
   greyscale until pointed at. Opt out per instance with .lrow-colour. */
.lrow:not(.lrow-colour) .lg img {
  filter: grayscale(1);
  opacity: .55;
  transition: filter .2s, opacity .2s;
}
.lrow:not(.lrow-colour) a.lg:hover img,
.lrow:not(.lrow-colour) a.lg:focus-visible img {
  filter: none;
  opacity: 1;
}

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

/* Scale the row's own height token down on phones, mirroring what the design
   does to the wordmarks at this breakpoint. Written as a max-width query to
   match the demo's own direction, so the two agree rather than compete. */
@media (max-width: 760px) {
  .lrow .lg img {
    height: calc(var(--lg-h, 34px) * .8);
    max-width: 116px;
  }
}

/* ------------------------------------------------------------------ *
 * 6. Elementor
 * ------------------------------------------------------------------ */

/* Containers are generated full-width (playbook §6.4), and the widgets bring
   their own <section> shells, so Elementor must add no box of its own. A
   stray padding here reads as a gap between two sections that should meet. */
.elementor-section-wrap > .elementor-section,
.e-con,
.e-con-inner,
.elementor-widget-wrap { padding: 0 !important; }

.e-con { --gap: 0px; --padding-top: 0; --padding-bottom: 0; --padding-left: 0; --padding-right: 0; }

/* Elementor's own widget wrapper must not interrupt the section rhythm. */
.elementor-widget:not(:last-child) { margin-block-end: 0; }

/* The demo's sections are the layout. Elementor's default 1140px content box
   would fight .wrap, which is width:min(1240px, 100% - 40px). */
.elementor-widget-container > section { margin: 0; }

/* ------------------------------------------------------------------ *
 * 7. Admin bar
 * ------------------------------------------------------------------ */

/* The header is position:sticky at top:0; the admin bar would sit over it. */
.admin-bar header#site-header { top: 32px; }
.admin-bar .drawer { top: 32px; }
@media (max-width: 782px) {
  .admin-bar header#site-header,
  .admin-bar .drawer { top: 46px; }
}

/* ------------------------------------------------------------------ *
 * 8. Core content classes the demo never needed
 * ------------------------------------------------------------------ */

.screen-reader-text {
  position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.alignleft, .alignright, .aligncenter { display: block; margin-inline: auto; }
.wp-caption { max-width: 100%; }
.wp-caption-text, .prose figcaption { color: var(--t3); font-size: 13px; margin-top: 10px; text-align: center; }
.prose .wp-block-image { margin-block: 32px; }
.prose .wp-block-image img { width: 100%; border-radius: var(--r-card); }

/* Floats only once there is room for text beside them. */
@media (min-width: 641px) {
  .alignleft { float: left; margin: 6px 28px 20px 0; }
  .alignright { float: right; margin: 6px 0 20px 28px; }
}

/* Gutenberg tables inherit the demo's table treatment. */
.prose .wp-block-table { overflow-x: auto; margin: 28px 0; border: 1px solid var(--line); border-radius: var(--r-card); }
.prose .wp-block-table table { margin: 0; }

.prose .wp-block-quote { border-left: 4px solid var(--blue); background: var(--bg); border-radius: 0 var(--r-card) var(--r-card) 0; padding: 22px 26px; }

/* ------------------------------------------------------------------ *
 * 9. Pagination — no demo page was long enough to need it
 * ------------------------------------------------------------------ */

.pager { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin-top: 46px; }
.pager .page-numbers {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 42px; height: 42px; padding: 0 14px;
  background: #fff; border: 1px solid var(--line); border-radius: var(--r-pill);
  color: var(--t1); font-size: 14.5px; line-height: 1;
  transition: background .18s, color .18s, border-color .18s;
}
.pager .page-numbers:hover { border-color: var(--blue); color: var(--blue); }
.pager .page-numbers.current { background: var(--ink); border-color: var(--ink); color: #fff; }
.pager .page-numbers.dots { border-color: transparent; background: none; }

/* ------------------------------------------------------------------ *
 * 10. Blog grid
 * ------------------------------------------------------------------ */

/* The demo's .irow is a fixed three-column grid built for exactly three cards.
   A WordPress archive returns any number, so let the count drive it — a
   hardcoded column count leaves a short row filling three of three and a long
   one overflowing (playbook §8.3). */
.irow { grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); }
@media (min-width: 1101px) {
  .irow { grid-template-columns: repeat(3, 1fr); }
}

/* ------------------------------------------------------------------ *
 * 11. Count-driven grid columns
 * ------------------------------------------------------------------ */

/* The demo wrote .steps, .band and .spec for exactly four items, because that
   is how many its pages had. A widget instance can hold three or five, and a
   hardcoded count leaves a three-item row filling three of four columns
   (playbook §8.3). The widgets emit the real count; these read it.

   Scoped to min-width:1101px on purpose: the design collapses all three to two
   columns at 1100px and one at 760px, and an unscoped rule here would win over
   both (§8.2). Only the desktop count is being made dynamic. */
@media (min-width: 1101px) {
  .steps { grid-template-columns: repeat(var(--steps-cols, 4), minmax(0, 1fr)); }
  .band  { grid-template-columns: repeat(var(--band-cols, 4), minmax(0, 1fr)); }
  .spec  { grid-template-columns: repeat(var(--spec-cols, 4), minmax(0, 1fr)); }
}

/* ------------------------------------------------------------------ *
 * 12. Search form
 * ------------------------------------------------------------------ */

.search-form { display: flex; gap: 10px; max-width: 460px; margin-top: 20px; }
.search-form .search-field {
  flex: 1; min-width: 0; padding: 12px 16px; font-family: inherit; font-size: 15px;
  border: 1.5px solid var(--line2); border-radius: var(--r-pill); background: #fff; color: var(--ink);
}
.search-form .search-field:focus-visible { outline: 3px solid var(--blue); outline-offset: 2px; }
.search-form .search-submit {
  padding: 12px 22px; border: none; border-radius: var(--r-pill);
  background: var(--blue); color: #fff; font-size: 15px; cursor: pointer;
}

/* ------------------------------------------------------------------ *
 * 13. Empty logo slot — visible to editors only
 * ------------------------------------------------------------------ */

/* When no logo image is set the theme falls back to the demo's text lockup,
   so a visitor never sees a gap. The cost of that is the empty slot is also
   invisible to the person who is supposed to fill it — which is how a site
   ships still wearing its placeholder.

   kd_logo() adds this class only for logged-in users who can customise, so
   the outline is a build-time affordance and never reaches the public. */

.logo.kd-logo-empty {
  outline: 1px dashed rgba(217,78,46, .55);
  outline-offset: 5px;
  border-radius: 2px;
  cursor: help;
}
.logo.kd-logo-empty.on-dark { outline-color: rgba(255, 255, 255, .4); }

/* ------------------------------------------------------------------ *
 * 14. Hero supporting line
 * ------------------------------------------------------------------ */

/* The supplied copy gives the hero four distinct parts — eyebrow, headline,
   a supporting line, then the lead. The demo only ever had three, so the
   supporting line needs its own treatment: heavier than the lead, lighter
   than the headline, so the hierarchy reads at a glance. */

.phero .hero-sub {
  color: #fff;
  font-size: clamp(17px, 1.5vw, 21px);
  line-height: 1.5;
  max-width: 760px;
  margin: 0 0 14px;
  opacity: .92;
}

@media (max-width: 760px) {
  .phero .hero-sub { font-size: 17px; }
}

/* ------------------------------------------------------------------ *
 * 15. Enquiry form
 * ------------------------------------------------------------------ */

/* The honeypot: hidden from people, offered to bots. NOT display:none —
   some bots skip those deliberately. Taken out of flow and off-screen so it
   is unreachable by pointer, keyboard and screen reader alike. */
.kd-hp {
  position: absolute !important;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* Field-level validation messages. The demo had no error state because its
   form never validated anything. */
.fld-err {
  display: block;
  margin-top: 6px;
  color: var(--red);
  font-size: 12.5px;
  line-height: 1.4;
}
.fld [aria-invalid="true"] { border-color: var(--red); }

/* The status line is hidden until it has something to say. */
.formmsg { display: none; }
.formmsg.on {
  display: block;
  background: var(--green-t);
  color: var(--green-d);
  border-radius: var(--r-card);
  padding: 14px 16px;
  font-size: 14.5px;
  line-height: 1.5;
  margin-bottom: 18px;
}

/* A single full-width field must not inherit the two-column grid. */
.cform .fld[style*="display:block"] { display: block; }

/* ------------------------------------------------------------------ *
 * 16. Homepage-only components
 *
 * The homepage brief swaps the hub's "intro + card grid + FAQ" for an
 * "outcome router + work showcase + results band" flow. The router and the
 * proof band already existed in the design and were unused; the rest below
 * are variants of existing components, not new ones.
 * ------------------------------------------------------------------ */

/* Positioning statement: one wide column of oversized editorial type.
   Sized between the hero H1 and a section heading, so it reads as a
   statement rather than a subheading, and stays a single column. */
.statement { max-width: 980px; }
.statement .statement-line {
  font-size: clamp(30px, 4vw, 52px);
  line-height: 1.1;
  letter-spacing: -1.2px;
  margin: 16px 0 24px;
}
.statement .statement-text {
  font-size: clamp(17px, 1.45vw, 21px);
  line-height: 1.6;
  color: var(--t1);
  max-width: 900px;
}
/* The picked-out phrases, mirroring the hero's highlighted words. */
.statement .accent { font-style: normal; color: var(--blue); }

/* The model: statement + a 2x2 of points. .split centres its columns, which
   pushes a short statement into the middle of a tall grid - top-align it. */
.split.model { align-items: start; }
.split.model > div > .btn { margin-top: 6px; }
@media (min-width: 761px) {
  .vgrid.two { grid-template-columns: repeat(2, 1fr); }
}

/* Featured work: the .wc card carrying a result line and discipline tags.
   Taller media than the hub's card grid so the three read as editorial. */
.wgrid-featured .wc .m { height: 220px; }
.wc .res { color: var(--t2); font-size: 14.5px; line-height: 1.55; }
.wc .res b { color: var(--ink); font-weight: 400; }
.wc .tags { display: flex; flex-wrap: wrap; gap: 7px; }
.wc .tags a,
.wc .tags span {
  font-size: 12px; color: var(--t2);
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--r-pill);
  padding: 5px 11px;
  transition: background .18s, color .18s, border-color .18s;
}
.wc .tags a:hover { background: var(--blue); color: #fff; border-color: var(--blue); }
.wc .lm { display: inline-flex; align-items: center; gap: 7px; font-size: 13.5px; color: var(--coral-text); margin-top: auto; padding-top: 6px; }
@media (max-width: 760px) {
  .wgrid-featured .wc .m { height: 190px; }
}

/* Impact band: a light section since 13 Sep 2026. Centred heading; each
   figure sits inside a sage circle on the light-grey band, everything centred. */
.proof .shead h2 { color: var(--ink); }
.proof .band { gap: 28px; justify-items: center; }
.proof .band .b {
  width: 100%; max-width: 250px; aspect-ratio: 1; border-radius: 50%; border: 2px solid var(--green-t); background: var(--green-t);
  display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding: 22px;
  transition: box-shadow .3s ease, transform .3s ease;
}
.proof .band .b:hover { box-shadow: 0 0 0 8px rgba(217,78,46, .08); transform: translateY(-3px); }
.proof .band .b b { color: var(--ink); justify-content: center; font-size: clamp(30px, 2.8vw, 40px); letter-spacing: -1.2px; }
.proof .band .b b i { color: var(--blue); }
.proof .band .b span { color: var(--t2); margin-top: 6px; max-width: 16ch; line-height: 1.35; }
@media (max-width: 1100px) {
  .proof .band { gap: 20px; }
  .proof .band .b { max-width: 220px; }
}
@media (max-width: 760px) {
  .proof .band { grid-template-columns: 1fr 1fr; }
  .proof .band .b { max-width: 190px; padding: 16px; }
  .proof .band .b b { font-size: 28px; }
}

/* ------------------------------------------------------------------ *
 * 17. Hero text width
 * ------------------------------------------------------------------ */

/* The demo caps the hero copy at 820px (.phero .in) with the lead at 700px
   and the supporting line at 760px, while the image below spans the full
   1240px wrap. With `wide` on, the text column matches the image: the
   design's own .phero.wide lifts the column cap, and these lift the
   per-paragraph caps that would otherwise still hold the text narrow. */
.phero.wide .in { max-width: none; }
.phero.wide .hero-sub,
.phero.wide p.lead { max-width: none; }

/* ------------------------------------------------------------------ *
 * 18. Motion
 *
 * Driven by assets/js/motion.js. Every rule that moves something lives
 * inside the no-preference query, so a visitor who has asked for reduced
 * motion gets the plain design and nothing in here applies. The `.kd-motion`
 * class is set by the script, so with JS off none of the hidden starting
 * states are ever applied and nothing can be left invisible.
 * ------------------------------------------------------------------ */

/* Cross-document page transitions where the browser supports them - a
   crossfade between pages instead of a cut. Zero JS. */
@view-transition { navigation: auto; }
::view-transition-old(root) { animation: kd-vt-out .22s ease both; }
::view-transition-new(root) { animation: kd-vt-in .3s ease both; }
@keyframes kd-vt-out { to { opacity: 0; } }
@keyframes kd-vt-in  { from { opacity: 0; } }

@media (prefers-reduced-motion: no-preference) {

  /* -- Fade-out before leaving, for browsers without view transitions -- */
  html.kd-leaving body { opacity: 0; transition: opacity .2s ease; }

  /* -- Staggered reveal --
     The container hands its fade to the items. `translate` rather than
     `transform`, so the design's own hover lifts (which use transform) are
     never overridden. */
  .kd-motion .reveal.stagger { opacity: 1; transform: none; transition: none; }
  .kd-motion .reveal.stagger > * {
    opacity: 0;
    translate: 0 26px;
    transition: opacity .6s ease calc(var(--i, 0) * 70ms),
                translate .6s cubic-bezier(.2, .7, .2, 1) calc(var(--i, 0) * 70ms);
  }
  .kd-motion .reveal.stagger.in > * { opacity: 1; translate: 0 0; }
  /* The flip cards flip on hover via a child; the item itself can stagger. */

  /* -- Image mask reveal --
     Media wipes in from the left inside its own frame. */
  .kd-motion .kd-mask {
    clip-path: inset(0 100% 0 0);
    transition: clip-path .95s cubic-bezier(.77, 0, .18, 1);
  }
  .kd-motion .kd-mask.in { clip-path: inset(0 0 0 0); }
  /* Inside a staggered grid the frame waits its turn. */
  .kd-motion .stagger > * .kd-mask { transition-delay: calc(var(--i, 0) * 70ms + .15s); }

  /* -- Image zoom on hover: the picture grows, the frame does not -- */
  .kd-motion .wc .m img,
  .kd-motion .bc .m img,
  .kd-motion .smedia img,
  .kd-motion .intro-media img { transition: transform .7s cubic-bezier(.2, .7, .2, 1); }
  .kd-motion .wc:hover .m img,
  .kd-motion .bc:hover .m img,
  .kd-motion .smedia:hover img,
  .kd-motion .intro-media:hover img { transform: scale(1.06); }

  /* -- Text reveal: each word rises out of its own clip --
     The clip must not cut descenders: a little bottom padding pulled back
     with a negative margin gives the g's and y's room. */
  .kd-tr .w {
    display: inline-block;
    overflow: hidden;
    vertical-align: bottom;
    padding-bottom: .12em;
    margin-bottom: -.12em;
  }
  .kd-tr .w > span {
    display: inline-block;
    transform: translateY(110%);
    transition: transform .75s cubic-bezier(.2, .7, .2, 1) calc(var(--w, 0) * 38ms);
  }
  .kd-tr.in .w > span { transform: none; }

  /* -- Hero parallax: the frame clips, the image is oversized so the drift
     never shows an edge. The script drives `translate` and `scale`; the
     settle-in zoom is a keyframe on the same properties, which wins while
     it runs and hands over to the script's values when it ends (both are
     1.12 at rest, so there is no step). Only scale and filter move, never
     opacity: the hero is the LCP and must never be hidden. -- */
  .kd-parallax { will-change: translate, scale; scale: 1.12; transition: scale .5s ease-out; }
  .kd-parallax-in { animation: kd-hero-in 1.9s cubic-bezier(.2, .7, .2, 1); }
  @keyframes kd-hero-in {
    from { scale: 1.3;  filter: brightness(.6) saturate(.75); }
    to   { scale: 1.12; filter: brightness(1)  saturate(1); }
  }
  /* The copy is the nearer plane: it eases the other way under the pointer
     and lags the page a little on scroll. */
  .kd-motion .phero .wrap > .in,
  .kd-motion .phead .wrap { will-change: translate; }

  /* -- SVG line drawing: stroke icons draw themselves in --
     Every shape in the sprite carries pathLength="1", so one dash value fits
     them all. Filled shapes ignore it. */
  .kd-motion .reveal.kd-draw .ic svg *,
  .kd-motion .reveal.kd-draw .dc-media svg *,
  .kd-motion .reveal.kd-draw .fc-media svg * {
    stroke-dasharray: 1;
    stroke-dashoffset: 1;
    transition: stroke-dashoffset .9s ease calc(var(--i, 0) * 70ms + .25s);
  }
  .kd-motion .reveal.kd-draw.in .ic svg *,
  .kd-motion .reveal.kd-draw.in .dc-media svg *,
  .kd-motion .reveal.kd-draw.in .fc-media svg * { stroke-dashoffset: 0; }

  /* -- Floating: icon plates bob gently, each on its own beat -- */
  .kd-motion .dc-media,
  .kd-motion .fc-media,
  .kd-motion .vcard .ic {
    animation: kd-float 5.5s ease-in-out infinite;
    animation-delay: calc(var(--i, 0) * -900ms);
  }
  @keyframes kd-float {
    0%, 100% { translate: 0 0; }
    50%      { translate: 0 -4px; }
  }

  /* -- Magnetic buttons and 3D tilt: the script sets the values; this makes
     the return to rest ease rather than snap -- */
  .kd-motion .btn,
  .kd-motion .cbtn,
  .kd-motion .soc a { transition: translate .35s cubic-bezier(.2, .7, .2, 1), transform .2s, background .2s, color .2s, border-color .2s, box-shadow .2s; }
  .kd-motion .kd-tilt { transition: transform .25s ease, box-shadow .22s, border-color .22s; transform-style: preserve-3d; }
  .kd-motion .kd-tilt:hover { transition-duration: .08s; }
}

/* ------------------------------------------------------------------ *
 * 19. Related services as tiles
 * ------------------------------------------------------------------ */

/* The .fcard tile as a whole-card link. The tile itself is the design's
   (icon plate, title, text); this only gives it the hover the text-link
   version had, and lets the card sit on the tinted band. */
a.fcard { color: inherit; transition: transform .22s, box-shadow .22s; }
a.fcard:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); z-index: 1; }
a.fcard:hover h3 { color: var(--blue); }
.rel-tiles .fc-body .lm { display: inline-flex; align-items: center; gap: 7px; font-size: 13.5px; margin-top: auto; padding-top: 8px; }
/* Column count follows the item count (3, or 4 for exactly four). Scoped to
   desktop so the design's 2-column and 1-column collapses are untouched. */
@media (min-width: 1101px) {
  .rel-tiles { grid-template-columns: repeat(var(--rel-cols, 3), minmax(0, 1fr)); }
}

/* ------------------------------------------------------------------ *
 * 20. Blog
 *
 * The demo's journal page carries its featured card as inline styles on a
 * .wc; here that is a class, so index.php stays clean and the card stacks
 * on a phone. The article extras (takeaway, FAQ accordion, tables) come
 * from the design already - only their rhythm inside .prose is set here.
 * ------------------------------------------------------------------ */
.wc.wc-feature { display: grid; grid-template-columns: 1fr 1fr; align-items: stretch; }
.wc.wc-feature .m { height: auto; min-height: 300px; }
.wc.wc-feature .b { justify-content: center; padding: 36px; }
.wc.wc-feature .mt { display: flex; gap: 9px; align-items: center; font-size: 12px; }
.wc.wc-feature .mt span { color: var(--t2); }
.wc.wc-feature h3 { font-size: 26px; line-height: 1.28; }
.wc.wc-feature p { color: var(--t2); font-size: 15px; line-height: 1.6; }
@media (max-width: 760px) {
  .wc.wc-feature { grid-template-columns: 1fr; }
  .wc.wc-feature .m { min-height: 220px; }
  .wc.wc-feature .b { padding: 24px 22px 26px; }
  .wc.wc-feature h3 { font-size: 22px; }
}

/* Article extras inside the prose column. */
.prose .takeaway p { margin: 0; }
.prose .takeaway p + p { margin-top: 10px; }
.prose .faq-list { margin: 22px 0 0; }
.prose details.fq .a p { margin: 0; font-size: 15px; }
.prose details.fq summary { font-size: 16px; font-weight: 400; color: var(--ink); }
.prose p.lede { font-size: 19px; line-height: 1.65; color: var(--t1); }

/* The cover image is capped at the prose width, so the picture and the text
   below it share one edge. */
.artwrap .post-cover { max-width: 760px; margin: 0 0 34px; }
.artwrap .post-cover img { width: 100%; height: auto; border-radius: var(--r-card); }

/* A compact table of contents: a dozen entries should not outrun the fold. */
.abox .toc { gap: 0; }
.abox .toc a { padding: 5px 10px; font-size: 13.5px; line-height: 1.4; }

/* Table of contents on a tablet or phone: the sidebar falls below the
   article there, so the list is repeated at the top as a collapsible box
   and the sidebar copy hides. Desktop keeps the sticky sidebar only. */
.toc-top { display: none; max-width: 760px; margin: 0 0 28px; padding: 0; overflow: hidden; }
.toc-top summary {
  list-style: none; cursor: pointer; padding: 16px 22px;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  font-size: 13px; letter-spacing: .7px; text-transform: uppercase; color: var(--t3);
}
.toc-top summary::-webkit-details-marker { display: none; }
.toc-top summary .pm {
  width: 26px; height: 26px; border-radius: var(--r-card); background: var(--bg); border: 1px solid var(--line);
  display: flex; align-items: center; justify-content: center; font-size: 16px; color: var(--ink); transition: transform .25s;
}
.toc-top[open] summary .pm { transform: rotate(45deg); }
.toc-top .toc { padding: 0 12px 14px; }
@media (max-width: 1100px) {
  /* Sticks under the header as a closed bar; opens to a scrollable list. */
  .toc-top { display: block; position: sticky; top: calc(var(--kd-hdr, 120px) + 10px); z-index: 20; box-shadow: 0 6px 20px rgba(30,42,42, .06); }
  .toc-top .toc { max-height: 55vh; overflow-y: auto; }
  .aside .toc-side { display: none; }
}

/* Jumping to a heading lands it below the sticky header - and below the
   sticky contents bar on a phone - rather than underneath them. */
.prose h2 { scroll-margin-top: calc(var(--kd-hdr, 120px) + 24px); }
@media (max-width: 1100px) {
  .prose h2 { scroll-margin-top: calc(var(--kd-hdr, 120px) + 90px); }
}

/* ------------------------------------------------------------------ *
 * 21. About page components
 *
 * The "one roof" constellation (kd_constellation), the scroll-driven
 * values list (kd_values), the hero's rotating tagline, the stat band
 * inside a dark section, the steps timeline line and the statement on a
 * dark ground. Every entrance state is guarded by .kd-motion and the
 * reduced-motion query: with JavaScript off or motion reduced the
 * finished figure is what renders.
 * ------------------------------------------------------------------ */

/* -- hero tagline with a rotating word -- */
.phero .hero-tag { font-size: clamp(19px, 2.2vw, 27px); line-height: 1.3; letter-spacing: -.3px; margin: 4px 0 16px; color: rgba(255, 255, 255, .88); }
.kd-rotate { display: inline-block; color: var(--blue); }
.kd-rotate em { font-style: normal; display: inline-block; }
@media (prefers-reduced-motion: no-preference) {
  .kd-motion .kd-rotate em { transition: opacity .28s ease, translate .28s ease; }
  .kd-motion .kd-rotate.is-out em { opacity: 0; translate: 0 -10px; }
  .kd-motion .kd-rotate.is-in em { opacity: 0; translate: 0 10px; transition: none; }
}

/* -- stat band inside a dark section -- */
.sec-band .band-in-dark { background: var(--d2); border: 1px solid rgba(255, 255, 255, .08); }
.sec-band .shead { margin-bottom: 30px; }

/* -- steps as a timeline: a line draws across the top of the cards -- */
.steps-line { position: relative; padding-top: 22px; }
.steps-line::before {
  content: ""; position: absolute; left: 0; right: 0; top: 8px; height: 2px;
  background: linear-gradient(90deg, var(--blue), rgba(217,78,46, .15));
  transform: scaleX(1); transform-origin: left;
}
.steps-line .st::before {
  content: ""; position: absolute; left: 22px; top: -19px; width: 12px; height: 12px; border-radius: 50%;
  background: var(--blue); box-shadow: 0 0 0 4px rgba(217,78,46, .18);
}
@media (prefers-reduced-motion: no-preference) {
  .kd-motion .steps-line::before { transform: scaleX(0); transition: transform 1.4s cubic-bezier(.2, .7, .2, 1) .15s; }
  .kd-motion .steps-line.in::before { transform: scaleX(1); }
  .kd-motion .steps-line .st::before { opacity: 0; transition: opacity .4s ease; }
  .kd-motion .steps-line.in .st::before { opacity: 1; }
  .kd-motion .steps-line.in .st:nth-child(1)::before { transition-delay: .35s; }
  .kd-motion .steps-line.in .st:nth-child(2)::before { transition-delay: .65s; }
  .kd-motion .steps-line.in .st:nth-child(3)::before { transition-delay: .95s; }
  .kd-motion .steps-line.in .st:nth-child(4)::before { transition-delay: 1.25s; }
}
@media (max-width: 1100px) {
  .steps-line { padding-top: 0; padding-left: 22px; }
  .steps-line::before { left: 8px; right: auto; top: 0; bottom: 0; width: 2px; height: auto; background: linear-gradient(180deg, var(--blue), rgba(217,78,46, .15)); transform-origin: top; }
  .kd-motion .steps-line::before { transform: scaleY(0); }
  .kd-motion .steps-line.in::before { transform: scaleY(1); }
  .steps-line .st::before { left: -19px; top: 26px; }
}

/* -- statement on a dark ground -- */
.sec-dark .statement .statement-line { color: #fff; }
.sec-dark .statement .statement-text { color: var(--tl); }
.sec-dark .statement .statement-text + .statement-text { margin-top: 16px; }

/* -- the one-roof constellation -- */
.roof { position: relative; aspect-ratio: 1000 / 720; max-width: 1000px; margin: 8px auto 0; }
.roof-svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.roof-svg line { stroke: var(--blue); stroke-width: 1.5; stroke-opacity: .5; vector-effect: non-scaling-stroke; stroke-dasharray: 1; stroke-dashoffset: 0; }
.roof-hub { position: absolute; left: 50%; top: 50%; translate: -50% -50%; z-index: 2; display: flex; flex-direction: column; align-items: center; gap: 10px; }
.roof-hub__glow {
  position: absolute; left: 50%; top: 46px; width: 260px; height: 260px; translate: -50% -50%; border-radius: 50%;
  background: radial-gradient(circle, rgba(133,181,173, .32), rgba(217,78,46, 0) 65%); pointer-events: none;
}
.roof-hub__mark {
  position: relative; width: 92px; height: 92px; border-radius: 50%; background: var(--ink); color: #fff;
  display: grid; place-items: center; box-shadow: 0 14px 34px rgba(217,78,46, .28), 0 0 0 6px rgba(217,78,46, .12);
}
.roof-hub__mark img { width: 48px; height: 48px; border-radius: 50%; }
.roof-hub__mark b { font-size: 34px; line-height: 1; }
.roof-hub__label { position: relative; font-size: 15px; letter-spacing: .2px; color: var(--ink); }
.roof-nodes { list-style: none; margin: 0; padding: 0; }
.roof-nodes li { position: absolute; left: var(--x); top: var(--y); translate: -50% -50%; z-index: 3; }
.roof-node {
  display: flex; flex-direction: column; align-items: center; gap: 5px; text-align: center; color: var(--ink);
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r-card); padding: 12px 16px; min-width: 156px; max-width: 200px;
  box-shadow: 0 8px 24px rgba(30,42,42, .06); transition: transform .25s ease, box-shadow .25s ease, border-color .25s ease;
}
.roof-node__ic { color: var(--blue); display: block; }
.roof-node b { font-size: 14.5px; font-weight: 400; line-height: 1.25; }
.roof-node__blurb { display: block; font-size: 12.5px; line-height: 1.4; color: var(--t2); max-height: 0; opacity: 0; overflow: hidden; transition: max-height .3s ease, opacity .3s ease; }
a.roof-node:hover, a.roof-node:focus-visible { transform: translateY(-4px); border-color: var(--blue); box-shadow: 0 16px 34px rgba(217,78,46, .16); }
a.roof-node:hover .roof-node__blurb, a.roof-node:focus-visible .roof-node__blurb { max-height: 60px; opacity: 1; }
.roof-caption { text-align: center; color: var(--t2); font-size: 16px; margin-top: 30px; }
@media (prefers-reduced-motion: no-preference) {
  .kd-motion .roof:not(.in) .roof-svg line { stroke-dashoffset: 1; }
  .kd-motion .roof-svg line { transition: stroke-dashoffset .75s ease calc(var(--i, 0) * 80ms + .25s); }
  .kd-motion .roof:not(.in) .roof-nodes li { opacity: 0; scale: .85; }
  .kd-motion .roof-nodes li { transition: opacity .5s ease calc(var(--i, 0) * 80ms + .8s), scale .5s cubic-bezier(.2, .7, .2, 1) calc(var(--i, 0) * 80ms + .8s); }
  .kd-motion .roof.in .roof-nodes li { animation: kd-float 7s ease-in-out infinite calc(var(--i, 0) * -900ms + 2s); }
  .kd-motion .roof-hub__glow { animation: roof-breathe 4.5s ease-in-out infinite; }
  @keyframes roof-breathe { 0%, 100% { scale: .9; opacity: .8; } 50% { scale: 1.12; opacity: 1; } }
}
@media (max-width: 1100px) {
  .roof-node { min-width: 128px; padding: 10px 12px; }
  .roof-node b { font-size: 13.5px; }
}
@media (max-width: 760px) {
  .roof { aspect-ratio: auto; }
  .roof-svg { display: none; }
  .roof-hub { position: static; translate: none; margin: 0 auto 26px; }
  .roof-nodes { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
  .roof-nodes li { position: static; translate: none; }
  .roof-node { min-width: 0; max-width: none; width: 100%; padding: 12px 12px 14px; }
  .roof-node__blurb { max-height: none; opacity: 1; }
  .kd-motion .roof.in .roof-nodes li { animation: none; }
}

/* -- scroll-driven values -- */
.sec-vals .wrap.vals { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.45fr); gap: 64px; align-items: start; }
.vals-side { position: sticky; top: calc(var(--kd-hdr, 120px) + 28px); }
.vals-side h2 { font-size: clamp(28px, 3vw, 42px); line-height: 1.12; letter-spacing: -1px; margin: 14px 0 0; color: #fff; }
.vals-side .sub { color: var(--tl); margin-top: 14px; }
.vals-bar { width: 3px; height: 180px; background: rgba(255, 255, 255, .12); border-radius: 3px; overflow: hidden; margin-top: 30px; }
.vals-bar i { display: block; width: 100%; height: var(--p, 0%); background: var(--blue); transition: height .25s linear; }
.vals-list { list-style: none; margin: 0; padding: 0; }
.val { display: grid; grid-template-columns: 64px minmax(0, 1fr); gap: 16px; padding: 34px 0; border-top: 1px solid rgba(255, 255, 255, .1); }
/* dimmed once revealed and not the one being read (.reveal.in sets opacity 1, so this outranks it) */
.kd-motion .val.in:not(.is-active) { opacity: .38; transition: opacity .4s ease; }
.val:last-child { border-bottom: 1px solid rgba(255, 255, 255, .1); }
.val-n { font-size: 15px; letter-spacing: 1.5px; color: var(--tl2); padding-top: 8px; transition: color .4s ease; }
.val h3 { display: inline-block; position: relative; font-size: clamp(22px, 2.2vw, 30px); line-height: 1.2; letter-spacing: -.5px; color: #fff; margin: 0 0 10px; padding-bottom: 6px; }
.val h3::after { content: ""; position: absolute; left: 0; bottom: 0; width: 100%; height: 2px; background: var(--blue); transform: scaleX(0); transform-origin: left; transition: transform .55s cubic-bezier(.2, .7, .2, 1); }
.val p { color: var(--tl); font-size: 16.5px; line-height: 1.7; max-width: 560px; margin: 0; }
.val.is-active .val-n { color: var(--blue); }
.val.is-active h3::after { transform: scaleX(1); }
/* lit for everyone the script cannot serve */
html:not(.kd-motion) .val h3::after { transform: scaleX(1); }
@media (prefers-reduced-motion: reduce) {
  .kd-motion .val.in:not(.is-active) { opacity: 1; }
  .val .val-n { color: var(--blue); }
  .val h3::after { transform: scaleX(1); }
}
@media (max-width: 1100px) {
  .sec-vals .wrap.vals { grid-template-columns: 1fr; gap: 24px; }
  .vals-side { position: static; }
  .vals-bar { display: none; }
  .kd-motion .val.in:not(.is-active) { opacity: 1; }
  .val h3::after { transform: scaleX(1); }
  .val .val-n { color: var(--blue); }
}

/* The contact page reuses the CTA band's .ncside rows on a light card, where
   the band's white values would vanish. */
.cgrid2 .ncside { background: var(--card); border-color: var(--line); }
.cgrid2 .ncside .rw { border-bottom-color: var(--line); }
.cgrid2 .ncside .rw b { color: var(--ink); }
.cgrid2 .ncside .rw small { color: var(--t3); }
.cgrid2 .ncside .ic { background: var(--blue-t); }

/* ------------------------------------------------------------------ *
 * 22. One team field (kd_one_team)
 *
 * The interactive disciplines map. Adapted to the site's own tokens: the
 * brand blue, the ink, the hairline, Poppins - the supplied design's extra
 * fonts are not loaded; its mono details use the system monospace stack.
 * Desktop shows the field; tablet and phone show the list.
 * ------------------------------------------------------------------ */
.sec-oneteam .wrap { width: min(1240px, 100% - 40px); }
.khdg-onet {
  --khdg-accent: var(--coral); --khdg-ink: var(--ink); --khdg-muted: var(--t2); --khdg-idle: var(--t3); --khdg-line: var(--line);
  --khdg-mono: ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
  color: var(--khdg-ink); width: 100%;
}
.khdg-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 16px 28px; margin-bottom: clamp(22px, 3vw, 40px); }
.khdg-head__left { flex: 1 1 320px; display: flex; flex-direction: column; gap: 12px; }
.khdg-title { margin: 0; font-size: clamp(30px, 4.2vw, 56px); line-height: 1.04; letter-spacing: -1.6px; text-wrap: balance; }
.khdg-intro { flex: 1 1 260px; max-width: 42ch; margin: 0; font-size: 16.5px; line-height: 1.65; color: var(--khdg-muted); }
.khdg-intro__mob { display: none; }

/* -- field -- */
/* The field and the list run edge to edge; the heading above stays in the wrap. */
.khdg-field, .khdg-list { width: 100vw; margin-left: calc(50% - 50vw); }
.khdg-field {
  position: relative; aspect-ratio: 16 / 9; max-height: 78vh; min-height: 360px;
  border-top: 1px solid var(--khdg-line); border-bottom: 1px solid var(--khdg-line); background: var(--page); overflow: hidden; cursor: crosshair;
}
.khdg-canvas { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.khdg-beam { position: absolute; height: 1px; background: var(--khdg-accent); transform-origin: 0 50%; opacity: 0; transition: opacity .25s; pointer-events: none; }
.khdg-cursor-glow {
  position: absolute; width: 44px; height: 44px; margin: -22px 0 0 -22px; border-radius: 50%;
  background: radial-gradient(circle, rgba(133,181,173, .16), rgba(217,78,46, 0) 70%); opacity: 0; transition: opacity .25s; pointer-events: none;
}
.khdg-cursor-dot { position: absolute; width: 12px; height: 12px; margin: -6px 0 0 -6px; border-radius: 3px; background: var(--khdg-accent); opacity: 0; transition: opacity .25s; pointer-events: none; }

.khdg-node {
  position: absolute; transform: translate(-50%, -50%) scale(1); transform-origin: 50% 50%; transition: transform .18s ease-out;
  display: flex; flex-direction: column; gap: 4px; align-items: flex-start; padding: 6px; cursor: pointer; user-select: none; text-decoration: none; color: inherit;
}
.khdg-node--right { align-items: flex-end; }
.khdg-node__num { font-family: var(--khdg-mono); font-size: 10px; letter-spacing: .14em; color: var(--khdg-idle); transition: color .18s; }
.khdg-node__name { font-size: clamp(15px, 1.9vw, 30px); line-height: 1.05; letter-spacing: -.5px; white-space: nowrap; color: var(--khdg-idle); transition: color .18s; }
.khdg-node__note {
  font-family: var(--khdg-mono); font-size: clamp(9px, .95vw, 11px); letter-spacing: .02em; color: var(--khdg-muted);
  opacity: 0; max-height: 0; overflow: hidden; white-space: nowrap; transition: opacity .25s, max-height .25s;
}
.khdg-node.is-near .khdg-node__name { color: var(--khdg-ink); }
.khdg-node.is-on .khdg-node__name, .khdg-node.is-on .khdg-node__num { color: var(--khdg-accent); }
.khdg-node.is-on .khdg-node__note { opacity: 1; max-height: 20px; }
.khdg-node:focus-visible { outline: 3px solid var(--blue); outline-offset: 2px; border-radius: 4px; }

.khdg-tag { position: absolute; bottom: 16px; font-family: var(--khdg-mono); font-size: 11px; letter-spacing: .12em; color: var(--khdg-muted); pointer-events: none; }
/* corner tags line up with the page gutter */
.khdg-tag--l { left: max(20px, calc(50vw - 620px)); }
.khdg-tag--r { right: max(20px, calc(50vw - 620px)); letter-spacing: .06em; }
.khdg-tag--r.is-on { color: var(--khdg-accent); }

/* -- list (tablet / phone) -- */
.khdg-list { display: none; list-style: none; margin-top: 0; margin-bottom: 0; padding: 4px 0; background: var(--page); border-top: 1px solid var(--khdg-line); border-bottom: 1px solid var(--khdg-line); }
.khdg-row { position: relative; display: flex; align-items: baseline; gap: 14px; padding: 16px max(20px, calc(50vw - 620px)); border-bottom: 1px solid var(--khdg-line); background: transparent; transition: background .25s; text-decoration: none; color: inherit; }
.khdg-list li:last-of-type .khdg-row { border-bottom: 0; }
.khdg-row__num { font-family: var(--khdg-mono); font-size: 11px; letter-spacing: .12em; color: var(--khdg-muted); flex: none; }
.khdg-row__body { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.khdg-row__name { font-size: clamp(18px, 4.6vw, 24px); line-height: 1.15; letter-spacing: -.4px; color: var(--khdg-ink); }
.khdg-row__note { font-family: var(--khdg-mono); font-size: 11px; letter-spacing: .02em; color: var(--khdg-muted); line-height: 1.4; }
a.khdg-row:hover, a.khdg-row:focus-visible { background: var(--card); }
a.khdg-row:hover .khdg-row__name, a.khdg-row:hover .khdg-row__num { color: var(--khdg-accent); }
.khdg-list__tag { padding: 14px max(20px, calc(50vw - 620px)) 10px; font-family: var(--khdg-mono); font-size: 11px; letter-spacing: .12em; color: var(--khdg-muted); }

@media (max-width: 899px) {
  .khdg-field { display: none; }
  .khdg-list { display: block; }
  .khdg-intro__desk { display: none; }
  .khdg-intro__mob { display: block; }
}
/* the pointer effects mean nothing to a touch screen; keep the field for wide tablets, but calm */
@media (hover: none) and (min-width: 900px) {
  .khdg-field { cursor: default; }
}

/* The hero's lead paragraph, moved into its own strip right after the hero
   (kd_page_hero: lead_position = below). The hero keeps to the headings and
   buttons; the page opens with the lead instead. */
.sec-lead { padding: 44px 0 0; }
.lead-strip { font-size: clamp(18px, 1.55vw, 23px); line-height: 1.6; color: var(--t1); max-width: 960px; margin: 0; }
/* Scroll-linked entrance: motion.js drives translate from off-screen left to
   rest as the strip travels up the viewport. The section clips the overhang. */
.sec-lead { overflow: hidden; }
.kd-motion .lead-strip[data-slide-in] { will-change: translate; }
.sec-lead + .sec { padding-top: 48px; }
@media (max-width: 760px) {
  .sec-lead { padding-top: 30px; }
  .lead-strip { font-size: 17px; }
  .sec-lead + .sec { padding-top: 34px; }
}

/* ------------------------------------------------------------------ *
 * 23. Enquiry section (kd_enquiry): heading beside the real form.
 * ------------------------------------------------------------------ */
.wrap.enq { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr); gap: 56px; align-items: start; }
.enq-side h2 { font-size: clamp(30px, 3.4vw, 44px); line-height: 1.12; letter-spacing: -1px; margin: 14px 0 16px; }
.enq-side .sub { color: var(--t2); font-size: 17px; line-height: 1.65; max-width: 52ch; }
.enq-side .ticks { flex-direction: column; gap: 10px; margin-top: 22px; }
/* the hero-style H1 accent, for a page hero used on the homepage */
.phero h1 em { font-style: normal; color: var(--blue); }
@media (max-width: 1100px) {
  .wrap.enq { grid-template-columns: 1fr; gap: 30px; }
}
