/* The mark flies and scales during the hero, which pushed its box past the
   right edge and gave the page a horizontal scrollbar. clip, not hidden:
   hidden would make this element a scroll container for its descendants and
   break the position: sticky the whole hero choreography depends on. clip
   does not, so sticky keeps working. */
html,
body {
  overflow-x: clip;
}

html,
body {
  width: 100%;
  max-width: 100%;
  padding: 0;
  margin: 0;
  font-family: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
  /* THE PAGE IS PRINTED ON, for one beat. Once the paper has gone the page
     runs the mark through the four inks it would be printed in, written here
     by NikaPort_pressRun as --page-wash. The fallback is the page's own grey,
     so with no JS, on mobile, and everywhere outside that one beat, this is
     the flat background it always was. */
  background: var(--page-wash, #f4f4f4);
  box-sizing: border-box;
}

.hero-title h1 {
  font-family: "Fredericka the Great", serif;
  font-weight: 400;
  font-style: normal;
  -webkit-font-smoothing: antialiased; /* fix weird outlines */
  -moz-osx-font-smoothing: grayscale;
  font-size: 3vw;
  margin: 0;
  color: #333;
}

/* WordPress Theme Reset - Add this FIRST */
.wp-site-block,
.wp-block-*,
.entry-content,
.site-content,
.content-area,
.page-content,
.post-content,
.container,
.row,
.col,
 {
  margin: 0 !important;
  padding: 0 !important;
  border: 0 !important;
  outline: 0 !important;
  font-size: 100% !important;
  vertical-align: baseline !important;
  background: transparent !important;
  box-sizing: border-box !important;
}

/* Reset common WordPress theme containers */
.site-content,
.content-area,
.page-header,
.entry-header,
.entry-footer,
.site-footer,
.site-header,
.navigation,
.main-navigation {
  all: unset !important;
  display: revert !important;
}

/* === CRITICAL: Remove WordPress container padding/margins === */
.fusion-fullwidth,
.fusion-builder-row,
.fusion-row,
.fusion-layout-column,
.fusion-column-wrapper,
.entry-content,
#main,
#content,
.site-content,
.content-area,
.page .post-content,
.wp-site-block {
  padding: 0 !important;
  margin: 0 !important;
  max-width: none !important;
  width: 100% !important;
}

/* === Remove container constraints === */
.fusion-builder-row,
.fusion-row {
  width: 100% !important;
  max-width: none !important;
  margin-left: 0 !important;
  margin-right: 0 !important;
}

/* === Remove column spacing === */
.fusion-layout-column {
  padding-left: 0 !important;
  padding-right: 0 !important;
  margin-left: 0 !important;
  margin-right: 0 !important;
}

/* === Ensure your main wrapper is full width === */
.nika-portfolio-wrapper {
  width: 100vw !important;
  max-width: none !important;
  margin: 0 !important;
  padding: 0 !important;
  overflow-x: hidden !important;
}
/* MODAL */

.at-modal-trigger {
  display: inline-flex;
  width: 50%;
  align-items: center;
  justify-content: center;
  padding: 14px 24px;
  border-radius: 2px;
  background: #333;
  color: #fff;
  font-weight: 500;
  cursor: pointer;
  transition: transform 0.2s ease, opacity 0.2s ease;
}

.at-modal-trigger:hover {
  transform: translateY(-1px);
  opacity: 0.9;
}

.at-modal {
  position: fixed;
  inset: 0;
  z-index: 9999;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

.at-modal.is-active {
  opacity: 1;
  pointer-events: auto;
}

.at-modal-overlay {
  position: absolute;
  inset: 0;
  background: rgba(0,0,0,0.6);
}

.at-modal-panel {
position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) scale(0.95);
  background: #fff;
  width: min(90vw, 600px);
  max-height: 90vh;
  overflow-y: auto;
  border-radius: 16px;
  padding: 32px;
  opacity: 0;
  transition: opacity 0.3s ease, transform 0.3s ease;
}

.at-modal.is-active .at-modal-panel {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}

.at-modal-close {
  position: absolute;
  top: 16px;
  right: 16px;
  background: none;
  border: 0;
  font-size: 24px;
  cursor: pointer;
}

/* FIXED LOGO & EMAIL */
.fixed-logo {
  position: fixed;
  top: 20px;
  left: 25px;
  z-index: 1000;
  display: block;
  max-width: 30px;
  height: auto;
}

.fixed-logo img {
  display: block;
  width: 30px;
  height: auto;
}

/* THEIR REST POSITION IS IN THE STYLESHEET, not only in the script.

   These two start on the sheet, not in the window's corners, and until
   NikaPort_openChrome has run the only thing painting them is CSS. With no
   transform here they appeared at the corners on the first frame and then
   jumped onto the sheet, which is the same failure the paper's clip had.

   The numbers are the ones openChrome computes at rest, written out: the
   sheet's own edge (NikaPort_PAPER_INSET 15%, NikaPort_PAPER_INSET_Y 7%), plus
   NikaPort_CHROME_PAD 26px clear of it, less the corner each one goes home to
   (logo 25/20, mail 20 and 80 tall off a 0 bottom). Change any of those and
   change these with them.

   Guarded above 990px because below it there is no sheet and the script
   clears the transform to match. */
@media (min-width: 991px) {
  .fixed-logo {
    transform: translate(calc(15vw + 1px), calc(7vh + 6px));
  }

  .fixed-email {
    transform: translate(calc(15vw + 6px), calc(-7vh - 26px));
  }
}

.fixed-email {
  position: fixed;
  bottom: 0px;
  left: 20px;
  z-index: 1001;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 50px;
  height: 80px;
  color: #777;
  text-decoration: none;
  transition: all 0.3s ease;
}

/* SECTIONS */

.section-layout {
  display: flex;
  width: 100%;
  box-sizing: border-box;
}

.section-headline {
  width: 70px;
  position: sticky;
  height: 100vh;
  top: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  box-sizing: border-box;
  margin-left: -12px;
}

.headline-clip {
  transform: rotate(-90deg) translateY(50%) translateX(-50%);
  transform-origin: top left;
  white-space: nowrap;
  position: absolute;
  top: 50%;
  left: 0;
  width: 100vh;
  text-align: center;
}

.headline-clip h2 {
  font-family: "Unna", Georgia, serif;
  font-size: 24px;
  font-weight: 400;
  color: #777;
  letter-spacing: 1.8px;
  margin: 0;
  display: inline-block;
  padding: 10px 20px;
}

.gradient-line {
  margin-left: 1px;
  display: inline-block;
  width: 15vh;
  height: 1px;
  background-color: #999;
  vertical-align: middle;
}

/* CONTENT */

/* HERO SECTION */

.hero-section {
  display: flex;
  flex-direction: row;
  width: 100%;
  height: auto;
}

.hero-content {
  width: 50vw;
  /* Was a hardcoded height: 250vh, which overshot the real content by ~400px
     and, more importantly, decided when .hero-holder unpinned: native sticky
     releases at (container bottom - holder height), so the mark started
     rising 500px before Latest Branding Work had finished. Height is now
     driven by the content itself, plus a short tail for the mark's flight.

     The tail used to be a full 100vh, because that is what native sticky
     needs to hold the mark on its own all the way to the end of Mediteria.
     It held, but it also meant a whole screen of scrolling before the next
     section could start. The flight in tangun-ca_code.JS now measures the
     sticky release and compensates for it, so the tail only has to be as
     long as the flight itself.

     Now that the pointer pushes the column UP rather than the mark exiting
     downward, the tail only has to cover the handoff. At 40vh the push shoved
     Mediteria off at the same moment it would have scrolled away anyway, and
     left most of a screen empty before Selected Works arrived. */
  height: auto;
  padding-bottom: 10vh;
  padding-left: 10vw;
  padding-right: 10vw;
  padding-top: 0vh;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  /* The ink the mark draws is an overlay on this column, so this is its
     containing block. */
  position: relative;
  z-index: 12;
  /* background: rgba(0, 173, 186, 0.5);  */
}

.hero-content .hero-title h1 {
  font-family: "Unna", Georgia, serif;
  font-size: clamp(2.6rem, 5.2vw, 5.6rem);
  font-weight: 700;
  line-height: 1.04;
  letter-spacing: -0.022em;
  text-wrap: balance;
  margin: 0;
}

.hero-content .hero-title p {
  font-family: Inter, serif;
  font-size: 16px;
  margin-top: 10px;
  padding-right: 0;
}

.website-design-note{
  position: relative;
  width: 40%;
  margin-top:-100vh;
  padding-bottom:150vh;
  color: #333;
  font-family: "Inter", Georgia, serif;
  font-size: 14px;
  font-weight: 400;


}

.StarIcon {
  font-size: 28px;
  margin-left: -10px;
  color: #4eb2ba;
  margin-bottom:-10px;
}

.LatestProjects {
  width: 100%;
  padding-top:25vh;
  padding-bottom:10vh;
}

.hero-holder {
  width: 50%;
  height: 100vh;
  /* NO perspective here, matching the original. It only ever had one inside
     the 990px mobile block. That means on desktop the entrance's
     translateZ(-120px) was visually inert, and its rotateX/rotateY rendered
     as flat squashes rather than foreshortening. Adding a perspective here
     changed the entrance, which is why it stopped matching the background. */
  position: sticky;
  padding-left:5vw;
  padding-right:5vw;
  top: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;

}

/* IMAGE WRAPPER — no sticky, no overflow issues */
.hero-sketch-image {
  /* THE PAPER IS A POSITIONED ELEMENT, THE SKETCH WAS NOT.
     .hero-background is position:absolute with z-index 0, so it paints above
     every static in-flow sibling no matter what the document order says. The
     sketch only ever cleared it by accident: the entrance writes a transform
     on the artwork every frame, and a transformed element honours z-index. In
     WebKit that did not lift it, so the paper covered the drawing. The
     wrapper, a plain div, now carries the stacking itself. */
  position: relative;
  z-index: 14;
   margin-top: 0px;
  margin-right: 5vw;
  width: 100%;
  height: auto;
  display: flex;
  align-items: center;
  justify-content: center;
  object-fit: contain;
}

.hero-sketch-image .sketch-art {
  z-index: 14;
  max-width: 100%;
  height: 65vh;
  width: 100%;
  display: block;
  transform: none; /* JS will override this */
}

.hero-sketch-image .sketch-art canvas {
  width: 100%;
  height: 100%;
  display: block;
  /* The sketch's closing skew swings from the top edge, so the top of the
     drawing stays where it is and only the foot moves. */
  transform-origin: 50% 0;
}

.hero-fill-img {
  margin-top: 0px;
  position: absolute;
  margin-right: 5vw;
  width: 100%;
  height: auto;
  z-index: 25;
  /* Pivot low so the sharp apex of the A is the leading edge when the mark
     tips over: rotating about a point near the base swings the tip through
     the longest arc, which is what sells it as the part doing the pushing. */
  transform-origin: 50% 78%;
  transform-style: preserve-3d;
  will-change: transform, opacity;
  mouse-events: none;
  display: flex;
  align-items: center;
  justify-content: center;
   object-fit: contain;
}

.hero-fill-img img {
  /* The original has no padding here. It was not changing the mark's drawn
     size (content-box, and max-width was never reached), but it is a
     deviation, so it goes. */
  opacity: 0;
  z-index: 14;
  max-width: 100%;
  height: 65vh;
  display: block;
 object-fit: contain;
}

/* The WebGL layer for the hero mark. Fills the holder the flat mark used to
   sit in. Only present once the scene has actually started, so the flat SVG
   below stays visible if it never does. */
.hero-3d-canvas {
  /* Full viewport, on the body, because the mark has to leave the hero's
     right-hand column and fly over to the Mediteria block on the left to
     push it. Fixed rather than sticky so it is not confined by any
     ancestor's containing block. Never interactive: it sits over the page,
     and the JS hides it once the hero's act is finished. */
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  z-index: 30;
  pointer-events: none;
}

/* Once the 3D mark is running, the flat one and its faked shadow stand down.
   The pencil sketch stays: it still crossfades on the way in. */
.hero-3d-on .hero-fill-img,
.hero-3d-on .hero-mark-shadow {
  display: none;
}

/* Ground shadow for the flying mark. Sits under it (z-index below the mark),
   flattened so it reads as lying on a surface rather than standing up, and
   tinted to pure black by brightness(0) so it works from the same artwork. */
.hero-mark-shadow {
  position: absolute;
  margin-right: 5vw;
  width: 100%;
  height: auto;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  opacity: 0;
  transform-origin: 50% 50%;
  will-change: transform, opacity, filter;
}

.hero-mark-shadow img {
  padding-right: 60px;
  padding-left: 60px;
  max-width: 100%;
  height: 65vh;
  display: block;
  object-fit: contain;
  filter: brightness(0);
}

.hero-background {
  position: absolute !important;
  width: 100vw !important;
  height: 100vh !important;
  margin-top: 0px !important;
    margin-left: -50vw;
  overflow: hidden !important;
  transform-origin: center center !important;
  z-index: 0 !important;
}

.hero-background img {
  position: absolute;
  /* Back to the original framing. The live values (120vh tall, -10vh top, and
     no left margin at all) cropped and re-centred the paper, which changes
     how its 3D turn reads. */
  width: 250vw !important;
  height: 160vh !important;
  margin-left: -50vw !important;
  margin-top: -25vh !important;
  pointer-events: none;
}

/* MOBILE */
/* (An older phone-only block for the hero stood here. Removed 2026-10-06:
   the phone now runs the same hero as the desktop, laid out for a tall
   screen by THE PHONE LAYOUT at the end of this file.) */


/* SECTION LAYOUTS */


/* GLOBAL SECTION LAYOUT */

@media (min-width: 990px) {
  .cards-container {
    max-width: 100%;
    width: 100%;
    justify-content: space-between;
    padding-right: 30px;
  }

  .hover-card {
    flex: 0 0 calc(33.333% - 115px);
    max-width: calc(33.333% - 115px);
  }

  .sectionIntro {
    flex: 0 0 100%;
    max-width: 100%;
    margin-right: 15vw;
  }

  /* (portfolio 3-across / single-column rules live in the two dedicated
     breakpoint blocks below, so cards are only laid out 3-across when three
     300px cards genuinely fit next to the 70px rail — never 2-then-1) */
}

/* ============================================================================
   PORTFOLIO CARD ROW — exactly two states, never 2-then-1:
     >= 1080px : three fixed 300px cards in one centered, capped row
     <  1080px : single centered column, one project per row (mobile-like)
   The intro stays on its own wrapped row in both states, so the container
   keeps flex-wrap:wrap; the two card widths (300px vs 100%) are what force
   the clean 3-or-1 outcome with no intermediate 2+1.
   ========================================================================== */
@media (min-width: 1080px) {
  #selected-works .cards-container,
  #case-studies .cards-container,
  #motion-branding .cards-container,
  #packaging-design .cards-container {
    max-width: 1000px;
    width: 100%;
    margin-left: auto;
    margin-right: auto;
    justify-content: center;
    align-items: flex-start;
    gap: 40px;
    padding-right: 0;
  }
  #selected-works .hover-card,
  #case-studies .hover-card,
  #motion-branding .hover-card,
  #packaging-design .hover-card {
    flex: 0 0 300px;
    max-width: 300px;
    width: 300px;
  }
  #selected-works .sectionIntro,
  #case-studies .sectionIntro,
  #motion-branding .sectionIntro,
  #packaging-design .sectionIntro {
    margin-right: 0;
  }
  /* title inset 10px from the left, website link 10px from the right */
  #case-studies .case-head {
    padding-left: 10px;
    padding-right: 10px;
  }
  /* cap each project image at (or below) the Case Studies laptop height */
  #motion-branding .project-media,
  #packaging-design .project-media {
    height: 180px;
  }
}

@media (max-width: 1079.98px) {
  #selected-works .cards-container,
  #case-studies .cards-container,
  #motion-branding .cards-container,
  #packaging-design .cards-container {
    max-width: 440px;
    width: 100%;
    margin-left: auto;
    margin-right: auto;
    justify-content: center;
    gap: 40px;
    padding-right: 0;
  }
  #selected-works .hover-card,
  #case-studies .hover-card,
  #motion-branding .hover-card,
  #packaging-design .hover-card {
    flex: 0 0 100%;
    max-width: 100%;
    width: 100%;
  }
  #selected-works .sectionIntro,
  #case-studies .sectionIntro,
  #motion-branding .sectionIntro,
  #packaging-design .sectionIntro {
    margin-right: 0;
  }
  /* Case Studies stacked: keep the whole card (image + copy) at its desktop
     300px width so the title, tags and button line up with the laptop image
     instead of spreading full-width. (Overrides the 100% rule above — same
     specificity, later in source.) */
  #case-studies .hover-card {
    max-width: 300px;
    margin-left: auto;
    margin-right: auto;
  }
  /* give the copy breathing room on both sides (image stays full-bleed) */
  #case-studies .case-head,
  #case-studies .project-tags {
    padding-left: 16px;
    padding-right: 16px;
  }
  #case-studies .at-button {
    margin-left: 16px;
  }

  /* Selected Works + Motion + Packaging: pad the whole card (image AND copy)
     so nothing touches the screen edges on mobile. border-box keeps the
     padding inside the 100% width instead of overflowing. */
  #selected-works .hover-card,
  #motion-branding .hover-card,
  #packaging-design .hover-card {
    box-sizing: border-box;
    padding-left: 16px;
    padding-right: 16px;
  }
}

/* RIGHT PANEL — scrollable cards */
.section-main-content-area {
  display: flex;
  flex-direction: column;
  justify-content: center;
  width: 100%;
  padding: 90px 0px 90px 10px;
  box-sizing: border-box;
  overflow-x: hidden;
}

.sectionIntro {
  display: flex;
  min-width: 90%;
  flex-direction: column;
  align-items: flex-end;
  padding: 20px 0px 20px 0px;
}

.sectionIntro h2 {
  color: #333;
  font-family: "Unna", Georgia, serif;
  font-size: 28px;
  font-weight: 400;
  color: #222;
  letter-spacing: 1.8px;
  margin: 0;
  display: inline-block;
}

.sectionIntro p {
  color: #333;
  font-family: "Inter", Georgia, serif;
  font-size: 14px;
  font-weight: 400;
  color: #333;
  padding-top: 8px; /* padding, not margin: #portfolio-root p resets margins */
  line-height: 1.5;
}

.cards-container {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 15px;
  width: 100%;
}

/* ✅ CARD: Flex column layout */
.hover-card {
  position: relative;
  background: transparent;
  flex: center;
  opacity: 0;
  overflow: visible;
  display: flex;
  flex-direction: column;
  min-height: 320px;
  transform: translateY(100px);
  transition: opacity 0.1s, transform 0.1s;
  padding-top: 20px;
  padding-bottom: 25px;
}

.selected-works .hover-card {
  background: #transparent;
  color: #fff;
}

.selected-works .hover-card .at-button {
  background: #ffffff;
  color: #333;
}

.dark-bg {
  background: #222;
  color: #fff;
}

/* MOTION BRANDING PRINTS TOO, and everything in it turns over with the ink.

   NikaPort_motionInk writes --motion-wash as a diagonal two-ink gradient from
   the section's cover progress, and with it the section's own overrides of
   --color-dark-text-primary/-secondary/-tertiary, plus --sec-line for rules
   and borders, --sec-veil for the media tint and --sec-contrast for a filled
   chip's label. Every rule below is written against one of those, so the run
   can use the full four inks including process yellow: when the field goes
   light the type goes dark with it.

   Every fallback is the colour the section already had, so mobile, a page
   with no JS, and the other dark section are all unchanged. */
#motion-branding.dark-bg {
  background: var(--motion-wash, #222);
  color: var(--color-dark-text-primary);
}

/* The titles and the rail go the WHOLE way, white to dark, the same crossing
   the fixed corner pieces make. They were on the tertiary ink, which
   interpolates between two mid greys (111 and 150), so they stayed grey on
   every plate and read as switched off on the bright ones. A title is not a
   piece of secondary information here: on a field this loud it is the only
   thing holding the section's name. */
#motion-branding .sectionIntro h2,
#motion-branding .headline-clip h2 {
  color: var(--color-dark-text-primary);
}

/* The rail's two lines are the title's own furniture, so they cross with it
   rather than staying a fixed grey. */
#motion-branding .gradient-line {
  background-color: var(--color-dark-text-primary);
  opacity: 0.55;
}

/* The subtitle goes with its title. It sits directly under it as the second
   line of the same statement, so leaving it on the secondary ink read as soft
   on the bright plates while the title above it was at full strength. */
#motion-branding .sectionIntro p {
  color: var(--color-dark-text-primary);
}

#motion-branding .hover-card .Section-H3-heading {
  color: var(--color-dark-text-primary);
}

#motion-branding .project-media {
  background: var(--sec-veil, rgba(244, 243, 241, 0.06));
}

#motion-branding .at-button {
  color: var(--color-dark-text-primary);
  border-color: var(--sec-line, rgba(244, 243, 241, 0.4));
}

/* The corner chip was a solid block of the section's old flat colour, which
   is a hole once the section is a gradient. It sits ON the field instead,
   ruled and lettered in the same ink as everything else, and fills on hover
   the way every other button here does. */
#motion-branding .section-cta {
  background: transparent;
  color: var(--color-dark-text-primary);
  border-color: var(--sec-line, rgba(244, 243, 241, 0.5));
}

#motion-branding .section-cta:hover {
  background: var(--color-dark-text-primary);
  color: var(--sec-contrast, #222);
  border-color: var(--color-dark-text-primary);
}
.dark-bg .sectionIntro h2 {
  color: #999;
  font-family: "Unna", Georgia, serif;
  font-size: 28px;
  font-weight: 400;
  color: #777;
  letter-spacing: 1.8px;
}
.dark-bg .sectionIntro p {
  color: #999;
}


.dark-bg .hover-card .Section-H3-heading {
  font-family: Unna;
  font-weight: 400;
  font-size: 24px;
  color: #f4f4f4;
}


/* ✅ BUTTON: */
.at-button {
  font-weight: 300;
  margin-top: 10px;
  font-family: Inter;
  font-size: 14px;
  height: 60px;
  padding-right: 30px;
  padding-left: 30px;
  margin-bottom: 20px;
  background: transparent;
  color: #333;
  text-decoration: none;
  border-radius: 2px;
  border-color: #333;
  border: 1px solid;
  transition: all 0.3s ease;
  display: flex;
  align-items: center;
  justify-content: center;
  /* The label and a trailing arrow are two flex children, so the whitespace
     between them in the markup is thrown away and they were touching. Only
     the two buttons that carry an arrow have a second child, so this changes
     nothing anywhere else. */
  gap: 9px;
  align-self: flex-start; /* Aligns to left (or use 'center') */
  z-index: 10;
}

/* THERE WAS NO HOVER AT ALL. The button has carried `transition: all 0.3s`
   since it was written, with nothing to transition to: every .at-button on the
   page was inert under the cursor, which is what Akin found on the two book
   links. It fills with the ink and the label reverses out, which is the same
   move .section-cta already makes, so the page has one button behaviour rather
   than two.

   The focus state is the same fill plus a ring, because a keyboard reader has
   to be able to see it and the fill alone is not an unambiguous focus. */
.at-button:hover,
.at-button:focus-visible {
  background: #333;
  color: #f4f4f4;
  border-color: #333;
}

.at-button:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 3px;
}

/* On a dark section it reverses the other way, or the fill is the background
   it is sitting on. */
.dark-bg .at-button:hover,
.dark-bg .at-button:focus-visible {
  background: var(--color-dark-text-primary);
  color: var(--sec-contrast, #222);
  border-color: var(--color-dark-text-primary);
}

.Proect-main-image {
  width: 100%;
  height: 240px; /* The visible window */
  overflow: hidden; /* This is the masking */
  position: relative;
  z-index: 1;
}

.Proect-main-image img {
  width: 90%;
  height: auto;
  display: block;
  transform: translateY(0);
  transition: transform 0.1s linear;
  /* make it taller so it can scroll inside */
  scale: 1;
  height: 520px; /* ← 3× the container height (example) */
  object-fit: cover;
  opacity: 0;
  animation: ImagefadeIn 1.6s ease forwards;
}


.hover-card .Section-H3-heading {
  display: block;
  width: 100%;
  padding-top: 10px;
  font-family: "Unna", Georgia, serif;
  font-size: 24px;
  font-weight: 400;
  line-height: 1.2;
  color: #222;
  transition: transform 0.3s ease;
}

.selected-works .hover-card .Section-H3-heading {
  font-family: Unna;
  font-weight: 400;
  font-size: 24px;
}

.hover-card .card-icon {
  position: absolute;
  top: -60px;
  right: 12px;
  width: 50px;
  border-radius: 50%;
  color: #333;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 24px;
  z-index: 5;
  transition: transform 0.3s ease;
}

.At-Contact-section {
  position: relative;
  width: 100%;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  padding: 0 20px;
  box-sizing: border-box;
  background: #f4f4f4; /* or your desired bg */
  font-family: "Inter", sans-serif;
}

/* Centered content (logo + name + location + email) */
.Contact-Center {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  text-align: center;
  max-width: 100%;
}

.contact-logo img {
  display: block;
  width: auto;
  height: 188px; /* adjust as needed */
}

.contact-name {
  font-family: "Unna", Georgia, serif;
  font-size: 24px;
  font-weight: 400;
  color: #222;
  margin: 40;
}

.contact-location {
  font-family: "Inter", sans-serif;
  font-size: 18px;
  font-weight: 400;
  color: #333;
  margin: 0;
}

.contact-email {
  font-family: "Inter", sans-serif;
  font-size: 18px;
  font-weight: 300;
  color: #333;
  text-decoration: none;
  transition: color 0.2s ease;
}

.contact-email:hover {
  color: var(--color-accent);
}



/* Copyright at the absolute bottom */
.contact-copyright {
  position: absolute;
  bottom: 20px;
  left: 0;
  right: 0;
  font-family: "Inter", sans-serif;
  font-size: 12px;
  font-weight: 300;
  color: #777;
  text-align: center;
  margin: 0;
}

/* Fade-in animation */
@keyframes ImagefadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

/* Fade-in animation */
@keyframes Scroll-Cards-SlideIn {
  from {
    opacity: 0;
    transform: translateX(90px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

/* Class applied by JS when in view */
.hover-card.scroll-animate {
  animation: Scroll-Cards-SlideIn 0.6s ease forwards;
  animation-delay: 0.4s;
}

/* ============================================================================
   BROUGHT-BACK CONTENT STYLING
   Layered additively on the base above. New class names only (nothing here
   redefines a base selector), plus design tokens and a few scoped overrides
   for the dark sections. Base values are respected; improved text contrast
   is applied via the tokens below (secondary/tertiary darkened for
   readability on light, lightened on dark).
   ========================================================================== */

:root {
  --font-display: "Fredericka the Great", cursive;
  --font-serif: "Unna", Georgia, serif;
  --font-sans: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;

  --color-bg: #f4f4f4;
  --color-bg-raised: #e8e7e4;
  /* your defined palette (#222 / #333 / #777), with the muted greys kept dark
     enough to stay readable on the light bg */
  --color-text-primary: #222;
  --color-text-secondary: #3d3d3d;
  --color-text-tertiary: #6f6f6f;
  --color-border: rgba(34, 34, 34, 0.15);

  --color-accent: #4eb2ba;

  --color-dark: #222;
  --color-dark-text-primary: #f4f4f4;
  --color-dark-text-secondary: #c9c9c9; /* your #999 nudged lighter for readability on the dark bg */
  --color-dark-text-tertiary: #969696;

  --edge: clamp(20px, 5vw, 80px);
  --max-content: 1180px;
  --dur-fast: 0.3s;
  --dur-mid: 0.6s;
  --ease-quart-out: cubic-bezier(0.25, 1, 0.5, 1);
  --ease-expo-out: cubic-bezier(0.16, 1, 0.3, 1);
}

/* shared text helpers used by the brought-back blocks */
.serif-h2 {
  font-family: var(--font-serif);
  font-weight: 400;
  font-size: clamp(1.5rem, 1vw + 1.1rem, 1.9rem);
  letter-spacing: 0.4px;
  color: var(--color-text-secondary);
}
.lede {
  font-family: var(--font-sans);
  font-weight: 300;
  font-size: 15px;
  line-height: 1.7;
  color: var(--color-text-secondary);
  max-width: 46ch;
}
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: 13px;
  letter-spacing: 0.02em;
  color: var(--color-text-secondary);
}
.eyebrow .spark { color: var(--color-accent); font-size: 18px; line-height: 1; }
/* brought-back reveal targets are shown by default (the base's reveal system
   is .scroll-animate on .hover-card; these .reveal blocks are not hidden) */
.reveal { opacity: 1; }

/* Margin reset for the brought-back content only. The base intentionally has
   no global `p { margin: 0 }`, so paragraphs/headings were inheriting the
   browser's default 1em margins — that was the "massive spaces between lines."
   Scoped so the hero (which you tuned with those defaults) is untouched. */
#portfolio-root p,
#portfolio-root h2,
#portfolio-root h3,
#portfolio-root blockquote,
.LatestProjects p,
.LatestProjects h2,
.pinned-photo-content p,
.pinned-photo-content h2,
.pinned-photo-content h3,
.pinned-photo-content blockquote,
.pinned-photo-content cite {
  margin: 0;
}

/* border-box for the brought-back content only. The base has no global
   box-sizing reset, so these blocks (width:100% + padding, content-box) were
   spilling their padding past the viewport — THAT was the horizontal
   side-scroll (About .section-main = 1584px, .cards-container = +30px), not
   the hero. Scoped here so the hero animation is left completely alone. */
#portfolio-root, #portfolio-root *,
.pinned-photo-block, .pinned-photo-block * { box-sizing: border-box; }

/* ---- Latest Branding Work (Mediteria) inside .LatestProjects -------------- */
.LatestProjects .serif-h2 { margin-bottom: 4px; }
.LatestProjects .lede { margin-top: 18px; font-size: 14px; }
.LatestProjects .at-button { margin-top: 24px; }

.project-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 16px 26px;
  margin-top: 16px;
}
.project-meta > div { display: flex; flex-direction: column; gap: 4px; }
.project-meta-label {
  font-size: 11px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--color-text-tertiary);
}
.project-meta-value {
  font-family: var(--font-serif);
  font-size: 16px;
  color: var(--color-text-primary);
}
.mosaic-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
  width: 100%;
  margin-top: 24px;
}
.mosaic-grid img { width: 100%; object-fit: cover; border-radius: 4px; display: block; }
.mosaic-grid img:first-child { grid-column: 1 / 3; height: 180px; }
.mosaic-grid img:not(:first-child) { height: 110px; }

/* ---- Portfolio card internals (inside the base's .hover-card) ------------- */
/* THE PICTURE GOES WHERE THE BUTTON GOES.

   Each card's only link used to be the words under it, and a reader who clicks
   the work itself expects to arrive at the work. This wraps the thumbnail in
   the card's own href.

   It is a bare block: no padding, no border, no line box of its own, so the
   media keeps the exact geometry it had. It is kept out of the tab order
   because the button below it is the same destination announced in words, but
   it is NOT aria-hidden, so each image keeps its alt text. */
.media-link {
  display: block;
  color: inherit;
  text-decoration: none;
}

.project-media {
  position: relative;
  width: 100%;
  height: 190px;
  overflow: hidden;
  border-radius: 6px;
  background: var(--color-bg-raised);
}
.project-media img {
  width: 100%;
  min-height: 230px;
  object-fit: cover;
}
.pack-card .project-media { height: 240px; }
.dark-bg .project-media { background: rgba(244, 243, 241, 0.06); }

/* Motion Branding + Packaging thumbnails: fill the block and center the
   image content vertically (was top-aligned because the tall min-height on
   the base .project-media img let the bottom get clipped). */
#motion-branding .project-media img,
#packaging-design .project-media img {
  height: 100%;
  min-height: 0;
  object-fit: cover;
  object-position: center;
}

/* logo variant (Selected Works) — whole logo on transparent, not cropped.
   Fixed equal height across all three cards so titles line up. */
.project-media--logo {
  background: transparent;
  height: 260px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.project-media--logo img {
  width: 60%;
  min-height: 0;
  height: auto;
  max-height: 72%;
  margin: 0;
  object-fit: contain;
}

/* Sütaş "scroll info" callouts — two stats flanking the top of the logo.
   Same 260px media height as the plain logo cards: callouts pinned to the
   top, logo filling the remaining space below them. */
.project-media--stats {
  height: 260px;
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-start;
  overflow: visible;
}
.project-media--stats .stat-callouts { flex: 0 0 auto; }
.project-media--stats img {
  flex: 1 1 auto;
  align-self: center;
  width: 66%;
  min-height: 0;
  height: auto;
  max-height: 100%;
  margin: 4px auto 0;
  object-fit: contain;
}
.stat-callouts {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 14px;
  padding: 6px 4px 0;
}
.stat-callout {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-width: 46%;
  font-family: var(--font-sans);
  font-size: 15px;
  font-weight: 300;
  line-height: 1.35;
  color: var(--color-text-secondary);
}
.stat-callout--left { align-items: flex-start; text-align: left; }
.stat-callout--right { align-items: flex-end; text-align: right; }
.stat-num { color: var(--color-accent); font-weight: 600; }
.stat-callout strong { color: var(--color-text-primary); font-weight: 600; }

/* Callout highlights (Akin, 2026-09-16, second pass). The callout copy sits
   on a white highlight in black; the figure inside it ("6 Million") on the
   accent colour in bold white. A highlight per LINE, not a box, at the
   original line spacing, and never more than two lines.
   - The highlight is on an inner inline span: the callout is a flex column,
     which makes its direct child a block, and a block background is one
     solid box.
   - The side extension is box-shadow, not padding, so it takes up no space
     and the copy wraps exactly as it did without a highlight. */
.stat-callout-text .stat-hl {
  background: #fff;
  color: #000;
  box-shadow: 0.22em 0 0 #fff, -0.22em 0 0 #fff;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
.stat-callout-text strong { color: #000; }

/* Two lines, never three, breaking where they always did. Each line is set
   explicitly with a <br> and kept whole. The two longest second lines
   ("12,500+ BIM stores", "100M+ packs a year") are about 15px wider than the
   callout column; the column's own alignment lets them run into the gap
   between the pair (left one rightward, right one leftward) instead of
   wrapping to a third line. */
.stat-callout-text .stat-hl { white-space: nowrap; }
/* Pasta Veneta's two second lines are ~145px each, wider together than the
   292px row inside the image, so that one row (and only that one, so the
   gaps between neighbouring cards stay as they were) reaches 12px past each
   side of the image. With the breaks fixed above, extra width cannot change
   where any line breaks. */
.project-highlight.stat-callouts.stat-callouts--wide {
  margin-left: -12px;
  margin-right: -12px;
  padding-left: 0;
  padding-right: 0;
}
.stat-callout-text .stat-num {
  background: var(--color-accent);
  color: #fff;
  font-weight: 700;
  box-shadow: 0.16em 0 0 var(--color-accent), -0.16em 0 0 var(--color-accent);
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

/* The Selected Works title is long for the vertical rail: at the site's
   24px it ran into the AT mark on a 700px-tall screen. It scales with the
   screen's height there instead, and the rules either side get shorter. */
#selected-works .headline-clip h2 {
  font-size: clamp(16px, 2.6vh, 24px);
  letter-spacing: 1.2px;
}
#selected-works .headline-clip .gradient-line { width: 8vh; }

/* The heart before the Selected Works title. */
.title-heart {
  display: inline-block;
  width: 0.78em;
  height: 0.78em;
  margin-right: 0.38em;
  vertical-align: -0.04em;
  fill: #d8283c;
}
.stat-arrow { align-self: center; font-size: 24px; line-height: 1; color: var(--color-text-tertiary); }

/* laptop-framed variant (Case Studies) — bezel + cropped screen window */
.project-media--framed {
  height: auto;
  aspect-ratio: 958 / 578;
  overflow: visible;
  background: none;
}
.project-media--framed .laptop-frame {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 100%;
  height: 100%;
  background: url("images/MachBookWebMockup.png") center / contain no-repeat;
  pointer-events: none;
  z-index: 2;
}
.project-media--framed .screen-window {
  position: absolute;
  top: 1.6%;
  left: 50%;
  transform: translateX(-50%);
  width: 83.3%;
  height: 96.5%;
  overflow: hidden;
  border-radius: 2px;
  z-index: 1;
}
.project-media--framed .screen-window img {
  width: 100%;
  min-height: 0;
  height: auto;
  display: block;
}

/* project-highlight badges (visible by default in this base — the staggered
   scroll-reveal is a later step) */
.project-highlight {
  position: absolute;
  top: 12px;
  left: 12px;
  z-index: 3;
  max-width: calc(100% - 24px);
  padding: 8px 12px;
  background: rgba(244, 243, 241, 0.94);
  color: var(--color-text-primary);
  font-family: var(--font-sans);
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1.4;
  border-radius: 4px;
}
.project-highlight--award {
  top: 16px;
  left: -6px;
  max-width: none;
  padding: 9px 18px 9px 16px;
  background: #bd8b1e;
  color: #fdfdfc;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border-radius: 0;
}
.project-highlight--award .award-trophy { font-size: 13px; }
/* the stat-callouts reuse .project-highlight but drop the boxed look */
.project-highlight.stat-callouts {
  position: static;
  max-width: none;
  background: none;
  border-radius: 0;
  color: inherit;
  font-weight: 400;
}

/* ============================================================================
   SELECTED WORKS — pinned "presentation" scroll reveal (desktop only)
   The section pins in place while a scroll-driven sequence reveals each
   project's two stat callouts (left slides in from the left, right from the
   right) followed by its button, one project at a time. Once all 9 steps are
   in, the pin releases and the page scrolls on to Case Studies naturally.
   Driven by JS toggling `.is-visible` at scroll-progress thresholds.
   ========================================================================== */
@media (min-width: 1080px) {
  /* tall track gives the sticky content room to hold its pin */
  #selected-works {
    min-height: 300vh;
    align-items: flex-start;
  }
  #selected-works .section-main-content-area {
    position: sticky;
    top: 0;
    height: 100vh;
    justify-content: center;
    padding-top: 0;
    padding-bottom: 0;
  }

  /* callouts + buttons start hidden; each eases in when its step fires */
  #selected-works .stat-callout,
  #selected-works .hover-card .at-button {
    opacity: 0;
    transition: opacity 0.6s var(--ease-quart-out),
                transform 0.6s var(--ease-quart-out);
    will-change: opacity, transform;
  }
  #selected-works .stat-callout--left  { transform: translateX(-20px); }
  #selected-works .stat-callout--right { transform: translateX(20px); }

  #selected-works .stat-callout.is-visible {
    opacity: 1;
    transform: translateX(0);
  }
  /* button reveal is opacity-only (CSS-triggered, no motion) */
  #selected-works .hover-card .at-button.is-visible {
    opacity: 1;
  }
}

/* ============================================================================
   CASE STUDIES — pinned "presentation" scroll reveal (desktop only)
   The section pins while scrolling: each laptop screenshot scrolls upward
   inside its screen mask (already at full opacity), and each project's
   website link eases in from the right. Pin releases once the sequence is
   through. Driven by JS. Mirrors the Selected Works mechanism.
   ========================================================================== */
@media (min-width: 1080px) {
  #case-studies {
    min-height: 300vh;
    align-items: flex-start;
  }
  #case-studies .section-main-content-area {
    position: sticky;
    top: 0;
    height: 100vh;
    justify-content: center;
    padding-top: 0;
    padding-bottom: 0;
  }

  /* website link starts hidden, slides in from the right */
  #case-studies .case-domain {
    opacity: 0;
    transform: translateX(20px);
    transition: opacity 0.6s var(--ease-quart-out),
                transform 0.6s var(--ease-quart-out);
    will-change: opacity, transform;
  }
  #case-studies .case-domain.is-visible {
    opacity: 1;
    transform: translateX(0);
  }

  /* button reveal — opacity-only, same as Selected Works; fires together
     with the website link once the project's screenshot has scrolled */
  #case-studies .hover-card .at-button {
    opacity: 0;
    transition: opacity 0.6s var(--ease-quart-out);
    will-change: opacity;
  }
  #case-studies .hover-card .at-button.is-visible {
    opacity: 1;
  }

  /* laptop screenshot scrolls up inside its mask (JS sets translateY) */
  #case-studies .project-media--framed .screen-window img {
    will-change: transform;
  }
}

/* ============================================================================
   MOTION BRANDING + PACKAGING — pinned reveal (desktop only)
   Both pin like the sections above. Packaging reveals its Award-Winning
   badges one-by-one (fade + slide from the left); every card's button then
   fades in alongside. Motion Branding stagger-reveals its buttons.
   ========================================================================== */
@media (min-width: 1080px) {
  #motion-branding,
  #packaging-design {
    min-height: 300vh;
    align-items: flex-start;
  }
  #motion-branding .section-main-content-area,
  #packaging-design .section-main-content-area {
    position: sticky;
    top: 0;
    height: 100vh;
    justify-content: center;
    padding-top: 0;
    padding-bottom: 0;
  }

  /* Award badge starts hidden, slides in from the left (it sits top-left) */
  #packaging-design .project-highlight--award {
    opacity: 0;
    transform: translateX(-20px);
    transition: opacity 0.6s var(--ease-quart-out),
                transform 0.6s var(--ease-quart-out);
    will-change: opacity, transform;
  }
  #packaging-design .project-highlight--award.is-visible {
    opacity: 1;
    transform: translateX(0);
  }

  /* buttons fade in (opacity-only), staggered per project */
  #motion-branding .hover-card .at-button,
  #packaging-design .hover-card .at-button {
    opacity: 0;
    transition: opacity 0.6s var(--ease-quart-out);
    will-change: opacity;
  }
  #motion-branding .hover-card .at-button.is-visible,
  #packaging-design .hover-card .at-button.is-visible {
    opacity: 1;
  }
}

/* Case-study header: eyebrow + bold sans title left, live-domain link right */
.case-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; margin-bottom: 14px; }
.case-eyebrow { font-family: var(--font-sans); font-size: 15px; font-weight: 300; color: var(--color-text-secondary); }
.case-title {
  padding-top: 0 !important;
  margin-top: 2px;
  font-family: "Unna", Georgia, serif !important;
  font-size: 24px !important;
  font-weight: 400 !important;
  line-height: 1.1;
  letter-spacing: 0.4px;
  color: #222 !important;
}
.case-domain {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-top: 4px;
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--color-text-primary);
  border-bottom: 1px solid transparent;
  transition: border-color var(--dur-fast) var(--ease-quart-out), color var(--dur-fast) var(--ease-quart-out);
}
.case-domain span { font-size: 15px; }
.case-domain:hover, .case-domain:focus-visible { color: var(--color-accent); border-color: var(--color-accent); }

/* key:value meta lines under a card, pipe-separated.

   These are CREDITS, not prose: a set of short rows that belong to each other
   and should read as one block under the title. At prose leading with a gap on
   top of it, three credit lines took as much room as the picture's caption and
   the card came apart into separate lines. Tight leading, and the rows sit
   directly on each other. */
.project-tags { padding-top: 8px; display: flex; flex-direction: column; gap: 1px; }
/* 10px of breathing room above each card CTA */
.hover-card .at-button { margin-top: 10px; }
/* Hanging indent, so a credit long enough to wrap reads as one row continued
   rather than as a new row starting. With the rows sitting this close, an
   unindented second line was indistinguishable from the next credit. */
.project-tags p { font-family: var(--font-sans); font-size: 13.5px; font-weight: 300; line-height: 1.32; color: var(--color-text-secondary); padding-left: 0.85em; text-indent: -0.85em; }
/* A line may break at a separator. It may not break somebody's name in half. */
.tag-name { white-space: nowrap; }
.project-tags strong { color: var(--color-text-primary); font-weight: 600; }
.tag-sep { color: var(--color-text-tertiary); font-weight: 300; margin: 0 4px; }
.dark-bg .project-tags p { color: var(--color-dark-text-secondary); }
.dark-bg .project-tags strong { color: var(--color-dark-text-primary); }
.dark-bg .tag-sep { color: var(--color-dark-text-tertiary); }

/* packaging/motion serif discipline subtitle under the serif title */
.pack-subtitle { padding-top: 4px; font-family: var(--font-serif); font-size: 17px; font-weight: 400; line-height: 1.18; color: var(--color-text-secondary); }
.dark-bg .pack-subtitle { color: var(--color-dark-text-secondary); }

.project-detail { padding-top: 10px; line-height: 1.55; font-family: var(--font-sans); font-size: 14px; font-weight: 300; color: var(--color-text-secondary); }
.dark-bg .project-detail { color: var(--color-dark-text-secondary); }

/* card CTA treatment brought back (uppercase + chevron), on top of base .at-button */
.hover-card .at-button { text-transform: uppercase; letter-spacing: 0.06em; font-size: 12px; }
.hover-card .at-button::after {
  content: "\2192";
  margin-left: 8px;
  display: inline-block;
  transition: transform var(--dur-fast) var(--ease-quart-out);
}
.hover-card .at-button:hover::after { transform: translateX(4px); }
/* dark-section buttons must be light (base .at-button uses literal #333) */
.dark-bg .at-button { color: var(--color-dark-text-primary); border-color: rgba(244, 243, 241, 0.4); }

/* ---- About: sticky pinned-photo block ------------------------------------ */
.pinned-photo-block { position: relative; display: grid; }
.pinned-photo-block > * { grid-column: 1; grid-row: 1; }
.pinned-photo-visual { position: sticky; top: 0; height: 100vh; overflow: hidden; z-index: 1; }
.pinned-photo-visual img { width: 100%; height: 100%; object-fit: cover; object-position: center 22%; }
.pinned-photo-visual::after {
  content: "";
  position: absolute;
  inset: 0;
  /* The last stop is FULLY opaque, so the bottom of this block is exactly
     #1a1a17 and nothing of the photograph reaches the seam. That is the same
     colour the footer's press run starts on, which is what makes the join
     between the two invisible: at 0.94 the near-black photograph still showed
     through and left a step of a few values right where the sections meet. */
  /* Fifteen points lighter down to the foot than it was (0.4 / 0.78 / 0.94),
     on Akin's instruction: the portrait was too far gone under it. The last
     stop is not his to lighten, for the reason above. */
  background: linear-gradient(180deg, rgba(26,26,23,0.25) 0%, rgba(26,26,23,0.63) 60%, rgba(26,26,23,0.88) 88%, rgb(26,26,23) 100%);
}
/* The picture is the left 85% of the original, which puts the face at 60% of
   its width instead of the middle. On a wide window that is the point: the
   portrait sits right of the copy. On a narrow one the picture is cropped to
   a tall slice from its middle and would cut the face in half, so the slice
   is taken from where the face is. */
@media (max-width: 990px) {
  .pinned-photo-visual img { object-position: 63% 22%; }
}
.pinned-photo-content {
  position: relative;
  z-index: 2;
  --color-text-primary: var(--color-dark-text-primary);
  --color-text-secondary: var(--color-dark-text-secondary);
  --color-text-tertiary: var(--color-dark-text-tertiary);
  --color-border: rgba(244, 243, 241, 0.16);
  --color-accent: #6bc4cb;
  color: var(--color-dark-text-primary);
  padding-top: 14vh;
  padding-bottom: 14vh;
}
/* buttons inside the dark about block must be light (base uses literal #333) */
.pinned-photo-content .at-button { color: var(--color-dark-text-primary); border-color: rgba(244, 243, 241, 0.4); }
.at-button--ghost-dark { color: var(--color-dark-text-primary); border-color: rgba(244, 243, 241, 0.4); }

.pinned-photo-content .section-main { width: 100%; padding: 0 var(--edge); display: flex; flex-direction: column; align-items: center; }
.pinned-photo-content .section-intro { width: 100%; max-width: var(--max-content); display: flex; flex-direction: column; }

.quote-block { max-width: var(--max-content); margin: clamp(50px, 10vh, 120px) auto; padding: 0 var(--edge); }
.quote-block blockquote {
  margin: 0;
  font-family: var(--font-serif);
  font-style: italic;
  font-size: clamp(1.7rem, 2.2vw + 1rem, 3rem);
  line-height: 1.3;
  color: var(--color-text-primary);
  max-width: 22ch;
}
.quote-block cite { display: block; margin-top: 18px; font-style: normal; font-family: var(--font-sans); font-size: 13px; color: var(--color-text-tertiary); }

.stats-row {
  max-width: var(--max-content);
  margin: 0 auto;
  padding: 40px var(--edge);
  display: flex;
  flex-wrap: wrap;
  gap: clamp(30px, 5vw, 70px);
  border-top: 1px solid var(--color-border);
  border-bottom: 1px solid var(--color-border);
}
.stat { flex: 1 1 160px; }
.stat .stat-number { font-family: var(--font-serif); font-size: clamp(2.2rem, 2vw + 1.4rem, 3.4rem); color: var(--color-text-primary); }
.stat .stat-label { margin-top: 6px; font-size: 13px; color: var(--color-text-tertiary); }

.timeline { max-width: var(--max-content); margin: clamp(50px, 9vh, 110px) auto; padding: 0 var(--edge); display: flex; flex-direction: column; gap: 40px; }
.timeline-item { display: grid; grid-template-columns: 120px 1fr; gap: clamp(20px, 4vw, 60px); padding-bottom: 40px; border-bottom: 1px solid var(--color-border); }
.timeline-item:last-child { border-bottom: none; }
.timeline-year { font-family: var(--font-serif); font-size: 20px; color: var(--color-accent); }
.timeline-role { font-family: var(--font-serif); font-size: 20px; margin-bottom: 8px; color: var(--color-text-primary); }
.timeline-body { font-size: 15px; color: var(--color-text-secondary); max-width: 62ch; }

.awards-list { max-width: var(--max-content); margin: clamp(50px, 9vh, 110px) auto; padding: 0 var(--edge); }
.awards-list table { width: 100%; border-collapse: collapse; }
.awards-list th, .awards-list td { text-align: left; padding: 14px 10px; border-bottom: 1px solid var(--color-border); font-size: 14px; font-weight: 300; color: var(--color-text-secondary); }
.awards-list th { font-family: var(--font-sans); font-size: 12px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--color-text-tertiary); font-weight: 400; }
.awards-list td:nth-child(2), .awards-list th:nth-child(2) { font-family: var(--font-serif); font-size: 16px; color: var(--color-text-primary); }
.awards-list th:first-child, .awards-list td:first-child { width: 44px; padding-right: 0; }
.award-icon { width: 30px; height: 30px; object-fit: contain; display: block; }
.awards-note { margin-top: 20px; font-size: 13px; color: var(--color-text-tertiary); max-width: 70ch; }

/* read-more collapse (awards first, then timeline) */
.about-more-toggle-wrap { max-width: var(--max-content); margin: clamp(30px, 6vh, 70px) auto 0; padding: 0 var(--edge); text-align: center; }
.about-more-toggle .about-more-toggle-label::after {
  content: " \25BE";
  display: inline-block;
  transition: transform var(--dur-fast) var(--ease-quart-out);
}
.about-more-toggle[aria-expanded="true"] .about-more-toggle-label::after { transform: rotate(180deg); }
.about-more[hidden] { display: none; }

/* ---- Affiliations: current role (ADWORKS) + advisory booking (Miller) -----
   Two linked panels inside the dark About block. Deliberately restrained to
   match the block's editorial tone: thin border, faint translucent fill, the
   block's own accent (#6bc4cb) for the role label + link, monochrome light
   logos so both brands read cleanly on the dark ground. */
.affiliations {
  max-width: var(--max-content);
  margin: clamp(50px, 10vh, 120px) auto;
  padding: 0 var(--edge);
}
.affiliations .eyebrow { margin-bottom: 26px; }
.affiliation-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: clamp(16px, 2.4vw, 30px);
}
.affiliation-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: clamp(26px, 3vw, 42px);
  color: var(--color-text-primary);
  text-decoration: none;
  background: rgba(244, 243, 241, 0.05);
  border: 1px solid var(--color-border);
  border-radius: 10px;
  transition: border-color var(--dur-fast) var(--ease-quart-out),
              background var(--dur-fast) var(--ease-quart-out),
              transform var(--dur-fast) var(--ease-quart-out);
}
.affiliation-card:hover,
.affiliation-card:focus-visible {
  border-color: var(--color-accent);
  background: rgba(244, 243, 241, 0.08);
  transform: translateY(-3px);
}
.affiliation-logo {
  display: flex;
  align-items: center;
  height: 46px;
  margin-bottom: 24px;
}
.affiliation-logo img { width: auto; }
/* optically balanced, not equal-height: ADWORKS is a wide, short wordmark
   (~4.5:1); Miller is a compact stacked icon+wordmark lockup (~1.7:1) */
.affiliation-logo--adworks img { height: 22px; }
.affiliation-logo--miller img { height: 46px; }
.affiliation-role {
  font-family: var(--font-sans);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-accent);
  margin-bottom: 12px;
}
.affiliation-body {
  font-family: var(--font-sans);
  font-size: 15px;
  font-weight: 300;
  line-height: 1.6;
  color: var(--color-text-secondary);
  max-width: 46ch;
}
.affiliation-link {
  margin-top: 24px;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 0.02em;
  color: var(--color-text-primary);
  border-bottom: 1px solid var(--color-border);
  padding-bottom: 3px;
  transition: color var(--dur-fast) var(--ease-quart-out),
              border-color var(--dur-fast) var(--ease-quart-out);
}
.affiliation-arrow { transition: transform var(--dur-fast) var(--ease-quart-out); }
.affiliation-card:hover .affiliation-link,
.affiliation-card:focus-visible .affiliation-link {
  color: var(--color-accent);
  border-color: var(--color-accent);
}
.affiliation-card:hover .affiliation-arrow,
.affiliation-card:focus-visible .affiliation-arrow {
  transform: translate(2px, -2px);
}
@media (max-width: 768px) {
  .affiliation-grid { grid-template-columns: 1fr; }
}

/* ============================================================================
   THE POINTER'S STAGE
   The 3D mark becomes a pointer after the hero and presents the rest of the
   page (tangun-ca_hero3d.js). These are the parts of the DOM it acts on.
   Every one of them also works with no pointer at all: without WebGL, on a
   stacked layout, or under reduced motion, the scroll handlers in
   tangun-ca_code.JS drive the same states with a CSS transition instead.
   ============================================================================ */

/* Selected Works: the logo is the FRONT of a two-layer stage, with the real
   packaging behind it. --swap is 0 for the logo, 1 for the packaging. The
   pointer writes that number every frame while it drags the logo aside; with
   no pointer, .is-swapped sets it to 1 and the transition below does the
   slide. */
.project-media--swap .swap-stage {
  position: relative;
  flex: 1 1 auto;
  align-self: stretch;
  min-height: 0;
  margin-top: 4px;
  overflow: hidden;
  border-radius: 6px;
}
.project-media--swap .swap-layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  min-height: 0;
  max-height: none;
  margin: 0;
  transition: transform 0.85s var(--ease-quart-out);
}
.project-media--swap .swap-front {
  z-index: 2;
  box-sizing: border-box;
  padding: 4% 17%;
  object-fit: contain;
  transform: translateX(calc(var(--swap, 0) * -122%));
}
.project-media--swap .swap-back {
  z-index: 1;
  object-fit: cover;
  transform: translateX(calc((1 - var(--swap, 0)) * 112%));
}
.project-media--swap.is-swapped { --swap: 1; }

/* The pointer scrubs --swap frame by frame, so a transition would fight it. */
.hero-3d-on .project-media--swap .swap-layer { transition: none; }

/* The flat footer logo holds the place at 10% while the pointer is out
   presenting, so the footer never reads as empty and you can see where the
   mark is going to land. It stays at 10% underneath once the mark arrives:
   the mark covers it exactly, being the same artwork at the same size.
   Gated on the class the pointer sets while it is actually drawing, so a page
   with no working pointer keeps its logo at full strength. */
.pointer-live .contact-logo img {
  opacity: 0.1;
  transition: opacity 0.6s var(--ease-quart-out);
}

/* ---- THE MARK LANDS AND THE LIGHTS COME ON ------------------------------

   The mark's whole journey ends by settling into the footer logo's place. The
   three lines under it wait at a quarter strength while it is still out
   presenting, and strike on one after another once it is home, the way a row
   of fluorescent tubes comes up: a stutter, a false start, then steady.

   IT IS KEYED TO THE MARK BEING HOME, which is `pointer-home`, not
   `pointer-landed`. `pointer-landed` goes on at 0.55 of the landing, when the
   logo's top is still at 73% of the screen and these three lines are below the
   fold: the strike ran where nobody could see it and the reader met it already
   over, at full strength. `pointer-home` waits for 0.985, where everything
   under the logo is on screen. It is a delay measured in scroll rather than in
   seconds, so it is right at any reading speed.

   The dim state is gated on `.pointer-live`, the class the pointer sets only
   while it is really drawing. A browser with no WebGL, or a reader who has
   asked for less motion, never gets that class, so the lines are simply on at
   full strength and nothing waits for a mark that is not coming.

   The flicker steps in hard cuts rather than fades: a tube does not ramp, it
   catches. That is what `steps(1, end)` is doing on each keyframe. */

.pointer-live .contact-name,
.pointer-live .contact-location,
.pointer-live .contact-email {
  opacity: 0.25;
  transition: opacity 0.5s var(--ease-quart-out);
}

.pointer-home .contact-name,
.pointer-home .contact-location,
.pointer-home .contact-email {
  opacity: 1;
  animation: contact-strike 0.92s steps(1, end) both;
}

/* One after another, left to right down the block. The gap is shorter than
   the strike itself, so the second tube catches while the first is still
   settling and the row reads as one action rather than three. */
.pointer-home .contact-name { animation-delay: 0.05s; }
.pointer-home .contact-location { animation-delay: 0.27s; }
.pointer-home .contact-email { animation-delay: 0.49s; }

@keyframes contact-strike {
  0% { opacity: 0.25; }
  7% { opacity: 1; }
  11% { opacity: 0.25; }
  16% { opacity: 0.92; }
  20% { opacity: 0.25; }
  38% { opacity: 0.25; }
  43% { opacity: 1; }
  49% { opacity: 0.4; }
  55% { opacity: 1; }
  62% { opacity: 0.66; }
  68% { opacity: 1; }
  100% { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .project-media--swap .swap-layer { transition: none; }

  /* No strike. The lines are on, and they stay on. */
  .pointer-live .contact-name,
  .pointer-live .contact-location,
  .pointer-live .contact-email,
  .pointer-home .contact-name,
  .pointer-home .contact-location,
  .pointer-home .contact-email {
    opacity: 1;
    animation: none;
    transition: none;
  }
}

/* ============================================================================
   SECTION CTA: "See all ... " link to the filtered portfolio
   The track fills its section, so the sticky link rides the bottom-right
   corner of the viewport only while that section is on screen, then leaves
   with it. Bottom-right keeps it clear of the fixed email icon (bottom-left).
   ========================================================================== */
.section-layout { position: relative; }
.section-cta-track {
  position: absolute;
  inset: 0;
  z-index: 60;
  pointer-events: none;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: flex-end;
  padding: 0 clamp(16px, 2.5vw, 36px) clamp(16px, 2.5vw, 28px) 0;
}
.section-cta {
  position: sticky;
  bottom: clamp(16px, 2.5vw, 28px);
  pointer-events: auto;
  display: inline-flex;
  align-items: center;
  height: 48px;
  padding: 0 22px;
  border: 1px solid #333;
  border-radius: 2px;
  background: #f4f4f4;
  color: #222;
  font-family: var(--font-sans);
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  box-shadow: 0 6px 24px rgba(34, 34, 34, 0.08);
  transition: background-color 0.3s var(--ease-quart-out), color 0.3s var(--ease-quart-out), border-color 0.3s var(--ease-quart-out);
}
.section-cta::after {
  content: "\2192";
  margin-left: 10px;
  transition: transform 0.3s var(--ease-quart-out);
}
.section-cta:hover { background: #222; color: #f4f4f4; border-color: #222; }
.section-cta:hover::after { transform: translateX(4px); }
.section-cta:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 3px; }
.dark-bg .section-cta { background: #222; color: #f4f4f4; border-color: rgba(244, 243, 241, 0.5); box-shadow: none; }
.dark-bg .section-cta:hover { background: #f4f4f4; color: #222; border-color: #f4f4f4; }
@media (max-width: 768px) {
  .section-cta { height: 44px; padding: 0 16px; font-size: 11px; }
}

/* About highlights: while the 3D mark is presenting the page it points up at
   each figure from just underneath (aboutHighlights() in tangun-ca_hero3d.js),
   so the label steps down to leave it room. Without the mark (stacked layout,
   no WebGL, reduced motion) pointer-live is never set and nothing moves. */
.pointer-live .stats-row .stat-label { margin-top: 58px; }

/* ============================================================================
   CARD LINKS ("Go to project", "Case Study"): no box, bold, arrow on hover
   Akin, 2026-09-17: the boxed button was too tall. Now a bold text link; the
   arrow slides in from the left on hover or keyboard focus. Its space is
   reserved so nothing shifts. Opacity stays with the scroll reveal rules
   above (.is-visible), which this does not touch.
   ========================================================================== */
.portfolio .hover-card .at-button {
  height: auto;
  margin-bottom: 0;
  padding: 6px 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  font-weight: 600;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 5px;
  transition: color 0.3s var(--ease-quart-out), opacity 0.6s var(--ease-quart-out);
}
/* the underline, text and arrow all take the accent on hover */
.portfolio .hover-card .at-button:hover,
.portfolio .hover-card .at-button:focus-visible { color: var(--color-accent); }
.portfolio .hover-card .at-button::after {
  margin-left: 8px;
  opacity: 0;
  transform: translateX(-10px);
  transition: opacity 0.3s var(--ease-quart-out), transform 0.35s var(--ease-expo-out);
}
.portfolio .hover-card .at-button:hover::after,
.portfolio .hover-card .at-button:focus-visible::after {
  opacity: 1;
  transform: translateX(0);
}
@media (prefers-reduced-motion: reduce) {
  .portfolio .hover-card .at-button::after { transition: none; }
}

/* "See all ..." shows only once its section has reached the top of the screen */
.section-cta {
  opacity: 0;
  visibility: hidden;
  transform: translateY(10px);
  transition: opacity 0.4s var(--ease-quart-out), transform 0.5s var(--ease-expo-out), visibility 0s linear 0.4s,
              background-color 0.3s var(--ease-quart-out), color 0.3s var(--ease-quart-out), border-color 0.3s var(--ease-quart-out);
}
.section-cta.is-shown {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity 0.4s var(--ease-quart-out), transform 0.5s var(--ease-expo-out), visibility 0s,
              background-color 0.3s var(--ease-quart-out), color 0.3s var(--ease-quart-out), border-color 0.3s var(--ease-quart-out);
}

/* Section titles: the 1.8px tracking read as spaced out at 28px (Akin,
   2026-09-17). Tightened on the headings above each section's cards. */
.sectionIntro h2,
.dark-bg .sectionIntro h2 { letter-spacing: 0.2px; }

/* PACKAGING: a second photo per project crossfades in when the pointer taps
   the card's centre (actTap in tangun-ca_hero3d.js), or at the same scroll
   step as the award badge without a pointer. Pinned desktop layout only; the
   stacked layout keeps the first photo. */
.project-media--alt .pack-alt {
  position: absolute;
  inset: 0;
  z-index: 2;
  width: 100%;
  height: 100%;
  min-height: 0;
  object-fit: cover;
  opacity: 0;
  transform: scale(1.06);
  transition: opacity 0.7s var(--ease-quart-out), transform 1.1s var(--ease-expo-out);
  pointer-events: none;
}
@media (min-width: 1080px) {
  .project-media--alt.is-visible .pack-alt { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .project-media--alt .pack-alt { transition: opacity 0.2s linear; transform: none; }
}

/* ============================================================================
   MOTION BRANDING: the thumbnails animate, and the mark becomes a play button
   Akin, 2026-09-18: when the cursor reaches an animation thumbnail the still
   should play a few frames of the real clip on a loop so it reads as
   animation, and the mark should turn sideways into a play button and hold
   there on a soft disc, because it is already a triangle.
   ========================================================================== */

/* A strip of fourteen frames cut from the project's own clip
   (tangun-ca/tools/flipbook.swift), stepped one frame at a time.

   The strip is an image, not a background. A percentage background-position
   resolves against the positioning area MINUS the image, not against the
   image, so with a strip fourteen times the width of the card the intended
   -1400% worked out to tens of thousands of pixels off the side and only the
   first frame was ever on screen. Translating the image by its own width is
   exact instead: at fourteen steps each one lands on a frame boundary, with
   no percentage of anything else involved.

   The image is sized by height, so each frame is as wide as the card and the
   count lives in one place, the steps() below. */
.project-media--motion { position: relative; }
.motion-flip {
  position: absolute;
  inset: 0;
  z-index: 2;
  overflow: hidden;
  opacity: 0;
  transition: opacity 0.4s var(--ease-quart-out);
  pointer-events: none;
}
.motion-flip img {
  height: 100%;
  width: auto;
  max-width: none;
  display: block;
  will-change: transform;
}
.project-media--motion.is-playing .motion-flip { opacity: 1; }
.project-media--motion.is-playing .motion-flip img {
  animation: motionFlip 1.5s steps(14) infinite;
}
@keyframes motionFlip {
  to { transform: translateX(-100%); }
}
@media (prefers-reduced-motion: reduce) {
  .project-media--motion.is-playing .motion-flip img { animation: none; }
}

/* The play button's disc. Sits just under the canvas, so the mark reads as
   the triangle on top of it. Everything about it is set from JS; with no
   pointer it never becomes visible. */
.pointer-play {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 29;
  width: var(--d, 120px);
  height: var(--d, 120px);
  margin-left: calc(var(--d, 120px) / -2);
  margin-top: calc(var(--d, 120px) / -2);
  transform: translate3d(var(--x, -500px), var(--y, -500px), 0);
  border-radius: 50%;
  background: rgba(20, 20, 20, 0.32);
  border: 1px solid rgba(244, 244, 244, 0.35);
  opacity: 0;
  pointer-events: none;
  will-change: transform, opacity;
}

/* ---- THE HERO'S FIVE BEATS ------------------------------------------------

   The left column is one story read top to bottom, and the sticky visual
   beside it is the same story. Every beat is a normal block in the flow: they
   stack and stay, so anything read once can be read again on the way back up.

   Vertical rhythm is the choreography. The gap between beats is what gives
   each stage of the visual its stretch of scroll to happen in, which is why
   it is measured in vh rather than rem: the stages are viewport events. Edit
   the copy freely, the triggers are the headings themselves. */

.beat {
  position: relative;
  max-width: 34rem;
}

.beat + .beat {
  /* Nearly a screen. The gap is not empty space, it is the stage the visual
     plays on: the extrusion alone is half a screen of scrolling, and the mark
     has to fly from one beat to the next between them. At 44vh the mark
     arrived at a heading only after that heading had left the top of the
     screen, so it underlined something nobody could see. */
  margin-top: 96vh;
}

/* The beat headlines are the page's display type, at h1 scale. They stay h2
   elements: the animation finds the beat it underlines by tag, and the whole
   choreography is anchored to these headings, so the markup is left alone and
   the size is done here. */
/* THE COPY TURNS OVER WITH THE PLATE.

   For one beat the page runs through four printing inks (NikaPort_pressRun),
   and any beat whose copy is on screen while that happens has to turn over
   with it or simply disappear on the magenta and the black. It is every beat
   rather than the one the wash belongs to, because the beat after it is
   already on screen and being read while the last plates are still running.

   Outside that stretch --wash-ink is written as exactly #222 and --wash-ink-2
   as exactly #3d3d3d, which are the two colours below, so this changes nothing
   anywhere else. The fallbacks cover a page with no JS at all. */
.beat h1,
.beat h2 {
  font-family: "Unna", Georgia, serif;
  font-size: clamp(2.6rem, 5.2vw, 5.6rem);
  font-weight: 700;
  line-height: 1.04;
  letter-spacing: -0.022em;
  color: var(--wash-ink, var(--color-text-primary));
  text-wrap: balance;
  margin: 0 0 22px;
}

.beat p {
  font-family: "Inter", sans-serif;
  font-size: 16px;
  line-height: 1.68;
  color: var(--wash-ink-2, var(--color-text-secondary));
  margin: 0 0 16px;
}

.beat-lede {
  margin-top: 18px !important;
  max-width: 30rem;
}

/* The words the mark loops its ink around. Emphasis without italics, because
   the annotation is the emphasis; nowrap so a circle never has to span a line
   break. */
.ink-target {
  font-style: normal;
  font-weight: 600;
  /* Turns over with the plate like the copy around it, or the one emphasised
     phrase in a paragraph is the only thing that vanishes on the black. */
  color: var(--wash-ink, var(--color-text-primary));
  white-space: nowrap;
}

/* The mark's ink. One overlay for the whole column, sized to it, drawn into by
   tangun-ca_code.JS. Never a scroll container, never interactive. */
.ink-layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
  z-index: 20;
}

.ink-layer path {
  fill: none;
  stroke: #2c2a28;
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.82;
}

/* ---- THE SKILL FILE ------------------------------------------------------

   Miller Advisors' real file, quoted as shipped. Dark, because it is a file
   and not a page, and because the mark reads brightest against it. Lines sit
   dimmed until the mark passes over them, which is what .is-lit is for. */

.skill-file {
  margin: 28px 0 24px;
  padding: 20px 22px 22px;
  background: var(--color-dark);
  border-radius: 6px;
  overflow: hidden;
}

.skill-file-name {
  font-family: "Inter", sans-serif;
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-dark-text-tertiary);
  margin-bottom: 14px;
}

.skill-file pre {
  margin: 0;
  overflow-x: auto;
}

.skill-file code {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 12.5px;
  line-height: 1.75;
  color: var(--color-dark-text-secondary);
  white-space: pre;
}

.skill-line {
  display: block;
  opacity: 0.42;
  transition: opacity 0.45s cubic-bezier(0.16, 1, 0.3, 1),
    color 0.45s cubic-bezier(0.16, 1, 0.3, 1);
}

.skill-line.is-lit {
  opacity: 1;
  color: var(--color-dark-text-primary);
}

.skill-line--rule {
  color: var(--color-dark-text-tertiary);
}

.sk-key {
  color: var(--color-accent);
}

.sk-h {
  color: var(--color-dark-text-primary);
}

/* ---- THE PROOF ----------------------------------------------------------- */

.skill-proof {
  margin-top: 26px;
  padding-top: 22px;
  border-top: 1px solid var(--color-border);
}

.skill-proof-lede {
  font-size: 15px !important;
}

.skill-proof-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 26px 34px;
  margin: 22px 0 24px;
}

.skill-proof-stats > div {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.skill-proof-stats dt {
  font-family: "Unna", Georgia, serif;
  font-size: 30px;
  line-height: 1;
  color: var(--color-text-primary);
}

.skill-proof-stats dd {
  margin: 0;
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-text-tertiary);
  max-width: 9rem;
}

/* ---- STACKED ------------------------------------------------------------- */

/* (An older phone-only block for the hero stood here. Removed 2026-10-06:
   the phone now runs the same hero as the desktop, laid out for a tall
   screen by THE PHONE LAYOUT at the end of this file.) */

/* A blank line before a heading inside the file, which a run of block level
   lines cannot get from the source without printing an empty line. */
.skill-line--gap {
  margin-top: 1.75em;
}

/* (An older phone-only block for the hero stood here. Removed 2026-10-06:
   the phone now runs the same hero as the desktop, laid out for a tall
   screen by THE PHONE LAYOUT at the end of this file.) */


/* ---- THE SECTIONS THAT SPAN THE PAGE -------------------------------------

   Three beats are not a column beside a picture, they are the page: the sheet
   the story opens on, the skill file, and the statement it closes on. They
   break out of the copy column to the full width of the window and keep the
   column's own left margin, so the type still starts on the line everything
   else does.

   .hero-content is half the viewport with a 10vw gutter each side, so its
   content box begins 10vw in: pulling back by that gutter and taking 100vw is
   what puts these on the page's own edges. Nothing here moves a beat's
   heading vertically, which is what the choreography is anchored to. */

.beat--wide {
  width: 100vw;
  margin-left: -10vw;
  padding-left: 10vw;
  padding-right: 10vw;
  box-sizing: border-box;
  max-width: none;
}

/* A headline may run the width of the page; a paragraph may not, and neither
   may a file: sixty character lines stretched across a 1300px panel leave the
   code stranded in the dark. */
.beat--wide .skill-file {
  max-width: 44rem;
}

/* A descendant selector, not a child one: a pinned beat wraps its copy, and
   with the child selector the paragraph lost its measure, ran the width of the
   page, and got short enough to move every beat below it 53px up the page. */
.beat--wide p,
.beat--wide .beat-lede,
.beat--wide .beat-close,
.beat--wide .skill-proof-lede {
  max-width: 34rem;
}

.beat--wide h1,
.beat--wide h2 {
  max-width: 20ch;
}

/* (An older phone-only block for the hero stood here. Removed 2026-10-06:
   the phone now runs the same hero as the desktop, laid out for a tall
   screen by THE PHONE LAYOUT at the end of this file.) */


/* ---- THE OPENING BEAT SITS LOW ON THE FIRST SCREEN -----------------------

   Every stage of the visual is triggered by its beat's heading crossing a line
   about two thirds down the screen. The opening beat is now the first thing in
   the document, so with the heading high on the page that line was already
   behind it at rest and the page loaded with a third of the sketch drawn.

   The heading is moved down the first screen instead, which is a spacing
   change and not a timing one: the trigger, the order and the animation are
   exactly as they were, and the drawing again starts on blank paper. */

.beat--sketch {
  /* Low enough on the first screen that the heading starts below the line that
     triggers the drawing, high enough that the words sit inside the sheet
     rather than falling out of its bottom edge. */
  padding-top: 16vh;
}

/* (An older phone-only block for the hero stood here. Removed 2026-10-06:
   the phone now runs the same hero as the desktop, laid out for a tall
   screen by THE PHONE LAYOUT at the end of this file.) */


/* ---- THE SHEET OPENS OUT -------------------------------------------------

   The page begins on a sheet of paper standing in the middle of the window,
   with clear space either side of it, and the sheet widens to the full page as
   the drawing is made on it. It is a CLIP, not a width: the texture neither
   moves nor stretches, it is uncovered.

   The copy keeps its distance from the sheet's edge rather than from the
   window's, so while the sheet is boxed the words sit inside it, and as it
   opens they settle onto the page's own margin. Both values are written by
   tangun-ca_code.JS from the progress the sketch is already drawn to, so the
   sheet opens exactly as the pencil works and no new timing exists. */

/* THE FALLBACKS ARE THE REST STATE, NOT ZERO.

   These three values are written by tangun-ca_code.JS, and until it has run
   the fallback in each var() is what paints. At zero that fallback WAS the
   fully open sheet, so a page whose first paint beat the script showed the
   paper bleeding to all four edges and the copy on the wrong margin, and then
   snapped into the boxed sheet. Nothing was mistimed: the browser was simply
   drawing the end of the animation before the beginning existed.

   It was not visible locally, where the script runs in a few milliseconds. It
   is very visible on a cold load, because the script that sets these only ran
   on `load`, which waits for Three.js, Lottie, the icon font, Google Fonts and
   the images on tangun.ca. Six seconds of full bleed paper, measured.

   So the fallbacks are now the sheet AT REST: 15% either side and 7% top and
   bottom, which are NikaPort_PAPER_INSET and NikaPort_PAPER_INSET_Y, and a
   copy margin of 10 + 15 * 0.6 = 19vw, which is NikaPort_PAPER_PAD at rest.
   Change one of those constants and change it here too. The first paint is
   then the first frame of the animation, and the script has nothing to
   correct. */

.hero-background {
  clip-path: inset(
    var(--paper-inset-y, 7%) var(--paper-inset, 15%)
    var(--paper-inset-y, 7%) var(--paper-inset, 15%)
  );
}

.beat--sketch {
  padding-left: var(--paper-pad, 19vw);
}

/* (An older phone-only block for the hero stood here. Removed 2026-10-06:
   the phone now runs the same hero as the desktop, laid out for a tall
   screen by THE PHONE LAYOUT at the end of this file.) */


/* ---- THE BEAT THAT HOLDS -------------------------------------------------

   The mark stands up during this beat, and then comes to it. So the copy waits
   in the middle of the page while that happens: centred, pinned, and given a
   stretch of scrolling to be held through. The mark flies to the heading where
   it is pinned and draws its line under it, which is the whole point of
   centring it: the page's own centre is where the mark can reach.

   The height is what the pin is held by. .beat-pin does the sticking, the
   section is the track it sticks within, and the empty span at the top of the
   section, not the heading, is what the visual's timing is measured from. */

.beat--system {
  /* A screen and a half of track: enough to hold the pin while the mark
     arrives, underlines and leaves, and no longer. */
  min-height: 150vh;
}

.beat--system .beat-pin {
  position: sticky;
  top: 22vh;
  max-width: 30rem;
  margin: 0 auto;
  text-align: center;
}

.beat--system .beat-pin p {
  margin-left: auto;
  margin-right: auto;
}

.beat-anchor {
  display: block;
  height: 0;
}

/* (An older phone-only block for the hero stood here. Removed 2026-10-06:
   the phone now runs the same hero as the desktop, laid out for a tall
   screen by THE PHONE LAYOUT at the end of this file.) */


/* The ink layer that does not travel with the page. Ink drawn on pinned copy
   lives here, where its shape stays put for as long as the copy is held. */
.ink-layer--pinned {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  overflow: visible;
  pointer-events: none;
  z-index: 20;
}

/* ---- THE OPENING BEAT HOLDS WHILE THE SHEET OPENS -----------------------

   The copy used to slide across the page at the same time as the page scrolled
   up under it, which reads as one diagonal drift rather than two decisions.
   Now the copy is pinned for as long as the sheet takes to open: it moves
   across, and only when it is done does it move up with everything else.

   The pin is set at the copy's own resting place, 50vh of spacer above the
   hero plus this section's own 16vh, so it takes hold at the first pixel of
   scrolling and there is no jump into it. */

/* Centred, and centred from the FIRST PIXEL.

   The copy used to rest at 66vh, which is where this section's top happens to
   sit at scroll 0, so the pin took hold immediately and nothing jumped. Moving
   the line to the middle of the screen breaks that: the section still starts at
   66vh, so the copy would drift up for 16vh of scrolling before the pin caught
   it, and the opening would begin off centre.

   The negative margin is the difference. It pulls the pinned box up to the
   middle line without moving the SECTION, so the copy is centred at scroll 0
   and stuck from the first pixel, while the anchor span at the section's top,
   which is what the sketch is timed from, does not move at all.

   Centred by transform for the reason in rule 4: a small stuck box leaves the
   whole track to hold with. */
.beat--sketch .beat-pin {
  position: sticky;
  top: 50vh;
  margin-top: -16vh; /* 50vh minus the section's own 66vh top */
  transform: translateY(-50%);
}

/* A sticky block can only be held within its own section, and this section was
   shorter than the copy inside it, so there was no room to hold anything and
   the copy simply scrolled. The section becomes the track the copy is held in,
   long enough to cover the sheet opening.

   The gap to the next beat gives back exactly what this takes, so the beat
   below starts where it always did and the whole visual keeps its timing. */
.beat--sketch {
  min-height: 76vh;
}

/* Enough specificity to beat `.beat + .beat`, which sets the standard gap. */
.beat + .beat.beat--mark {
  margin-top: 61vh;
}

/* ---- THE MARK'S BEAT IS HELD -------------------------------------------

   The copy waits in the middle of the page while the sketch becomes the mark
   beside it, holds while the paper goes, and is still there while the finished
   mark sits alone on the bare page. Then it lets go and the mark stands up.

   CENTRED BY TRANSFORM, not by a full height flex box. Sticking a 100vh box at
   the top and centring inside it would work, but the box is then a screen tall
   and every pixel of track under it buys only that pixel of hold. A small box
   stuck at the middle line and pulled back by half its own height is centred at
   any viewport and leaves the whole track to hold with, which is where the long
   pause the mark needs comes from.

   The transform is safe here because nothing measures this box. The timing is
   read from the empty span outside it, which is untransformed and never moves.

   THE TRACK IS PAID FOR, and it is paid for twice over. The gap that used to
   sit between this beat and the next is now inside this beat as track, so the
   words are held through the space instead of scrolling through it. And the
   extra beyond that is deliberate: it is the room the longer hold before the
   extrusion needs, which is why NikaPort_BEAT_LINES["beat-system"] went to 2.2
   in the same change. Those two numbers move together. See THE BEATS DRIVE THE
   CLOCK in tangun-ca_code.JS. */

.beat--mark {
  min-height: 181vh;
}

/* Sixty more for the backflip, and NikaPort_FLIP_ROOM in tangun-ca_code.JS is
   the 0.6 that pays for it. Same deal as the pause above: the two move
   together or the settle moves. Wide layouts only, to match the script. */
@media (min-width: 991px) {
  .beat--mark {
    min-height: 241vh;
  }
}

/* The two fixed corner pieces sit on the ink too. brightness(0) takes the
   grey artwork to black and invert() takes it to white, so the pair driven
   together is a crossfade from the artwork to a white version of itself. */
.fixed-logo img,
.fixed-email img {
  /* --chrome-dark, not --wash-dark: these two float over the whole page, so
     what is behind them is the hero's ink in the hero and Motion Branding's
     once that section owns the screen. NikaPort_pressRun takes whichever is
     darker. */
  filter: brightness(calc(1 - var(--chrome-dark, 0)))
    invert(var(--chrome-dark, 0));
}

.beat--mark .beat-pin {
  position: sticky;
  top: 50vh;
  transform: translateY(-50%);
}

/* The gap after it is now a breath, because the holding is done by the track
   above rather than by empty space. */
.beat + .beat.beat--system {
  margin-top: 24vh;
}

/* (An older phone-only block for the hero stood here. Removed 2026-10-06:
   the phone now runs the same hero as the desktop, laid out for a tall
   screen by THE PHONE LAYOUT at the end of this file.) */

/* ---- THE FILE BEAT, DESIGNED -------------------------------------------

   The argument is held on the left while the file goes past on the right,
   which is the shape of what is being described: a person reasoning, and a
   document that outlives the reasoning. The proof follows as a band the whole
   page wide.

   The section is the track the argument is held in. Its height is what decides
   how long the file takes to pass, so it is set here and not guessed at
   elsewhere. */

.beat--skill {
  padding-top: 8vh;
}

.skill-split {
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1fr);
  gap: 0 6vw;
  align-items: start;
}

/* IT ARRIVES AND HOLDS, the way the beat above it does.

   At 16vh the argument swept all the way up to just under the top of the
   window before it stopped, so by the time it settled the claim it follows had
   long gone and the two beats never shared the screen. Held lower, it comes to
   rest while the copy above is still on its way out, and the new section reads
   as pushing the old one up rather than arriving after it.

   It cannot go much lower than this: the argument is 439px tall and the window
   it has to fit in is the whole of one, so 30vh leaves it finishing around
   79vh with the file still running beside it. */
.skill-argument .beat-pin {
  position: sticky;
  top: 30vh;
}

/* Sized to its column rather than to the page: at full display scale this
   headline took three lines of a half-width column and left the argument
   underneath it with nowhere to go. */
.skill-argument h2 {
  font-size: clamp(2rem, 3.4vw, 3.5rem);
  max-width: 16ch;
  margin-bottom: 26px;
}

.beat--wide .skill-argument p {
  max-width: 30rem;
}

/* The file runs past the held argument, with room after it so the last line
   can be read before the beat lets go. */
.skill-document {
  padding-top: 14vh;
  padding-bottom: 26vh;
}

.beat--wide .skill-file {
  max-width: none;
}

.skill-model-note {
  margin-top: 26px !important;
  font-size: 14px !important;
  color: var(--color-text-tertiary);
  max-width: 30rem;
}

/* ---- THE PROOF BAND ----------------------------------------------------- */

.skill-proof {
  margin-top: 0;
  padding-top: 5vh;
  border-top: 1px solid var(--color-border);
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1fr);
  gap: 0 6vw;
  align-items: start;
}

.beat--wide .skill-proof-lede {
  grid-row: 1;
  margin: 0 !important;
  font-size: 16px !important;
  max-width: 30rem;
}

.skill-proof-stats {
  grid-column: 2;
  grid-row: 1;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0 24px;
  margin: 0 !important;
}

.skill-proof-stats dt {
  font-size: clamp(2rem, 3.4vw, 3.4rem);
  line-height: 0.95;
  /* Each figure is pointed at in turn, and comes up as it is. */
  opacity: 0.32;
  transition: opacity 0.5s cubic-bezier(0.16, 1, 0.3, 1),
    color 0.5s cubic-bezier(0.16, 1, 0.3, 1);
}

.skill-proof-stats dd {
  opacity: 0.32;
  transition: opacity 0.5s cubic-bezier(0.16, 1, 0.3, 1);
}

.skill-proof-stats .is-counted dt,
.skill-proof-stats .is-counted dd {
  opacity: 1;
}

/* ---- THE PROMISE -------------------------------------------------------- */

.beat--paper {
  min-height: 120vh;
  padding-top: 10vh;
}

/* Centred, like the two beats above it, so the page's own claim sits in the
   middle of the screen while the mark comes and signs it.

   The mark needed nothing done to it. It aims at the heading's LIVE position
   and draws under whatever rect it finds there, so moving the copy moves the
   signature with it. What matters is that the copy is pinned for the whole
   window, and it is: the pin takes hold 40vh before the window opens and does
   not let go until 69vh after it closes. */
.beat--paper .beat-pin {
  position: sticky;
  top: 50vh;
  transform: translateY(-50%);
  /* Centred on both axes, the same treatment as the beat about the system:
     this is the page's own claim, and it is the one thing on the page that
     should not be sitting against a margin. */
  max-width: 40rem;
  margin: 0 auto;
  text-align: center;
}

.beat--paper .beat-pin h1,
.beat--paper .beat-pin .beat-lede {
  margin-left: auto;
  margin-right: auto;
}

.beat--wide .beat-lede {
  max-width: 36rem;
  margin-top: 26px !important;
}

/* The gaps between the last three beats: the pins do the holding now, so the
   empty stretches between them come down to a breath rather than a screen.

   The two values SWAPPED when the beats did (2026-09-24). They were never
   about which beat they belong to, they are about how far the mark has to
   travel to reach the next one, and the order of the journey is what changed.
   The longer gap follows the system beat, because the mark has to stand up and
   cross the page from there; the shorter one follows the promise, because from
   the signature it only has to reach the file. */
.beat + .beat.beat--paper {
  margin-top: 34vh;
}

/* Closed up, so the argument is already coming as the claim leaves. The two
   numbers work together: the gap decides when this beat starts moving and the
   pin above decides where it stops, and the push is the overlap between the
   two. See the pin rule for the rest of it. */
.beat + .beat.beat--skill {
  margin-top: 12vh;
}

/* ---- THE CASE, IN A BOX -------------------------------------------------

   The hero argues for four beats, and then hands over to a client who already
   has the thing. So the case is SET APART rather than run on: a sheet laid on
   the page, ruled with a hairline, holding both deliverables at once.

   The panel is the only surface in the hero, and the two book covers are the
   only colour in the panel. Everything else here is the page's own greys, so
   the eye goes to the books and then down to the figures under them. */

.miller-case {
  /* It belongs to the argument above it and was sitting most of a screen
     below it, which read as a separate section rather than as the evidence. */
  margin-top: 4vh;
  padding: clamp(28px, 4vw, 64px);
  background: #fbfbfa;
  border: 1px solid var(--color-border);
  border-radius: 3px;
  /* No shadow. The panel is a sheet printed on the page, not an object resting
     on it, and the hairline is enough to say where it ends. */
}

.miller-case__eyebrow {
  font-family: "Inter", sans-serif;
  font-size: 12px !important;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-text-tertiary);
  margin: 0 0 14px !important;
}

/* What the panel IS, said before whose it is. The accent is the page's, not
   Miller's, because this label is the site talking about its own work. */
.miller-case__kicker {
  color: var(--color-accent);
  font-weight: 600;
  margin-right: 8px;
}

.miller-case h3 {
  font-family: "Unna", Georgia, serif;
  /* Deliberately below the beats' own display scale. This is a client's story
     inside Akin's page, not a sixth beat competing with the five. */
  font-size: clamp(1.9rem, 3.1vw, 3rem);
  font-weight: 700;
  line-height: 1.06;
  letter-spacing: -0.02em;
  color: var(--color-text-primary);
  margin: 0 0 18px;
}

.miller-case__lede {
  max-width: 44rem;
  margin: 0 !important;
}

/* The claim and the count that backs it, on one row. They were the panel's
   first block and its last, a screen and a half apart, saying the same thing
   twice. */
.miller-case__top {
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
  gap: clamp(28px, 4vw, 64px);
  align-items: start;
}

/* Two volumes of one thing, so they are grouped and divided rather than boxed:
   a single hairline between them says "and", where two outlines would have
   said "or". */
.miller-books {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(28px, 3.4vw, 56px);
  margin-top: clamp(32px, 4.5vh, 56px);
  padding-top: clamp(28px, 3.4vh, 44px);
  border-top: 1px solid var(--color-border);
}

.miller-books > * + * {
  border-left: 1px solid var(--color-border);
  padding-left: clamp(28px, 3.4vw, 56px);
}

/* The cover stands BESIDE its copy rather than above it, which is most of the
   height the panel gave back. It is a book on a shelf next to its description,
   which is also how you would actually meet it. */
.miller-book {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: clamp(18px, 1.8vw, 30px);
  align-items: start;
}

.miller-book__body {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

.miller-book__art {
  width: clamp(92px, 7.5vw, 124px);
  height: auto;
  display: block;
  /* The covers are artwork, not UI: the shadow puts them on the sheet. */
  filter: drop-shadow(0 14px 24px rgba(34, 34, 34, 0.18));
}

.miller-book__tag {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: "Inter", sans-serif;
  font-size: 12px !important;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--color-text-tertiary);
  margin: 0 0 10px !important;
}

/* WHICH ERA EACH BOOK BELONGS TO, said in one word and flagged so it is read
   before the heading. The pair is the whole argument of the panel, so they get
   to be the only two coloured things in it. */
.tag-flag {
  display: inline-block;
  padding: 4px 9px 3px;
  border-radius: 2px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.1em;
  line-height: 1;
  color: #fff;
}

.tag-flag--classic {
  background: var(--color-accent);
}

/* The new one will not hold still: it runs the same four printing inks the
   hero runs, so the two colour moments on the page are the same idea. The
   text colour turns over with it, because process yellow cannot carry white.
   Held on each ink and changed over quickly, like the plates. */
.tag-flag--new {
  background: #0093d3;
  animation: tag-press 7.2s infinite;
}

@keyframes tag-press {
  0%, 21% { background: #0093d3; color: #fff; }
  25%, 46% { background: #e5007e; color: #fff; }
  50%, 71% { background: #ffed00; color: #1a1a1a; }
  75%, 96% { background: #1a1a1a; color: #fff; }
  100% { background: #0093d3; color: #fff; }
}

@media (prefers-reduced-motion: reduce) {
  .tag-flag--new {
    animation: none;
  }
}

.miller-book h4 {
  font-family: "Unna", Georgia, serif;
  font-size: clamp(1.4rem, 1.9vw, 1.85rem);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.015em;
  color: var(--color-text-primary);
  margin: 0 0 6px;
}

/* The one line that carries the whole distinction between the two. It gets to
   be the only italic on the page for exactly that reason. */
.miller-book__sub {
  font-family: "Unna", Georgia, serif;
  font-style: italic;
  font-size: 17px !important;
  line-height: 1.4;
  color: var(--color-text-primary);
  margin: 0 0 14px !important;
}

.miller-book p {
  max-width: 32rem;
}

.miller-book .at-button {
  margin-top: auto;
}

/* In the top row the proof is a column, not a band, so it drops the rule and
   the two-up grid it had when it ran the width of the page. Four figures
   across a narrow column set them in 5ch of space each; two by two lets them
   stay at display scale, which is the point of them. */
.miller-case .skill-proof {
  display: block;
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

.miller-case .skill-proof-stats {
  grid-column: auto;
  grid-row: auto;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(18px, 2.4vh, 28px) 24px;
}

.miller-case .skill-proof-lede {
  grid-row: auto;
  margin-top: clamp(18px, 2.4vh, 26px) !important;
  max-width: none;
}

@media (max-width: 990px) {
  .skill-split,
  .skill-proof {
    display: block;
  }

  .skill-argument .beat-pin,
  .beat--paper .beat-pin {
    position: static;
    transform: none;
  }

  .skill-document {
    padding-top: 6vh;
    padding-bottom: 0;
  }

  .skill-proof-stats {
    display: flex;
    flex-wrap: wrap;
    gap: 26px 34px;
    margin-top: 24px !important;
  }

  .skill-proof-stats dt,
  .skill-proof-stats dd {
    opacity: 1;
  }

  .beat--paper {
    min-height: 0;
  }

  /* One column throughout: the claim over its figures, and each cover over
     its copy. Beside only works while there is width to put things beside. */
  .miller-case__top {
    grid-template-columns: minmax(0, 1fr);
  }

  .miller-book {
    grid-template-columns: minmax(0, 1fr);
    gap: 20px;
  }

  /* Stacked, the two books are one after another, so the rule that divided
     them becomes the rule that separates them and the indent goes. A vertical
     hairline down a single column would be pointing at nothing. */
  .miller-books {
    grid-template-columns: minmax(0, 1fr);
  }

  .miller-books > * + * {
    border-left: 0;
    border-top: 1px solid var(--color-border);
    padding-left: 0;
    padding-top: clamp(28px, 4vh, 40px);
  }

  /* The button can no longer be pushed to a shared baseline, because there is
     no second column to line up with. */
  .miller-book .at-button {
    margin-top: 10px;
  }
}

/* ---- THE PROJECT ARROW ----------------------------------------------------

   The affordance that replaced the cards' buttons. See the matching block in
   tangun-ca_code.JS for why it is built from two elements and why the rule
   that hides the native cursor hangs off a class rather than off .media-link:
   on a phone, and with no JS, the ordinary pointer has to stay.
--------------------------------------------------------------------------- */

.project-cursor {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 9999;
  /* Position only, and NO transition: this is rewritten every frame. */
  transform: translate3d(var(--x, -200px), var(--y, -200px), 0);
  pointer-events: none;
  will-change: transform;
}

.project-cursor__disc {
  display: grid;
  place-items: center;
  width: 58px;
  height: 58px;
  /* Centred on the pointer itself, not hanging below and right of it. */
  margin: -29px 0 0 -29px;
  border-radius: 50%;
  /* Paper, so the mark reads over a dark still and a bright one alike. The
     same pairing as the site's icon. */
  background: #f4f4f1;
  box-shadow: 0 6px 22px rgba(20, 20, 20, 0.26);
  opacity: 0;
  transform: scale(0.55);
  transition: opacity 0.18s var(--ease-quart-out),
              transform 0.26s var(--ease-expo-out);
}

.project-cursor.is-on .project-cursor__disc {
  opacity: 1;
  transform: scale(1);
}

.project-cursor svg {
  display: block;
  width: 33px;
  height: 25px;
}

.project-cursor path,
.project-cursor .pc-shaft { fill: #222; }

/* Only while the arrow is actually up. */
body.has-project-cursor .media-link,
body.has-project-cursor .media-link * { cursor: none; }

/* The keyboard's way in. With the button gone the picture is the card's link,
   so its focus has to be visible. */
.media-link:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 4px;
  border-radius: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .project-cursor__disc { transition: opacity 0.12s linear; transform: none; }
  .project-cursor.is-on .project-cursor__disc { transform: none; }
}

/* ---- THE CARD ROW SITS UNDER ITS TITLE ------------------------------------

   With the per-card buttons gone the cards are shorter, and the space between
   a section's title block and its first picture was left over from a layout
   that had more in it: 20px under the subcopy, a 40px row gap, and 20px on top
   of the card, which is 80px of nothing between a heading and the thing it
   heads. The title, the subcopy and the work are one statement and should read
   as one.

   Small screens get the same treatment harder, because there the sections
   stack and every pixel of dead space is a pixel of work pushed off the
   bottom of the phone.

   Only the four home-page sections are touched, by id. The same classes are
   used on portfolio.html, which has its own rhythm.
--------------------------------------------------------------------------- */

#selected-works .sectionIntro,
#case-studies .sectionIntro,
#motion-branding .sectionIntro,
#packaging-design .sectionIntro {
  padding-top: 8px;
  padding-bottom: 6px;
}

#selected-works .hover-card,
#case-studies .hover-card,
#motion-branding .hover-card,
#packaging-design .hover-card {
  padding-top: 14px;
}

/* One row of cards, so the row gap is only ever the space under the title. */
@media (min-width: 1080px) {
  #selected-works .cards-container,
  #case-studies .cards-container,
  #motion-branding .cards-container,
  #packaging-design .cards-container {
    column-gap: 40px;
    row-gap: 14px;
  }
}

/* One card per row, so the row gap is doing two jobs: it separates the cards
   from each other, which still needs room, and it separates the title from the
   first card, which does not. The pull-up gives back only the second. */
@media (max-width: 1079.98px) {
  #selected-works .cards-container,
  #case-studies .cards-container,
  #motion-branding .cards-container,
  #packaging-design .cards-container {
    column-gap: 40px;
    row-gap: 30px;
  }

  #selected-works .sectionIntro,
  #case-studies .sectionIntro,
  #motion-branding .sectionIntro,
  #packaging-design .sectionIntro {
    padding-bottom: 0;
    margin-bottom: -20px;
  }

  #selected-works .hover-card,
  #case-studies .hover-card,
  #motion-branding .hover-card,
  #packaging-design .hover-card {
    padding-top: 10px;
    padding-bottom: 14px;
  }
}

/* ---- ABOUT: HOW THE WORDS SIT ON THE PICTURE -----------------------------

   The sticky portrait and its scrim are unchanged. What changed is the
   placement of everything on top of it.

   Before, every block was centred in the full content width and stacked with
   the same gap, so the copy ran straight across his face and the picture was
   only there to be darkened. Now the prose is held in a column down the left
   and the portrait keeps the right of the frame, which is the whole reason to
   have a person on the page. The figures stay full width along the foot,
   where what is behind them is a dark shirt.
--------------------------------------------------------------------------- */

.about-col {
  max-width: var(--max-content);
  margin: 0 auto;
  padding: 0 var(--edge);
}

/* The column the prose is held in. Wide enough for a real measure, narrow
   enough to leave the face clear. */
.about-col > * {
  max-width: 34rem;
}

.pinned-photo-content .quote-block {
  max-width: 34rem;
  margin: 0;
  padding: 0;
}

/* THE STATEMENT, at the register the rest of the page speaks in.

   It was set in italic at body-adjacent size and read as a caption. The page's
   own voice is Unna roman at display scale, and this is the one line on the
   page that is his rather than the work's, so it gets that voice. */
.quote-block blockquote {
  margin: 22px 0 0;
  font-family: var(--font-serif);
  font-style: normal;
  font-size: clamp(2.1rem, 3.1vw + 0.5rem, 3.9rem);
  line-height: 1.06;
  letter-spacing: -0.02em;
  color: var(--color-text-primary);
  /* 17ch, so "authentic brands win." holds its line. At 15 the last word
     dropped to a line of its own. */
  max-width: 17ch;
  /* The opening quote mark hangs into the margin, so the first letter of the
     line and the block's left edge agree. */
  text-indent: -0.42em;
}

/* The tail of the statement, not a footnote to it. At 13px tertiary it was
   grey type on a photograph, which is the hardest thing to read on a page. */
.quote-block cite {
  display: block;
  margin-top: 26px;
  max-width: 44ch;
  font-style: normal;
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 1.62;
  color: var(--color-text-secondary);
}

/* The biography is separate from the statement and says so with a rule. */
.about-bio {
  margin-top: clamp(38px, 6vh, 74px);
  padding-top: clamp(26px, 4vh, 44px);
  border-top: 1px solid var(--color-border);
}

.about-bio__label {
  /* His name, set as a name. Tracked-out capitals in the tertiary grey made
     the one proper noun in the block the least visible thing in it. */
  margin: 0 0 10px;
  font-family: var(--font-serif);
  font-size: 21px;
  letter-spacing: 0;
  text-transform: none;
  color: var(--color-text-primary);
}

.about-bio .lede {
  margin: 0;
  max-width: 44ch;
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.68;
  color: var(--color-text-secondary);
}

/* THE FIGURES, AS A LEDGER.

   The row keeps the page's own left edge, the one the column above it uses.
   Zeroing its side padding pulled the ledger 72px further left than the
   statement over it, and two left edges in one block is one too many.

   Four equal cells with a gap between them read as four unrelated numbers.
   Ruled cells read as one specification, which is what they are. The rules
   are the same hairline the rest of the block uses.

   The row keeps its shape and its class names: the mark points at each
   .stat-number in turn from underneath, stepping across as the row travels,
   and .pointer-live still reserves the space under each figure for it. */
.stats-row {
  margin-top: clamp(46px, 8vh, 96px);
  padding-top: clamp(26px, 4vh, 42px);
  padding-bottom: clamp(26px, 4vh, 42px);
  gap: 0;

  /* The two rules are drawn INSET to the content, not on the padding box.
     As borders they ran the full width of the row and so reached 72px past
     the cells they were ruling, while the dividers between the cells stopped
     at the content edge: one rule bleeding and the next one not reads as a
     mistake rather than as a choice. Drawn as backgrounds they start and stop
     exactly where the figures do, and it takes no extra element to do it. */
  border-top: none;
  border-bottom: none;
  background-image:
    linear-gradient(var(--color-border), var(--color-border)),
    linear-gradient(var(--color-border), var(--color-border));
  background-repeat: no-repeat;
  background-size: calc(100% - 2 * var(--edge)) 1px;
  background-position: var(--edge) 0, var(--edge) 100%;
}

.stats-row .stat {
  flex: 1 1 0;
  padding: 0 clamp(16px, 2.4vw, 34px);
  border-left: 1px solid var(--color-border);
}

.stats-row .stat:first-child {
  padding-left: 0;
  border-left: none;
}

.stat .stat-label {
  margin-top: 10px;
  font-family: var(--font-sans);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  line-height: 1.5;
  color: var(--color-text-tertiary);
}

/* THE WAY IN TO THE REST. It was a bordered box sitting on a photograph,
   which is the one thing on this page that looked like a form control. It is
   a line of type with a rule under it, the same manner as the section links. */
.about-more-toggle-wrap {
  margin-top: clamp(34px, 5vh, 60px);
  padding: 0 var(--edge);
  max-width: var(--max-content);
  margin-left: auto;
  margin-right: auto;
  /* Left, with the column and the ledger. It was centred, which put it on its
     own axis under a block that has exactly one. */
  text-align: left;
}

.pinned-photo-content .about-more-toggle {
  /* .at-button is a 60px tall flex box with margins. None of that belongs on
     a line of type with a rule under it. */
  display: inline-flex;
  align-items: center;
  height: auto;
  margin: 0;
  padding: 0 0 7px;
  border: none;
  border-bottom: 1px solid var(--color-border);
  border-radius: 0;
  background: none;
  font-family: var(--font-sans);
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-text-secondary);
  transition: color var(--dur-fast, 0.2s) var(--ease-quart-out),
              border-color var(--dur-fast, 0.2s) var(--ease-quart-out);
}

.pinned-photo-content .about-more-toggle:hover,
.pinned-photo-content .about-more-toggle:focus-visible {
  color: var(--color-text-primary);
  border-bottom-color: var(--color-text-primary);
}

/* On a phone there is no room beside the portrait, so the column is the page
   and the ledger folds to two by two rather than squeezing four across. */
@media (max-width: 860px) {
  .about-col > *,
  .pinned-photo-content .quote-block { max-width: none; }

  /* No margin left to hang the quote mark into: at this width the page edge
     is 20px and the hang is most of it, so the mark sat on the screen edge. */
  .quote-block blockquote { text-indent: 0; }

  .stats-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    row-gap: clamp(24px, 4vh, 40px);
  }

  .stats-row .stat { padding: 0 0 0 clamp(14px, 4vw, 22px); }
  .stats-row .stat:nth-child(odd) { padding-left: 0; border-left: none; }
}

/* ---- THE CASE PANEL'S TWO LINKS ------------------------------------------

   They are the only things on this page a reader can follow to see the actual
   deliverables, and as outlined ghosts on a near-white panel they read as
   disabled. Filled in the page's ink they are the first thing the eye finds in
   the panel, which is right: the argument is made, these are the proof.
--------------------------------------------------------------------------- */

.miller-case .at-button {
  background: #222;
  color: #f4f4f1;
  border-color: #222;
}

.miller-case .at-button:hover,
.miller-case .at-button:focus-visible {
  /* Into the accent rather than out to an outline, so the hover is a step up
     in presence and not a step down into the panel. */
  background: var(--color-accent);
  border-color: var(--color-accent);
  color: #10231f;
}

/* ---- THE COPY WAITS ITS TURN ---------------------------------------------

   A project's name is always readable. Everything else on the card, the
   discipline line, the credits, the description, the case study's eyebrow and
   its address, waits at 15% until the mark reaches that card, and comes up as
   it arrives. The row then reads as one thing being presented at a time rather
   than four finished cards sitting there at once.

   `is-visited` is set by the section acts in tangun-ca_hero3d.js off the same
   turn-taking that already drives the callouts and the packaging crossfade, so
   the copy follows the mark exactly.

   GATED ON .pointer-live, AND THAT MATTERS. No WebGL, a phone, or reduced
   motion means there is no mark and no turn will ever come, so the copy has to
   be at full strength from the start. Dimming it unconditionally would leave
   those readers with cards they cannot read at all.
--------------------------------------------------------------------------- */

.pointer-live .hover-card .pack-subtitle,
.pointer-live .hover-card .project-tags,
.pointer-live .hover-card .project-detail,
.pointer-live .hover-card .case-eyebrow,
.pointer-live .hover-card .case-domain {
  opacity: 0.15;
  transition: opacity 0.55s var(--ease-quart-out);
}

.pointer-live .hover-card.is-visited .pack-subtitle,
.pointer-live .hover-card.is-visited .project-tags,
.pointer-live .hover-card.is-visited .project-detail,
.pointer-live .hover-card.is-visited .case-eyebrow,
.pointer-live .hover-card.is-visited .case-domain {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .pointer-live .hover-card .pack-subtitle,
  .pointer-live .hover-card .project-tags,
  .pointer-live .hover-card .project-detail,
  .pointer-live .hover-card .case-eyebrow,
  .pointer-live .hover-card .case-domain { opacity: 1; transition: none; }
}

/* ---- THE FOOTER ON THE PRESS ---------------------------------------------

   See THE FOOTER GOES THROUGH THE PRESS TOO in tangun-ca_code.JS for what
   drives these. Every fallback here is the colour the footer used before, so
   with no JS at all the section is exactly the light page it always was.

   The section is taller than a screen now. The run needs travel to happen in,
   and the landing that follows it needs to happen on the finished colour; at
   exactly 100vh the two were fighting over the same quarter of a screen and
   the plates would have strobed past in five wheel notches.
--------------------------------------------------------------------------- */

/* THE SECTION'S HEIGHT IS NOT MINE TO CHANGE. It is 100vh, set where it always
   was, and the run is fitted into the travel that gives it rather than the
   other way round. An earlier pass made this taller to buy the plates more
   room; Akin asked for a background colour, not a longer footer. */
.At-Contact-section {
  background: var(--foot-wash, #f4f4f4);
}

.contact-name { color: var(--foot-ink, #222); }
.contact-location,
.contact-email { color: var(--foot-ink-2, #333); }
.contact-copyright { color: var(--foot-ink-3, #777); }

/* The logo is dark artwork. Same crossfade as the two fixed corner pieces:
   brightness(0) takes it to black, invert() takes it to white, and the pair
   driven together goes from the artwork to a white version of itself. It is
   nearly transparent while the mark is live and about to replace it, so this
   is mostly for the readers who never get a mark at all. */
.contact-logo img {
  filter: brightness(calc(1 - var(--foot-dark, 0)))
    invert(var(--foot-dark, 0));
}


/* ============================================================================
   THE SHOWCASE: ONE PROJECT PER SECTION (2026-10-05)

   Replaces the three-card rows. A section is a tall track with one stage held
   in it; the tags arrive with the scroll, the picture changes in step, and a
   box in the bottom right corner holds the details and the way on.

   TWO STATES, AND THE DEFAULT IS THE PLAIN ONE. Everything up to the
   `.is-live` rules is the stacked layout: a strip of pictures, every tag
   shown, the box open in the flow. That is what a phone gets, and what a page
   with no script gets. NikaPort_showcase() adds `.is-live` at 991px and up,
   and only then does the stage pin and anything wait to be revealed. Nothing
   here is hidden by a rule the script is not there to undo.

   The old card rules (#selected-works .hover-card and the rest) are still in
   this file and match nothing now. They are left because the Digital Branding
   section is coming back and still uses them.
   ============================================================================ */

.showcase {
  position: relative;
  background: var(--color-bg);
  color: var(--color-text-primary);
}

.showcase-stage {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 22px;
  padding: 84px 20px 44px;
  box-sizing: border-box;
}

/* The rail belongs to the pinned layout only. */
.showcase .section-headline { display: none; }

.showcase-title h2 {
  font-family: var(--font-serif);
  font-size: clamp(28px, 2.5vw, 40px);
  font-weight: 400;
  line-height: 1.08;
  letter-spacing: 0.2px;
  color: var(--color-text-primary);
}

.showcase-title p {
  padding-top: 8px;
  font-family: var(--font-sans);
  font-size: 15px;
  font-weight: 300;
  line-height: 1.45;
  color: var(--color-text-secondary);
}

/* ---- the pictures -------------------------------------------------------- */

.showcase-media {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  margin: 0 -20px;
  padding: 0 20px;
  scrollbar-width: none;
}
.showcase-media::-webkit-scrollbar { display: none; }

.showcase-shot {
  flex: 0 0 86%;
  width: 86%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  border-radius: 6px;
  scroll-snap-align: center;
  background: var(--color-bg-raised);
}

.showcase-shot--logo {
  object-fit: contain;
  background: transparent;
}

.showcase--video .showcase-shot {
  flex-basis: 100%;
  width: 100%;
  aspect-ratio: 16 / 9;
}

/* THE REEL (Reveal Box): several clips instead of one film. An upright or
   square clip sits in a frame and is shown whole, with a small label under it
   saying what it is; in the case of HUMAN ONE, whose it is. */
.showcase--reel .showcase-media { align-items: center; }
.showcase--reel video.showcase-shot { aspect-ratio: 16 / 9; }

.showcase-shot--frame {
  flex: 0 0 auto;
  width: auto;
  aspect-ratio: auto;
  display: flex;
  gap: 10px;
  background: none;
  border-radius: 0;
}
.show-clip { position: relative; }
.show-clip video {
  display: block;
  height: auto;
  object-fit: cover;
  border-radius: 6px;
  background: #111;
}
/* Sized by width, so that two upright clips side by side are never wider
   than the pictures they share the strip with. */
.show-clip--tall video { aspect-ratio: 9 / 16; width: min(41vw, 230px); }
.show-clip--square video { aspect-ratio: 1; width: min(74vw, 400px); }
.show-clip__label {
  display: block;
  padding-top: 8px;
  font-family: var(--font-sans);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  line-height: 1.4;
  /* As wide as its clip and no wider: a long label wraps under the clip
     instead of pushing the next one along the strip. */
  width: 0;
  min-width: 100%;
  box-sizing: border-box;
  color: var(--color-text-secondary);
}

/* ---- the tags ------------------------------------------------------------ */

.showcase-tags {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0;
}

/* Not boxed (Akin, 2026-10-05). In the stacked layout they are a plain list,
   one hairline between each. */
.show-tag {
  display: block;
  padding: 13px 0 14px;
  border-top: 1px solid rgba(34, 34, 34, 0.16);
}

.show-tag strong {
  display: block;
  font-family: var(--font-serif);
  font-size: 21px;
  font-weight: 400;
  line-height: 1.12;
  color: var(--color-text-primary);
}

.show-tag strong b {
  font-weight: 700;
  color: #2f8f97; /* the accent, taken dark enough to read as text on paper */
}

.show-tag > span,
.show-tag > a {
  display: block;
  padding-top: 4px;
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 300;
  line-height: 1.4;
  color: var(--color-text-secondary);
}

/* THE ONE TAG THAT GOES SOMEWHERE, and it says where before it is pressed.

   A small white button carrying Google's own G, in Google's own colours: the
   one place on this page a third party's mark is doing the persuading. The
   claim beside it is "see it in the wild", and the G is the reader's proof
   that what they are about to see is not ours.

   It stays quiet by being small and white on paper, the size of a line of
   small type with a hairline round it. The colour is all in the 16px mark,
   and nothing moves until it is under the cursor. */
.show-tag > a.show-tag__google {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 9px;
  padding: 7px 11px 7px 9px;
  border: 1px solid rgba(34, 34, 34, 0.22);
  border-radius: 2px;
  background: #fff;
  color: #222;
  font-family: var(--font-sans);
  font-size: 12.5px;
  font-weight: 400;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  transition: border-color 0.3s var(--ease-quart-out), box-shadow 0.3s var(--ease-quart-out),
    transform 0.4s var(--ease-expo-out);
}
.show-tag__google .g-mark {
  display: block;
  flex: none;
  width: 16px;
  height: 16px;
}
.show-tag__google .g-out {
  color: #6f6f6f;
  transition: transform 0.3s var(--ease-quart-out), color 0.3s var(--ease-quart-out);
}
.show-tag > a.show-tag__google:hover,
.show-tag > a.show-tag__google:focus-visible {
  border-color: #222;
  box-shadow: 0 4px 14px rgba(34, 34, 34, 0.1);
  transform: translateY(-1px);
}
.show-tag__google:hover .g-out,
.show-tag__google:focus-visible .g-out {
  color: #222;
  transform: translate(2px, -2px);
}
.show-tag > a.show-tag__google:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 3px; }

/* ---- the box in the corner ------------------------------------------------ */

.showcase-info {
  background: #f4f4f4;
  border: 1px solid #333;
  border-radius: 2px;
  color: #222;
}

.showcase-info__head {
  position: relative;
  display: block;
  width: 100%;
  margin: 0;
  padding: 13px 46px 13px 16px;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: default;
}

.showcase-info__name {
  display: block;
  font-family: var(--font-serif);
  font-size: 21px;
  line-height: 1.1;
}

.showcase-info__role {
  display: block;
  padding-top: 4px;
  font-family: var(--font-sans);
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.06em;
  line-height: 1.35;
  text-transform: uppercase;
}

/* A plus that turns into a minus as the box opens. Only drawn where the box
   actually opens and closes. */
.showcase-info__icon {
  display: none;
  position: absolute;
  right: 16px;
  top: 50%;
  width: 14px;
  height: 14px;
  margin-top: -7px;
}
.showcase-info__icon::before,
.showcase-info__icon::after {
  content: "";
  position: absolute;
  left: 0;
  top: 6.5px;
  width: 14px;
  height: 1px;
  background: currentColor;
  transition: transform 0.45s var(--ease-expo-out);
}
.showcase-info__icon::after { transform: rotate(90deg); }

.showcase-info__body { display: grid; grid-template-rows: 1fr; }
.showcase-info__inner {
  min-height: 0;
  overflow: hidden;
}
.showcase-info__inner > :first-child { border-top: 1px solid rgba(34, 34, 34, 0.18); }

.showcase-info__facts {
  margin: 0;
  padding: 12px 16px 2px;
}
.showcase-info__facts > div {
  display: grid;
  grid-template-columns: 92px 1fr;
  gap: 10px;
  padding: 3px 0;
}
.showcase-info__facts dt {
  font-family: var(--font-sans);
  font-size: 10.5px;
  letter-spacing: 0.08em;
  line-height: 1.7;
  text-transform: uppercase;
  color: #6f6f6f;
}
.showcase-info__facts dd {
  margin: 0;
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 300;
  line-height: 1.4;
  color: #222;
}

.showcase-info__case {
  display: inline-block;
  margin: 6px 16px 0;
  font-family: var(--font-sans);
  font-size: 13px;
  color: #222;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}
.showcase-info__case::after { content: " \2192"; }
.showcase-info__case:hover,
.showcase-info__case:focus-visible { color: #2f8f97; }

.showcase-info__label {
  padding: 16px 16px 8px;
  font-family: var(--font-sans);
  font-size: 10.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #6f6f6f;
}

.showcase-info__others {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  padding: 0 16px;
}
.showcase-info__others a {
  display: block;
  border: 1px solid rgba(34, 34, 34, 0.28);
  border-radius: 2px;
  background: #fbfbfa;
  color: #222;
  text-decoration: none;
  overflow: hidden;
  transition: border-color 0.3s var(--ease-quart-out);
}
.showcase-info__others img {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  background: #fff;
  transition: transform 0.6s var(--ease-expo-out);
}
/* The two brand marks are cut-outs, not photographs: shown whole. */
#selected-works .showcase-info__others img { object-fit: contain; padding: 6px; box-sizing: border-box; }
.showcase-info__others span {
  display: block;
  padding: 6px 8px 7px;
  border-top: 1px solid rgba(34, 34, 34, 0.16);
  font-family: var(--font-sans);
  font-size: 11.5px;
  line-height: 1.25;
}
.showcase-info__others a:hover,
.showcase-info__others a:focus-visible { border-color: #222; }
.showcase-info__others a:hover img { transform: scale(1.05); }

.showcase-info__all {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 46px;
  margin: 14px 16px 16px;
  padding: 0 16px;
  border: 1px solid #222;
  border-radius: 2px;
  background: #222;
  color: #f4f4f4;
  font-family: var(--font-sans);
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color 0.3s var(--ease-quart-out), color 0.3s var(--ease-quart-out);
}
.showcase-info__all::after {
  content: "\2192";
  margin-left: 10px;
  transition: transform 0.3s var(--ease-quart-out);
}
.showcase-info__all:hover,
.showcase-info__all:focus-visible { background: #f4f4f4; color: #222; }
.showcase-info__all:hover::after { transform: translateX(4px); }
.showcase-info a:focus-visible,
.showcase-info__head:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }

/* ---- the sound button ------------------------------------------------------

   Loud while the film is silent, because the film is half its sound and
   nobody turns on what they have not noticed. Once it is on, the button has
   done its job and shrinks to a small mark in the corner. */

.showcase-sound {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  height: 48px;
  padding: 0 20px 0 14px;
  border: 1px solid #222;
  border-radius: 24px;
  background: #f4f4f4;
  color: #222;
  font-family: var(--font-sans);
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color 0.3s var(--ease-quart-out), color 0.3s var(--ease-quart-out),
    opacity 0.4s var(--ease-quart-out), padding 0.4s var(--ease-expo-out);
}
.showcase-sound:hover { background: #222; color: #f4f4f4; }
.showcase-sound:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 3px; }

.showcase-sound__icon {
  position: relative;
  display: block;
  width: 22px;
  height: 22px;
}
.showcase-sound__icon svg { display: block; width: 22px; height: 22px; }
.showcase-sound .snd-body { fill: currentColor; }
.showcase-sound .snd-wave,
.showcase-sound .snd-off {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
}
.showcase-sound .snd-wave { display: none; }

/* The ring that asks for the click. Two slow pulses, then it rests and
   comes round again: a nudge, not an alarm. */
.showcase-sound__icon::after {
  content: "";
  position: absolute;
  inset: -9px;
  border: 1px solid currentColor;
  border-radius: 50%;
  opacity: 0;
  animation: showcase-sound-ring 3.2s var(--ease-quart-out) infinite;
}
@keyframes showcase-sound-ring {
  0% { opacity: 0.7; transform: scale(0.6); }
  45% { opacity: 0; transform: scale(1.5); }
  100% { opacity: 0; transform: scale(1.5); }
}

.showcase-sound.is-on {
  padding: 0 13px;
  opacity: 0.5;
}
.showcase-sound.is-on:hover,
.showcase-sound.is-on:focus-visible { opacity: 1; }
.showcase-sound.is-on .showcase-sound__label {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
}
.showcase-sound.is-on .snd-wave { display: block; }
.showcase-sound.is-on .snd-off { display: none; }
.showcase-sound.is-on .showcase-sound__icon::after { animation: none; }

/* ============================================================================
   LIVE: the stage pins and the scroll presents the project.
   ============================================================================ */

/* #portfolio-root in the selector on purpose: the old card layout set these
   sections' heights by id (#selected-works { min-height: 300vh }), and those
   rules are still in the file. */
#portfolio-root .showcase.is-live {
  /* One screen to arrive, a third of a screen for each tag, and most of a
     screen with the box open before the section lets go. */
  min-height: calc(170vh + var(--steps, 5) * 34vh);
}

.showcase.is-live .showcase-stage {
  position: sticky;
  top: 0;
  display: block;
  height: 100vh;
  padding: 0;
  overflow: hidden;
}

/* THE RAIL IS THE SECTION'S NAME (Akin, 2026-10-05): the side headline with
   its two lines, on every section. The header and sub copy that briefly sat
   top left are not shown here; they exist only for the stacked layout. */
.showcase.is-live .section-headline {
  display: flex;
  position: absolute;
  z-index: 5;
  left: 0;
  top: 0;
  height: 100%;
}

.showcase.is-live .showcase-title { display: none; }

/* On a picture the rail goes white with everything else that is read there. */
/* #portfolio-root again, for the same reason as the height: Motion Branding's
   rail was coloured by id from the ink run it used to have. */
#portfolio-root .showcase--full.is-live .headline-clip h2 {
  color: #fff;
  text-shadow: 0 1px 14px rgba(0, 0, 0, 0.45);
}
#portfolio-root .showcase--full.is-live .gradient-line { background-color: rgba(255, 255, 255, 0.75); }

/* ---- live, centre: the logo and its ring of tags --------------------------- */

.showcase--center.is-live .showcase-media {
  position: absolute;
  left: 50%;
  top: 50%;
  display: block;
  width: min(51.2vh, 44vw);
  height: 32vh;
  margin: 0;
  padding: 0;
  overflow: visible;
  transform: translate(-50%, -50%);
}

.showcase.is-live .showcase-shot {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  aspect-ratio: auto;
  opacity: 0;
  transform: scale(0.965);
  transition: opacity 0.6s var(--ease-quart-out), transform 0.9s var(--ease-expo-out);
}
.showcase.is-live .showcase-shot.is-on {
  opacity: 1;
  transform: none;
}

/* The section opens on this: the logo alone, in the middle. Akin asked for
   20vh and then for a quarter more, because the artwork is a cut-out with
   empty space round it and at 20vh the logo itself read small.

   The quarter more did nothing he could see, because the file was still 45%
   air top and bottom: 25vh of file was 14vh of logo. The picture is now a
   copy trimmed to the artwork (Logo-SutasAyran-Trimmed.png), so this height
   is the height of the logo itself. */
.showcase--center.is-live .showcase-shot--logo {
  inset: auto;
  left: 50%;
  top: 50%;
  width: auto;
  height: 25vh;
  transform: translate(-50%, -50%) scale(0.965);
}
.showcase--center.is-live .showcase-shot--logo.is-on {
  transform: translate(-50%, -50%);
}

.showcase--center.is-live .showcase-shot:not(.showcase-shot--logo) {
  box-shadow: 0 18px 50px rgba(34, 34, 34, 0.12);
}

.showcase--center.is-live .showcase-tags { display: block; }

/* --x and --y are the tag's place on the ring, written by the script from its
   data-angle. --dx and --dy are a short step back toward the middle, so a tag
   arrives by moving out from the logo it is about. */
.showcase--center.is-live .show-tag {
  position: absolute;
  left: calc(50% + var(--x, 0px));
  top: calc(50% + var(--y, 0px));
  width: max-content;
  max-width: min(248px, 19vw);
  padding: 0;
  border: 0;
  opacity: 0;
  visibility: hidden;
  /* --ax is which edge of the tag sits on the ring: its inner edge for a tag
     to the left or the right, so the words run away from the picture and
     never over it, and its middle for one above or below. */
  transform: translate(calc(var(--ax, -50%) + var(--dx, 0px)), calc(-50% + var(--dy, 0px)));
  transition: opacity 0.5s var(--ease-quart-out), transform 0.8s var(--ease-expo-out),
    visibility 0s linear 0.5s;
}
.showcase--center.is-live .show-tag.is-on {
  opacity: 1;
  visibility: visible;
  transform: translate(var(--ax, -50%), -50%);
  transition: opacity 0.5s var(--ease-quart-out), transform 0.8s var(--ease-expo-out),
    visibility 0s;
}
.showcase--center.is-live .show-tag[data-side="left"] { text-align: right; }
.showcase--center.is-live .show-tag[data-side="right"] { text-align: left; }
.showcase--center.is-live .show-tag[data-side="mid"] { text-align: center; }
.showcase--center.is-live .show-tag strong { font-size: clamp(21px, 1.75vw, 27px); }

/* ---- live, full: the picture is the window --------------------------------- */

.showcase--full.is-live { background: #1a1a17; }

.showcase--full.is-live .showcase-media {
  position: absolute;
  inset: 0;
  display: block;
  margin: 0;
  padding: 0;
  overflow: hidden;
}

.showcase--full.is-live .showcase-shot {
  border-radius: 0;
  object-fit: cover;
  transform: scale(1.03);
  transition: opacity 0.9s var(--ease-quart-out), transform 1.6s var(--ease-expo-out);
}
.showcase--full.is-live .showcase-shot.is-on { transform: none; }

/* The reel's framed clips: whole, side by side, standing on the dark stage
   above the caption. The frame keeps to the top three quarters of the window
   so the labels under the clips clear the caption in the bottom left. */
.showcase--reel.is-live .showcase-shot--frame {
  inset: 7vh 0 auto 0;
  height: 72vh;
  justify-content: center;
  gap: 2.6vh;
}
.showcase--reel.is-live .show-clip { height: 100%; }
.showcase--reel.is-live .show-clip video {
  width: auto;
  height: 100%;
  border-radius: 4px;
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.5);
}
.showcase--reel.is-live .show-clip__label {
  position: absolute;
  left: 0;
  top: 100%;
  width: auto;
  min-width: 0;
  padding-top: 12px;
  white-space: nowrap;
  color: rgba(255, 255, 255, 0.72);
}

/* THE TAGS ARE NOT BOXED (Akin, 2026-10-05): white copy, straight on the
   picture. What keeps it readable on a pale picture is not a box but a soft
   shade laid into the bottom left corner of the stage, under the copy and
   over the picture, plus a shadow on the letters themselves. On a dark frame
   neither is visible; on a pale one they are the difference. */
.showcase--full.is-live .showcase-stage::after {
  content: "";
  position: absolute;
  z-index: 2;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(120% 90% at 0% 100%, rgba(18, 18, 16, 0.5) 0%, rgba(18, 18, 16, 0.22) 34%, rgba(18, 18, 16, 0) 62%),
    linear-gradient(90deg, rgba(18, 18, 16, 0.3) 0, rgba(18, 18, 16, 0) 130px);
}

/* Stacked in the bottom left, clear of the mail icon and well away from the
   middle of the picture, which is where the work is. */
.showcase--full.is-live .showcase-tags {
  position: absolute;
  z-index: 5;
  left: 98px;
  bottom: clamp(20px, 2.8vw, 34px);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 16px;
  width: min(360px, 30vw);
}
.showcase--full.is-live .show-tag {
  padding: 0;
  border: 0;
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px);
  text-shadow: 0 1px 18px rgba(0, 0, 0, 0.55), 0 0 2px rgba(0, 0, 0, 0.35);
  transition: opacity 0.5s var(--ease-quart-out), transform 0.8s var(--ease-expo-out),
    visibility 0s linear 0.5s;
}
.showcase--full.is-live .show-tag.is-on {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity 0.5s var(--ease-quart-out), transform 0.8s var(--ease-expo-out),
    visibility 0s;
}
.showcase--full.is-live .show-tag strong { color: #fff; }
.showcase--full.is-live .show-tag > span {
  font-size: 13.5px;
  font-weight: 400;
  color: rgba(255, 255, 255, 0.92);
}
/* One caption at a time: they all stand on the same spot and take turns. */
.showcase--single.is-live .showcase-tags { display: block; height: 72px; }
.showcase--single.is-live .show-tag {
  position: absolute;
  left: 0;
  bottom: 0;
  width: max-content;
  max-width: 100%;
}
.showcase--full.is-live .show-tag strong { font-size: clamp(22px, 1.9vw, 28px); }

.showcase.is-live .showcase-sound {
  position: absolute;
  z-index: 6;
  top: 26px;
  right: clamp(16px, 2.5vw, 36px);
}

/* ---- live: the box ---------------------------------------------------------

   Closed, it is a bar a fifth of the window wide that looks like the button
   it replaced. It opens under the cursor, on focus, on a click, and by itself
   as the section is about to leave (`.is-open`, set by the script). */

.showcase.is-live .showcase-info {
  position: absolute;
  z-index: 60;
  right: clamp(16px, 2.5vw, 36px);
  bottom: clamp(16px, 2.5vw, 28px);
  width: max(20vw, 264px);
  box-shadow: 0 6px 24px rgba(34, 34, 34, 0.08);
  opacity: 0;
  visibility: hidden;
  transform: translateY(10px);
  transition: opacity 0.4s var(--ease-quart-out), transform 0.5s var(--ease-expo-out),
    visibility 0s linear 0.4s;
}
.showcase.is-live.has-info .showcase-info {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity 0.4s var(--ease-quart-out), transform 0.5s var(--ease-expo-out),
    visibility 0s;
}

.showcase.is-live .showcase-info__head {
  cursor: pointer;
  transition: background-color 0.3s var(--ease-quart-out), color 0.3s var(--ease-quart-out);
}
.showcase.is-live .showcase-info__icon { display: block; }

.showcase.is-live .showcase-info__body {
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.6s var(--ease-expo-out);
}
.showcase.is-live .showcase-info__inner {
  visibility: hidden;
  transition: visibility 0s linear 0.6s;
}

/* The bar reverses out like every other button on the page, and stays
   reversed for as long as the box is open, so it reads as the pressed tab of
   what is showing under it. */
.showcase.is-live .showcase-info__head:hover,
.showcase.is-live .showcase-info:hover .showcase-info__head,
.showcase.is-live .showcase-info:focus-within .showcase-info__head,
.showcase.is-live .showcase-info.is-open .showcase-info__head {
  background: #222;
  color: #f4f4f4;
}

.showcase.is-live .showcase-info:hover .showcase-info__body,
.showcase.is-live .showcase-info:focus-within .showcase-info__body,
.showcase.is-live .showcase-info.is-open .showcase-info__body {
  grid-template-rows: 1fr;
}
.showcase.is-live .showcase-info:hover .showcase-info__inner,
.showcase.is-live .showcase-info:focus-within .showcase-info__inner,
.showcase.is-live .showcase-info.is-open .showcase-info__inner {
  visibility: visible;
  transition: visibility 0s;
}
.showcase.is-live .showcase-info:hover .showcase-info__icon::after,
.showcase.is-live .showcase-info:focus-within .showcase-info__icon::after,
.showcase.is-live .showcase-info.is-open .showcase-info__icon::after {
  transform: rotate(0deg);
}

@media (prefers-reduced-motion: reduce) {
  .showcase .showcase-shot,
  .showcase .show-tag,
  .showcase .showcase-info,
  .showcase .showcase-info__body,
  .showcase .showcase-sound { transition-duration: 0.01s !important; }
  .showcase-sound__icon::after { animation: none; }
}


/* ============================================================================
   THE PHONE LAYOUT, REDESIGNED (2026-10-06)

   Akin: "Mobile for Tangun is terrible. Redesign completely." What was wrong,
   read off the screen: a hero that opened on a blank sheet and then a blank
   screen; the logo and the mail icon floating over the copy all the way down;
   the About copy set across his face; and every project as a strip of small
   pictures over a list of small type.

   So below 991px the page is its own layout, not the desktop one folded up:

     THE BAR      the logo and the mail icon live in a bar across the top, on
                  paper, and nothing sits over the copy any more
     THE HERO     the drawing is a stage held under the bar while the three
                  beats are read beneath it, one to a screen, so the sketch,
                  the mark and the words are on screen together
     THE ABOUT    the portrait is a picture with the statement under it,
                  not a backdrop with the statement over it
     THE WORK     each project opens on its picture edge to edge, with its
                  name over it; the points read as a list at reading size;
                  the details are a dark card with the way on

   Everything here is inside one media query at the end of the file, so it
   wins over the older phone rules above without having to hunt them down,
   and the desktop layout cannot be touched by it. The 3D mark joins from the
   About block down: see THE PHONE'S OWN POINTER in tangun-ca_hero3d.js.
   ============================================================================ */

@media (max-width: 990px) {
  :root { --m-bar: 54px; --m-edge: 22px; }

  /* ---- the header: nothing but the mail icon ---------------------------------
     Akin, 2026-10-06 (second round): "I want transparent header, no need the
     logo at header in mobile since 3D logo is at play." So there is no bar
     and no logo. The mail icon stays, top right, and is drawn in difference
     against whatever is under it, so it reads on paper, on ink and on a
     picture without anything having to tell it which it is on. */
  .fixed-logo { display: none; }
  .fixed-email {
    top: 2px;
    right: 8px;
    bottom: auto;
    left: auto;
    width: 52px;
    height: 52px;
    transform: none !important;
    mix-blend-mode: difference;
  }
  .fixed-email img {
    width: 28px;
    height: auto;
    filter: brightness(0) invert(1) !important;
  }

  /* ---- the hero: THE SAME HERO AS THE DESKTOP, stood on its end --------------
     Akin, same round: "I want full conceptual copy of desktop like how it
     starts, how copy is inside the paper and sketch turns to 3D logo."

     So the phone no longer has a hero of its own. The scripts run exactly
     what they run on a wide screen: the boxed sheet that opens as the pencil
     works, the sketch, the flat mark, the press run, the extrusion in real
     3D, the underline, the handover. All that changes here is where things
     stand. Side by side becomes one above the other in the same screen: the
     drawing in the upper half, the words held in the lower half, both inside
     the sheet. Copy and visual share one grid cell, so the visual is held
     behind the copy for the whole hero exactly as its column is on desktop.

     The mark is 36vh tall here, not 65: MARK_VH in tangun-ca_hero3d.js is the
     same number and the two must move together. */
  .hero-section {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
  }
  .hero-content,
  .hero-holder { grid-area: 1 / 1; }
  .hero-holder {
    width: 100%;
    height: 100vh;
    padding: 12vh 0 0;
    align-self: start;
    justify-content: flex-start;
  }
  .hero-sketch-image,
  .hero-fill-img,
  .hero-mark-shadow { margin-right: 0; }
  .hero-sketch-image .sketch-art,
  .hero-fill-img img,
  .hero-mark-shadow img { height: 36vh; }
  .hero-mark-shadow img { padding-left: 0; padding-right: 0; }
  .hero-background { top: 0; left: 0; margin-left: 0; }
  /* The words of the first two beats leave upward THROUGH the drawing, which
     on a wide screen is beside them and here is above them. They are faded
     out as they reach it (--beat-fade, written by NikaPort_phoneBeatFade), so
     copy never crosses the sketch or the solid. The last beat is left alone:
     by then the mark is a cursor and there is nothing up there to cross. */
  .hero-content .beat--sketch .beat-pin,
  .hero-content .beat--mark .beat-pin { opacity: var(--beat-fade, 1); }
  /* NO SHEET OPENING ON A PHONE (Akin, 2026-10-06): the paper is the whole
     screen from the first frame. NikaPort_paperInset() returns zero here, and
     this is the same answer for the frame before the script runs. */
  .hero-background { clip-path: none; }

  .hero-content {
    width: 100%;
    padding-left: 0;
    padding-right: 0;
  }
  .hero-content .beat,
  .hero-content .beat--wide {
    width: auto;
    max-width: none;
    margin-left: 0;
    margin-right: 0;
    padding-left: 11vw;
    padding-right: 11vw;
    text-align: center;
  }
  /* The words are held in the lower half, under the drawing. */
  .hero-content .beat .beat-pin {
    top: 73vh;
    max-width: none;
    margin-left: auto;
    margin-right: auto;
    text-align: center;
  }
  /* EXCEPT THE LAST BEAT, which is held in the middle of the screen (Akin,
     2026-10-06: "A mark is not a brand. titled section is not centered
     vertically"). By the time it is read the mark has shrunk to a cursor and
     come down to underline it, so there is no drawing above it to leave room
     for, and the words have the screen to themselves. */
  .hero-content .beat--system .beat-pin {
    top: 50vh;
    transform: translateY(-50%);
  }
  .hero-content .beat h2 {
    max-width: none;
    font-size: clamp(32px, 9.4vw, 46px);
    line-height: 1;
    letter-spacing: -0.02em;
    text-align: center;
  }
  .hero-content .beat p {
    max-width: 31ch;
    margin-left: auto;
    margin-right: auto;
    font-size: 15.5px;
    line-height: 1.5;
    text-align: center;
  }

  /* ---- the About: a portrait, then the statement ----------------------------- */

  .pinned-photo-block {
    display: block;
    background: #1a1a17;
  }
  .pinned-photo-visual {
    position: relative;
    top: auto;
    height: 62vh;
    height: 62svh;
    overflow: hidden;
  }
  .pinned-photo-visual img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: 62% 12%;
  }
  /* The picture runs out into the dark the copy stands on. */
  .pinned-photo-visual::after {
    content: "";
    position: absolute;
    inset: auto 0 0 0;
    height: 46%;
    background: linear-gradient(180deg, rgba(26, 26, 23, 0) 0%, #1a1a17 92%);
    pointer-events: none;
  }
  .pinned-photo-content {
    position: relative;
    margin-top: -9vh;
    padding: 0 0 72px;
    background: none;
  }
  .pinned-photo-content::before,
  .pinned-photo-content::after { display: none; }
  .pinned-photo-content .about-col {
    padding: 0 var(--m-edge);
    margin: 0;
  }
  .pinned-photo-content .quote-block blockquote {
    font-size: clamp(36px, 10.6vw, 50px);
    line-height: 1;
    max-width: none;
  }
  .pinned-photo-content .quote-block cite {
    max-width: 36ch;
    font-size: 16.5px;
    line-height: 1.6;
  }
  .pinned-photo-content .stats-row {
    margin: 44px var(--m-edge) 0;
    padding: 0;
  }

  /* ---- the work: one project to a section -----------------------------------
     Akin, 2026-10-06 (second round):
       "section videos can be full screen and the content starts from bottom
        when we scroll while the full height video is sticky"
       "Images like sutas can be sticky on top while copy scrolls bottom
        behind and project images change on sticky part"
       "Packaging design section can be full screen changing images and copy
        scrolls"
       "black boxes on light backgrounds too much contrast... keep the outline
        if necessary, low opacity light bg could work"

     So there are two shapes. A --full section (Motion, Reveal Box, Packaging)
     holds its picture or film the full height of the screen and the words
     travel up over it, one caption at a time, in white. The --center section
     (Sütaş) holds its picture across the top and the words pass up behind
     it. In both, WHICH picture is up follows the caption being read:
     NikaPort_showcase() does that on a phone too now (`.is-phone`), from
     where the captions are on the screen rather than from a pinned track.

     Until the script has said so (.is-phone), every picture is simply
     stacked and the last one shows, so nothing is hidden waiting for it. */

  .showcase { padding: 0; border: 0; }
  .showcase-stage { display: block; position: relative; padding: 0; gap: 0; }

  .showcase-media {
    position: sticky;
    top: 0;
    z-index: 1;
    display: block;
    height: 100vh;
    height: 100svh;
    margin: 0;
    padding: 0;
    overflow: hidden;
    background: #1a1a17;
  }
  .showcase-shot,
  .showcase--video .showcase-shot,
  .showcase--reel video.showcase-shot {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    aspect-ratio: auto;
    object-fit: cover;
    border-radius: 0;
    transition: opacity 0.7s var(--ease-quart-out);
  }
  .showcase.is-phone .showcase-shot:not(.is-on) { opacity: 0; }

  /* ---- full: the picture is the screen, the words go up over it -------------- */

  /* A column, so that the section's name can come AFTER the picture although
     it is written before it: it stands on the foot of the first screen, and
     pulled up from above the picture it landed on the section before. */
  .showcase--full .showcase-stage {
    display: flex;
    flex-direction: column;
    background: #1a1a17;
    padding-bottom: 16vh;
  }
  .showcase--full .showcase-media { order: 1; flex: none; }
  .showcase--full .showcase-title { order: 2; }
  .showcase--full .showcase-sound { order: 3; }
  .showcase--full .showcase-tags { order: 4; }
  .showcase--full .showcase-info { order: 5; }
  /* A shade in the lower half, which is where the words are read. */
  .showcase--full .showcase-media::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: linear-gradient(180deg, rgba(18, 18, 16, 0.28) 0%, rgba(18, 18, 16, 0) 22%, rgba(18, 18, 16, 0) 46%, rgba(18, 18, 16, 0.62) 100%);
  }
  .showcase--full .showcase-title,
  .showcase--full .showcase-sound,
  .showcase--full .showcase-tags,
  .showcase--full .showcase-info { position: relative; z-index: 2; }

  /* The section's name stands at the foot of the first screen, on the film. */
  .showcase--full .showcase-title {
    margin-top: -40vh;
    padding: 0 var(--m-edge);
  }
  .showcase--full .showcase-title h2 { color: #fff; text-shadow: 0 1px 22px rgba(0, 0, 0, 0.5); }
  .showcase--full .showcase-title p { color: rgba(255, 255, 255, 0.88); text-shadow: 0 1px 14px rgba(0, 0, 0, 0.5); }

  /* The sound button stays in reach for the whole film, top left. */
  .showcase--full .showcase-sound {
    position: sticky;
    top: 10px;
    z-index: 4;
    align-self: flex-start;
    margin: 20px var(--m-edge) 0;
    height: 42px;
  }

  .showcase--full .showcase-tags {
    display: block;
    margin: 34vh var(--m-edge) 0;
    border: 0;
  }
  /* One caption to a screen, with the picture to itself in between. */
  .showcase--full .show-tag {
    margin: 0 0 52vh;
    padding: 0;
    border: 0;
    text-shadow: 0 1px 20px rgba(0, 0, 0, 0.6), 0 0 2px rgba(0, 0, 0, 0.4);
  }
  .showcase--full .show-tag strong { color: #fff; font-size: 30px; line-height: 1.04; }
  .showcase--full .show-tag > span {
    max-width: 30ch;
    padding-top: 8px;
    font-size: 16px;
    font-weight: 400;
    line-height: 1.45;
    color: rgba(255, 255, 255, 0.94);
  }

  /* The reel's upright clips. One fills the screen; two share it, one above
     the other, each with its label in its own corner. */
  .showcase-shot--frame {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 0;
    background: #000;
  }
  .showcase-shot--frame .show-clip { position: relative; flex: 1 1 0; min-height: 0; }
  .showcase-shot--frame .show-clip video,
  .show-clip--tall video,
  .show-clip--square video {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    aspect-ratio: auto;
    object-fit: cover;
    border-radius: 0;
  }
  .show-clip__label {
    position: absolute;
    left: var(--m-edge);
    top: 64px;
    width: auto;
    min-width: 0;
    padding: 5px 9px;
    border-radius: 2px;
    background: rgba(18, 18, 16, 0.55);
    color: rgba(255, 255, 255, 0.92);
    white-space: nowrap;
  }
  .showcase-shot--frame .show-clip + .show-clip .show-clip__label { top: 14px; }
  /* The copy stacks at the top of the screen, so a clip's label goes to the
     foot of its own picture. */
  .showcase-shot--frame .show-clip .show-clip__label,
  .showcase-shot--frame .show-clip + .show-clip .show-clip__label {
    top: auto;
    bottom: 14px;
  }
  /* The Dior preview is two views side by side. Upright, the screen takes the
     left one, the close view of the box, rather than the seam between them. */
  #experiential video.showcase-shot:first-child { object-position: 21% 50%; }

  /* ---- centre: the picture across the top, the words behind it ---------------- */

  .showcase--center .showcase-stage { background: var(--color-bg); padding-bottom: 12vh; }
  .showcase--center .showcase-media {
    z-index: 3;
    height: 46vh;
    height: 46svh;
    background: #fff;
    box-shadow: 0 1px 0 rgba(34, 34, 34, 0.1), 0 18px 40px rgba(34, 34, 34, 0.08);
  }
  .showcase--center .showcase-shot--logo {
    object-fit: contain;
    padding: 9vh 18vw 5vh;
    box-sizing: border-box;
    background: #fff;
  }
  .showcase--center .showcase-title { padding: 40px var(--m-edge) 0; }
  .showcase-title h2 {
    font-size: clamp(34px, 9.6vw, 46px);
    line-height: 1;
    letter-spacing: -0.015em;
  }
  .showcase-title h2 .title-heart { width: 0.62em; height: 0.62em; margin-right: 0.18em; }
  .showcase-title p { padding-top: 12px; font-size: 16.5px; line-height: 1.5; }
  .showcase--center .showcase-tags {
    margin: 30px var(--m-edge) 0;
    border-bottom: 1px solid rgba(34, 34, 34, 0.16);
  }
  .showcase--center .show-tag { padding: 22px 0 24px; }
  .showcase--center .show-tag strong { font-size: 26px; line-height: 1.08; }
  .showcase--center .show-tag > span,
  .showcase--center .show-tag > a { padding-top: 7px; font-size: 16px; line-height: 1.5; }

  /* ---- the details: a pale panel with an outline -------------------------------
     Not a black box. On a picture it is frosted paper; on paper it is barely
     there, an outline and a breath of tone. */
  .showcase-info {
    margin: 0 var(--m-edge);
    border: 1px solid rgba(34, 34, 34, 0.22);
    border-radius: 4px;
    background: rgba(244, 244, 244, 0.86);
    -webkit-backdrop-filter: blur(18px);
    backdrop-filter: blur(18px);
    color: var(--color-text-primary);
    overflow: hidden;
  }
  .showcase--center .showcase-info { margin-top: 34px; background: rgba(255, 255, 255, 0.5); }
  .showcase--full .showcase-info { border-color: rgba(255, 255, 255, 0.5); }
  .showcase-info__head { padding: 20px 20px 16px; }
  .showcase-info__name { font-size: 26px; }
  .showcase-info__inner { padding: 0 20px 20px; }
  .showcase-info__facts dd { font-size: 14.5px; }
  /* "Read the case study" IS THE BUTTON (Akin, 2026-10-06: "should be boxed
     so they are more visible than other buttons of the section"). Filled, in
     the page's own accent, full width; "All ..." under it stays an outline,
     so there is one obvious thing to press and one quieter one. */
  .showcase-info__case {
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 54px;
    margin: 16px 0 4px;
    padding: 0 18px;
    border: 0;
    border-radius: 2px;
    background: #2f8f97;
    color: #fff;
    font-size: 13px;
    font-weight: 500;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    text-decoration: none;
  }
  .showcase-info__case:hover,
  .showcase-info__case:focus-visible { background: #222; color: #fff; }
  .showcase-info__all {
    height: 52px;
    border: 1px solid #222;
    background: transparent;
    color: #222;
    font-size: 12.5px;
  }

  /* ---- the two film sections: the panel is INVERTED ------------------------------
     Akin, 2026-10-06: "Invert the colors of motion and experiential marketing
     section infoboxes. Now it looks contrast on black video bg." A pale panel
     on a near-black film was the loudest thing on the screen. On these two it
     is dark glass with light type and a light outline, so it sits in the film
     instead of on it. Packaging keeps the pale panel: its pictures are light.
     Phone only, like everything in this block. */
  #motion-branding .showcase-info,
  #experiential .showcase-info {
    background: rgba(22, 22, 20, 0.72);
    border-color: rgba(244, 244, 244, 0.3);
    color: #f4f4f4;
  }
  #motion-branding .showcase-info__name,
  #experiential .showcase-info__name { color: #f4f4f4; }
  #motion-branding .showcase-info__role,
  #experiential .showcase-info__role,
  #motion-branding .showcase-info__facts dt,
  #experiential .showcase-info__facts dt,
  #motion-branding .showcase-info__label,
  #experiential .showcase-info__label { color: rgba(244, 244, 244, 0.6); }
  #motion-branding .showcase-info__facts dd,
  #experiential .showcase-info__facts dd { color: #f4f4f4; }
  #motion-branding .showcase-info__inner > :first-child,
  #experiential .showcase-info__inner > :first-child { border-top-color: rgba(244, 244, 244, 0.2); }
  #motion-branding .showcase-info__others a,
  #experiential .showcase-info__others a {
    border-color: rgba(244, 244, 244, 0.24);
    background: rgba(244, 244, 244, 0.06);
    color: #f4f4f4;
  }
  #motion-branding .showcase-info__others span,
  #experiential .showcase-info__others span { border-top-color: rgba(244, 244, 244, 0.18); color: #f4f4f4; }
  #motion-branding .showcase-info__all,
  #experiential .showcase-info__all {
    border-color: rgba(244, 244, 244, 0.7);
    background: transparent;
    color: #f4f4f4;
  }
  #motion-branding .showcase-info__head,
  #experiential .showcase-info__head { background: transparent; color: #f4f4f4; }

  /* ---- full: THE COPY STACKS AT THE TOP (Akin, 2026-10-06) -----------------------
     "They all stay sticky on top one by one while scrolling... I want them to
     be all visible, doesn't matter if it covers the video."

     The film is held behind (rules above). Each piece of copy comes up from
     the bottom and stops under the one before it, and stays: the name, the
     sound button, then each caption. --stick is where a piece stops, written
     by phoneStack() in tangun-ca_code.JS as the sum of the heights above it.

     The captions are list items; the list itself is taken out of the box
     tree (display: contents) so that each item is held by the whole section
     and not by a list that ends where its last item does. */
  .showcase--full.is-phone .showcase-title,
  .showcase--full.is-phone .showcase-sound,
  .showcase--full.is-phone .show-tag,
  .showcase--full.is-phone .showcase-info {
    position: sticky;
    top: var(--stick, 18px);
    z-index: 3;
  }
  .showcase--full.is-phone .showcase-title { margin-top: -30vh; }
  .showcase--full.is-phone .showcase-title h2 { font-size: clamp(28px, 8vw, 38px); }
  .showcase--full.is-phone .showcase-title p { padding-top: 6px; font-size: 14px; }
  .showcase--full.is-phone .showcase-sound { z-index: 4; margin-top: 30vh; }
  .showcase--full.is-phone .showcase-tags { display: contents; }
  .showcase--full.is-phone .show-tag {
    order: 4;
    display: block;
    margin: 44vh var(--m-edge) 0;
    padding: 0;
  }
  /* Smaller than when they had a screen each: they share one now. */
  .showcase--full.is-phone .show-tag strong { font-size: 21px; line-height: 1.08; }
  .showcase--full.is-phone .show-tag > span {
    max-width: none;
    padding-top: 3px;
    font-size: 14px;
    line-height: 1.38;
  }
  .showcase--full.is-phone .showcase-info { margin-top: 46vh; z-index: 5; background: rgba(244, 244, 244, 0.94); }
  .showcase--full.is-phone .showcase-info__others img { aspect-ratio: 16 / 9; }
  /* A spare screen at the foot, which the follower is pulled up over. See
     "WHAT COMES NEXT SLIDES OVER THE STACK" in tangun-ca_code.JS. */
  /* It has to be a real box at the end of the content, not padding: a stuck
     piece is held inside its container's CONTENT, so padding gave the panel,
     the last thing in it, no room to be held at all. */
  .showcase--full.is-phone .showcase-stage { padding-bottom: 0; }
  .showcase--full.is-phone .showcase-stage::after {
    content: "";
    order: 9;
    flex: none;
    height: 100vh;
  }
  .after-held {
    position: relative;
    z-index: 6;
    margin-top: -100vh;
  }

  /* The stack is read at the top now, so that is where the shade goes. */
  .showcase--full.is-phone .showcase-media::after {
    background: linear-gradient(180deg, rgba(18, 18, 16, 0.78) 0%, rgba(18, 18, 16, 0.62) 34%, rgba(18, 18, 16, 0.18) 62%, rgba(18, 18, 16, 0.3) 100%);
  }

  /* ---- the footer ------------------------------------------------------------- */

  /* A full screen, no less: it slides up over the last section's held stack,
     and anything shorter leaves the foot of that stack showing under it. */
  .At-Contact-section { min-height: 100vh; height: auto; }

  /* ---- the 3D pointer --------------------------------------------------------
     The room the desktop opens under each About figure for it is not needed
     here: the figures are a two column grid and it points from beside them. */
  .pointer-live .stats-row .stat-label { margin-top: 8px; }
}
