/* Site additions on top of the Webflow export. */

/* ------------------------------------------------------------ brand tokens
   LK Brand v2.1 (docs/brand/brand-digest.md). The Webflow variables are the
   template's names; pointing them at the brand values rethemes every surface
   without touching webflow.css. Volt #E6DE2E, Ink #161617/#222223, Paper
   #FAFAF7. The template's orange survives only as a variable name: anything
   still reading it gets Volt. */
:root {
  --bg-colors--cream: #FAFAF7;            /* Paper, the lead light surface */
  --bg-colors--creamy: #EDEAE2;           /* brand cream, secondary light */
  --bg-colors--black: #161617;            /* Ink deep */
  --bg-colors--black-gray: #222223;       /* Ink */
  --bg-colors--brand-background: #222223; /* Ink */
  --bg-colors--orange: #E6DE2E;           /* orange is banned; alias to Volt */
  --bg-colors--yellow-main: #E6DE2E;      /* Volt */
  --text-colors--black: #161617;          /* Ink-deep text on Paper */
  --text-colors--dark-gray: #77777A;      /* brand n500 */
  --line-colors--dark-gray: #48484A;      /* hairline on Ink */
  --line-colors--medium-gray: #A8A8AB;    /* brand n400 */

  /* Motion. Two easings for the whole site: ease-out for anything leaving or
     settling, the spring for anything arriving (it overshoots a touch and
     lands, like the back-to-top button). Durations in three sizes plus one for
     page-load entrances. Reduced-motion users keep opacity and colour changes
     and lose all travel; see the block near the end of this file. */
  --ease-out: cubic-bezier(0.2, 0, 0, 1);
  --ease-spring: cubic-bezier(0.34, 1.4, 0.64, 1);
  --dur-fast: 150ms;
  --dur-base: 260ms;
  --dur-slow: 460ms;
  --dur-enter: 640ms;
}

/* Text selection carries the signal. */
::selection { background: #E6DE2E; color: #161617; }

/* Headings promoted to h1 for semantics keep their original visual size. */
.u-h2 { font-size: var(--_typography---heading-size--h2); line-height: var(--_typography---heading-line-height--h2-line-height); letter-spacing: var(--_typography---letter-spacing--2px); margin-top: 0; margin-bottom: 0; font-weight: 500; }
.u-h3 { font-size: var(--_typography---heading-size--h3); line-height: var(--_typography---heading-line-height--h3-line-height); letter-spacing: var(--_typography---letter-spacing--2px); margin-top: 0; margin-bottom: 0; font-weight: 500; }
.u-h4 { font-size: var(--_typography---heading-size--h4); line-height: var(--_typography---heading-line-height--h4-line-height); letter-spacing: var(--_typography---letter-spacing--1-5px); margin-top: 0; margin-bottom: 0; font-weight: 600; }
.u-h5 { font-size: var(--_typography---heading-size--h5); line-height: var(--_typography---heading-line-height--h5-line-height); letter-spacing: var(--_typography---letter-spacing--1-5px); margin-top: 0; margin-bottom: 0; font-weight: 500; }

/* Every image element now carries its intrinsic width/height so the browser can
   reserve space before the file loads (Cumulative Layout Shift). Those also
   act as presentational hints, so an image whose CSS constrains only one axis
   (the logos are max-width:200px with no height) would otherwise be forced to
   its full intrinsic height and squash. height:auto restores aspect-ratio
   sizing. Deliberately a bare element selector: any Webflow rule that sets a
   real height, such as .work-thumbnail-image, outranks it and still wins. */
img {
  height: auto;
}

/* Visible keyboard focus. Gold-600 rather than Volt: Volt on Paper measures
   1.6:1 and disappears, and the same ring has to work on both surfaces. */
:focus-visible { outline: 2px solid #A47E1B; outline-offset: 2px; }
.w-nav-button:focus-visible { outline: 2px solid #A47E1B; }

.faq-accordion { cursor: pointer; }

/* Preserve the exported grid alignment after giving career rows unique IDs. */
[id^="about-career-info-"] { justify-self: end; }

/* Reduced motion keeps color and opacity feedback without spatial movement. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation: none !important;
    transition-property: color, background-color, border-color, opacity !important;
    transition-duration: 120ms !important;
  }
  [data-w-id] { opacity: 1 !important; transform: none !important; filter: none !important; }
}

/* Skip link: hidden until keyboard focus. */
.skip-link {
  position: absolute;
  left: -9999px;
  z-index: 1000;
  padding: 12px 20px;
  background: var(--bg-colors--brand-background, #222223);
  color: #fff;
  border-radius: 0 0 8px 0;
}
.skip-link:focus {
  left: 0;
  top: 0;
}

/* Service/Expertise stack: cards are position:sticky and pile up on scroll.
   The template spaces them with a transparent flex gap, so the pinned card
   underneath peeks through while two cards overlap (visible with bright
   images). Move the spacing into the cards so the incoming card covers the
   previous one seamlessly. */
.service-section-content {
  grid-row-gap: 0;
}
.service-item {
  padding-bottom: 48px;
}
.service-item:last-child {
  padding-bottom: 0;
}
@media screen and (max-width: 991px) {
  .service-item {
    padding-bottom: 100px;
  }
  .service-item:last-child {
    padding-bottom: 0;
  }
}

/* Footer newsletter wrappers, restored verbatim from the live template CSS
   (zephyr-studio.webflow.io, .footer-newsletter-*): the Exflow scrape kept
   .footer-field/.footer-submit-button in webflow.css but dropped these three
   wrapper classes together with the form markup. ".footer-newsletter-from"
   (sic) is the template's own class name. */
.footer-newsletter-block {
  width: 100%;
  max-width: 310px;
}
.footer-newsletter-form-block {
  margin-bottom: 0;
}
.footer-newsletter-from {
  justify-content: flex-start;
  align-items: center;
  display: flex;
  position: relative;
}
@media screen and (max-width: 991px) {
  .footer-newsletter-block {
    max-width: 290px;
  }
}
@media screen and (max-width: 479px) {
  .footer-newsletter-block {
    max-width: 100%;
  }
}

/* The scroll parallax translates card images vertically inside an unclipped
   card, so an image can poke above its card's top border into the previous
   card of the stack. Clip the card box (clip, not hidden: keeps sticky). */
.service-item {
  overflow: clip;
}

/* Article body typography.
   Markdown in a post renders real h2/h3 elements inside .blog-rich-text, and the
   site's element styles size headings for page titles (h2 is 92px at desktop).
   Dropped into running copy that reads as display type wedged between two
   paragraphs with no space around it. The template's original posts used bold
   lead-ins rather than headings, so this never came up. Scope article headings
   to a reading scale and give the flow real vertical rhythm. */
/* Section eyebrow dot ("Selected", "Shortly", "Projects"). The template paints
   it with the near-black brand background, which reads as a stray grey speck.
   It is the one repeated accent mark on the page, so give it the brand yellow. */
.sub-title-dot {
  background-color: #E6DE2E; /* Volt, exact */
}

/* Focus-area bullets.
   The row is a flex line with align-items:center, so the 6px dot centres
   against the whole text block. On one line that looks right; as soon as the
   text wraps the dot drifts into the gap between the two lines. Pin it to the
   optical centre of the first line instead, and stop it being squashed when
   the text is long. */
.pricing-card-features-list-block {
  align-items: flex-start;
}
.pricing-card-features-list-dot {
  flex: 0 0 auto;
  /* half a line box, less half the dot: sits on the first line at any width */
  margin-top: calc((1.5em - 6px) / 2);
}

/* The light logo exists only for the open mobile menu (see below). It has to
   be hidden everywhere else, including desktop, so this rule sits outside the
   breakpoint that shows it. */
.nav-brand-logo-open {
  display: none;
}

/* Mobile menu.
   Webflow's mobile panel is a 200px card floating under the burger: the page
   shows through it, the items sit in a cramped column, and on the light pages
   the dark logo and burger disappear against whatever is behind them. Replace
   it with a full-screen surface.

   .w-nav-overlay is the element Webflow shows and hides, so everything hangs
   off it and no extra JavaScript is needed. Webflow writes an inline height
   (the whole document height, several thousand pixels) onto it, which is why
   the height below has to be !important. svh is the viewport iOS actually
   shows, excluding the browser chrome. */
@media screen and (max-width: 991px) {
  .navbar .w-nav-overlay {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    width: 100%;
    height: 100vh !important;
    height: 100svh !important;
  }

  .navigation-menu-wrapper {
    width: 100%;
    height: 100%;
    /* [data-nav-menu-open] ships min-width:200px and text-align:center, which
       is what made the panel a narrow centred card. */
    min-width: 0;
    max-width: none;
    text-align: left;
    margin: 0;
    /* 96px clears the 62px navbar with room to breathe; 25px is the site
       gutter, so the menu items line up with the page content behind them. */
    padding: 96px 25px 40px;
    border-radius: 0;
    background-color: #161617;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    align-items: flex-start;
    overflow-y: auto;
  }

  /* Webflow's [data-nav-menu-open] carries display:block !important, so the
     wrapper cannot be a flex container and cannot centre anything itself. Let
     the inner column fill the wrapper's content box and centre there instead:
     the four links and the button sit in the middle of the screen rather than
     bunched under the logo with half a screen of black below them. */
  .navigation-menu {
    flex-flow: column;
    justify-content: center;
    align-items: flex-start;
    gap: 24px;
    width: 100%;
    min-height: 100%;
  }
  .navigation-menu .navigation-link-text {
    color: var(--text-colors--white, #fff);
    font-size: 32px;
    line-height: 1.25;
  }
  /* The button is the last item in the same column; give it its own step of
     air rather than letting it read as a fifth link. */
  .navigation-menu .nav-button.none {
    margin-top: 16px;
  }

  /* The bar itself has to stay above the panel, or the burger cannot be
     tapped again to close it. */
  .navbar .nav-content-wrapper {
    position: relative;
    z-index: 2;
  }

  /* Sub pages carry a dark logo and dark burger lines for their cream
     background. Over the open panel they would be invisible, so swap both to
     the light treatment while it is open. (The second logo is hidden by a base
     rule outside this media query, or it would show on desktop too.) */
  .navbar:has(.w-nav-button.w--open) .nav-brand-logo.on-light {
    display: none;
  }
  .navbar:has(.w-nav-button.w--open) .nav-brand-logo-open {
    display: block;
  }
  .navbar:has(.w-nav-button.w--open) .menu-icon-top,
  .navbar:has(.w-nav-button.w--open) .menu-icon-middle,
  .navbar:has(.w-nav-button.w--open) .menu-icon-bottom {
    background-color: var(--text-colors--white, #fff);
  }

  /* Stop the page scrolling underneath the open panel. */
  html:has(.w-nav-button.w--open),
  body:has(.w-nav-button.w--open) {
    overflow: hidden;
  }
}

/* Inline form confirmation (see the fetch handler in site.js).
   Webflow ships .w-form-done as centred text on #ddd and .w-form-fail on
   #ffdede, which belong to no palette on this site. These are shown in place of
   the form after a successful send, so they need to sit in the surface they
   replace: cream on the contact page, black in the footer. */
.w-form-done,
.w-form-fail {
  text-align: left;
  padding: 22px 24px;
  border-radius: var(--_border-radius---border-radius-10, 10px);
  font-size: 16px;
  line-height: 1.5;
}
.w-form-done {
  background: rgba(0, 0, 0, 0.04);
  border: 1px solid rgba(0, 0, 0, 0.14);
  color: #000;
}
.w-form-fail {
  background: rgba(168, 30, 20, 0.07);
  border: 1px solid rgba(168, 30, 20, 0.28);
  color: #8c1711;
  margin-top: 12px;
}

/* The footer sits on black, so the newsletter's confirmation inverts. */
.footer-newsletter-block .w-form-done,
.footer-newsletter-block .w-form-fail {
  padding: 14px 16px;
  font-size: 15px;
}
.footer-newsletter-block .w-form-done {
  background: rgba(255, 255, 255, 0.08);
  border-color: rgba(255, 255, 255, 0.22);
  color: #fdf8e7;
}
.footer-newsletter-block .w-form-fail {
  background: rgba(255, 133, 119, 0.12);
  border-color: rgba(255, 133, 119, 0.35);
  color: #ff9d92;
}

/* Article card excerpt on the blog listing. Clamped to three lines so cards in
   a row keep the same height regardless of how long a description runs. */
.blog-excerpt {
  margin: 10px 0 0;
  font-size: 15px;
  line-height: 1.5;
  /* Was opacity 0.72, which landed at 3.48:1 on Paper. Same quiet step, as a
     colour that passes 4.5:1. */
  color: #6B6B6E;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.blog-rich-text h2 {
  font-size: 32px;
  line-height: 1.2;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 56px 0 16px;
}
.blog-rich-text h3 {
  font-size: 24px;
  line-height: 1.3;
  font-weight: 600;
  margin: 40px 0 12px;
}
.blog-rich-text h2:first-child,
.blog-rich-text h3:first-child {
  margin-top: 0;
}
.blog-rich-text p {
  margin: 0 0 20px;
}
.blog-rich-text p:last-child {
  margin-bottom: 0;
}
.blog-rich-text ul,
.blog-rich-text ol {
  margin: 0 0 20px;
  padding-left: 22px;
}
.blog-rich-text li {
  margin-bottom: 8px;
}
/* Figures inside an article: full text-column width, brand radius, mono caption. */
/* webflow.css caps .w-richtext figure at 60% for CMS images; article figures
   here are diagrams with labels and need the whole text column. */
.blog-rich-text figure {
  margin: 40px 0;
  max-width: 100%;
  width: 100%;
}
.blog-rich-text figure img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 12px;
}
.blog-rich-text figcaption {
  margin-top: 12px;
  text-align: left;
  font-size: 14px;
  line-height: 1.5;
  opacity: 0.72;
}
/* Inline bold in article copy.
   webflow.css styles a bare `strong` as a standalone emphasis block:
   font-size: var(--_typography---text-size--text-large), which is 40px at
   desktop. Inside a 16px paragraph that renders a bolded phrase two and a half
   times the size of the sentence around it. Inline emphasis has to inherit the
   text it sits in; only the weight should change. */
.blog-rich-text strong,
.blog-rich-text b {
  font-size: inherit;
  line-height: inherit;
  letter-spacing: inherit;
  color: inherit;
  font-weight: 600;
}
/* Links inside a post had no rule at all, so they fell back to the browser's
   blue. They now read like the links on the about page: the paragraph's own
   colour, italic and underlined at rest, Volt underline on hover and focus. */
.blog-rich-text a {
  color: inherit;
  font-style: italic;
  text-decoration: underline;
  text-decoration-thickness: auto;
  text-underline-offset: auto;
  transition:
    color var(--dur-fast) var(--ease-out),
    text-decoration-color var(--dur-fast) var(--ease-out),
    text-underline-offset var(--dur-fast) var(--ease-out);
}
.blog-rich-text a:hover,
.blog-rich-text a:focus-visible {
  text-decoration-color: #E6DE2E;
  text-decoration-thickness: 2px;
  text-underline-offset: 5px;
}
.blog-rich-text figcaption a { font-style: inherit; }
.blog-rich-text code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.92em;
  background: rgba(0, 0, 0, 0.06);
  padding: 2px 5px;
  border-radius: 4px;
}
@media screen and (max-width: 767px) {
  .blog-rich-text h2 {
    font-size: 26px;
    margin-top: 40px;
  }
  .blog-rich-text h3 {
    font-size: 21px;
    margin-top: 32px;
  }
}

/* ---------------------------------------------------------------- mobile fixes
   Three problems that only appear on narrow screens. */
@media screen and (max-width: 991px) {
  /* 1. The hero is height:82vh with overflow:hidden on the wrapper, so its
     content is silently cut off when it does not fit. At a 320px viewport
     (an iPhone with Display Zoom set to Larger Text) the title wraps to five
     lines instead of four and the service tags were clipped by 125px. A fixed
     box holding variable-length text can only ever be a guess; let it grow.

     82vh also left a band of empty cream under the hero on shorter phones
     while the text above it looked cramped. The card inside the hero is inset
     by the same few pixels on every side, so the section is a full viewport
     tall and the gap under the card matches the gaps beside and above it.
     svh is the viewport excluding browser chrome, which is what iOS actually
     shows; vh stays as the fallback for older engines. */
  .hero-section {
    height: auto;
    min-height: 82vh;
    min-height: 100svh;
    display: flex;
    flex-direction: column;
  }
  .hero-content-wrapper {
    height: auto;
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
  }
  .hero-content {
    height: auto;
    flex: 1 1 auto;
    padding-bottom: 28px;
  }

  /* 2. One mobile gutter, everywhere.
     Measured across the site there were five different left edges at 393px:
     18, 23, 25, 40 and 48. On /works/ the page title sat at 40 while the cards
     below it sat at 25, on the same screen. The containers are the source, so
     fix it there rather than per section: everything that uses a page
     container now starts at the same 25px the cards and Expertise items use. */
  .container-large,
  .container-medium,
  .container-small {
    padding-left: 25px;
    padding-right: 25px;
  }

  /* 3. The category label flips to "View Work" on hover: two lines stacked in a
     20px window with overflow:hidden, so only one shows. The block is a fixed
     130px, and at mobile widths "Product Design" wraps to two lines, making the
     window 40px and revealing both at once. Keep each label on one line. */
  .work-category-block {
    width: auto;
    max-width: 62%;
  }
  .work-category {
    white-space: nowrap;
  }

  /* 4. The Experience table is the template's awards table, which swaps columns
     by breakpoint: desktop shows Position and Company, mobile shows "Awards
     Name" and "Awards Title" instead. Used as an experience list that surfaces
     leftover template headings and a second line per row ("Creative
     Excellence", "Top Campaign"). Show the same two columns as desktop. */
  .awards-hide-wrap {
    display: none;
  }
  .awards-info-block.n {
    display: block;
  }
  .awards-row,
  .awards-row-title {
    flex-wrap: nowrap;
    justify-content: space-between;
    align-items: baseline;
    gap: 16px;
  }
  /* The position takes the space it needs and wraps inside its own column; the
     company stays on the right rather than dropping to a line of its own, so
     every row reads the same way whether the job title is short or long. */
  .awards-row > .awards-info-block.n,
  .awards-row-title > .awards-info-block.n {
    flex: 1 1 auto;
    min-width: 0;
  }
  .awards-row > .awards-info-block:not(.n),
  .awards-row-title > .awards-info-block:not(.n) {
    /* Shrinkable, not fixed: "Unikrn (Acquired by Entain)" is wider than the
       space left over and would otherwise overflow into the job title. */
    flex: 0 1 auto;
    min-width: min-content;
    text-align: right;
  }

  /* 5. The About portrait sat at a 12px inset while the heading and intro above
     it use the 40px container gutter, so the photo hung wider than the text it
     belongs to. Match them. (The template's class name carries a typo,
     "iamge"; kept verbatim because renaming it would break the export.) */
  .about-top-bg-iamge-wrapper {
    padding-left: 25px;
    padding-right: 25px;
  }
}

/* Work card label scrim.
   .work-info (title, year, category) is white text positioned absolutely over
   the thumbnail, with nothing behind it. The template's stock photos happened
   to be dark along their bottom edge; real project photography often is not (a
   pale sofa, a light desk), and the labels then measure as low as 1.2:1 against
   WCAG AA's 4.5:1. This gradient darkens only the bottom of the image, fading
   out entirely by mid-card. It is invisible on images that are already dark
   there, and it keeps the labels legible no matter which photo is swapped in
   later. Sits inside the wrapper's overflow:hidden so it follows the 16px
   radius; .work-info paints above it by virtue of coming later in the DOM. */
.work-thumbnail-image-wrapper {
  position: relative;
}
.work-thumbnail-image-wrapper::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 50%;
  pointer-events: none;
  background: linear-gradient(
    to top,
    rgba(0, 0, 0, 0.66) 0%,
    rgba(0, 0, 0, 0.6) 14%,
    rgba(0, 0, 0, 0.34) 40%,
    rgba(0, 0, 0, 0.1) 70%,
    rgba(0, 0, 0, 0) 100%
  );
}

/* ------------------------------------------------------- audit fixes 2026-08
   From the accessibility/visual audit: tap targets and conversion path. */

/* The burger glyph is 30x20; the tappable area has to be 48x48 without moving
   the visual. */
.menu-button.w-nav-button {
  padding: 14px 9px;
  margin: -14px -9px;
}

/* Nav text links: full-height hit boxes instead of 20px text lines. */
.navigation-link {
  padding-top: 10px;
  padding-bottom: 10px;
}

/* Contact form fields: bottom-border inputs measured ~30px tall, under the
   44px touch guideline, and the tap area was invisible. */
.contact-field.w-input,
.contact-field.w-select,
.footer-field.w-input {
  min-height: 48px;
}

/* Mobile: the only conversion path was inside the closed menu. Keep a compact
   "Let's talk" pill visible next to the burger. */
@media screen and (max-width: 991px) {
  .nav-right .nav-button {
    display: flex;
  }
  .nav-right .nav-button .button {
    padding: 10px 18px;
  }
  .nav-right {
    display: flex;
    align-items: center;
    gap: 18px;
  }
}

/* Footer helpers added with the review fixes. */
.footer-newsletter-note {
  margin: 0 0 10px;
  font-size: 14px;
  line-height: 1.5;
  color: #A8A8AB;
}
.footer-quiet-line {
  font-size: 14px;
  color: #77777A;
  letter-spacing: 0.04em;
}

/* Byline link on posts: quiet, present. */
.blog-byline-link {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid #E6DE2E;
}

/* ------------------------------------------------------ audit round 2 (owner)
   Fixes from Ljubisa's mobile walkthrough, 2026-09-01. */

/* Reviews: the cards were near-black on a black section, held apart only by a
   shadow. They are Paper now, on both the marquee wall and the slider, with
   Ink text and a hairline divider. Stars come from rating-star.svg in gold-500
   (Volt on Paper measures 1.6:1 and the old orange is banned). */
/* The card is two nested layers. The outer one is a 6px rim that keeps the
   marquee cards visually separated where they touch or overlap; painting it
   light fused neighbouring cards into one slab. Rim shows the section behind,
   only the inner layer is Paper. */
.testimonial-card {
  background-color: transparent;
}
.testimonial-card-content {
  background-color: #FAFAF7;
}
.testimonial-author-coment {
  color: #161617;
}
.author-name {
  color: #161617;
}
.author-title {
  color: #77777A;
}
.testimonial-card-divider {
  background-color: #E4E4E2;
}

/* Slider arrows: Ink glyph on the Volt disc (white on Volt is unreadable),
   and on mobile the discs sat a full 100px below the card, floating in
   nothing. Pull them up under the card. */
.testimonial-arrow-icon {
  color: #161617;
}
@media screen and (max-width: 991px) {
  .testimonial-card-divider {
    margin-top: 32px;
    margin-bottom: 32px;
  }
  /* Cards vary in height with the quote, so anything anchored below them
     floats. Anchor the arrows to the top right instead, in the space between
     the section title and the card, where they always sit tight. */
  .testimonial-slider-wrapper {
    padding-top: 64px;
    padding-bottom: 0;
  }
  .testimonial-left-arrow {
    inset: 0 80px auto auto;
  }
  .testimonial-right-arrow {
    inset: 0 24px auto auto;
  }
}

/* Mobile bar: the logo at 200px forced the "Let's talk" pill to wrap onto two
   lines. Smaller logo, a compact pill that cannot wrap, and the duplicate CTA
   inside the full-screen menu goes away (the bar already carries it). */
@media screen and (max-width: 991px) {
  .nav-brand-logo {
    width: 148px;
  }
  .nav-right .nav-button .button {
    padding: 9px 16px;
  }
  .nav-right .nav-button .button-text {
    font-size: 14px;
    white-space: nowrap;
  }
  .nav-right .nav-button .button-content {
    flex-wrap: nowrap;
  }
  .navigation-menu .nav-button.none {
    display: none;
  }
}

/* Expertise on phones: the sticky card stack means only a sliver of each
   illustration ever shows. Owner's call: images are desktop and tablet only. */
@media screen and (max-width: 767px) {
  .service-image-wrapper {
    display: none;
  }
}

/* One rhythm between a section title and its content on mobile: everything
   was 50px except the FAQ at 30. */
@media screen and (max-width: 991px) {
  .faq-section-content {
    /* the template already carries 30px here; 20 more lands on the same
       50px rhythm as every other section */
    margin-top: 20px;
  }
}

/* The footer's quiet line sat 10px under the social links. */
.footer-quiet-line {
  margin-top: 32px;
}

/* Subpage rhythm: works and blog open 60px under the page title; contact sat
   at 147 and about at 100. Same 60 everywhere on mobile. */
@media screen and (max-width: 991px) {
  .contact-section {
    padding-top: 60px;
  }
  .about-section {
    padding-top: 60px;
  }
}

/* Marquee lockstep. The wall animates each t-card-container by a percentage
   of its own width, and cards used to size themselves to their text, so the
   three groups per row had three different widths, drifted at three different
   speeds, and ended up overlapping. One fixed card width makes every group
   identical, which keeps the loop's 12px gaps constant forever. Wall is
   desktop/tablet only (hidden under 992px), so no mobile impact. */
.t-card-container .testimonial-card {
  width: 440px;
  flex: 0 0 440px;
}

/* -------------------------------------------------------------- /toolbox/
   A chapter of the brand manual as a page: numbered sections, hairline-ruled
   rows, mono metadata, one Volt moment on hover. Tokens from brand v2.1. */

.tbx-section-wrap {
  padding-top: 40px;
  padding-bottom: 120px;
}

/* Section navigation. The old table of contents was a single block at the top:
   easy to scroll past, and it printed the same eight titles the reader was
   about to meet, so the first section header read as a repeat. This rail stays
   with the reader instead, marks where they are, and never restates a heading
   next to itself. Sticky column on desktop, sticky Ink bar on phones. */
.tbx-layout {
  display: grid;
  grid-template-columns: 232px minmax(0, 1fr);
  gap: 64px;
  align-items: start;
}
.tbx-rail {
  position: sticky;
  top: 40px;
  align-self: start;
}
/* No hairline under the label. It sat a few pixels off the black rule beside
   it, and two nearly-aligned lines read worse than one. The section names take
   the freed space instead. */
.tbx-rail-label {
  display: block;
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #A8A8AB;
  padding-bottom: 24px;
}
.tbx-rail-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.tbx-rail-item {
  margin: 0;
}
.tbx-rail-link {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 12px 0 12px 16px;
  border-left: 2px solid transparent;
  font-size: 14px;
  line-height: 1.35;
  color: #77777A;
  text-decoration: none;
  transition: color 150ms var(--ease-out), border-color 150ms var(--ease-out);
}
.tbx-rail-num {
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 11px;
  letter-spacing: 0.1em;
  color: #A8A8AB;
}
/* The rail carries the full title; the phone bar swaps in the short label. */
.tbx-rail-short {
  display: none;
}
.tbx-rail-link:hover,
.tbx-rail-link:focus-visible {
  color: #161617;
}
.tbx-rail-link.is-active {
  color: #161617;
  font-weight: 600;
  border-left-color: #E6DE2E;
}
.tbx-rail-link.is-active .tbx-rail-num {
  color: #77777A;
}

.tbx-section {
  padding-top: 72px;
  /* deep links land with the heading clear of the viewport edge */
  scroll-margin-top: 96px;
}
/* The first heading starts level with the rail. With the shared 72px on it,
   section 01 sat below both the rail label and its own rail entry. */
.tbx-section:first-child {
  padding-top: 0;
}

.tbx-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 16px;
  padding-bottom: 18px;
  border-bottom: 2px solid #161617;
}
.tbx-head-left {
  display: flex;
  align-items: baseline;
  gap: 16px;
}
.tbx-num {
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 14px;
  letter-spacing: 0.1em;
  color: #77777A;
}
.tbx-title {
  margin: 0;
  font-size: 28px;
  line-height: 1.2;
  letter-spacing: -0.01em;
  font-weight: 600;
  color: #161617;
}

.tbx-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.tbx-item {
  margin: 0;
}
/* The row holds no arrow column, so the domain ends flush with the rule above
   it. The arrow is parked outside the text instead: on hover the text slides
   left by exactly the arrow's width plus its gap, and the arrow takes the
   space it left, landing flush with the same rule. */
.tbx-row {
  position: relative;
  display: block;
  padding: 18px 0;
  border-bottom: 1px solid #E4E4E2;
  text-decoration: none;
  color: inherit;
}
.tbx-row-main {
  display: grid;
  grid-template-columns: 200px minmax(0, 1fr) auto;
  gap: 24px;
  align-items: baseline;
}
.tbx-name {
  font-size: 17px;
  font-weight: 600;
  color: #161617;
  letter-spacing: -0.005em;
}
.tbx-line {
  font-size: 15px;
  line-height: 1.55;
  color: #77777A;
}
.tbx-domain {
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 12px;
  letter-spacing: 0.06em;
  color: #77777A;
  white-space: nowrap;
  transition: transform 260ms var(--ease-out);
}
.tbx-arrow {
  position: absolute;
  right: 0;
  top: 50%;
  margin-top: -9px;
  color: #161617;
  opacity: 0;
  transform: translateX(-8px);
  transition: opacity 180ms var(--ease-out), transform 260ms var(--ease-out);
}
/* Sliding the whole row pulled the tool name out past the left margin it
   shares with the heading above. Only the domain gives up its place, which is
   all the arrow needs. */
.tbx-row:hover .tbx-domain,
.tbx-row:focus-visible .tbx-domain {
  transform: translateX(-26px);
}
.tbx-row:hover .tbx-arrow,
.tbx-row:focus-visible .tbx-arrow {
  opacity: 1;
  transform: translateX(0);
}
.tbx-row:hover .tbx-name,
.tbx-row:focus-visible .tbx-name {
  text-decoration: underline;
  text-decoration-color: #E6DE2E;
  text-decoration-thickness: 2px;
  text-underline-offset: 5px;
}

.tbx-outro {
  margin-top: 96px;
  padding-top: 24px;
  border-top: 1px solid #E4E4E2;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 24px;
}
.tbx-outro-text {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.tbx-outro-line {
  margin: 0;
  max-width: 46ch;
  font-size: 15px;
  line-height: 1.55;
  color: #77777A;
}
.tbx-outro-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 48px;
  padding: 12px 24px;
  border-radius: 12px;
  background: #161617;
  color: #FAFAF7;
  font-size: 15px;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color 150ms var(--ease-out);
}
.tbx-outro-cta:hover,
.tbx-outro-cta:focus-visible {
  background: #222223;
}
.tbx-outro-cta svg {
  transition: transform 150ms var(--ease-out);
}
.tbx-outro-cta:hover svg {
  transform: translateX(4px);
}

/* Between 992 and 1279 the rail is showing but the viewport is not wide enough
   to also carry a 200px name column and a long domain on one line: the
   description column collapsed to a 138px ribbon and rows grew to 246px tall.
   In that band the row stacks the way it does on phones. */
@media screen and (min-width: 992px) and (max-width: 1279px) {
  .tbx-layout {
    gap: 40px;
  }
  .tbx-row-main {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "name domain" "line line";
    row-gap: 8px;
  }
  .tbx-name { grid-area: name; }
  .tbx-domain { grid-area: domain; }
  .tbx-line { grid-area: line; padding-right: 32px; }
}

/* Phones and small tablets. The bar is gone. Ink across a Paper page was
   heavy, and it restated the heading sitting directly under it, which is the
   same duplication the desktop index had. Eight sections is a short scroll and
   the back-to-top button covers the return trip. */
@media screen and (max-width: 991px) {
  .tbx-layout {
    display: block;
  }
  .tbx-rail {
    display: none;
  }
  .tbx-section {
    scroll-margin-top: 24px;
  }
}

/* Phones. Three tiers per row instead of two competing on one line: the name
   is the loudest thing, the description is body text under it, the domain is
   the quietest and sits last. The arrow is permanent here, because there is no
   hover to reveal it and nothing else says these rows are links. */
@media screen and (max-width: 767px) {
  .tbx-section-wrap {
    padding-bottom: 64px;
  }
  .tbx-section {
    padding-top: 48px;
  }
  .tbx-title {
    font-size: 24px;
  }
  .tbx-row {
    padding: 20px 0;
  }
  .tbx-row-main {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "name" "line" "domain";
    gap: 0;
    transform: none;
  }
  .tbx-name {
    grid-area: name;
    /* keep clear of the arrow parked in the corner */
    padding-right: 30px;
    font-size: 19px;
    line-height: 1.3;
  }
  .tbx-line {
    grid-area: line;
    padding-right: 0;
    margin-top: 6px;
  }
  .tbx-domain {
    grid-area: domain;
    margin-top: 10px;
    font-size: 11px;
    color: #A8A8AB;
    transform: none;
  }
  /* The arrow is a sibling of the grid, not a cell in it, so it stays
     absolute here too and just moves up beside the name. */
  .tbx-arrow {
    top: 22px;
    margin-top: 0;
    opacity: 1;
    transform: none;
    color: #A8A8AB;
  }
  .tbx-outro {
    /* the last row's own hairline already closes the list, so a second rule
       40px under it just read as a stray line */
    margin-top: 40px;
    padding-top: 0;
    border-top: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 20px;
  }
  .tbx-outro-line {
    max-width: none;
  }
}

/* Nobody gets a sliding row if they asked for less motion. */
@media (prefers-reduced-motion: reduce) {
  .tbx-domain,
  .tbx-arrow,
  .to-top,
  .to-top svg {
    transition: none;
  }
  /* The domain still steps aside for the arrow (instantly, no travel);
     leaving it in place made the arrow sit on top of it. */
  /* The button still appears and disappears, it just does not travel. */
  .to-top,
  .to-top.is-visible:hover,
  .to-top.is-visible:focus-visible,
  .to-top.is-visible:active {
    transform: none;
  }
  .to-top.is-visible:hover svg {
    transform: none;
  }
}

/* Suggestion modal. A tool recommendation is not a client enquiry, so it gets
   its own form and the reader keeps their place in a 48-item list. Native
   <dialog>, which brings Escape, focus containment and a backdrop with it. */
.tbx-modal {
  margin: auto;
  padding: 0;
  border: 0;
  width: calc(100% - 32px);
  max-width: 520px;
  background: transparent;
  color: inherit;
}
/* Browsers without dialog support treat this as a plain block, so keep it
   closed by hand as well. */
.tbx-modal:not([open]) {
  display: none;
}
.tbx-modal::backdrop {
  background: rgba(22, 22, 23, 0.66);
}
.tbx-modal-card {
  background: #FAFAF7;
  border-radius: 12px;
  padding: 32px;
}
.tbx-modal-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
}
.tbx-modal-title {
  margin: 0;
  font-size: 22px;
  line-height: 1.25;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: #161617;
}
.tbx-modal-close {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  margin: -8px -8px 0 0;
  padding: 0;
  border: 0;
  border-radius: 12px;
  background: transparent;
  color: #77777A;
  cursor: pointer;
  transition: color 150ms var(--ease-out), background-color 150ms var(--ease-out);
}
.tbx-modal-close:hover,
.tbx-modal-close:focus-visible {
  color: #161617;
  background: #EDEAE2;
}
.tbx-modal-intro {
  margin: 8px 0 24px;
  font-size: 15px;
  line-height: 1.55;
  color: #77777A;
}
.tbx-form {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.tbx-field {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.tbx-field-label {
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #77777A;
}
.tbx-input {
  width: 100%;
  min-height: 48px;
  padding: 12px 14px;
  border: 1px solid #E4E4E2;
  border-radius: 12px;
  background: #FFFFFF;
  color: #161617;
  font-family: inherit;
  font-size: 15px;
  line-height: 1.5;
  transition: border-color 150ms var(--ease-out);
}
.tbx-input:focus {
  border-color: #161617;
  outline: none;
}
.tbx-input:focus-visible {
  outline: 2px solid #A47E1B;
  outline-offset: 2px;
}
.tbx-textarea {
  resize: vertical;
  min-height: 112px;
}
.tbx-submit {
  min-height: 48px;
  margin-top: 8px;
  padding: 12px 24px;
  border: 0;
  border-radius: 12px;
  background: #161617;
  color: #FAFAF7;
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
  transition: background-color 150ms var(--ease-out);
}
.tbx-submit:hover:not(:disabled) {
  background: #222223;
}
.tbx-submit:disabled {
  opacity: 0.6;
  cursor: default;
}
/* site.js builds these two when a form has no Webflow status siblings. */
.tbx-modal-card .w-form-done,
.tbx-modal-card .w-form-fail {
  margin-top: 16px;
  padding: 14px 16px;
  border-radius: 12px;
  font-size: 15px;
  line-height: 1.5;
}
.tbx-modal-card .w-form-done {
  background: #EDEAE2;
  color: #161617;
}
.tbx-modal-card .w-form-fail {
  background: #F6E7E7;
  color: #7A2222;
}

/* Back to top, every page. Hidden until the reader is far enough down that
   scrolling back would be work. */
.to-top {
  position: fixed;
  right: 24px;
  bottom: 24px;
  z-index: 40;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  padding: 0;
  border: 1px solid #48484A;
  border-radius: 50%;
  background: #161617;
  color: #FAFAF7;
  cursor: pointer;
  opacity: 0;
  visibility: hidden;
  transform: translateY(20px) scale(0.92);
  /* Leaving: fade and drop on a plain ease, then stop being focusable. The
     zero-duration visibility change is delayed so the fade is still visible. */
  transition:
    opacity 200ms var(--ease-out),
    transform 200ms var(--ease-out),
    background-color 150ms var(--ease-out),
    visibility 0s linear 200ms;
}
/* Arriving: slides up from below and fades in, on an easing that overshoots a
   little so it lands rather than just stops. */
.to-top.is-visible {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
  transition:
    opacity 260ms var(--ease-out),
    transform 460ms var(--ease-spring),
    background-color 150ms var(--ease-out),
    visibility 0s;
}
.to-top svg {
  transition: transform 240ms var(--ease-spring);
}
.to-top.is-visible:hover,
.to-top.is-visible:focus-visible {
  background: #222223;
  transform: translateY(-3px) scale(1.05);
}
.to-top.is-visible:hover svg,
.to-top.is-visible:focus-visible svg {
  transform: translateY(-2px);
}
.to-top.is-visible:active {
  transform: translateY(0) scale(0.96);
  transition-duration: 100ms;
}
/* The mobile menu is a full-screen panel; the button has no business on top
   of it. */
body:has(.w-nav-button.w--open) .to-top {
  opacity: 0;
  visibility: hidden;
}
/* reCAPTCHA plants its badge in this exact corner the first time anyone
   focuses a form field, so step over it when it turns up. */
body:has(.grecaptcha-badge) .to-top {
  bottom: 88px;
}
@media screen and (max-width: 767px) {
  .to-top {
    right: 16px;
    bottom: 16px;
  }
  body:has(.grecaptcha-badge) .to-top {
    bottom: 80px;
  }
  .tbx-modal-card {
    padding: 24px 20px;
  }
  .tbx-modal-title {
    font-size: 20px;
  }
}

/* ==========================================================================
   Detailed case study (layout: "deep").

   Two layers on purpose. The summary is an Ink panel so it reads as a card
   rather than as chapter one, and it answers role, problem, what I did and
   what happened before anyone decides whether to keep reading. Everything
   under "The story" is the long version, with a rail that stays put.

   Volt appears on Ink only. On Paper it sits at 1.6:1, so yellow-toned text
   there is Gold 700 instead, per the brand.
   ========================================================================== */
.cs-hero {
  padding-top: 64px;
  padding-bottom: 40px;
}
.cs-badge {
  display: inline-block;
  margin: 0 0 24px;
  padding: 6px 12px;
  border: 1px solid #E6DE2E;
  border-radius: 4px;
  background: #FAFAF7;
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #805B10;
}
.cs-title {
  margin: 0;
  font-size: 56px;
  line-height: 1.05;
  letter-spacing: -0.02em;
  font-weight: 500;
  color: #161617;
}
.cs-premise {
  margin: 24px 0 0;
  max-width: 34ch;
  font-size: 24px;
  line-height: 1.4;
  color: #161617;
}

/* ---------------------------------------------------------------- summary */
.cs-summary-wrap {
  padding-bottom: 24px;
}
.cs-summary {
  padding: 40px;
  border-radius: 12px;
  background: #222223;
}
.cs-summary-h {
  margin: 0 0 32px;
  /* Webflow sets a display line-height on h2 and h3. Left alone it puts 36px
     of dead space above this text and knocks it out of line with the columns
     beside it. */
  line-height: 1.4;
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-weight: 400;
  color: #A8A8AB;
}
.cs-summary-grid {
  display: grid;
  grid-template-columns: 232px minmax(0, 1fr);
  gap: 48px;
  align-items: start;
}
.cs-facts {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.cs-fact dt {
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #77777A;
}
.cs-fact dd {
  margin: 4px 0 0;
  font-size: 15px;
  line-height: 1.45;
  color: #FAFAF7;
}
.cs-summary-cols {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 40px;
}
.cs-summary-label {
  margin: 0 0 12px;
  line-height: 1.4;
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-weight: 400;
  color: #E6DE2E;
}
.cs-summary-text {
  margin: 0;
  font-size: 17px;
  line-height: 1.55;
  color: #FAFAF7;
}
.cs-did {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.cs-did li {
  position: relative;
  padding-left: 18px;
  font-size: 16px;
  line-height: 1.5;
  color: #FAFAF7;
}
.cs-did li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 10px;
  width: 8px;
  height: 1px;
  background: #E6DE2E;
}

/* Dividers are borders on the items, not a grey container showing through a
   1px gap: that trick also paints the container's own top padding, which put a
   24px grey bar above the first metric. */
.cs-metrics {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  margin-top: 40px;
  padding-top: 32px;
  border-top: 1px solid #48484A;
}
.cs-metric {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 0 24px;
}
.cs-metric:first-child {
  padding-left: 0;
}
.cs-metric + .cs-metric {
  border-left: 1px solid #48484A;
}
.cs-metric-value {
  font-size: 34px;
  line-height: 1.1;
  letter-spacing: -0.02em;
  font-weight: 600;
  color: #E6DE2E;
}
.cs-metric-label {
  font-size: 15px;
  line-height: 1.4;
  color: #FAFAF7;
}
.cs-metric-note {
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 12px;
  line-height: 1.45;
  letter-spacing: 0.06em;
  /* n500 on Ink is 4.0:1, under the bar. n400 clears it at 7.7:1. */
  color: #A8A8AB;
}
.cs-jump {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-top: 40px;
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #E6DE2E;
  text-decoration: none;
}
.cs-jump svg {
  transition: transform 200ms cubic-bezier(0.2, 0, 0, 1);
}
.cs-jump:hover svg,
.cs-jump:focus-visible svg {
  transform: translateY(3px);
}

/* ------------------------------------------------------------------ story */
.cs-body-wrap {
  padding-top: 56px;
  padding-bottom: 120px;
}
.cs-layout {
  display: grid;
  grid-template-columns: 232px minmax(0, 1fr);
  gap: 64px;
  align-items: start;
}
.cs-rail {
  position: sticky;
  top: 40px;
  align-self: start;
}
.cs-rail-label {
  display: block;
  padding-bottom: 24px;
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #A8A8AB;
}
.cs-rail-list {
  margin: 0;
  padding: 0;
  list-style: none;
}
.cs-rail-link {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 12px 0 12px 16px;
  border-left: 2px solid transparent;
  font-size: 14px;
  line-height: 1.35;
  color: #77777A;
  text-decoration: none;
  transition: color 150ms cubic-bezier(0.2, 0, 0, 1), border-color 150ms cubic-bezier(0.2, 0, 0, 1);
}
.cs-rail-num {
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 11px;
  letter-spacing: 0.1em;
  color: #A8A8AB;
}
.cs-rail-link:hover,
.cs-rail-link:focus-visible {
  color: #161617;
}
.cs-rail-link.is-active {
  color: #161617;
  font-weight: 600;
  border-left-color: #E6DE2E;
}
.cs-rail-link.is-active .cs-rail-num {
  color: #77777A;
}

.cs-chapter {
  padding-top: 80px;
  scroll-margin-top: 32px;
}
.cs-chapter:first-child {
  padding-top: 0;
}
.cs-chapter-head {
  display: flex;
  align-items: baseline;
  gap: 16px;
  padding-bottom: 18px;
  border-bottom: 2px solid #161617;
}
.cs-chapter-num {
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 14px;
  letter-spacing: 0.1em;
  color: #77777A;
}
.cs-chapter-title {
  margin: 0;
  font-size: 28px;
  line-height: 1.2;
  letter-spacing: -0.01em;
  font-weight: 600;
  color: #161617;
}
.cs-p {
  margin: 24px 0 0;
  max-width: 68ch;
  font-size: 17px;
  line-height: 1.65;
  color: #222223;
}

/* The decision block. The reason this layout exists: a call, the evidence for
   it, and what it cost. The cream panel alone sets it apart from the prose; the
   earlier Volt side bar was the generic callout tell and is gone. */
.cs-decision {
  margin: 32px 0 0;
  padding: 24px;
  background: #EDEAE2;
  border-radius: 12px;
}
.cs-decision-row {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr);
  gap: 16px;
  align-items: baseline;
}
.cs-decision-row + .cs-decision-row {
  margin-top: 16px;
  padding-top: 16px;
  border-top: 1px solid #DDD9CE;
}
.cs-decision-key {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #55555A;
}
/* The decision is the point of the block, so it is marked rather than enlarged:
   three rows of identical type read as one system, and the darker first label
   carries the hierarchy. No dot before it (his call, 2026-09-23: no decorative
   Volt dots in front of labels). */
.cs-decision-row:first-child .cs-decision-key {
  color: #161617;
}
.cs-decision-val {
  margin: 0;
  padding-right: 24px;
  font-size: 17px;
  line-height: 1.55;
  color: #222223;
}
.cs-decision-call {
  color: #161617;
}

.cs-quote {
  margin: 40px 0 0;
  padding-left: 24px;
  border-left: 2px solid #E4E4E2;
}
.cs-quote-text {
  margin: 0;
  max-width: 46ch;
  font-size: 22px;
  line-height: 1.45;
  letter-spacing: -0.01em;
  color: #161617;
}
.cs-quote-source {
  margin-top: 16px;
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #77777A;
}

.cs-inline-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 24px;
  margin: 32px 0 0;
  padding: 24px 0;
  border-top: 1px solid #E4E4E2;
  border-bottom: 1px solid #E4E4E2;
}
.cs-inline-stat {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.cs-inline-stat-value {
  font-size: 28px;
  line-height: 1.1;
  letter-spacing: -0.02em;
  font-weight: 600;
  color: #161617;
}
.cs-inline-stat-label {
  font-size: 14px;
  line-height: 1.45;
  color: #55555A;
}

.cs-steps {
  margin: 32px 0 0;
  padding: 0;
  max-width: 68ch;
  list-style: none;
  counter-reset: cs-step;
}
.cs-steps li {
  position: relative;
  padding-left: 40px;
  font-size: 16px;
  line-height: 1.6;
  color: #222223;
}
.cs-steps li + li {
  margin-top: 16px;
}
.cs-steps li::before {
  counter-increment: cs-step;
  content: counter(cs-step, decimal-leading-zero);
  position: absolute;
  left: 0;
  top: 2px;
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 12px;
  letter-spacing: 0.1em;
  color: #A8A8AB;
}

.cs-aside {
  margin: 32px 0 0;
  padding: 20px 24px;
  border-radius: 12px;
  background: #EDEAE2;
}
.cs-aside p {
  margin: 0;
  max-width: 62ch;
  font-size: 15px;
  line-height: 1.6;
  color: #77777A;
}

.cs-figure {
  margin: 40px 0 0;
}
.cs-figure img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 12px;
}
.cs-figure figcaption {
  margin-top: 12px;
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 12px;
  line-height: 1.5;
  letter-spacing: 0.06em;
  color: #55555A;
}

.cs-outro {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 24px;
  margin-top: 96px;
  padding-top: 24px;
  border-top: 1px solid #E4E4E2;
}
.cs-back,
.cs-contact {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 15px;
  color: #161617;
  text-decoration: none;
}
.cs-back svg {
  transition: transform 150ms cubic-bezier(0.2, 0, 0, 1);
}
.cs-back:hover svg {
  transform: translateX(-4px);
}
.cs-contact {
  text-decoration: underline;
  text-decoration-color: #E6DE2E;
  text-decoration-thickness: 2px;
  text-underline-offset: 4px;
}

/* Tablets and phones: the rail goes, exactly as it does on the toolbox. A dark
   strip across a Paper page was heavy and it restated the heading under it,
   and the back-to-top button covers the return trip. */
@media screen and (max-width: 991px) {
  .cs-layout {
    display: block;
  }
  .cs-rail {
    display: none;
  }
  .cs-summary-grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 32px;
  }
  .cs-title {
    font-size: 44px;
  }
}

@media screen and (max-width: 767px) {
  .cs-hero {
    padding-top: 40px;
    padding-bottom: 32px;
  }
  .cs-title {
    font-size: 34px;
  }
  .cs-premise {
    margin-top: 16px;
    max-width: none;
    font-size: 19px;
  }
  .cs-summary {
    padding: 24px 20px;
  }
  .cs-summary-h {
    margin-bottom: 24px;
  }
  .cs-summary-cols {
    grid-template-columns: minmax(0, 1fr);
    gap: 24px;
  }
  .cs-metrics {
    grid-template-columns: minmax(0, 1fr);
    margin-top: 32px;
    padding-top: 24px;
  }
  .cs-metric {
    padding: 0;
  }
  /* stacked here, so the divider moves from the side to the top */
  .cs-metric + .cs-metric {
    margin-top: 20px;
    padding-top: 20px;
    border-left: 0;
    border-top: 1px solid #48484A;
  }
  .cs-metric-value {
    font-size: 28px;
  }
  .cs-body-wrap {
    padding-top: 40px;
    padding-bottom: 64px;
  }
  .cs-chapter {
    padding-top: 56px;
  }
  .cs-chapter-title {
    font-size: 24px;
  }
  .cs-p {
    font-size: 16px;
  }
  /* Stack the decision block: a 96px label column next to text is unreadable
     at this width. */
  .cs-decision {
    padding: 20px 20px 20px 20px;
    border-radius: 0 8px 8px 0;
  }
  .cs-decision-row {
    grid-template-columns: minmax(0, 1fr);
    gap: 6px;
  }
  .cs-decision-val {
    padding-right: 0;
  }
  .cs-quote-text {
    font-size: 19px;
  }
  .cs-outro {
    flex-direction: column;
    align-items: stretch;
    gap: 16px;
    margin-top: 56px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .cs-jump svg,
  .cs-back svg {
    transition: none;
  }
}

/* ------------------------------------------------------------ blog categories
   The blog is one person's and it is widening past design: travel, building,
   finds, hobbies, good things. The rail under the title says so at a glance.
   Chips are real links to /blog/category/<slug>/ (no JS, shareable, indexable).
   A world with no posts yet is a quiet dashed "soon" chip, so the promise is
   honest and nothing pretends to exist. Active chip is Ink on Paper; the rest
   are Paper with a hairline. Motion follows the back-to-top button: a small
   lift on hover on the spring curve, plain ease on the way back. */
.blog-cats {
  /* the list block below already opens with its own top space, so a short
     margin here lands the first row of cards 80px under the chips */
  margin: 0 0 24px;
}
.blog-cats-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.blog-cat {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 40px;
  padding: 0 16px;
  border-radius: 999px;
  border: 1px solid rgba(22, 22, 23, 0.18);
  background: transparent;
  color: #161617;
  font-size: 14px;
  line-height: 1;
  font-weight: 500;
  letter-spacing: 0.01em;
  text-decoration: none;
  transition:
    transform 0.22s var(--ease-spring),
    background-color 0.18s ease,
    border-color 0.18s ease,
    color 0.18s ease;
}
a.blog-cat:hover,
a.blog-cat:focus-visible {
  transform: translateY(-2px);
  border-color: #161617;
}
a.blog-cat:active {
  transform: translateY(0);
  transition-duration: 0.08s;
}
.blog-cat.is-active {
  background: #161617;
  border-color: #161617;
  color: #FAFAF7;
}
.blog-cat-count {
  font-size: 12px;
  font-weight: 500;
  opacity: 0.6;
  font-variant-numeric: tabular-nums;
}
.blog-cat.is-active .blog-cat-count {
  opacity: 0.7;
}
.blog-cat.is-empty {
  color: #77777A;
  border-style: dashed;
  cursor: default;
}
.blog-cat-soon {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #A8A8AB;
}

/* Client-side filtering (site.js): a card outside the chosen world is hidden,
   the ones that stay rise in with a short stagger. Without JavaScript the
   category pages render the same result server-side. */
.blog-collection-item.is-filtered-out {
  display: none !important;
}
.blog-collection-item.is-entering {
  animation: blog-card-in 0.36s var(--ease-out) both;
}
@keyframes blog-card-in {
  from {
    opacity: 0;
    transform: translateY(14px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
/* Category line above each card title: a Volt dot (the one accent on the
   card), the world in small caps, then the topic quieter. */
.blog-card-cat {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 10px;
  font-size: 12px;
  line-height: 1;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #161617;
}
.blog-card-cat-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #E6DE2E;
  flex: none;
}
.blog-card-cat-topic {
  color: #6B6B6E;
  text-transform: none;
  letter-spacing: 0.02em;
}
/* On the article page the topic sits after the category link. */
/* #77777A was 4.26:1 on Paper; #6B6B6E is 5.1:1. */
.blog-topic {
  color: #6B6B6E;
}
.blog-byline-link { color: #6B6B6E; }
/* Section labels ("Articles", "Related") inherit the template's #757575, which
   is 4.34:1 on Paper at 18px. One step darker passes on every page. */
.sub-title { color: #6B6B6E; }

/* Phones: seven chips wrap to three rows and push the first article 124px
   down, so the rail becomes one row that scrolls sideways. "All" and "Design"
   are in view, the rest peek past the edge, which is the cue to swipe. No
   scrollbar; a thumb can reach every chip. */
@media (max-width: 767px) {
  .blog-cats {
    margin-bottom: 32px;
  }
  .blog-cats-list {
    flex-wrap: nowrap;
    gap: 8px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding-bottom: 4px;
    scroll-snap-type: x proximity;
  }
  .blog-cats-list::-webkit-scrollbar {
    display: none;
  }
  .blog-cats-list > li {
    flex: none;
    scroll-snap-align: start;
  }
  .blog-cat {
    min-height: 36px;
    padding: 0 14px;
    font-size: 13px;
    white-space: nowrap;
  }
}
@media (prefers-reduced-motion: reduce) {
  .blog-cat,
  a.blog-cat:hover,
  a.blog-cat:focus-visible {
    transition: none;
    transform: none;
  }
}

/* ------------------------------------------------------------------ motion pass
   2026-09-05. Adds motion where the Webflow export leaves the page static, and
   ties every duration and easing to the tokens in :root. Rules of the house:
   arrive on the spring, leave on ease-out; only the right-most element moves
   on hover, never the text that shares a left margin; reduced motion keeps the
   fades and drops the travel. */

/* Rise-in for lists: works grid, blog cards, toolbox rows, case-study figures.
   site.js adds is-risen on first sight and sets --rise-i for the batch that
   arrives together, so a grid ripples in rather than popping. */
[data-rise] {
  opacity: 0;
  transform: translateY(16px);
  transition:
    opacity var(--dur-slow) var(--ease-out),
    transform var(--dur-slow) var(--ease-spring);
  transition-delay: calc(var(--rise-i, 0) * 70ms);
}
[data-rise="settle"] { transform: scale(1.02); }
[data-rise].is-risen { opacity: 1; transform: none; }
/* No JS: Webflow's own snippet never adds w-mod-js, so nothing waits. */
html:not(.w-mod-js) [data-rise] { opacity: 1; transform: none; }

/* Home hero entrance: name first, then the two lines under it, once. The
   background image is left alone so the largest paint is not delayed. */
@keyframes rise-in {
  from { opacity: 0; transform: translateY(18px); }
  to { opacity: 1; transform: none; }
}
.hero-title { animation: rise-in var(--dur-enter) var(--ease-spring) both; }
.hero-bottom-left-descption-wrap { animation: rise-in var(--dur-enter) var(--ease-spring) 140ms both; }
.hero-bottom-right-service-tag { animation: rise-in var(--dur-enter) var(--ease-spring) 240ms both; }

/* One hover language. Cards lift, text links take the Volt underline that the
   toolbox rows already use, arrows nudge (toolbox rows, back to top). */
.work-item-block,
.blog-item-block {
  transition: transform var(--dur-base) var(--ease-out);
}
.work-link:hover .work-item-block,
.work-link:focus-visible .work-item-block,
.blog-link-block:hover .blog-item-block,
.blog-link-block:focus-visible .blog-item-block {
  transform: translateY(-4px);
}
.about-links,
.blog-byline-link,
.footer-link-text {
  transition:
    color var(--dur-fast) var(--ease-out),
    text-decoration-color var(--dur-fast) var(--ease-out),
    text-underline-offset var(--dur-fast) var(--ease-out);
}
.about-links:hover,
.blog-byline-link:hover,
.footer-link-text:hover {
  text-decoration: underline;
  text-decoration-color: #E6DE2E;
  text-decoration-thickness: 2px;
  text-underline-offset: 5px;
}

/* Nav: a Volt dot under the current page. Between pages the dot carries a
   view-transition name, so in browsers with cross-document view transitions
   it slides from the old item to the new one instead of reappearing. */
.navigation-link { position: relative; }
.nav-dot {
  position: absolute;
  left: 50%;
  bottom: -8px;
  width: 6px;
  height: 6px;
  margin-left: -3px;
  border-radius: 50%;
  background: #E6DE2E;
  view-transition-name: nav-dot;
}
@media (max-width: 991px) {
  .nav-dot { display: none; }
}
/* Mobile menu: Webflow slides the panel in; the links follow in a short ripple. */
@keyframes menu-link-in {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: none; }
}
.w-nav-menu[data-nav-menu-open] .navigation-link { animation: menu-link-in 420ms var(--ease-spring) both; }
.w-nav-menu[data-nav-menu-open] .navigation-link:nth-child(2) { animation-delay: 50ms; }
.w-nav-menu[data-nav-menu-open] .navigation-link:nth-child(3) { animation-delay: 100ms; }
.w-nav-menu[data-nav-menu-open] .navigation-link:nth-child(4) { animation-delay: 150ms; }
.w-nav-menu[data-nav-menu-open] .navigation-link:nth-child(5) { animation-delay: 200ms; }
.w-nav-menu[data-nav-menu-open] .navigation-link:nth-child(6) { animation-delay: 250ms; }

/* Page transitions without a client-side router: the browser cross-fades the
   whole document on navigation where it can (Chromium), and does nothing
   elsewhere. Webflow's scripts still run per page exactly as before. */
@view-transition { navigation: auto; }
::view-transition-old(root) { animation-duration: 160ms; animation-timing-function: cubic-bezier(0.2, 0, 0, 1); }
::view-transition-new(root) { animation-duration: 240ms; animation-timing-function: cubic-bezier(0.2, 0, 0, 1); }

@media (prefers-reduced-motion: reduce) {
  [data-rise] { opacity: 1; transform: none; transition: none; }
  .hero-title,
  .hero-bottom-left-descption-wrap,
  .hero-bottom-right-service-tag,
  .w-nav-menu[data-nav-menu-open] .navigation-link { animation: none; }
  @view-transition { navigation: none; }
}

/* ------------------------------------- short case study, pointing at the long one
   A project can run as a pair: a two-minute page and the detailed one behind
   it. The caption under a figure carries the brief while the artwork is still a
   placeholder, and the real caption once it is not, so it uses the same mono
   register as the deep layout's figcaption rather than inventing a second one.
   The closing block is the handover between the two pages: one line of reason,
   then the button. It is centred because it is the only element on the page
   that is not part of the story. */
.work-figure-caption {
  margin: 12px 0 0;
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 12px;
  line-height: 1.5;
  letter-spacing: 0.06em;
  color: #55555A;
}

.work-full-cta {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
  margin-top: 24px;
  padding: 48px 0 8px;
  border-top: 1px solid rgba(22, 22, 23, 0.12);
  text-align: center;
}
.work-full-cta-lede {
  max-width: 56ch;
  margin: 0;
  font-size: 18px;
  line-height: 1.5;
  color: var(--text-colors--dark-gray);
}

@media (max-width: 767px) {
  .work-full-cta {
    padding-top: 40px;
  }
  .work-full-cta-lede {
    font-size: 16px;
  }
}

/* ------------------------------------------- case-study hero, brand book ch. 26
   "The hero answers everything: who, what, and the one number." The Webflow
   template built this hero for exactly two children in a 90px flex stack, so
   dropping a headline and a stat into it spaced everything 90px apart and left
   the right half empty. Instead the hero is now two columns doing two jobs:
   the story on the left (title, then the headline tight underneath it, then the
   quiet meta row), the evidence on the right (the number, then the action).
   The wrapper's align-items: flex-end does the rest, sitting the number on the
   same baseline as the meta row.

   Volt marks the result, but Volt on Paper fails contrast, so the number stays
   Ink and Volt does the pointing with a rule above it. Never colour alone. */
.work-headline {
  max-width: 18ch;
  margin: 16px 0 0;
  font-size: 40px;
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--text-colors--black);
}

.work-details-hero-content-right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 40px;
  text-align: right;
}
.work-hero-stat {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
  padding-top: 12px;
  border-top: 3px solid var(--bg-colors--yellow-main);
}
.work-hero-stat-value {
  font-size: 56px;
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--text-colors--black);
}
.work-hero-stat-label {
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #55555A;
}

/* Block 08. One link on to the next case, so the set reads as a body of work.
   It sits AFTER the closing call to action, because the job of this page is to
   send the reader into the long version; the next case is where they go when
   they are done, not a competing offer halfway down. Full-width row with a rule
   above it so it reads as footer navigation rather than a stray line. The arrow
   is permanent, since there is no hover on a phone, and it is the only thing
   that moves: the label and the title keep the page's left edge. */
.work-next {
  display: flex;
  align-items: baseline;
  gap: 24px;
  padding: 40px 0 8px;
  border-top: 1px solid rgba(22, 22, 23, 0.12);
  color: var(--text-colors--black);
  text-decoration: none;
}
.work-next-label {
  flex: none;
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #55555A;
}
.work-next-title {
  font-size: 32px;
  line-height: 1.2;
  letter-spacing: -0.02em;
  border-bottom: 2px solid transparent;
  transition: border-color 150ms var(--ease-out);
}
.work-next-arrow {
  flex: none;
  margin-left: auto;
  align-self: center;
  transition: transform 260ms var(--ease-out);
}
.work-next:hover .work-next-title { border-bottom-color: var(--bg-colors--yellow-main); }
.work-next:hover .work-next-arrow { transform: translateX(8px); }
@media (max-width: 767px) {
  .work-headline { font-size: 24px; }
  .work-hero-stat-value { font-size: 32px; }
  .work-next { flex-direction: column; gap: 8px; }
  .work-next-title { font-size: 20px; }
}

/* Case-study hero, narrow screens. The template's wrapper stops being two
   columns below 991px, so the right column stops behaving like one: the number
   and the button go back to the same left edge as everything else. These sit at
   the end of the file on purpose, after the base hero rules they override. */
@media (max-width: 991px) {
  .work-details-hero-content-right {
    align-items: flex-start;
    gap: 32px;
    text-align: left;
  }
  .work-hero-stat { align-items: flex-start; }
}

@media (max-width: 767px) {
  .work-headline { font-size: 28px; max-width: none; }
  .work-hero-stat-value { font-size: 40px; }
}

/* Next-case row on phones. An earlier rule stacked it into a column, which
   stranded the arrow; this restores the row and puts the label on its own line
   so the title and the arrow share the last one. Later in the file on purpose. */
@media (max-width: 767px) {
  .work-next {
    flex-flow: row wrap;
    align-items: center;
    gap: 4px 16px;
  }
  .work-next-label { width: 100%; }
  .work-next-title { font-size: 22px; }
}

/* Sources under a chapter. A portfolio claim that carries its own receipt is
   worth more than one that does not, so a chapter can cite what backs it: the
   employer's own release notes, a public figure. Quiet by default, because the
   story is the point and the citation is the proof, not the content. */
.cs-sources {
  margin: 32px 0 0;
  padding: 16px 20px;
  background: #F2F0EA;
  border-radius: 12px;
}
.cs-sources-label {
  display: block;
  margin-bottom: 8px;
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #55555A;
}
.cs-sources-list {
  margin: 0;
  padding: 0;
  list-style: none;
}
.cs-sources-list li + li { margin-top: 6px; }
.cs-sources-list a {
  font-size: 15px;
  line-height: 1.5;
  color: #222223;
  text-decoration: none;
  border-bottom: 1px solid #C9C5B8;
  transition: border-color 150ms var(--ease-out);
}
.cs-sources-list a:hover { border-bottom-color: var(--bg-colors--yellow-main); }

/* Case-study hero: keep the cover at the ratio it was designed at. The
   template forced 90vh (100vh from 1440px) with object-fit: cover, which
   zoomed and cropped any cover shorter than the screen. Now the image
   follows its own width/height, capped at 90vh so a tall cover never
   pushes past the fold. */
.work-details-hero-bg,
.work-details-hero-bg[class] {
  height: auto;
  max-height: 90vh;
  object-fit: cover;
}

/* Figure captions are centred under their image on both case-study layouts
   (his call, 2026-09-23). A measure cap keeps a long caption from running the
   full figure width as one thin line. */
.cs-figure figcaption,
.work-figure-caption {
  max-width: 72ch;
  margin-left: auto;
  margin-right: auto;
  text-align: center;
}

/* ------------------------------------------ case-study audit, 2026-09-23
   Accessibility pass before the case studies go public. */

/* Section labels on the short page are real h2s now (screen readers jump by
   heading). Strip Webflow's h2 look so they keep the small label style. */
h2.sub-title {
  margin: 0;
  font-family: inherit;
  letter-spacing: normal;
  text-transform: none;
}

/* Contrast to WCAG AA. #77777A on Paper measured 4.27:1, on Ink 3.56:1. */
.work-full-cta-lede { color: #55555A; }
.cs-fact dt { color: #A8A8AB; }
.cs-rail-link { color: #55555A; }
.cs-rail-num,
.cs-rail-label { color: #6B6B6E; }

/* Type floor for a reader skimming at arm's length: nothing under 12px,
   captions at 13px. */
.cs-fact dt,
.cs-summary-label { font-size: 12px; }
.cs-figure figcaption,
.work-figure-caption { font-size: 13px; }

/* The footer email field only changed its text colour on focus. */
.footer-field:focus-visible {
  outline: 2px solid #A47E1B;
  outline-offset: 2px;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Figures open full size in a new tab: on a phone a 2110px plate shows at
   about a sixth of its size, so the labels inside it need a way to be read. */
.cs-zoom {
  display: block;
  cursor: zoom-in;
}

/* One Paper tint for every inset box (decision and sources were two). */
.cs-sources { background: #EDEAE2; }

/* The active rail item is marked by colour and the Volt bar only; a bolder
   weight re-wrapped two-line titles as you scrolled. */
.cs-rail-link.is-active { font-weight: inherit; }

@media screen and (max-width: 767px) {
  /* Three stats wrapped 2 + 1 on a phone and left one stranded. */
  .cs-inline-stats { grid-template-columns: 1fr; gap: 16px; }
}

/* Figure lightbox (site.js). Ink backdrop, the plate at full width up to its
   own size; on phones it keeps a readable width and scrolls sideways. */
.lb {
  max-width: none;
  max-height: none;
  width: 100vw;
  height: 100vh;
  margin: 0;
  padding: 0;
  border: 0;
  background: rgba(22, 22, 22, 0.94);
  cursor: zoom-out;
}
.lb::backdrop { background: transparent; }
.lb[open] { display: flex; align-items: center; justify-content: center; }
.lb-scroll {
  max-width: 100vw;
  max-height: 100vh;
  overflow: auto;
  padding: 64px 24px;
}
.lb-img {
  display: block;
  width: min(2110px, calc(100vw - 48px));
  height: auto;
  border-radius: 12px;
}
.lb-close {
  position: fixed;
  top: 16px;
  right: 16px;
  width: 48px;
  height: 48px;
  border: 0;
  border-radius: 50%;
  background: #FAFAF7;
  color: #161616;
  font-size: 32px;
  line-height: 1;
  cursor: pointer;
  z-index: 1;
}
.lb-close:focus-visible { outline: 2px solid #E6DE2E; outline-offset: 2px; }
@media screen and (max-width: 767px) {
  .lb { cursor: default; }
  .lb[open] { justify-content: flex-start; }
  .lb-img { width: 900px; max-width: none; }
}

/* Centre the close icon optically: an SVG cross in a flex box, not a
   text glyph sitting on a baseline. */
.lb-close {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}
.lb-close svg { display: block; }

/* Short-page gallery items are <figure> now, so the caption is tied to its
   image for screen readers; drop the browser's default figure margin. */
figure.work-overview-image-wrapper { margin-bottom: 0; }

/* Contrast: quote source was 4.27:1 at 11px, footer quiet line 4.05:1. */
.cs-quote-source { font-size: 12px; color: #55555A; }
.footer-quiet-line { color: #A8A8AB; }

/* Inline links in short case-study paragraphs. */
.work-overview-description a {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: #E6DE2E;
  text-decoration-thickness: 2px;
  text-underline-offset: 4px;
}
.work-overview-description a:hover { text-decoration-color: currentColor; }

/* Inline links in deep case-study prose, same treatment as the short page. */
.cs-p a {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: #E6DE2E;
  text-decoration-thickness: 2px;
  text-underline-offset: 4px;
}
.cs-p a:hover { text-decoration-color: currentColor; }

/* Screens strip at the end of a case study (CaseStudyScreens.astro). An Ink
   plate like the figures, one shared height for phone and web screens, and
   a sideways scroll with snap. Arrows for mouse users; phones just swipe. */
.cs-screens {
  margin-top: 32px;
  padding: 24px 0;
  background: #161616;
  border-radius: 12px;
}
.cs-chapter .cs-screens { margin-top: 24px; }
.cs-screens-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 0 24px 16px;
}
.cs-screens-note {
  margin: 0;
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 12px;
  line-height: 1.5;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #A8A8AB;
}
.cs-screens-nav { display: flex; gap: 8px; margin-left: auto; }
.cs-screens-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1px solid #48484A;
  border-radius: 50%;
  background: transparent;
  color: #FAFAF7;
  cursor: pointer;
  transition: border-color var(--dur-fast, .15s) var(--ease-out, ease), color var(--dur-fast, .15s) var(--ease-out, ease);
}
.cs-screens-btn:hover:not(:disabled) { border-color: #E6DE2E; color: #E6DE2E; }
.cs-screens-btn:disabled { opacity: 0.3; cursor: default; }
.cs-screens-btn:focus-visible,
.cs-screens-track:focus-visible,
.cs-screen-link:focus-visible { outline: 2px solid #E6DE2E; outline-offset: 2px; }
.cs-screens-track {
  display: flex;
  gap: 24px;
  margin: 0;
  padding: 0 24px 16px;
  list-style: none;
  overflow-x: auto;
  scroll-snap-type: x proximity;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  scroll-padding: 0 24px;
  scrollbar-width: none;
}
.cs-screens-track::-webkit-scrollbar { display: none; }
/* The native scrollbar is hidden (on Windows it brings arrow buttons); this
   line shows where the strip is instead: Ink track, Volt marker, the same
   marker as the active item in the case-study rail. site.js sizes it. */
.cs-screens-progress {
  position: relative;
  height: 2px;
  margin: 8px 24px 0;
  background: #2E2E30;
  border-radius: 2px;
  overflow: hidden;
}
.cs-screens-thumb {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 20%;
  background: #E6DE2E;
  border-radius: 2px;
  will-change: transform;
}
.cs-screen {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin: 0;
  scroll-snap-align: start;
}
.cs-screen-link { display: block; border-radius: 24px; }
.cs-screen img {
  display: block;
  width: auto;
  height: 480px;
  border-radius: 24px;
}
.cs-screen--web .cs-screen-link,
.cs-screen--web img { border-radius: 12px; }
.cs-screen-label {
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 12px;
  line-height: 1.5;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #A8A8AB;
}
@media screen and (max-width: 767px) {
  .cs-screens { padding: 16px 0; }
  .cs-screens-head { padding: 0 16px 12px; }
  .cs-screens-nav { display: none; }
  .cs-screens-track { gap: 16px; padding: 0 16px 12px; scroll-padding: 0 16px; }
  .cs-screens-progress { margin: 4px 16px 0; }
  .cs-screen img { height: 400px; }
}

/* Lightbox for a screen: fit the whole screen to the viewport height instead
   of the figure rule (full width, or 900px wide and scrolling on a phone). */
.lb.lb-screen .lb-img {
  width: auto;
  max-width: calc(100vw - 48px);
  max-height: calc(100vh - 128px);
  border-radius: 24px;
}
@media screen and (max-width: 767px) {
  .lb.lb-screen[open] { justify-content: center; }
  .lb.lb-screen .lb-img { width: auto; max-width: calc(100vw - 48px); }
}

/* Certilia review, 25 Sept: the last pieces under the 12px floor and the
   AA line, shared by every deep case study. */
.cs-rail-num { font-size: 12px; }
.cs-chapter-num { color: #6B6B6E; }
/* On a phone a 2110px figure is too small to read in place; say that a tap
   opens it. Captions only follow zoomable figures. */
@media screen and (max-width: 767px) {
  a.cs-zoom + figcaption::after {
    content: " Tap to enlarge.";
    color: #6B6B6E;
  }
}

/* Private interview deck (DeckBar.astro, works/mastercard-clients.astro).
   Ink strip on top so it's always clear which mode the site is in, and a
   Lock that ends the private session. */
.deck-bar {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 8px 16px;
  background: #161616;
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.deck-bar a { color: #FAFAF7; text-decoration: none; min-height: 44px; display: inline-flex; align-items: center; }
.deck-bar-lock {
  padding: 0 16px;
  border: 1px solid #48484A;
  border-radius: 100px;
  min-height: 32px !important;
}
.deck-bar-lock:hover { border-color: #E6DE2E; color: #E6DE2E !important; }
.deck-bar a:focus-visible { outline: 2px solid #E6DE2E; outline-offset: 2px; }

.deck-hub { padding: 120px 0 160px; }
.deck-hub-title {
  margin: 16px 0 16px;
  font-size: clamp(40px, 6vw, 72px);
  line-height: 1.05;
  font-weight: 500;
  letter-spacing: -0.02em;
}
.deck-hub-lede { margin: 0 0 56px; font-size: 18px; line-height: 1.5; color: #55555A; max-width: 40ch; }
.deck-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 16px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.deck-tile {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 3 / 2;
  padding: 32px;
  background: #FFFFFF;
  border: 1px solid #E4E2DA;
  border-radius: 12px;
  color: #161616;
  text-decoration: none;
  transition: transform var(--dur-fast, .15s) var(--ease-out, ease), border-color var(--dur-fast, .15s) var(--ease-out, ease);
}
.deck-tile:hover { transform: translateY(-4px); border-color: #161616; }
.deck-tile:focus-visible { outline: 2px solid #A47E1B; outline-offset: 2px; }
.deck-tile img { max-width: 70%; max-height: 64px; width: auto; height: auto; object-fit: contain; }
.deck-tile-name { font-size: 20px; font-weight: 500; }
@media screen and (max-width: 767px) {
  .deck-hub { padding: 64px 0 96px; }
  .deck-grid { grid-template-columns: repeat(2, 1fr); gap: 12px; }
  .deck-tile { padding: 20px; }
}

/* ------------------------------------------------ slop pass, 27 Sept 2026
   From the "Anatomy of Slop" audit (github.com/ljubisakukulj/website-slop-audit).
   Local branch slop-fixes only, nothing here is on staging or live yet. */

/* Radii. Measured seven different rectangle radii across the site. Brand
   digest: 10px controls, 12px cards, 999px chips. Full-width panels keep 24.
   The template redefines these tokens per breakpoint; one set wins here. */
:root, body {
  --_border-radius---border-radius-8: 10px;
  --_border-radius---border-radius-16: 12px;
  --_border-radius---border-radius-20: 12px;
  --_border-radius---border-radius-22: 12px;
  --_border-radius---border-radius-24: 24px;
  --_border-radius---border-radius-32: 24px;
}

/* Ways to work together: a white card inside a beige card, three times over.
   Now one column each, divided by rules, like the Experience table. */
.pricing-card {
  background-color: transparent;
  border-radius: 0;
  border-top: 1px solid var(--bg-colors--black, #161617);
  padding: 0 0 8px;
}
.pricing-card-top {
  background-color: transparent;
  border-radius: 0;
  padding: 24px 0 0;
}
.pricing-card-bottom {
  margin-top: 32px;
  padding-left: 0;
  padding-right: 0;
}

/* FAQ: nine boxes became nine rows with hairlines between them. */
.faq-section-content {
  grid-row-gap: 0;
  border-top: 1px solid #E4E4E2;
}
.faq-accordion {
  background-color: transparent;
  border-radius: 0;
  border-bottom: 1px solid #E4E4E2;
  padding: 24px 0;
}

/* Client logos sit straight on the page, no tile behind each one. */
.brands-item-block {
  background-color: transparent;
}
.brands-content-blur.l {
  background-image: linear-gradient(90deg, #FAFAF7 30%, rgba(250, 250, 247, 0));
}
.brands-content-blur.r {
  background-image: linear-gradient(90deg, rgba(250, 250, 247, 0), #FAFAF7 70%);
}

/* Expertise on phones: the figures are hidden below 768, but the sticky
   stack still reserved their space, leaving close to a screen of empty dark
   between items. Plain flow on phones. */
@media screen and (max-width: 767px) {
  .service-item {
    position: static;
    padding-bottom: 40px;
  }
  .service-item:last-child {
    padding-bottom: 0;
  }
}

/* Phone hero: the centre crop of a wide stage photo is mostly dark crowd.
   Aim the crop at the speaker instead. */
@media screen and (max-width: 767px) {
  .hero-bg-image {
    object-position: 68% 50%;
  }
}

/* ------------------------------------------------ spacing pass, 28 Sept 2026
   Measured on every page: section gaps of 90, 100, 120, 140 and 160, title
   gaps of 90 and 100, and five different left edges on the homepage alone
   (40, 46, 48, 52, 58 at 1440). One scale on the 8pt grid instead:
   sections 128 / 96 / 80, title-to-content 96 / 64 / 48, one gutter per size. */
:root, body {
  --_section-padding---section-padding--section-padding-40: 40px;
  --_section-padding---section-padding--section-padding-60: 64px;
  --_section-padding---section-padding--section-padding-90: 96px;
  --_section-padding---section-padding--section-padding-100: 96px;
  --_section-padding---section-padding--section-padding-120: 128px;
  --_section-padding---section-padding--section-padding-140: 128px;
  --_section-padding---section-padding--section-padding-160: 128px;
  --_section-padding---section-margin--section-margin-100: 96px;
  --lk-gutter: 48px;
}
@media screen and (max-width: 991px) {
  :root, body {
    --_section-padding---section-padding--section-padding-40: 32px;
    --_section-padding---section-padding--section-padding-60: 48px;
    --_section-padding---section-padding--section-padding-90: 64px;
    --_section-padding---section-padding--section-padding-100: 64px;
    --_section-padding---section-padding--section-padding-120: 96px;
    --_section-padding---section-padding--section-padding-140: 96px;
    --_section-padding---section-padding--section-padding-160: 96px;
    --_section-padding---section-margin--section-margin-100: 64px;
    --lk-gutter: 32px;
  }
}
@media screen and (max-width: 767px) {
  :root, body {
    --_section-padding---section-padding--section-padding-40: 24px;
    --_section-padding---section-padding--section-padding-60: 48px;
    --_section-padding---section-padding--section-padding-90: 48px;
    --_section-padding---section-padding--section-padding-100: 48px;
    --_section-padding---section-padding--section-padding-120: 80px;
    --_section-padding---section-padding--section-padding-140: 80px;
    --_section-padding---section-padding--section-padding-160: 80px;
    --_section-padding---section-margin--section-margin-100: 48px;
    --lk-gutter: 24px;
  }
}
.pricing-section { padding-bottom: var(--_section-padding---section-padding--section-padding-140); }
.blog-details-bottom-content { margin-top: var(--_section-padding---section-padding--section-padding-120); }

/* One gutter. Every page container starts at the same x. */
.container-large,
.container-medium,
.container-small {
  padding-left: var(--lk-gutter);
  padding-right: var(--lk-gutter);
}

/* Inset dark panels (hero, Expertise, Reviews, Recognition, footer) sit 12px
   (7 on phones) inside the page, so their text landed 12px right of every
   other section. One 8px inset, and the container inside it gives back the
   difference so the text still starts on the gutter. */
:root, body { --lk-inset: 8px; }
.hero-section,
.service-section,
.testimonial-section,
.awards-recognition-section,
.footer {
  padding-left: var(--lk-inset);
  padding-right: var(--lk-inset);
}
.hero-section { padding-top: var(--lk-inset); padding-bottom: var(--lk-inset); }
.footer { padding-bottom: var(--lk-inset); }
.hero-content,
.service-section .padding > .w-layout-blockcontainer,
.testimonial-section .padding > .w-layout-blockcontainer,
.awards-recognition-section .padding > .w-layout-blockcontainer,
.footer .footer-padding > .w-layout-blockcontainer {
  padding-left: calc(var(--lk-gutter) - var(--lk-inset));
  padding-right: calc(var(--lk-gutter) - var(--lk-inset));
}

/* Component spacing onto the 8pt grid (measured 6, 9, 10, 13, 18, 22). */
.button { padding: 12px 24px; }
.button-content { grid-column-gap: 8px; grid-row-gap: 8px; }
.service-tag { padding: 8px 12px; }
.title, .sub-title-wrap { grid-column-gap: 8px; grid-row-gap: 8px; }
.testimonial-card { padding: 8px; }
.author-name-title { grid-column-gap: 4px; grid-row-gap: 4px; }
.blog-post-date-block { margin-top: 8px; }
.tbx-row { padding-top: 16px; padding-bottom: 16px; }
.cs-chapter-head { padding-bottom: 16px; }

/* Leftovers from the spacing measurement. */
.main > .work-section:first-child { padding-top: var(--_section-padding---section-padding--section-padding-140); }
.footer { padding-top: var(--lk-inset); }
@media screen and (max-width: 767px) {
  .about-section { padding-top: var(--_section-padding---section-padding--section-padding-140); }
}
@media screen and (max-width: 991px) {
  /* the wrapper already carries a 30px row gap */
  .faq-section-content { margin-top: calc(var(--_section-padding---section-margin--section-margin-100) - 30px); }
}
/* Logos lost their tiles, so the tile height is only empty space now. */
.brands-item-block { height: auto; padding-top: 24px; padding-bottom: 24px; }

/* All caps only for short tags (two or three words). Phrases read in
   sentence case: uppercase mono sentences are slow to read and were the most
   agreed "slop" tell in the Hacker News thread on the 10 tells post. */
.work-hero-stat-label,
.cs-screens-note,
.cs-quote-source,
.cs-jump {
  text-transform: none;
  letter-spacing: 0.02em;
}
.work-hero-stat-label { display: block; }
.work-hero-stat-label::first-letter { text-transform: uppercase; }

/* ------------------------------------------------ his review, 28 Sept 2026 */

/* Corners: 12 and 24 only (pills and circles aside). His call over the brand
   digest's 10px controls. */
:root, body {
  --_border-radius---border-radius-8: 12px;
  --_border-radius---border-radius-10: 12px;
}

/* Hero: the name sat across his face. It now sits just above the bullets at a
   smaller size, so the top of the photo stays clear. */
.hero-content {
  justify-content: flex-end;
  gap: 32px;
}
.hero-title-wrap { max-width: 640px; }
.hero-title {
  font-size: 64px;
  line-height: 1.05;
}
@media screen and (max-width: 991px) {
  .hero-title { font-size: 48px; }
}
@media screen and (max-width: 767px) {
  .hero-content { gap: 24px; }
  .hero-title { font-size: 40px; }
}

/* Ways to work together: the buttons ran the full column width. Now they size
   to their label, sit on the left under the list, and line up across the three
   columns however long each list is. */
.pricing-card {
  display: flex;
  flex-direction: column;
}
.pricing-card-bottom {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
}
.pricing-card-button-wrapper {
  justify-content: flex-start;
  margin-top: auto;
  padding-top: 32px;
}
.button-link.pricing-button,
.button-link.button-black.pricing-button {
  width: auto;
  flex: 0 0 auto;
}
.button.pricing-button { width: auto; }

/* Reviews: less air around the rule between quote and name. */
.testimonial-card-divider {
  margin-top: 24px;
  margin-bottom: 24px;
}

/* Reviews wall loop (site.js adds the copies). Spacing is padding on each
   group rather than a flex gap, so one copy's width is exactly half the row
   and the loop lands on an identical frame. The template's own per-group
   slide is switched off. */
.testimonial-card-block-flex.lk-marquee {
  width: max-content;
  gap: 0;
  animation: lk-marquee 120s linear infinite;
}
.testimonial-card-block-flex.lk-marquee.is-reverse { animation-direction: reverse; }
.lk-marquee > .t-card-container {
  transform: none !important;
  padding-right: 12px;
}
.testimonial-card-wrapper:hover .lk-marquee { animation-play-state: paused; }
@keyframes lk-marquee {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  .testimonial-card-block-flex.lk-marquee { animation: none; }
}
/* Copyright line sits on the same baseline as the social links. */
.footer-quiet-line { margin-top: 0; }
/* The back-to-top button (48px, 24px from the edge) parks over the right end
   of this row once the page is scrolled to the bottom. Keep the row clear of
   it plus 16px; the term with 100vw gives the space back once the container
   stops at its maximum width and the row moves in from the edge. */
.footer-content-bottom {
  padding-right: max(0px, calc(88px - var(--lk-gutter) - max(0px, (100vw - 2012px) / 2)));
}
/* Door to the password-gated admin area (deploy/admin). Quiet on purpose, and
   on the left: the back-to-top button sits over the right end of this row. */
.footer-socail-link.footer-admin-link { color: #A8A8AB; transition: color var(--dur-fast) var(--ease-out); }
.footer-socail-link.footer-admin-link:hover, .footer-socail-link.footer-admin-link:focus-visible { color: #FAFAF7; }

/* ------------------------------------------------ his review 2, 28 Sept 2026 */

/* Ways to work together, redesigned. One flat panel per offer (no card inside
   a card), a clear title, the list under a hairline, and the button pinned to
   the bottom so all three line up. The button's dot was #222 on #161616,
   invisible, which read as extra padding on the right; it is Volt now, like
   every other black button on the site. */
.pricing-card {
  background-color: #EDEAE2;
  border-top: 0;
  border-radius: 24px;
  padding: 32px;
}
.pricing-card-top {
  padding: 0;
}
.pricing-title {
  font-size: 24px;
  line-height: 1.25;
  letter-spacing: -0.01em;
}
.pricing-top-descption-block { margin-top: 16px; }
.pricing-top-descption {
  color: #59595B;
  font-weight: 400;
}
.pricing-card-bottom {
  margin-top: 24px;
  padding-top: 24px;
  border-top: 1px solid rgba(22, 22, 23, 0.12);
}
.pricing-card-features-list-title {
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #77777A;
}
.pricing-card-features-list-wrapper {
  margin-top: 16px;
  grid-row-gap: 16px;
}
.pricing-card-button-wrapper { padding-top: 40px; }
.button-dot-on-black.button-black-7 { background-color: #E6DE2E; }
@media screen and (max-width: 767px) {
  .pricing-card { padding: 24px; }
}

/* Toolbox rows: more room between the description and the domain, a shorter
   measure for the description, and the hover arrow on the domain's line
   (it was centred on the whole row, so it dropped on two-line rows). The
   domain's centre sits 28px under the row top on every row. */
.tbx-row-main { column-gap: 48px; }
.tbx-line { max-width: 60ch; }
.tbx-arrow {
  top: 19px;
  margin-top: 0;
}
/* Services: descriptions use the panel's full width, and on desktop the three
   panels share rows (subgrid), so the hairline, the list and the buttons line
   up across all three whatever each description's length. */
.pricing-top-descption-block,
.pricing-top-descption { max-width: none; }
@media screen and (min-width: 992px) {
  .pricing-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    grid-template-rows: auto auto;
  }
  .pricing-card {
    display: grid;
    grid-row: span 2;
    grid-template-rows: subgrid;
    row-gap: 0;
  }
}

/* Services: no "Typical focus areas" label; the list starts under the rule. */
.pricing-card-features-list-title-block { display: none; }
.pricing-card-features-list-wrapper { margin-top: 0; }
/* The dot formula above assumed a 24px line; this list runs at 20px, so every
   dot sat 2px under the text. Centre it on the first line's lowercase. */
.pricing-card-features-list-dot { margin-top: 7px; }
.pricing-card-features-list, .service-descption { text-wrap: pretty; }

/* The home header (.navbar-wrapper) and the subpage header (.v2) had
   different top padding (36 vs 24 on desktop, 32 vs 28/30 on tablet), so the
   logo, menu and CTA jumped 12px when leaving the homepage. One value. */
.navbar-wrapper.v2 { padding-top: 36px; }
@media screen and (max-width: 991px) {
  .navbar-wrapper.v2 { padding-top: 32px; }
}
@media screen and (max-width: 767px) {
  .navbar-wrapper.v2 { padding-top: 26px; }
}

/* Hello ticker: one line of greetings slid out and snapped back after the
   last one. Two identical copies (the second is aria-hidden), each ending in
   the same spacing, moving by exactly one copy: the loop has no seam. */
.text-marquee .brands-content {
  display: flex;
  flex-wrap: nowrap;
  width: max-content;
  animation: lk-ticker 28s linear infinite;
  gap: 0;
}
.text-marquee .hero-sub-title { white-space: nowrap; flex: 0 0 auto; }
@keyframes lk-ticker {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  .text-marquee .brands-content { animation: none; }
}
/* Full-width photos (About, case-study heroes) use the same 8px inset as the
   homepage panels, not the template's 12. */
.about-top-bg-iamge-wrapper,
.work-details-hero-bg-image-wrapper {
  padding-left: var(--lk-inset);
  padding-right: var(--lk-inset);
}

/* Article meta row (By, Date, Category, Duration): four columns, label above
   value, with a hairline above and below. On one flex row the blocks squeezed
   and broke mid-label. Phones get two columns. */
.blog-details-info {
  display: grid;
  grid-template-columns: repeat(4, auto);
  justify-content: space-between;
  align-items: start;
  gap: 24px 32px;
  padding: 24px 0;
  border-top: 1px solid rgba(34, 34, 35, 0.12);
  border-bottom: 1px solid rgba(34, 34, 35, 0.12);
}
.blog-details-info-block {
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
}
.blog-details-info-title {
  font-size: 14px;
  line-height: 20px;
}
@media (max-width: 479px) {
  .blog-details-info {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    justify-content: stretch;
    gap: 16px 24px;
    padding: 16px 0;
  }
}

/* Article cover: the fixed 520px height cropped the sides of every cover.
   The image keeps its own ratio and shows edge to edge. The text below sat
   120px away, which read as a hole once the cover was no longer cropped. */
.blog-main-thumbnail-image {
  height: auto;
}
.blog-main-thumbnail-image-wrapper {
  margin-top: 48px;
}
.blog-details-bottom-content {
  margin-top: 56px;
}
@media (max-width: 479px) {
  .blog-main-thumbnail-image-wrapper {
    margin-top: 32px;
  }
  .blog-details-bottom-content {
    margin-top: 40px;
  }
}
