/*
 * The home page's revamp of 12 October 2026: what is new, kept out of the
 * older stylesheets so that nothing they hold had to be rewritten.
 *
 * Opacity and transform are the only things that move, nothing moves under
 * reduced motion or with the page's own motion switch off
 * (`body[data-motion]`, flagship.js), and everything is whole without a
 * script: a reveal is added to a finished page, never needed by one.
 */

/*
 * Tested, then promised: the workshop, in the workshop's own photographs.
 *
 * Six phone pictures taken on different days under different lamps, shown in
 * their own colours: this part of the page is evidence, and should not look
 * like the advertising. The ground is the brand's berry so the chapter stands
 * apart from the campaign pictures around it. It was charcoal, with the
 * pictures in grey, until 15 October 2026 (operator: "change the color to
 * something else from our brand color not grey black"); the pictures were then
 * tinted into the berry for a day, until he asked for them as they are ("can
 * this not be in red tint normal images"). The one thing done to them is a
 * light matte grade that lifts their blacks, so nothing in them reads black.
 */
.tested {
  padding-block: clamp(64px, 8vw, 150px);
  background: var(--berry);
  color: var(--offwhite);
}

.tested-inner {
  display: grid;
  width: min(1360px, calc(100% - 48px));
  margin-inline: auto;
  align-items: start;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: clamp(32px, 6vw, 120px);
}

.tested-copy {
  position: sticky;
  top: 128px;
}

.tested .section-kicker {
  color: var(--champagne);
  font-size: 12px;
  letter-spacing: 0.2em;
}

.tested h2 {
  margin-bottom: clamp(20px, 2.2vw, 36px);
  color: var(--offwhite);
  font-size: clamp(46px, 5.6vw, 104px);
  font-weight: 300;
  letter-spacing: -0.045em;
  line-height: 1;
}

.tested-copy > p:not(.section-kicker) {
  max-width: 36ch;
  margin-bottom: 16px;
  font-size: clamp(15px, 1.1vw, 19px);
  line-height: 1.65;
}

.tested .text-link {
  min-height: 44px;
  margin-top: 8px;
  color: var(--offwhite);
  font-size: 13px;
}

.tested .text-link .icon {
  filter: brightness(0) invert(1);
}

.tested-copy > .tested-note {
  margin: clamp(24px, 3vw, 48px) 0 0;
  color: rgb(250 248 244 / 0.72);
  font-size: 12px;
  letter-spacing: 0.04em;
}

.tested-frames {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(10px, 1.2vw, 20px);
  /* Room for the middle column, which sits lower than its neighbours. */
  padding-bottom: clamp(24px, 3vw, 48px);
}

.tested-frames figure {
  margin: 0;
}

/* `translate`, not `transform`: the entrance below animates transform, and the two then add up. */
.tested-frames figure:nth-child(3n + 2) {
  translate: 0 clamp(24px, 3vw, 48px);
}

.tested-frames figure {
  overflow: hidden;
  isolation: isolate;
  background: var(--berry);
}

.tested-frames figcaption {
  position: relative;
  background: var(--berry);
}

.tested-frames img {
  display: block;
  width: 100%;
  /* The height attribute would otherwise stand as 900px beside a 236px width. */
  height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  /* Blacks lifted to about 7%, whites kept: their darkest 1% is luminance 31 to 45 of 255. */
  filter: contrast(0.86) brightness(1.06);
}

/* The microscope's black barrel and the setter's hair: lifted a little more, to luminance 27 at its darkest 1%. */
.tested-frames img[src*="tested-microscope"] {
  filter: contrast(0.8) brightness(1.08);
}

.tested-frames figcaption {
  margin-top: 10px;
  color: rgb(250 248 244 / 0.78);
  font-size: 12px;
  letter-spacing: 0.04em;
  line-height: 1.5;
}

.tested :focus-visible {
  outline: 2px solid var(--offwhite);
  outline-offset: 4px;
}

@media (max-width: 899px) {
  .tested-inner {
    width: calc(100% - 32px);
    grid-template-columns: minmax(0, 1fr);
  }

  .tested-copy {
    position: static;
  }

  .tested-frames {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    padding-bottom: 0;
  }

  .tested-frames figure:nth-child(3n + 2) {
    translate: none;
  }

  .tested-frames figure:nth-child(even) {
    translate: 0 24px;
  }

  .tested-frames {
    padding-bottom: 24px;
  }
}

/*
 * Motion that follows the scroll, where the browser can tie an animation to
 * it (Chrome and Android since 2023, Safari since 26): nine in ten visitors.
 * It runs off the main thread and there is no listener. Everywhere else, and
 * under reduced motion, the finished page is simply there: the animation is
 * added to it inside both conditions and never needed by it.
 *
 * `animation-timeline` is written after `animation`, which would reset it.
 */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    /* The workshop's photographs rise into place, and drift a little inside their frames. */
    body[data-motion="full"] .tested-frames figure {
      animation: revamp-rise linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 70%;
    }

    body[data-motion="full"] .tested-frames img {
      animation: revamp-drift linear both;
      animation-timeline: view();
      animation-range: cover 0% cover 100%;
    }

    body[data-motion="full"] .tested-copy > * {
      animation: revamp-rise linear both;
      animation-timeline: view();
      animation-range: entry 10% entry 90%;
    }

    /*
     * The offer's line under the campaign is not among these. It stands at the
     * foot of the first screen, and on a window that cuts it there it was held
     * half-way through its entry: the sentence at part of its ink for as long
     * as nobody scrolled (measured 4.1:1 at 1350x940, where it is 5.2:1).
     */
  }
}

@keyframes revamp-rise {
  from {
    opacity: 0;
    transform: translateY(16px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes revamp-drift {
  from {
    transform: scale(1.1) translateY(-3.5%);
  }
  to {
    transform: scale(1.1) translateY(3.5%);
  }
}

/*
 * One band of light across the campaign, once as the page arrives and once on
 * each turn (campaign-hero.js restarts it): the way a piece catches a lamp as
 * it is turned. White at a few percent, never a colour, and it ends.
 */
.stage-slides::after {
  position: absolute;
  z-index: 3;
  inset: -10% auto -10% 0;
  width: 26%;
  background: linear-gradient(100deg, transparent 0%, rgb(250 248 244 / 0.16) 45%, rgb(250 248 244 / 0.3) 50%, rgb(250 248 244 / 0.16) 55%, transparent 100%);
  content: "";
  opacity: 0;
  pointer-events: none;
  transform: translateX(-120%) skewX(-12deg);
}

@media (prefers-reduced-motion: no-preference) {
  body[data-motion="full"] .stage-slides[data-glint]::after {
    animation: revamp-glint 1500ms cubic-bezier(0.3, 0, 0.2, 1) 500ms both;
  }

  /* A piece on its tile catches the same light under a pointer. Hover only, and only where there is one. */
  @media (hover: hover) and (pointer: fine) {
    body[data-motion="full"] .product-card .product-image::after,
    body[data-motion="full"] .brand-world-image::after {
      position: absolute;
      z-index: 1;
      inset: 0 auto 0 0;
      width: 40%;
      background: linear-gradient(100deg, transparent, rgb(250 248 244 / 0.34), transparent);
      content: "";
      opacity: 0;
      pointer-events: none;
      transform: translateX(-140%) skewX(-12deg);
    }

    body[data-motion="full"] .brand-world-image {
      position: relative;
    }

    body[data-motion="full"] .product-card:hover .product-image::after,
    body[data-motion="full"] .brand-world-card:hover .brand-world-image::after {
      animation: revamp-glint 900ms cubic-bezier(0.3, 0, 0.2, 1) both;
    }
  }
}

@keyframes revamp-glint {
  0% {
    opacity: 0;
    transform: translateX(-120%) skewX(-12deg);
  }
  20% {
    opacity: 1;
  }
  100% {
    opacity: 0;
    transform: translateX(520%) skewX(-12deg);
  }
}

/*
 * Midnight torch: on the men's panel a pool of light follows the pointer
 * across the ink, as a lamp would across wool (revamp.js writes --torch-x and
 * --torch-y, one frame at a time). No pointer, no torch: a phone has the panel
 * as it is.
 */
.men-home-launch::after {
  position: absolute;
  z-index: 1;
  inset: 0;
  background: radial-gradient(circle 340px at var(--torch-x, 30%) var(--torch-y, 40%), rgb(199 200 202 / 0.2), transparent 70%);
  content: "";
  opacity: 0;
  pointer-events: none;
  transition: opacity 500ms var(--ease);
}

.men-home-launch[data-torch]::after {
  opacity: 1;
}

/*
 * Between pages: the old page gives way to the new one in a short dissolve,
 * where the browser can do that across a full page load (Chrome 126, Safari
 * 18.2). The same rule is in the app's globals.css, so it holds in both
 * directions between this page and the rest of the shop.
 */
@media (prefers-reduced-motion: no-preference) {
  @view-transition {
    navigation: auto;
  }

  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation-duration: 280ms;
    animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
  }
}

/*
 * The rail card's rule for its title, `.product-runway-card strong`, also
 * catches the card's two other <strong>s: the price and the rating's number.
 * Each was given the title's two-line box and stood at the top of it, so the
 * price rode above its MRP and the "4.8", in the title's 15px, above its
 * stars. The price keeps its face and size; the number takes its line's.
 */
.product-runway-card .sale-price,
.product-runway-card .product-rating strong {
  display: inline;
  min-height: 0;
  margin: 0;
}

.product-runway-card .product-rating strong {
  font: inherit;
  font-weight: 600;
}

/*
 * A grid card's price on a narrow card. With the MRP and the "% off" pill at
 * a size that can be read, the pill no longer fits beside the price and its
 * MRP and goes to a second line: on every card today, but only because every
 * price on the page today is long enough. A shorter one would keep its pill
 * beside it and leave that card a line shorter than its neighbour, as four
 * of the eight were on an upright tablet before the sizes changed. So in
 * these two ranges the pill has the second line by rule, as it has on the
 * listing page's cards.
 */
@media (max-width: 429px), (min-width: 768px) and (max-width: 900px) {
  /* `article`: the colour stage is a product card too, and its price stands in a line of its own shape. */
  article.product-card .price-stack {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    justify-items: start;
  }

  article.product-card .price-stack .discount-label {
    grid-column: 1 / -1;
  }
}

/*
 * The promise strip under the hero, 18 October 2026: cash on delivery leads,
 * on blush with its condition in the same cell, then free delivery, returns
 * and the warranty. Four across from a tablet up, two by two on a phone.
 */
.service-promise { padding: clamp(18px, 2vw, 28px) 0; border-bottom: 1px solid var(--champagne); display: grid; gap: 10px; }
.service-promise-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
.service-promise-list li { display: grid; gap: 4px; align-content: start; padding: 14px 16px; border: 1px solid var(--champagne); border-radius: 4px; background: var(--offwhite); }
.service-promise-list strong { font: 500 clamp(15px, .5vw + 11px, 19px)/1.25 Jost, sans-serif; color: var(--berry); }
.service-promise-list span { font-size: 12px; line-height: 1.5; color: var(--charcoal); }
.service-promise-list .service-promise-lead { background: var(--blush); border-color: var(--rose); }
.service-promise-link { justify-self: start; font-size: 12px; }
@media (max-width: 767px) {
  .service-promise { padding: 16px 0 12px; }
  .service-promise-list { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .service-promise-list li { padding: 12px; }
  .service-promise-list strong { font-size: 15px; }
}

/*
 * Small type.
 *
 * The page had about two hundred runs of text under 11px at every width, down
 * to 6px: the struck-through MRP at 8 and 9, the "% off" pill at 7 and 8, the
 * rating at 8.5, each section's label at 9 and 10, and the footer's small
 * print at 9 and 10. DESIGN.md asks for 12. What is read as a sentence, and
 * every link and button, is 12px here; what is left at 11 is listed below with
 * its reason, and nothing on the page is under 11.
 *
 * Nothing is made smaller, and that is by construction. Every rule below is
 * the SAME selector as the rule that set the smaller size, in the same range
 * of widths, and this stylesheet is the page's last: so it replaces that rule
 * and no other. A longer selector elsewhere that already gives one of these a
 * larger size (the 12px labels of the three newest sections) still wins, as it
 * did before. Do not prefix these to make them stronger.
 * test/landing/small-type.test.ts holds the list to the stylesheets.
 *
 * One thing keeps its size on purpose. The wordmark's SINGAPORE line is part
 * of a drawn lockup, set in em against the wordmark (`.brand-origin`): a
 * picture made of letters.
 *
 * These are here, in one block, and not in the seven stylesheets that set
 * them: one of those is shared with the listing and product pages' static
 * files (merchandising.css), and a list in one place can be read and checked.
 *
 * Measured on 12 October 2026, 724 pieces of text at twelve widths from 320
 * to 2560. Under 11px: 195 to 223 showed before and 19 or 20 after (the
 * letters of the two wordmarks' SINGAPORE and the seal's two lines). Under
 * 12px: 273 to 298 before and 175 to 201 after, every one of them on the list
 * below. None past its edge, no sideways scroll, the page's layout shift
 * unchanged. Larger words take more room: sentences and the footer's two
 * addresses run to one more line in places, two of the three links under the
 * first grid join the third on two lines on a phone, and on a 320px screen six
 * short labels are two lines that were one.
 */

/*
 * 11px, and why each is not 12.
 *
 * The price block: on the rail's cards the price, its struck-through MRP and
 * the "% off" pill are one line. At 12px two of the seventeen break that line
 * on a tablet (768 and 1024px wide), and the rail's cards are of two heights.
 * Labels in capitals: tracked capitals at 11px are as tall as lower-case at
 * 14, and a section's label at 12 breaks into two lines on a phone.
 * Badges on a picture, the collection-and-SKU line, the step numerals and the
 * four colour tiles: each sits in a fixed slot that 12px does not fit.
 */
.listed-price,
.discount-label,
.story-pricing .listed-price,
.story-pricing .discount-label,
.stage-bottom #stage-price .listed-price,
.stage-bottom #stage-price .discount-label,
.quick-price .listed-price,
.search-price .listed-price,
.search-price .discount-label,
.merch-badge,
.product-runway-card small,
.real-product-story small,
.runway-end-card small,
.section-kicker,
.celeste-campaign > div > p,
.illustration-story-card small,
.standard-visual figcaption,
.care-steps > li > span,
.knowledge-eyebrow,
.colour-scroll-scene .stage-copy > span,
.colour-scroll-scene .colour-status,
.footer-company address .office-label,
.illustration-story-card > span > span {
  font-size: 11px;
}

/* 12px: sentences, links and buttons. The first twelve were under 11; the rest were 11. */
.product-rating,
.product-runway-card .product-rating,
.saved-line .product-rating,
.care-note,
.knowledge-go,
.colour-scroll-scene .stage-hint,
.footer-company address small,
.footer-base > p,
.footer-base .footer-legal a,
.product-detail-link,
.product-page-link,
.product-runway-controls > p,
.runway-end-card span,
.knowledge-card p,
.footer-company address strong,
.footer-company address .footer-office,
.category-intro .text-link,
.care-kit-groups li,
.immersive-home .shop-edit .product-detail-link,
.immersive-home .celeste-selection .product-detail-link,
.gift-note-help,
.card-view-button,
.immersive-home .hero-price,
.colour-scroll-skip,
.colour-scroll-scene .stage-bottom > p,
.colour-scroll-scene .stage-bottom .button,
.men-launch-detail > span {
  font-size: 12px;
}

/*
 * One badge was a line at 10px and two at 11 ("The sparkle edit", on a card
 * 195px wide). It is held clear of the heart in the picture's corner, which
 * needs 52px, and was given 70: at 60 it is a line again. A phone already has 60.
 */
.product-image .merch-badge {
  max-width: calc(100% - 60px);
}

/* A piece's name over its picture. At 320px the longest, "Bloom Multi Stone Pendant", is a line at 11 and two at 12. */
@media (min-width: 375px) {
  .immersive-home .brand-world-caption > span {
    font-size: 12px;
  }
}

@media (min-width: 768px) and (max-width: 900px) {
  .celeste-selection .text-link {
    font-size: 12px;
  }
}

@media (min-width: 768px) and (max-width: 1100px) {
  .price-paths p,
  .price-paths a,
  .look-tabs button {
    font-size: 12px;
  }
}

@media (min-width: 768px) and (max-width: 1050px) {
  .colour-scroll-scene .stage-bottom .button,
  .colour-scroll-scene .stone-tile > span {
    font-size: 11px;
  }

  /* Beside a price block that is wider than it was, "925 silver" broke after the number. The price still wraps under itself. */
  .colour-scroll-scene .stage-bottom > p {
    white-space: nowrap;
  }
}

/* A tile is 83px wide on an upright tablet, and "White stone" with its dot is 85: as on the narrowest phone, the dot goes. */
@media (min-width: 768px) and (max-width: 840px) {
  .colour-scroll-scene .stone-tile > span > .gem {
    display: none;
  }
}

@media (max-width: 767px) {
  .section-heading > .text-link,
  .section-heading > .text-button,
  .care-steps p,
  .gift-story .button,
  .pairings-heading p,
  .immersive-home .hero-type > p:first-child,
  .colour-scroll-scene .colour-universe .section-heading > p,
  .more-moods > span,
  .shopping-reassurance a,
  .colour-scroll-scene .touch-hint {
    font-size: 12px;
  }

  .footer h3,
  .mood-card small,
  .price-paths a,
  .colour-scroll-scene .stone-tile > span,
  .colour-scroll-scene .stage-bottom .button,
  .men-launch-copy .men-launch-intro {
    font-size: 11px;
  }
}

@media (max-width: 600px) {
  .product-card .product-rating {
    font-size: 12px;
  }

  .product-card .listed-price,
  .product-card .discount-label,
  .mobile-merch-badge .merch-badge-inline {
    font-size: 11px;
  }

  /* At 11px a collection and its SKU broke after the dot, in a label 104px wide on a 360px phone. Untracked, they are a line. */
  .real-product-story small {
    letter-spacing: 0;
  }
}

/* Three price links share a phone's width, and the middle one has a rule on both sides: with 10px of padding each way it broke after the ampersand. */
@media (max-width: 430px) {
  .price-paths a:nth-of-type(2) {
    padding-inline: 5px;
  }
}

@media (max-width: 374px) {
  .gift-story .button {
    font-size: 11px;
  }

  /* 96px to a link: the words are 83, and the arrow after them is what did not fit. */
  .price-paths a > .icon {
    display: none;
  }

  /* "THE ARYAMOND EDIT" in a label 125px wide: tracked as it was, it is 136. */
  .illustration-story-card small {
    letter-spacing: 0.02em;
  }

  /*
   * "Green stone" at 11px is wider than a quarter of a 320px screen with its
   * dot beside it. The photograph above the word is already of that colour, so
   * at this width the dot goes and the word is whole.
   */
  .colour-scroll-scene .stone-tile > span > .gem {
    display: none;
  }
}

/*
 * The Celeste card: the picture above and the words in their band under it,
 * never across it. Until 15 October 2026 the band lay over the picture's
 * foot. The picture the operator gave that day carries a tennis bracelet low
 * on the wrist, at 87-90% of its height, which the band would have covered
 * (nothing is laid over a piece, at any width).
 *
 * Held at its left (the bracelet is the piece nearest an edge) and at its
 * foot: below the bracelet is a tenth of the picture in plain navy, so a
 * narrow card loses that first and the face last.
 */
.celeste-campaign {
  display: flex;
  flex-direction: column;
}

.celeste-campaign > img {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  height: auto;
  object-position: 30% 100%;
}

.celeste-campaign > div {
  position: relative;
  inset: auto;
}

@media (max-width: 767px) {
  .celeste-campaign {
    height: auto;
  }

  .celeste-campaign > img {
    flex: none;
    aspect-ratio: 1280 / 1380; /* the picture's own, so a phone sees all of it */
  }
}

/*
 * The operator's picture starts at her eyes as he gave it, so it is cut just
 * under them (a sliver of eye at a card's edge reads as a mistake). The scroll
 * zoom the other campaign films take (immersive-home.css, up to 1.14 times and
 * lifted 3%) would take that edge up into the nose and the bracelet towards
 * the band. Held still.
 */
.immersive-home[data-motion=full] .celeste-campaign > img { animation-name: none; transform: none; }
