/*
 * Portfolio: the archive wall and the single project.
 *
 * One stylesheet for both, because the two share the thing that makes this
 * section different from every other one in the theme: the surface is the
 * CLIENT'S brand colour rather than a token, and the ink on it was measured
 * in PHP against that exact colour rather than chosen at authoring time.
 *
 * Both views carry that pair under the same two names, --ad-portfolio-brand
 * and --ad-portfolio-ink: the archive sets them on .ad-project, the single
 * view on .ad-portfolio-single__band. Shared names are safe because each is
 * set inline on the element that reads it and the two blocks never nest, but
 * that is the reason neither may be set on an ancestor: one view's colour
 * would then inherit into the other's. The value is per-item content, so
 * nothing here ever hardcodes a brand colour and no rule is generated per
 * client.
 *
 * Two consequences run through the whole file:
 *
 * 1. Nothing on a card may repaint text in a token colour. The global
 *    a:hover in base.css turns a link accent blue, which is unmeasured
 *    against 33 arbitrary surfaces, so both card links pin themselves to
 *    currentColor and signal state with an underline, a border and a lift
 *    instead (SC 1.4.1, 1.4.3).
 * 2. The same goes for the focus ring. base.css draws it in the accent, which
 *    disappears on a card whose brand colour is near that blue, so on a card
 *    the ring is currentColor: the one value already proven at 4.5:1 on that
 *    exact surface, which clears the 3:1 an indicator needs (SC 2.4.11,
 *    2.4.13).
 *
 * Breakpoints are 1100px and 640px, matching --ad-bp-stack and --ad-bp-mobile.
 * The only motion is the reveal transition, whose rules and reduced-motion
 * handling live in hero.css, and the card lift, which is stopped below for
 * both prefers-reduced-motion and this site's own motion switch (SC 2.2.2).
 */

/* ====================================================== archive: the page */

.ad-portfolio {
  padding-block: 120px var(--ad-space-section);
  padding-inline: var(--ad-space-page);
}

.ad-portfolio__head {
  padding-block-end: 32px;
  margin-block-end: 48px;
  border-block-end: 1px solid var(--ad-color-hairline);
}

.ad-portfolio__eyebrow {
  display: flex;
  align-items: center;
  gap: 12px;
  font-family: var(--ad-font-mono);
  font-size: 12px;
  letter-spacing: .16em;
  color: var(--ad-color-accent);
}

.ad-portfolio__square {
  flex: none;
  width: 8px;
  height: 8px;
  background: var(--ad-color-accent);
}

.ad-portfolio__title {
  margin-block-start: 20px;
  font-size: clamp(34px, 5.2vw, 56px);
  letter-spacing: -.04em;
  line-height: 1.05;
  color: var(--ad-color-text);
}

.ad-portfolio__intro {
  max-width: 620px;
  margin-block-start: 20px;
  font-size: 17px;
  line-height: 1.55;
  color: var(--ad-color-text-muted);
  text-wrap: pretty;
}

.ad-portfolio__count {
  margin-block-start: 16px;
  font-family: var(--ad-font-mono);
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ad-color-text-meta);
}

.ad-portfolio__empty {
  font-size: 17px;
  color: var(--ad-color-text-secondary);
}

/* ------------------------------------------------------- group wayfinding */

.ad-portfolio__nav {
  margin-block-end: 48px;
}

.ad-portfolio__nav-list {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

/*
 * A 44px target rather than a bare text link, because these sit close
 * together and are the only navigation on the page (SC 2.5.8). The boundary
 * uses --ad-color-border-input, the token measured at 3:1 or better on every
 * surface in the palette, since it is what identifies the control
 * (SC 1.4.11).
 */
.ad-portfolio__nav-link {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  min-height: var(--ad-size-hit);
  padding-inline: 18px;
  font-family: var(--ad-font-mono);
  font-size: 12px;
  letter-spacing: .12em;
  color: var(--ad-color-text-secondary);
  border: 1px solid var(--ad-color-border-input);
  transition: border-color .2s ease, color .2s ease;
}

.ad-portfolio__nav-link:hover,
.ad-portfolio__nav-link:focus-visible {
  color: var(--ad-color-accent);
  border-color: var(--ad-color-accent);
}

.ad-portfolio__nav-count {
  color: var(--ad-color-text-meta);
}

.ad-portfolio__nav-link:hover .ad-portfolio__nav-count,
.ad-portfolio__nav-link:focus-visible .ad-portfolio__nav-count {
  color: inherit;
}

/* -------------------------------------------------------------- the groups */

.ad-portfolio__group + .ad-portfolio__group {
  margin-block-start: 88px;
}

.ad-portfolio__group-head {
  display: flex;
  align-items: baseline;
  gap: 16px;
  padding-block-end: 16px;
  margin-block-end: 28px;
  border-block-end: 1px solid var(--ad-color-hairline);
}

.ad-portfolio__group-title {
  font-size: 26px;
  letter-spacing: -.02em;
  color: var(--ad-color-text);
}

.ad-portfolio__group-count {
  font-family: var(--ad-font-mono);
  font-size: 11px;
  letter-spacing: .12em;
  color: var(--ad-color-text-meta);
}

/* ---------------------------------------------------------------- the grid */

.ad-portfolio__list {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--ad-space-card-gap);
}

/*
 * The list item carries data-reveal and the card inside it carries the
 * chrome. Keeping them apart matters: the reveal rule in hero.css owns the
 * `transition` shorthand on whatever it is applied to, so the card's own
 * border and transform transitions would either be dropped or would clobber
 * the reveal.
 */
.ad-portfolio__item {
  display: flex;
}

/* ============================================ the card, archive and single */

.ad-project {
  position: relative;
  display: flex;
  flex: 1;
  flex-direction: column;
  /*
   * The fallbacks are not decoration. A card whose stored colour was junk
   * gets the panel token from PHP already, but if the inline property never
   * arrives at all the card still renders on a tested surface in a tested
   * ink rather than transparent and black.
   */
  background: var(--ad-portfolio-brand, var(--ad-color-panel));
  color: var(--ad-portfolio-ink, var(--ad-color-text));
  border: 1px solid var(--ad-color-hairline);
  transition: border-color .3s ease, transform .3s ease;
}

/*
 * focus-within, not only hover: the card a visitor is inside is identifiable
 * without a mouse (SC 2.4.7). currentColor rather than the accent, because
 * the accent is invisible on a card whose brand colour is close to it, while
 * the ink is proven against this exact surface.
 */
.ad-project:hover,
.ad-project:focus-within {
  border-color: currentColor;
  transform: translateY(-4px);
}

/* ------------------------------------------------------------ the logo band */

.ad-project__brand {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 132px;
  padding: 28px;
}

/*
 * width and height stay auto so the aspect ratio holds for artwork that
 * ranges from a wordmark to a square mark; the cell height token caps it so
 * a tall logo cannot push the card out of the grid rhythm. Beats the global
 * img{height:auto} on specificity.
 */
.ad-project__logo {
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: var(--ad-size-logo-cell-h);
  object-fit: contain;
}

/* ------------------------------------------------------------- the mockup */

/*
 * No panel fill and no gradient behind the render: the concept is a wall of
 * client brands, so the mockup floats on the brand colour itself. contain
 * rather than cover, because these are device renders and cropping one cuts
 * the frame off the device.
 */
.ad-project__shot {
  position: relative;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  aspect-ratio: 16 / 10;
  padding-inline: 28px;
  overflow: hidden;
}

.ad-project__img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center bottom;
}

/* --------------------------------------------------------------- the body */

.ad-project__body {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 12px;
  padding: 28px;
}

/*
 * The domain is full-strength ink, never a faded one. An opacity or a mix
 * would undo the 4.5:1 that PHP just proved for this exact pair, so the
 * hierarchy is carried by size, weight and letter-spacing instead of by a
 * second colour (SC 1.4.3).
 */
.ad-project__host {
  font-family: var(--ad-font-mono);
  font-size: 12px;
  letter-spacing: .08em;
  color: inherit;
}

.ad-project__name {
  font-size: 22px;
  letter-spacing: -.02em;
  line-height: 1.15;
  text-wrap: pretty;
}

/*
 * The global a and a:hover would paint this in a token colour that has never
 * been measured against this card's surface, so both states pin to the
 * computed ink and the hover signal is the card border and lift instead.
 */
.ad-project__name-link,
.ad-project__name-link:hover,
.ad-project__name-link:focus-visible {
  color: inherit;
}

/*
 * The link overlay. The anchor is only the client name, which keeps its
 * accessible name to that name rather than to the whole card (SC 2.4.4),
 * while this stretched pseudo-element makes the card itself the pointer
 * target, well past the 44px a 22px line of text would give (SC 2.5.8).
 */
.ad-project__name-link::after {
  content: "";
  position: absolute;
  inset: 0;
}

/*
 * The second real link in the card. z-index lifts it clear of the title
 * link's overlay so it stays clickable, and min-height gives it its own 44px
 * target. Underlined at rest, because on an arbitrary brand surface there is
 * no colour left to distinguish a link with (SC 1.4.1).
 */
.ad-project__live {
  position: relative;
  z-index: 1;
  align-self: start;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: var(--ad-size-hit);
  margin-block-start: auto;
  padding-block-start: 12px;
  font-size: 14px;
  font-weight: 700;
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 4px;
}

.ad-project__live:hover,
.ad-project__live:focus-visible {
  color: inherit;
  text-decoration-thickness: 2px;
}

.ad-project__live svg {
  flex: none;
}

/*
 * See the note at the top of the file: the accent ring in base.css vanishes
 * on a card whose brand colour is near that blue, so on a card the ring is
 * the computed ink. The 2px offset keeps it on the brand surface, inside the
 * body's 28px padding, rather than out on the page ground where a light ink
 * would disappear (SC 2.4.11, 2.4.13).
 */
.ad-project__name-link:focus-visible,
.ad-project__live:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

/* ------------------------------------------------------------ pagination */

/*
 * A safety net for an archive left on the default ten per page. The links
 * come from paginate_links(), so the class names are core's.
 */
.ad-portfolio__pagination {
  margin-block-start: 64px;
  padding-block-start: 32px;
  border-block-start: 1px solid var(--ad-color-hairline);
}

.ad-portfolio__pagination ul {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.ad-portfolio__pagination .page-numbers {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--ad-size-hit);
  min-height: var(--ad-size-hit);
  padding-inline: 12px;
  font-family: var(--ad-font-mono);
  font-size: 13px;
  color: var(--ad-color-text-secondary);
  border: 1px solid var(--ad-color-border-input);
}

.ad-portfolio__pagination a.page-numbers:hover,
.ad-portfolio__pagination a.page-numbers:focus-visible {
  color: var(--ad-color-accent);
  border-color: var(--ad-color-accent);
}

/*
 * The current page is marked by aria-current in the markup, so this is a
 * second, visual signal rather than the only one (SC 1.4.1).
 */
.ad-portfolio__pagination .page-numbers.current {
  background: var(--ad-color-accent);
  color: var(--ad-color-on-accent);
  border-color: var(--ad-color-accent);
  font-weight: 700;
}

.ad-portfolio__pagination .page-numbers.dots {
  border-color: transparent;
  color: var(--ad-color-text-meta);
}

/* ================================================== single: the page shell */

/*
 * The single view is not the archive card enlarged. Its whole identity block
 * sits on a full-bleed band in the client's colour, the two mockups sit on
 * the page ground below it, and the walk to the neighbouring projects closes
 * the page.
 *
 * The per-item pair reaches this section as --ad-portfolio-brand and
 * --ad-portfolio-ink, set inline on the band by single-portfolio.php. Both
 * consequences listed at the top of this file apply inside that band, and one
 * more with them: the ink was computed against THAT brand colour and nothing
 * else, so a faded label, an accent fill or an opacity anywhere on the band
 * would be an unmeasured ratio on an unknown background. Everything on the
 * band is either the full-strength ink or the exact inversion of it
 * (SC 1.4.3).
 */

.ad-portfolio-single {
  /*
   * No inline padding on the page itself, because the band has to reach both
   * edges. The measure lives on the three inner blocks below instead. The top
   * padding other templates carry is gone for the same reason: the band is
   * what meets the sticky header, and a gap above it would read as a stripe
   * of page ground the design does not have.
   */
  padding-block: 0 var(--ad-space-section);
}

.ad-portfolio-single__article {
  display: flex;
  flex-direction: column;
  gap: 88px;
}

/* One measure for everything that is not the brand colour itself. */
.ad-portfolio-single__band-inner,
.ad-portfolio-single__screens,
.ad-portfolio-single__nav {
  max-width: 1120px;
  margin-inline: auto;
  padding-inline: var(--ad-space-page);
}

/* --------------------------------------------------------------- the band */

/*
 * The client's colour, edge to edge. The fallbacks are not decoration: PHP
 * already swaps a junk brand value for a tested surface, but if the style
 * attribute never arrives at all the band still renders on a tested pair
 * rather than as transparent on black.
 */
.ad-portfolio-single__band {
  background: var(--ad-portfolio-brand, var(--ad-color-panel));
  color: var(--ad-portfolio-ink, var(--ad-color-text));
}

.ad-portfolio-single__band-inner {
  display: flex;
  flex-direction: column;
  align-items: start;
  gap: 20px;
  padding-block: 72px 80px;
}

/*
 * 44px of target where the type alone would give 18px (SC 2.5.8), and an
 * underline at rest, because on an arbitrary brand surface there is no second
 * colour left to mark a link with (SC 1.4.1). The global a:hover would repaint
 * it in the accent, which has never been measured against this band, so both
 * states pin to the inherited ink and the hover signal is the rule thickening.
 */
.ad-portfolio-single__back-link {
  display: inline-flex;
  align-items: center;
  min-height: var(--ad-size-hit);
  font-family: var(--ad-font-mono);
  font-size: 12px;
  letter-spacing: .12em;
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 6px;
}

.ad-portfolio-single__back-link:hover,
.ad-portfolio-single__back-link:focus-visible {
  color: inherit;
  text-decoration-thickness: 2px;
}

.ad-portfolio-single__logo {
  display: flex;
}

/*
 * width and height stay auto so a wordmark and a square mark both keep their
 * ratio; the caps stop a tall mark from pushing the title down the band. Beats
 * the global img{height:auto} on specificity.
 */
.ad-portfolio-single__logo-img {
  width: auto;
  height: auto;
  max-width: 260px;
  max-height: 72px;
  object-fit: contain;
}

/* Inherits the band ink rather than taking --ad-color-text like the archive
   h1, which would be a token colour on an unknown surface. */
.ad-portfolio-single__title {
  font-size: clamp(34px, 5.6vw, 60px);
  letter-spacing: -.04em;
  line-height: 1.04;
  color: inherit;
  text-wrap: pretty;
}

/*
 * Label and value, told apart by type alone. Every string here is the one
 * computed ink at full strength, so the hierarchy is carried by size, weight
 * and tracking: the label is small mono capitals, the value is large and
 * bold. Fading the label would undo the ratio PHP just proved (SC 1.4.3).
 *
 * The margins are resets. A dl carries a block margin and a dd an inline
 * start margin from the UA sheet, and the second one is directional.
 */
.ad-portfolio-single__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 16px 48px;
  margin: 0;
}

.ad-portfolio-single__meta-row {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.ad-portfolio-single__meta-label {
  font-family: var(--ad-font-mono);
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: inherit;
}

.ad-portfolio-single__meta-value {
  margin: 0;
  font-size: 19px;
  font-weight: 700;
  letter-spacing: -.01em;
  color: inherit;
}

/*
 * The one thing a visitor is here to do, and the only inversion on the page:
 * the fill is the ink and the label is the brand colour. Contrast is
 * symmetric, so the inverted pair carries the identical measured ratio the
 * band was proved at, which an accent fill never could (SC 1.4.3). min-height
 * holds the 44px target (SC 2.5.8), and the fill is a shape rather than a
 * colour change, so the control is identifiable without colour (SC 1.4.1).
 *
 * No transition here on purpose: this element carries data-reveal, and the
 * reveal rule in hero.css owns the transition shorthand on whatever it is
 * applied to, so one declared here would be dropped or would clobber the
 * reveal.
 */
.ad-portfolio-single__live {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  min-height: var(--ad-size-hit);
  margin-block-start: 12px;
  padding-block: 10px;
  padding-inline: 24px;
  background: var(--ad-portfolio-ink, var(--ad-color-text));
  color: var(--ad-portfolio-brand, var(--ad-color-panel));
  font-size: 15px;
  font-weight: 700;
}

/* Pinned against the global a:hover for the same reason as the back link. */
.ad-portfolio-single__live:hover,
.ad-portfolio-single__live:focus-visible {
  color: var(--ad-portfolio-brand, var(--ad-color-panel));
}

/* The hover signal is a rule under the label only. Underlining the whole
   anchor would draw one through the host and under the arrow as well. */
.ad-portfolio-single__live:hover .ad-portfolio-single__live-label,
.ad-portfolio-single__live:focus-visible .ad-portfolio-single__live-label {
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-thickness: 2px;
}

/*
 * The destination is visible as well as announced, so it is part of the
 * accessible name (SC 2.5.3). It is a domain, so it takes the mono face and a
 * smaller size to sit under the label. Again type, never a lighter ink.
 */
.ad-portfolio-single__live-host {
  font-family: var(--ad-font-mono);
  font-size: 12px;
  font-weight: 400;
  letter-spacing: .04em;
}

.ad-portfolio-single__live svg {
  flex: none;
}

/*
 * The focus ring. base.css draws it in the accent, which disappears on a band
 * whose brand colour is near that blue, so on the band the ring is the ink:
 * the one value proven at 4.5:1 on this exact surface, well past the 3:1 an
 * indicator needs (SC 1.4.11, 2.4.11).
 *
 * The call to action is the exception that proves it. Its own currentColor is
 * the brand colour, so a currentColor ring would be drawn in the band's own
 * fill; it rings in the ink instead, and the offset puts that ring on the band
 * rather than on the button.
 */
.ad-portfolio-single__back-link:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 3px;
}

.ad-portfolio-single__live:focus-visible {
  outline: 2px solid var(--ad-portfolio-ink, var(--ad-color-text));
  outline-offset: 3px;
}

/* ------------------------------------------------------------ the mockups */

/*
 * Below the band the page is back on tested ground, so these rules use the
 * theme tokens again.
 */

.ad-portfolio-single__screens-title {
  margin-block-end: 28px;
  font-family: var(--ad-font-mono);
  font-size: 12px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ad-color-text-meta);
}

/*
 * The two renders read as one object: the desktop runs most of the measure
 * and the phone overlaps its end corner, which is the entire reason for
 * showing them together. The phone is out of flow and the block padding below
 * is what it hangs into, so the overlap costs the section no rhythm and
 * nothing is clipped.
 */
.ad-portfolio-single__stage {
  position: relative;
  padding-block-end: 40px;
}

/*
 * No frame and no panel fill behind either render, for the reason the archive
 * gives above: these are device mockups, and a device inside a second box
 * reads as a screenshot of a screenshot.
 */
.ad-portfolio-single__shot {
  position: relative;
}

/* The auto margin keeps the desktop on the start side in both directions
   without naming one, and leaves the end of the measure for the phone. */
.ad-portfolio-single__shot--desktop {
  width: 86%;
  margin-inline-end: auto;
}

/*
 * Sized as a fraction of the stage rather than in pixels, so the phone stays
 * shorter than the desktop render at every width and cannot grow up into the
 * heading. z-index is explicit because both shots are positioned, and paint
 * order would otherwise rest on document order alone.
 */
.ad-portfolio-single__shot--mobile {
  position: absolute;
  z-index: 1;
  inset-block-end: 0;
  inset-inline-end: 0;
  width: 22%;
  min-width: 104px;
}

/* Block, so the image contributes no inline descender gap under itself, and
   beats the global img{height:auto} where WordPress prints the attributes. */
.ad-portfolio-single__img {
  display: block;
  width: 100%;
  height: auto;
}

/*
 * One mockup, so there is no overlap to build. The lone render is centred and
 * capped: without the cap a single phone would blow up to the width the pair
 * would have used, and a lone desktop would sit off to one side under a gap
 * where the phone never arrived.
 */
.ad-portfolio-single__stage--solo {
  padding-block-end: 0;
}

.ad-portfolio-single__stage--solo .ad-portfolio-single__shot {
  position: static;
  width: 100%;
  max-width: 900px;
  margin-inline: auto;
}

.ad-portfolio-single__stage--solo .ad-portfolio-single__shot--mobile {
  max-width: 320px;
}

/* ------------------------------------------------------ previous and next */

/*
 * Nothing on the public site links into a project, so this and the back link
 * are the whole way out of one.
 */
.ad-portfolio-single__nav {
  padding-block-start: 40px;
  border-block-start: 1px solid var(--ad-color-hairline);
}

.ad-portfolio-single__nav-list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ad-space-card-gap);
}

.ad-portfolio-single__nav-item {
  display: flex;
}

/*
 * The row is NOT reversed. Previous is first in the DOM, and a flex row
 * already runs start to end in whatever direction the document is in, so
 * previous lands on the right in Hebrew and on the left in English on its
 * own. Reversing it would make the pair read backwards in one of them.
 *
 * Auto margins rather than space-between, so the first and last projects in
 * the set, which have one link and not two, still put that link on the side
 * its direction word claims.
 */
.ad-portfolio-single__nav-item--prev {
  margin-inline-end: auto;
}

.ad-portfolio-single__nav-item--next {
  margin-inline-start: auto;
  text-align: end;
}

/*
 * A bordered block rather than a bare pair of words. The boundary uses
 * --ad-color-border-input, the token measured at 3:1 or better on every
 * surface in the palette, because here it is what identifies the control
 * (SC 1.4.11), and min-height carries the 44px target (SC 2.5.8).
 */
.ad-portfolio-single__nav-link {
  display: flex;
  flex: 1;
  flex-direction: column;
  justify-content: center;
  gap: 6px;
  min-height: var(--ad-size-hit);
  padding-block: 16px;
  padding-inline: 20px;
  border: 1px solid var(--ad-color-border-input);
  transition: border-color .2s ease, color .2s ease;
}

.ad-portfolio-single__nav-link:hover,
.ad-portfolio-single__nav-link:focus-visible {
  color: var(--ad-color-accent);
  border-color: var(--ad-color-accent);
}

.ad-portfolio-single__nav-label {
  font-family: var(--ad-font-mono);
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ad-color-text-meta);
}

/* The label follows the link into its hover colour instead of staying the one
   grey thing inside a highlighted control. */
.ad-portfolio-single__nav-link:hover .ad-portfolio-single__nav-label,
.ad-portfolio-single__nav-link:focus-visible .ad-portfolio-single__nav-label {
  color: inherit;
}

.ad-portfolio-single__nav-title {
  font-size: 18px;
  font-weight: 700;
  letter-spacing: -.02em;
  line-height: 1.2;
}

/* ============================================================= responsive */

@media (max-width: 1100px) {
  .ad-portfolio__list {
    grid-template-columns: repeat(2, 1fr);
  }

  /* The band is the tallest thing on the page and the first thing under the
     header, so it is the first place to give height back. */
  .ad-portfolio-single__band-inner {
    padding-block: 56px 64px;
  }
}

@media (max-width: 640px) {
  .ad-portfolio {
    padding-block: 88px var(--ad-space-section-mobile);
    padding-inline: var(--ad-space-page-mobile);
  }

  /* The band still reaches both edges here, so the page keeps no inline
     padding and the measure inside it takes the mobile value. */
  .ad-portfolio-single {
    padding-block: 0 var(--ad-space-section-mobile);
  }

  .ad-portfolio-single__band-inner,
  .ad-portfolio-single__screens,
  .ad-portfolio-single__nav {
    padding-inline: var(--ad-space-page-mobile);
  }

  .ad-portfolio__list {
    grid-template-columns: 1fr;
  }

  .ad-portfolio__group + .ad-portfolio__group {
    margin-block-start: var(--ad-space-section-mobile);
  }

  .ad-portfolio__group-title {
    font-size: 22px;
  }

  /* Sides only. The block padding stays, so the brand colour keeps its air. */
  .ad-project__brand,
  .ad-project__shot,
  .ad-project__body {
    padding-inline: var(--ad-space-page-mobile);
  }

  .ad-portfolio-single__article {
    gap: 56px;
  }

  .ad-portfolio-single__band-inner {
    padding-block: 40px 48px;
  }

  .ad-portfolio-single__meta {
    gap: 16px 32px;
  }

  /*
   * The overlap needs width to read as depth. At this size it would drop a
   * 70px phone on top of the only view of the desktop work, so the pair
   * becomes a stack instead: both renders at full size, one after the other.
   */
  .ad-portfolio-single__stage {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 24px;
    padding-block-end: 0;
  }

  .ad-portfolio-single__shot--desktop {
    width: 100%;
    margin-inline: 0;
  }

  .ad-portfolio-single__shot--mobile {
    position: static;
    width: 100%;
    max-width: 280px;
  }

  /* A column, so the auto margins would push next across the cross axis and
     stack the pair down a diagonal. */
  .ad-portfolio-single__nav-list {
    flex-direction: column;
  }

  .ad-portfolio-single__nav-item--prev,
  .ad-portfolio-single__nav-item--next {
    margin-inline: 0;
  }

  .ad-portfolio-single__nav-item--next {
    text-align: start;
  }
}

/* ================================================================ motion */

/*
 * The lift is the only movement this file adds. base.css collapses the
 * transition under prefers-reduced-motion, which makes the card jump rather
 * than glide, so the transform is removed outright for both the OS preference
 * and this site's own switch (SC 2.2.2). The single view adds no transform of
 * its own, so it needs nothing here.
 */
@media (prefers-reduced-motion: reduce) {
  .ad-project:hover,
  .ad-project:focus-within {
    transform: none;
  }
}

[data-ad-motion="off"] .ad-project:hover,
[data-ad-motion="off"] .ad-project:focus-within {
  transform: none;
}
