/* ===== PetLand — case study =====
   Slide 1: Hero + Key numbers.

   TRANSFERRED FROM FIGMA — file uMdjtaYVvRQFWSeG1yAV6v, page Cases,
   frame `PetLand` node 10:5, 1440 x 17471. Slides are that frame's direct
   children, split by its `Section divider` layers. This sheet grows one
   slide at a time; each block carries the node id it came from.

   Node ids for slide 1:
     1206:4424  Hero · PetLand
     1206:4541  Key numbers · PetLand

   THE CASE HAS ITS OWN STYLE, NOT THE SITE'S. Every colour, size and gap
   below is a --pl-* custom property declared on `.case-petland` and nowhere
   else, so css/base/tokens.css and the shared sheets stay untouched and this
   page cannot leak into them. The SHELL around the case — the sticky topbar
   and the nav dock — is the site's and stays themed, exactly as the
   Iconography case does it.

   DARK ONLY, by design: the Figma board is drawn on #232232 and the whole
   palette is built against it. No [data-theme] hooks anywhere in here. */

/* Inter, self-hosted. Same two faces (and the same reasoning) as
   work/iconography/iconography.css: the site makes no third-party requests,
   and the variable file covers every weight in one download per subset.
   SIL OFL 1.1. It is the FALLBACK here — the design is set in SF Pro, which
   is the system face on Apple hardware, so -apple-system is asked for first
   and Inter catches everyone else. */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("../../assets/fonts/inter-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("../../assets/fonts/inter-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
                 U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
                 U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Shantell Sans, self-hosted the same way and for the same reason. The board
   sets its annotation voice in it — the "Persona 1 / 2" tabs here, and the
   FigJam-ish lettering on the slides still to come. Latin subset only,
   47.5 KB, font-display: swap, and nothing waits on it: the labels paint in
   the fallback and reflow when it lands. SIL OFL 1.1.

   It is the one face on this page the site did not already own. If it is not
   worth 47.5 KB, delete this block and the --pl-font-hand token below falls
   straight through to the UI face with nothing else to change. Once the case
   is finished the glyph set is knowable and this could be subset to the few
   characters it actually uses, which would be single-digit KB. */
@font-face {
  font-family: "Shantell Sans";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../../assets/fonts/shantell-sans-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ============================================================ tokens == */
/* --- measure ---
   1040, from the section frames (Key numbers 1206:4541 is x=200 w=1040 in a
   1440 board, so 200 of side padding). NOT the site's --container (72rem /
   1152) — the case is built on its own grid and every later slide measures
   against this.

   Declared on BOTH the case and the topbar, not on `.case-petland` alone:
   the sticky bar is a SIBLING of the article, so a token scoped to the
   article does not reach it, `max-width: calc(var(--pl-content) + …)` becomes
   an invalid declaration, and the bar silently runs the full window — which
   is exactly how the back link ended up at the window edge instead of over
   the case's left column. Same trap case.css's --case-pad sets on this bar;
   see .pl-topbar below. */
:where(.case-petland, .pl-topbar) {
  --pl-content: 1040px;
  --pl-gutter: 24px;
}

/* Read off the Figma frame, not chosen. Where a number is a measurement it
   carries the node it was measured on. */
.case-petland {
  /* --- colour (sampled from the frame, see the note on --pl-bg) --- */
  /* The board's own fill. The hero frame paints nothing of its own, so this
     is what shows through it — taken off the rendered frame, since the fill
     does not come back with the layer's code. */
  --pl-bg:            #232232;
  /* Every card, plate and placeholder on the board. */
  --pl-surface:       #2f2e3e;
  --pl-ink:           #ffffff;
  /* Labels and the hero's own standfirst. Deliberately quiet on this ground
     — it is the board's secondary, not a contrast mistake to "fix". */
  --pl-ink-soft:      #555466;
  /* Type set ON --pl-surface: the key numbers, and the placeholder captions.
     Two values, not one, because the board uses two. */
  --pl-ink-on-plate:  #9695aa;
  --pl-placeholder-ink: #9999ad;
  --pl-placeholder-line: #6b6b80;
  /* The quietest type on the board: the labels inside empty slots, which are
     meant to recede rather than be read. */
  --pl-ink-faint:     #5a586e;
  --pl-rule:          rgb(255 255 255 / .1);
  /* The persona cards are #2f2d3e, one step off the #2f2e3e everything else
     on the board uses. Almost certainly a slip rather than a decision — but
     it is what the file says, and guessing which one was meant is not this
     page's call to make. Both are declared; if they should be one colour,
     delete this and point .pl-persona at --pl-surface. */
  --pl-surface-card:  #2f2d3e;
  /* The board's annotation voice: the "Persona N" tabs and the "Motivation"
     legend. Darker than --pl-ink-on-plate, which is the key numbers. */
  --pl-ink-annot:     #767591;
  --pl-track:         #3f3e55;
  --pl-accent:        #08f;
  --pl-divider-line:  rgb(85 84 102 / .25);
  /* FigJam's own accent — the stamp, the parked cursor and its name tag. */
  --pl-cursor:        #9747ff;

  /* --- type --- */
  /* The board is set in SF Pro. On Apple hardware -apple-system IS SF Pro, so
     the page renders exactly as drawn; everywhere else Inter stands in, which
     is the closest thing the site already ships. */
  --pl-font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro Display",
             "Inter", system-ui, "Segoe UI", Roboto, sans-serif;
  /* The annotation face. Falls through to --pl-font if the woff2 above is
     ever dropped — the labels then read as quiet UI text rather than as
     handwriting, which is a downgrade and not a break. */
  --pl-font-hand: "Shantell Sans", -apple-system, BlinkMacSystemFont, "Inter",
                  system-ui, sans-serif;
  /* Figma's "normal" leading for SF Pro: the 46px title box is 110 tall for
     two lines, i.e. 55 a line. */
  --pl-lh: 1.2;

  /* Every gap between dividers on the board is 160. Slide 1 does not use it
     yet; the next slide does, and it belongs with the other measurements. */
  --pl-section-gap: 160px;

  position: relative;
  z-index: var(--z-content);
  background: var(--pl-bg);
  color: var(--pl-ink);
  font-family: var(--pl-font);
  line-height: var(--pl-lh);
  -webkit-font-smoothing: antialiased;
  /* Clearance for the fixed nav dock, same run-out the other two cases hold
     themselves now that none of them has a closing footer. */
  padding-bottom: var(--dock-space);
}

/* typography.css sets `h1, h2, h3 { font-family: var(--font-display) }` — the
   site's Georgia — on the ELEMENT, so headings inside the case do not inherit
   --pl-font from `.case-petland` and the hero title came out serif. Put the
   case's family back on the headings explicitly; the board has no serif
   anywhere. */
.case-petland :is(h1, h2, h3, h4) { font-family: var(--pl-font); }

/* The board's ground has to run edge to edge, not sit in a column — so the
   article paints it and `.pl-container` holds the content to 1040. */
.pl-container {
  width: 100%;
  max-width: calc(var(--pl-content) + var(--pl-gutter) * 2);
  margin-inline: auto;
  padding-inline: var(--pl-gutter);
}

/* The shared sticky topbar hard-codes case.css's own --case-pad, which is not
   even declared outside `.case` — the shorthand is then invalid and the bar
   loses its padding entirely. Same fix as the Iconography case: zero the
   horizontal padding here and let an inner .pl-container place the row, so
   the back link lines up with the case content rather than with a column
   this page does not use. */
.pl-topbar { padding: var(--space-4) 0; }
.pl-topbar__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
}

/* ============================================= 01 — HERO (1206:4424) == */
/* The board draws the hero full-bleed at 1440 with its text at x=303 and the
   phone's art ending at x=1039.6 — neither edge lands on the 200/1240 column
   every other slide uses, so the block is 103 in from the left and 200 short
   on the right. Reproduced here ON the column instead: text against its left
   edge, phone against its right. Everything INSIDE the two (type, sizes, the
   gaps down the stack, the phone itself) is the mock's, to the pixel.

   Verticals, measured on the frame: phone art starts at y=105.17, the logo at
   174, the last line of meta ends at 573.5, the frame at 645. */
.pl-hero { padding-block: 105px 27px; }

.pl-hero__inner {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-6);
}

/* 174 - 105: the text column starts lower than the phone's art.
   478 is the board's own text block (x 303 → 781); without it the column
   shrinks to the widest line and the meta grid's fixed 246 track has nothing
   left to put the second column in. */
.pl-hero__text {
  margin-top: 69px;
  flex: 0 1 478px;
  min-width: 0;
}

/* --- logo placeholder (1206:4431) ---
   TODO: logo — Cristina supplies the mark; this is the slot it lands in,
   at the size and radius the board gives it. */
.pl-logo {
  width: 61px;
  height: 61px;
  border-radius: 14px;
  background: var(--pl-surface);
  border: 1.5px dashed var(--pl-placeholder-line);
  display: grid;
  place-items: center;
  font-size: 13px;
  color: var(--pl-placeholder-ink);
}

/* 262.7 - 235 (logo bottom) */
.pl-hero__title {
  margin-top: 28px;
  max-width: 478px;
  font-size: 46px;
  font-weight: 700;
  line-height: var(--pl-lh);
  letter-spacing: -0.01em;
  color: var(--pl-ink);
}

/* 392 - 372.7 (title bottom) */
.pl-hero__standfirst {
  margin-top: 19px;
  max-width: 403px;
  font-size: 15px;
  font-weight: 400;
  color: var(--pl-ink-soft);
}

/* --- meta: My role / Scope / Status (1206:4426…1357:4151) ---
   Two columns on the board — the second starts at x=549 against the first at
   303, so a 246 track — and Status drops to a second row under My role.
   Row 1 label sits at y=469, row 2 at 533. */
.pl-hero__meta {
  margin-top: 41px;
  display: grid;
  grid-template-columns: 246px auto;
  row-gap: 23px;
}
.pl-hero__meta dt {
  font-size: 15px;
  font-weight: 500;
  color: var(--pl-ink-soft);
}
/* 491.55 - 487 (label bottom): the value sits tight under its label. */
.pl-hero__meta dd {
  margin: 4px 0 0;
  font-size: 15px;
  font-weight: 500;
  color: var(--pl-ink);
}
/* The pairs are laid out as two columns of (label, value), so each <div>
   wraps one pair and the grid places the pairs, not the six elements. */
.pl-hero__meta > div { min-width: 0; }

/* --- phone (1206:4436) ---
   The bezel art is BIGGER than its frame and overflows it on every side
   (the image node sits at -13.39, -12.83 and measures 251.001 x 513.158),
   so the box here is the ART, and the screen is placed inside it at the
   offset that puts it back where the board has it:
     screen x = (802 + 4) - 788.61 = 17.39     y = (118 + 4) - 105.17 = 16.83
   The webp has a transparent window, so it lies OVER the screen rather than
   beside it. */
.pl-phone {
  position: relative;
  flex: none;
  width: 251px;
  height: 513px;
}
/* TODO: phone media — the home screen itself. Same box and radius as the
   board's own placeholder, so dropping the real screen in changes nothing
   around it. */
.pl-phone__screen {
  position: absolute;
  left: 17.39px;
  top: 16.83px;
  width: 216.228px;
  height: 479.5px;
  border-radius: 34px;
  background: var(--pl-surface);
  display: grid;
  place-items: center;
  font-size: 16px;
  color: var(--pl-placeholder-ink);
  overflow: hidden;
}
.pl-phone__bezel {
  position: absolute;
  inset: 0;
  width: 251px;
  height: 513px;
  pointer-events: none;
}

/* ===================================== 02 — KEY NUMBERS (1206:4541) == */
/* 672.3 - 645: the plate sits 27 under the hero frame. */
.pl-stats {
  margin-top: 27px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 207px;
  /* 48 at the 1040 cap, which is the board's number. Below the cap the plate
     is narrower than it was drawn and three 72px figures start crowding their
     rules, so the padding gives way before the type does. */
  padding-inline: clamp(24px, 4.6vw, 48px);
  border-radius: 20px;
  background: var(--pl-surface);
  overflow: clip;
}
.pl-stat {
  flex: 1 0 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  /* 32 at the cap, same reasoning as the plate's own padding above. */
  padding-inline: clamp(8px, 3vw, 32px);
  text-align: center;
}
.pl-stat__value {
  font-size: 72px;
  font-weight: 600;
  line-height: var(--pl-lh);
  color: var(--pl-ink-on-plate);
  white-space: nowrap;
}
.pl-stat__label {
  font-size: 17px;
  font-weight: 400;
  color: var(--pl-ink-on-plate);
}
/* 1px x 140 on the board. A border on the stat would move with its padding;
   a separate element is what Figma has (1206:4548, 1217:4161) and it keeps
   the rule the same height whatever the stats do. */
.pl-stats__rule {
  flex: none;
  width: 1px;
  height: 140px;
  background: var(--pl-rule);
}

/* =================================== 03 — PROBLEM (11:17) == */
/* The statement, the four stacks of screens it describes, and the count
   under them. The board's own gaps: 279 down from the key numbers, 89 to the
   stacks, 49 to the caption. Three different distances again, so they are
   written out rather than averaged into a rhythm that is not there. */
.pl-problem         { margin-top: 279px; }
.pl-problem__flow   { margin-top: 89px; }
.pl-problem__count  { margin-top: 49px; }

.pl-problem__flow {
  display: block;
  width: 100%;
  aspect-ratio: 2240 / 1042;
  border-radius: 20px;
}

/* 32px Medium, with the numbers picked out in full ink against the board's
   secondary. */
.pl-count {
  width: 100%;
  font-size: 32px;
  font-weight: 500;
  line-height: 1.25;
  color: var(--pl-ink-soft);
}
.pl-count b {
  font-weight: 500;   /* the board emphasises with colour, not weight */
  color: var(--pl-ink);
}

/* ================================ SECTION DIVIDER (1203:22967) == */
/* A 1px rule across the FULL 1440 board, not across the column — so it sits
   outside .pl-container and spans the article. The source is an SVG whose
   whole content is `M0 0.5H1440 stroke=#555466 stroke-opacity=0.25`; drawn
   here instead of fetched, because a one-line path is cheaper as a border
   than as a request.

   160 above and 160 below: that is the board's own section rhythm (caption
   bottom 2157 -> divider 2317 -> Personas 2477) and the number the brief
   names. It gives way on narrow screens rather than eating a third of a
   phone screen in white space, but never grows past the board's 160. */
.pl-divider {
  height: 1px;
  border: 0;
  margin-block: clamp(72px, 15vw, var(--pl-section-gap));
  background: var(--pl-divider-line);
}

/* ======================================================== sections == */
/* The board sets every section as a column with its heading on top. The gap
   is per-section (Personas is 73), so it is a property the section sets
   rather than a number baked in here. */
.pl-section {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--pl-section-gap-inner, 73px);
}
/* The board sets 40 under its heading where Personas sets 73. Per-section,
   so it is a modifier rather than a second rule fighting the first. */
.pl-section--tight { --pl-section-gap-inner: 40px; }

/* Section headings are the same 46px Bold as the hero title, with the
   section's name running into the sentence in --pl-ink-soft. One paragraph
   on the board, one heading here. */
.pl-h2 {
  font-size: 46px;
  font-weight: 700;
  line-height: var(--pl-lh);
  letter-spacing: -0.01em;
  color: var(--pl-ink);
}
.pl-h2__lead { color: var(--pl-ink-soft); }

/* ==================================== 04 — PERSONAS (1363:4278) == */
/* Two cards, 510 each with a 20 gutter, which is exactly the 1040 column.
   1fr tracks rather than a literal 510 so the pair keeps filling the column
   below the cap instead of overflowing it. */
.pl-personas {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 20px;
  width: 100%;
}

/* Both cards are 593 on the board — card 1's content stops ~66 short and the
   rest is slack. Stretching the grid row gives the same two equal cards
   without pinning a height that real text would overflow; the min-height
   holds the board's number as the floor. */
.pl-persona {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 28px;
  min-height: 593px;
  padding: 32px;
  border-radius: 20px;
  background: var(--pl-surface-card);
}

/* The handwritten tab at the top of each card. */
.pl-persona__index {
  font-family: var(--pl-font-hand);
  font-size: 20px;
  font-weight: 400;
  color: var(--pl-ink-annot);
}

.pl-persona__id {
  display: flex;
  align-items: center;
  gap: 16px;
}
.pl-persona__avatar {
  flex: none;
  width: 56px;
  height: 56px;
  border-radius: 50%;   /* the board's 28 on a 56 box IS a circle */
  object-fit: cover;
}
.pl-persona__name {
  font-size: 20px;
  font-weight: 600;
  color: var(--pl-ink);
}
/* 2px under the name, per the board. */
.pl-persona__role {
  margin-top: 2px;
  font-size: 15px;
  color: var(--pl-ink-on-plate);
}

.pl-persona__intro {
  display: flex;
  flex-direction: column;
  gap: 20px;
  width: 100%;
  color: var(--pl-ink);
}
.pl-persona__line  { font-size: 15px; }
/* The quote is a step larger than the line above it — 17, not 15. It is the
   persona speaking, so it is marked up as a quotation and not just styled
   like one. */
.pl-persona__quote {
  font-size: 17px;
  font-style: normal;   /* <blockquote>/<q> lean by default; the board does not */
}

.pl-persona__motivation {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
  width: 100%;
}
.pl-persona__legend {
  font-size: 12px;
  font-weight: 600;
  color: var(--pl-ink-annot);
}

/* --- one motivation bar --- */
.pl-bar {
  display: flex;
  flex-direction: column;
  gap: 6px;
  width: 100%;
}
.pl-bar__label {
  font-size: 15px;
  color: var(--pl-ink);
}
.pl-bar__track {
  width: 100%;
  height: 6px;
  border-radius: 3px;
  background: var(--pl-track);
  overflow: clip;
}
/* The fill is a percentage of the track, not the board's literal pixel width
   (223 / 446 / 133.8 of a 446 track = 50 / 100 / 30), so the bars stay true
   at any card width. The value is passed in the markup, where it belongs —
   it is data about the persona, not styling. */
.pl-bar__fill {
  width: var(--pl-bar);
  height: 100%;
  border-radius: 3px;
  background: var(--pl-accent);
}

/* The closing note on card 2 only. */
.pl-persona__note {
  font-size: 15px;
  color: var(--pl-ink-on-plate);
}

/* ================================== 05 — HYPOTHESES (1225:4150) == */
/* A FigJam board: three stickies pinned at angles, a stamp, somebody's
   cursor, and a note in the corner. It is a COMPOSITION — the pieces overlap
   and lean on each other, so it cannot reflow into a grid and keep meaning
   anything. It scales as one picture instead.

   HOW THE SCALING WORKS. The board is a container, and --pl-u is one board
   pixel expressed against its width: at the board's full 1040.496 it is
   exactly 1px, and it shrinks with the column. Every number below is then
   the Figma number times --pl-u, so the source reads as the measurements it
   came from rather than as a table of percentages — and the type scales with
   the art instead of breaking out of it.

   The positions ARE the Figma numbers, but unrotated. The file gives each
   sticky's bounding box AFTER its rotation; the top-left here is that box's
   centre minus half the sticky, which is where `rotate()` about the centre
   puts it back. */
.pl-board-wrap { container-type: inline-size; width: 100%; }

.pl-board {
  --pl-u: calc(100cqw / 1040.496);
  /* FigJam sets its stickies in Inter, not in the page's SF Pro. The site
     already carries Inter, so this costs nothing. */
  --pl-font-board: "Inter", system-ui, sans-serif;
  position: relative;
  width: 100%;
  aspect-ratio: 1040.496 / 470.662;
  border-radius: calc(16.258 * var(--pl-u));
  background: var(--pl-surface);
  overflow: clip;
}

/* 1px dots on a 20 pitch, #59586E, first centre at (1,1) — drawn rather than
   fetched. Figma exports this as 1,100-odd separate paths, 194 KB of SVG for
   a background texture; two gradient stops do the same job for nothing. */
.pl-board__grid {
  position: absolute;
  left: calc(20 * var(--pl-u));
  top: calc(20 * var(--pl-u));
  width: calc(1022 * var(--pl-u));
  height: calc(442 * var(--pl-u));
  background-image: radial-gradient(circle at calc(1 * var(--pl-u)) calc(1 * var(--pl-u)),
                    #59586e calc(1 * var(--pl-u)), transparent 0);
  background-size: calc(20 * var(--pl-u)) calc(20 * var(--pl-u));
}

/* --- a sticky (1300:4156, :4161, :4166) --- */
.pl-sticky {
  position: absolute;
  width: calc(290.201 * var(--pl-u));
  min-height: calc(290.201 * var(--pl-u));
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: calc(11.38 * var(--pl-u));
  padding: calc(22.761 * var(--pl-u));
  border-radius: calc(2 * var(--pl-u));
  box-shadow: 0 calc(4.877 * var(--pl-u)) calc(11.38 * var(--pl-u)) rgb(0 0 0 / .22);
  font-family: var(--pl-font-board);
  color: #1e1e1e;
  transform: rotate(var(--pl-tilt));
  transition: transform .2s ease-out;
}
/* The same hover as the VB24 board: a little further round, a little bigger. */
@media (hover: hover) {
  .pl-sticky:hover { transform: rotate(var(--pl-tilt-h)) scale(1.02); }
}
.pl-sticky--01 { left: calc(39.05 * var(--pl-u));  top: calc(64.72 * var(--pl-u)); --pl-tilt: 2.5deg;  --pl-tilt-h: 4.5deg; background: #ffe58f; }
.pl-sticky--02 { left: calc(377.25 * var(--pl-u)); top: calc(72.23 * var(--pl-u)); --pl-tilt: -1deg;   --pl-tilt-h: -3deg;  background: #b8f0c4; }
.pl-sticky--03 { left: calc(700.14 * var(--pl-u)); top: calc(62.28 * var(--pl-u)); --pl-tilt: 1.5deg;  --pl-tilt-h: 4deg;   background: #bfe0ff; }

.pl-sticky__eyebrow {
  font-size: calc(9.755 * var(--pl-u));
  font-weight: 600;
  letter-spacing: calc(0.7804 * var(--pl-u));
  color: rgb(30 30 30 / .55);
}
.pl-sticky__body {
  font-size: calc(14.632 * var(--pl-u));
  line-height: calc(21.135 * var(--pl-u));
}
/* If / then / because are bold inside the sentence. They are the shape of a
   hypothesis, not emphasis for its own sake, so <b> rather than <strong>. */
.pl-sticky__body b { font-weight: 700; }
/* The spacer frame in the file is a flex:1 push — a margin does the same
   thing without an empty element. */
.pl-sticky__sign {
  margin-top: auto;
  font-size: calc(11 * var(--pl-u));
  color: rgb(30 30 30 / .45);
}

/* --- the +1 stamp (1300:4171) --- */
.pl-board__stamp {
  position: absolute;
  left: calc(935.29 * var(--pl-u));
  top: calc(49.29 * var(--pl-u));
  padding: calc(4.877 * var(--pl-u)) calc(8.129 * var(--pl-u));
  border: calc(1.626 * var(--pl-u)) solid var(--pl-cursor);
  border-radius: calc(81.289 * var(--pl-u));
  background: #fff;
  font-family: var(--pl-font-board);
  font-size: calc(10.568 * var(--pl-u));
  font-weight: 700;
  color: var(--pl-cursor);
  transform: rotate(8deg);
}

/* --- somebody else's cursor, parked on the board (1300:4173, :4174) --- */
/* The svg box sits 0.609 / 1.351 out from the node, which is exactly where
   its path starts: the white stroke hangs outside the shape.
   .pl-board__presence is the one box that flees the visitor's cursor, so it
   carries the board position and the tag sits against the arrow by margin:
   973.03 - 961.04 across, 343.85 - 322.99 - 22.4655 down. */
.pl-board__presence {
  position: absolute;
  left: calc(961.04 * var(--pl-u));
  top: calc(322.99 * var(--pl-u));
}
.pl-board__cursor {
  display: block;
  width: calc(16.0412 * var(--pl-u));
  height: calc(22.4655 * var(--pl-u));
}
.pl-board__cursor-tag {
  margin-left: calc(11.99 * var(--pl-u));
  margin-top: calc(-1.6055 * var(--pl-u));
  padding: calc(3.252 * var(--pl-u)) calc(6.503 * var(--pl-u));
  border-radius: calc(4.877 * var(--pl-u));
  background: var(--pl-cursor);
  font-family: var(--pl-font-board);
  font-size: calc(9.755 * var(--pl-u));
  font-weight: 600;
  color: #fff;
}

/* --- the note in the corner (1300:4176) --- */
.pl-board__note {
  position: absolute;
  left: calc(784.49 * var(--pl-u));
  top: calc(403.83 * var(--pl-u));
  padding: calc(11.38 * var(--pl-u)) calc(13.006 * var(--pl-u));
  border-radius: calc(3.252 * var(--pl-u));
  background: #3e3d52;
  box-shadow: 0 calc(2 * var(--pl-u)) calc(6 * var(--pl-u)) rgb(0 0 0 / .12);
  font-family: var(--pl-font-board);
  font-size: calc(10.568 * var(--pl-u));
  line-height: calc(14.632 * var(--pl-u));
  font-weight: 500;
  color: #a9a8ba;
  white-space: nowrap;
  transform: rotate(-2deg);
}

/* =================================== 06 — INTERVIEWS (1225:4161) == */
/* Heading, then two sub-blocks 40 apart: the Instagram poll and the two
   transcripts. Each sub-block is its own caption plus its row, 16 between
   them — so the caption belongs to the row rather than floating above both. */
.pl-subsection {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 16px;
  width: 100%;
}
/* The caption is the board's annotation voice again, at 20 like the persona
   tabs — the same face doing the same job, so it reuses the token. */
.pl-caption {
  font-family: var(--pl-font-hand);
  font-size: 20px;
  font-weight: 400;
  color: var(--pl-ink-on-plate);
}

/* --- the poll's three findings (1225:4163) --- */
.pl-findings {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 20px;
  width: 100%;
}
.pl-finding {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  min-height: 170px;
  padding: 32px;
  border-radius: 20px;
  background: var(--pl-surface-card);
}
/* tabular-nums is not decoration: the value counts up from 1 on the way in,
   and proportional digits would make the number jump its own width on every
   frame. */
.pl-finding__value {
  font-size: 40px;
  font-weight: 600;
  line-height: var(--pl-lh);
  color: var(--pl-ink);
  font-variant-numeric: tabular-nums;
}
.pl-finding__label {
  font-size: 18px;
  line-height: 1.4;
  color: var(--pl-ink-on-plate);
}

/* --- the two transcripts (1304:4153) --- */
.pl-chats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 20px;
  width: 100%;
}
.pl-chat {
  display: flex;
  flex-direction: column;
  height: 560px;
  border-radius: 20px;
  background: var(--pl-surface-card);
  overflow: clip;
}
.pl-chat__header {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: none;
  padding: 24px 32px;
  border-bottom: 1px solid var(--pl-track);
}
.pl-chat__who {
  font-size: 16px;
  font-weight: 600;
  line-height: 1.4;
  color: var(--pl-ink);
}

/* The scroller. Bottom padding matches the top, so the last answer ends as
   far from the window's edge as the first one starts. */
.pl-chat__log {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 22px;
  padding: 24px 32px;
  overflow-y: auto;
  overflow-x: clip;
  /* The page's own scroll is smooth (reset.css sets it on <html>), and that
     applies to programmatic scrolling too. The auto-scroll writes scrollTop
     every frame, so smooth here would fight itself — each write would still
     be easing when the next one lands. */
  scroll-behavior: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--pl-track) transparent;
}

/* One question and its answer. The number sits in its own 38 column so every
   question starts on the same line, and the rule marks the answer as a reply. */
.pl-qa {
  display: grid;
  grid-template-columns: 38px minmax(0, 1fr);
  row-gap: 8px;
  font-size: 15px;
  line-height: 1.45;
}
.pl-qa__num,
.pl-qa__q {
  font-weight: 600;
  color: #6997ff;
}
.pl-qa__a {
  grid-column: 2;
  padding-left: 12px;
  border-left: 2px solid rgb(105 151 255 / .45);
  color: #c2c1d2;
}

/* ========================================== 07 — CJM (1216:4167) == */
/* Heading, the map, then three emotion points. 40 between each, like the
   Hypotheses and Interviews sections.

   THE MAP IS A RASTER, and that was a measurement, not a preference. The
   frame is 481 nodes, 167 of them text. Figma's SVG export outlines every
   one of those into a compound path — 174 paths, 2.76 MB, 930 KB even
   gzipped, and it arrives with a #505050 base rect and the whole 1440 x
   17471 page background baked in behind it. The same frame as webp at 2x is
   142 KB and, compared against the source crop at 1:1, indistinguishable.
   Swapping back is one <img src>; the stylesheet does not care which it is. */
/* The section is a flex column with align-items: flex-start, so a child that
   does not say otherwise shrinks to its content — and the image inside is
   width: 100% of that, which resolves to nothing. The wrapper has to claim
   the column. (It is also why .pl-findings, .pl-points and .pl-chats each
   carry width: 100%.) */
.pl-cjm-scroller { width: 100%; }

.pl-cjm {
  width: 100%;
  /* The intrinsic ratio, so the box is the right height before the file
     lands and nothing below it jumps when it does. */
  aspect-ratio: 1040 / 610;
  border-radius: 20px;
  display: block;
}

/* --- the three emotion points (1216:4171) --- */
.pl-points {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 20px;
  width: 100%;
}
.pl-point {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  padding: 32px;
  border-radius: 20px;
  background: var(--pl-surface-card);
}
.pl-point__level {
  font-family: var(--pl-font-hand);
  font-size: 20px;
  font-weight: 400;
  color: var(--pl-ink-annot);
}
.pl-point__title {
  font-size: 22px;
  font-weight: 700;
  color: var(--pl-ink);
}
.pl-point__note {
  font-size: 18px;
  line-height: 1.4;
  color: var(--pl-ink-on-plate);
}

/* ================================== 08 — COMPETITORS (1216:4184) == */
/* Heading, the comparison as a picture, a caption under it.

   A PLAIN SCREENSHOT, on request, and deliberately not a readable one. On
   the board this block is a draft pasted in at about quarter scale — the
   frame is named "Screens (draft v1)" and its cell type is 4.1px — so it is
   shown here at the board's own 1040, exactly as it reads there. Chasing
   legibility was tried and dropped: it needs 2600 of width, which pans at
   every window size and costs 190 KB. This is the cheap version on purpose.

   PNG, also on request, where the rest of the case is webp. The file is
   1560 wide (1.5x the 1040 it is shown at) quantised to 128 colours:
   116 KB, and indistinguishable from the 4x source at display size. For
   reference, the same render as webp q80 would be 31.7 KB, and dropping to
   a 1x asset would be 68 KB at the cost of looking soft on a 2x screen.

   The table itself is still in the markup, wrapped in .pl-sr. The picture
   carries seven columns of real content that a screen reader cannot read
   and a search engine cannot index, and no sentence of alt text stands in
   for a 7 x 7 comparison. It costs nothing on screen. */
.pl-figure {
  width: 100%;
  margin: 0;
}
.pl-competitors {
  display: block;
  width: 100%;
  /* The intrinsic ratio of the export, so the box is right before the file
     lands and nothing below it jumps when it does. */
  aspect-ratio: 4160 / 2628;
  border-radius: 20px;
}

/* 20px Medium, centred, under the block. */
.pl-figcaption {
  width: 100%;
  margin-top: 16px;
  font-size: 20px;
  font-weight: 500;
  line-height: 1.25;
  color: var(--pl-ink-soft);
  text-align: center;
}

/* Text that is there for a screen reader and not for the eye — here, the
   comparison table behind the picture above. */
.pl-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
/* ================================ 09 — DECISIONS (1248:4292) == */
/* A statement on its own — the section IS the sentence, so it is a heading
   with nothing under it.

   Note the board puts 224 between the divider above and this text, where
   every other section gets 160. That gap is the only one of its kind on the
   whole frame, so this keeps the 160 the brief names and the rest of the
   page already uses. */

/* ================================= 10 — WIREFLOW (1433:4150) == */
/* Heading, then the lo-fi flow 80 below it — wider than the 40 the other
   sections use, and it reads as deliberate: a diagram needs air that a row
   of cards does not. */
.pl-section--airy { --pl-section-gap-inner: 80px; }

.pl-wireflow {
  display: block;
  width: 100%;
  aspect-ratio: 2080 / 2411;
  border-radius: 20px;
}

/* =============================== 11 — VALIDATION (1272:4151) == */
/* Another statement that is its own section, like Decisions.

   The three blocks under it sit at the board's own gaps — 48 to the quotes,
   130 to the recording, 40 to the test setup. They are not a rhythm, they
   are three different distances, so they are written out rather than folded
   into one token that would be a lie. */
.pl-after-quotes    { margin-top: 107px; }
.pl-after-recording { margin-top: 40px; }

/* --- the quotes, as a scatter of chat bubbles (2161:9818) --- */
/* Six bubbles pinned on a 1040 x 547 field, placed by hand so none of them
   overlap — a composition, like the hypotheses board, so it scales as one
   picture on the same --pl-u trick rather than reflowing. Below 860 it
   becomes a staggered conversation, which is what six quotes are once the
   scatter stops fitting. The avatars beside them are the test participants;
   see the note in the markup before this goes anywhere public. */
.pl-quotes-wrap {
  container-type: inline-size;
  width: 100%;
  margin-top: 106px;
}
.pl-quotes {
  --pl-u: calc(100cqw / 1040);
  position: relative;
  width: 100%;
  aspect-ratio: 1040 / 547;
}
.pl-quote {
  position: absolute;
  display: flex;
  align-items: flex-end;   /* the avatar sits on the bubble's baseline */
  gap: calc(14 * var(--pl-u));
}
/* A photograph of each test participant, cropped to the board's own framing.
   They were briefly swapped for numbered discs and put back: Cristina's call
   is that the photographs stay. Recorded so it does not get re-opened. */
.pl-quote__avatar {
  flex: none;
  width: calc(64 * var(--pl-u));
  height: calc(64 * var(--pl-u));
  border-radius: 50%;
  object-fit: cover;
}
/* One tight corner, bottom-left, pointing at the disc beside it. */
.pl-quote__bubble {
  flex: none;
  padding: calc(20 * var(--pl-u)) calc(26 * var(--pl-u));
  border-radius: calc(28 * var(--pl-u)) calc(28 * var(--pl-u)) calc(28 * var(--pl-u)) calc(8 * var(--pl-u));
  background: var(--pl-surface-card);
  font-size: calc(32 * var(--pl-u));
  line-height: calc(42 * var(--pl-u));
  color: var(--pl-ink);
}
/* The board's own text-box widths. They are what makes each bubble break
   where it breaks, and the scatter depends on those shapes. */
.pl-quote__bubble span {
  display: block;
  width: calc(var(--pl-qw) * var(--pl-u));
}

.pl-quote--1 { left: calc(707 * var(--pl-u));   top: 0;                         --pl-qw: 235; }
.pl-quote--2 { left: calc(107.5 * var(--pl-u)); top: calc(19 * var(--pl-u));    --pl-qw: 412; }
.pl-quote--3 { left: calc(43.5 * var(--pl-u));  top: calc(166 * var(--pl-u));   --pl-qw: 280; }
.pl-quote--4 { left: calc(493 * var(--pl-u));   top: calc(190.5 * var(--pl-u)); --pl-qw: 281; }
.pl-quote--7 { left: calc(146 * var(--pl-u));   top: calc(401 * var(--pl-u)); }
.pl-quote--8 { left: calc(681 * var(--pl-u));   top: calc(381 * var(--pl-u));   --pl-qw: 238; }
/* The top-right bubble reaches 32 past the 1040 column. On a wide page that
   sits in the margin; on a narrow one it would pass the gutter, so the field
   scales to its true width there. */
@media (max-width: 1120px) {
  .pl-quotes {
    --pl-u: calc(100cqw / 1072);
    aspect-ratio: 1072 / 547;
  }
}
/* Quote 7 is the one the board sets not to wrap. */
.pl-quote--7 .pl-quote__bubble span { width: auto; white-space: nowrap; }

/* --- the test recording (1278:4150) --- */
/* TODO: test recording — Cristina supplies the screen capture. This is the
   board's own placeholder at its own size, so dropping the video in changes
   nothing around it. Note the plate is #2e2d3e here, a third near-identical
   surface after #2f2e3e and #2f2d3e; the board's, not a choice. */
.pl-recording {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  width: 100%;
  aspect-ratio: 1040 / 585;
  border-radius: 20px;
  background: #2e2d3e;
}
.pl-recording__play { width: 72px; height: 72px; }
.pl-recording__title {
  font-size: 17px;
  font-weight: 500;
  color: var(--pl-ink-on-plate);
}
.pl-recording__note {
  font-family: var(--pl-font-hand);
  font-size: 16px;
  color: var(--pl-ink-annot);
}

/* --- how the test was run (1216:4419) --- */
.pl-setup {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 20px;
  width: 100%;
}
.pl-setup__card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  padding: 28px;
  border-radius: 20px;
  background: var(--pl-surface-card);
}
.pl-setup__value {
  font-size: 40px;
  font-weight: 600;
  line-height: var(--pl-lh);
  color: var(--pl-ink);
}
.pl-setup__label {
  font-size: 16px;
  line-height: 1.3;
  color: var(--pl-ink-on-plate);
}

/* =============================== 12 — ITERATIONS (1277:4150) == */
/* Statement, then the before/after strip 104 below it. webp at 2x, 60 KB —
   the block is real screenshots, so there is nothing to keep as text. */
.pl-after-headline { margin-top: 104px; }

.pl-iterations {
  display: block;
  width: 100%;
  aspect-ratio: 2080 / 1914;
  border-radius: 20px;
}

/* ================================== 13 — SOLUTION (12:96) == */
/* Four steps on one plate. Built as markup rather than exported, because the
   phones in it are EMPTY placeholders carrying Russian working labels — a
   picture would bake those into the page. The step names, the descriptions
   and the plate are the board's; the phone captions are translations of its
   working labels and are marked TODO. See the note in the markup.

   The board's four columns centre on 162 / 406 / 650 / 885 of the plate —
   spacings of 244, 244, 235, so not actually even. Four equal columns with
   42 of side padding lands within ~8px of all four and is the honest
   regularisation of a row that was meant to be even. */
.pl-flow {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  width: 100%;
  /* The board's plate is 489 tall; the content alone comes to 466, so the
     floor holds the rest of its bottom margin rather than letting the plate
     close up around the text. */
  min-height: 489px;
  align-content: start;
  padding: 39px 42px 56px;
  border-radius: 20px;
  background: var(--pl-surface);
}
.pl-step {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
.pl-step__name {
  font-family: var(--pl-font-hand);
  font-size: 20px;
  color: var(--pl-ink);
}
/* TODO: solution screens — the four screens that go in these slots. The box
   is the board's, so dropping them in moves nothing. The fill is the PAGE
   colour, not a surface: on the board these read as holes cut in the plate. */
.pl-step__phone {
  margin-top: 14px;
  width: 128.631px;
  height: 258.66px;
  border-radius: 11.26px;
  background: var(--pl-bg);
  display: grid;
  place-items: center;
  padding: 12px;
  font-size: 17px;
  color: var(--pl-ink-faint);
}
.pl-step__note {
  margin-top: 18px;
  max-width: 200px;
  font-size: 15.687px;
  color: var(--pl-ink);
  text-wrap: pretty;
}

/* ===================== 14 — PLACEHOLDER PLATES (12:139 and friends) == */
/* Three blocks on the board are empty plates with a note to self in the
   middle: the design system, the animation, and the success GIF under
   Results. They carry no content in Figma at all. They are kept because they
   are part of the board's shape, marked TODO, and each is one line to delete
   if they should not ship. */
.pl-plate {
  display: grid;
  place-items: center;
  width: 100%;
  aspect-ratio: 1040 / 489;
  padding: 32px;
  border-radius: 20px;
  background: var(--pl-surface);
  text-align: center;
}
.pl-plate--tall { aspect-ratio: 1040 / 585; }
.pl-plate__label {
  max-width: 728px;
  font-size: 36px;
  color: var(--pl-ink-faint);
}
.pl-plate--tall .pl-plate__label { color: #6a687d; }

@media (max-width: 1087px) {
  .pl-cjm-scroller {
    width: 100vw;
    margin-inline: calc(50% - 50vw);
    padding-inline: var(--pl-gutter);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: thin;
    scrollbar-color: var(--pl-track) transparent;
  }
  .pl-cjm { min-width: 1040px; }
}

/* Below the point where the 478-wide title and the 251-wide phone stop
   fitting side by side with air between them. */
@media (max-width: 860px) {
  .pl-hero { padding-block: 48px 0; }
  .pl-hero__inner {
    flex-direction: column;
    align-items: center;
    gap: 48px;
  }
  /* flex: none matters. The row turned into a COLUMN, so the desktop
     `flex: 0 1 478px` stopped sizing the width and started sizing the
     HEIGHT — a 478-tall box whose content ended 50px short of it, which read
     as a stray gap above the phone. */
  .pl-hero__text {
    flex: none;
    margin-top: 0;
    width: 100%;
    max-width: 478px;
  }
  /* The hero no longer ends on the phone, so the gap to the key numbers has
     to be held here instead of by the hero's own padding-bottom. */
  .pl-stats { margin-top: 48px; }

  /* 46 is a desktop headline; it breaks "Subscriptions" onto two lines on a
     375 screen. Floors at 32, which still clears the standfirst by the same
     proportion the board has. */
  .pl-hero__title { font-size: clamp(32px, 7.4vw, 46px); }

  /* 246 is wider than a phone column; the pairs stack and keep their rhythm. */
  .pl-hero__meta {
    grid-template-columns: 1fr;
    row-gap: 23px;
  }

  /* Three 72px numbers cannot sit in a row at 375. The plate turns into a
     column and the rules turn with it. */
  .pl-stats {
    flex-direction: column;
    min-height: 0;
    padding: 40px 24px;
  }
  .pl-stat { padding-inline: 0; }
  .pl-stat__value { font-size: clamp(48px, 13vw, 72px); }
  .pl-stats__rule {
    width: 100%;
    height: 1px;
    margin-block: 32px;
  }

  /* The section heading is the same 46 as the hero title and needs the same
     floor; the two track each other deliberately. */
  .pl-h2 { font-size: clamp(32px, 7.4vw, 46px); }
  /* 73 under a heading that is now a third of its desktop size reads as a
     hole rather than as a break. */
  .pl-section { --pl-section-gap-inner: 40px; }

  /* Two 510 cards cannot sit side by side on a phone. They stack, and the
     min-height goes with the row: a stacked card is as tall as its own
     content, and 593 of floor would leave card 1 with 66 of dead space
     nothing fills. */
  .pl-personas { grid-template-columns: minmax(0, 1fr); }
  .pl-persona {
    min-height: 0;
    padding: 24px;
    gap: 24px;
  }

  /* The Hypotheses board stops being a composition and becomes a stack.
     Scaling it all the way down was the other option and it is not one: at
     375 the board is 327 wide, which is 31% — 4.6px body text. So the board
     keeps its ground and its dot grid, the stickies go under each other at
     full size, and --pl-u drops back to a real pixel, which puts every
     number in here at exactly the value the file gives. */
  .pl-board {
    --pl-u: 1px;
    aspect-ratio: auto;
    display: flex;
    flex-direction: column;
    gap: 20px;
    padding: 20px;
  }
  .pl-board__grid { inset: 0; width: auto; height: auto; }
  /* Not 100%: the sticky keeps its tilt, and a rotated box is WIDER than the
     box it was — 287 of content at 2.5 degrees spans ~297, which the board
     clips. 8px of slack each side is enough for the tilt at this height and
     keeps the stickies reading as paper lying on a board rather than as
     full-bleed panels. */
  .pl-sticky {
    position: static;
    width: calc(100% - 16px);
    align-self: center;
    min-height: 0;
  }
  /* The stamp, the parked cursor and its name tag are pinned to board
     coordinates and mean nothing in a stack — a cursor especially, on a
     device that has none. They go, and the three hypotheses and the note,
     which are the content, stay. */
  .pl-board__stamp,
  .pl-board__presence { display: none; }
  .pl-board__note {
    position: static;
    align-self: flex-start;
    white-space: normal;
  }

  /* The quotes stop being a scatter and become a staggered conversation,
     left then right, in the order of the mobile board (2140:13688). */
  .pl-quotes-wrap { margin-top: 32px; }
  .pl-quotes {
    aspect-ratio: auto;
    display: flex;
    flex-direction: column;
    gap: 10px;
  }
  .pl-quote {
    position: static;
    align-items: flex-end;
    align-self: flex-start;
    gap: 8px;
    max-width: 100%;
  }
  .pl-quote--2 { order: 1; }
  .pl-quote--1 { order: 2; align-self: flex-end; }
  .pl-quote--3 { order: 3; }
  .pl-quote--4 { order: 4; align-self: flex-end; }
  .pl-quote--8 { order: 5; }
  .pl-quote--7 { order: 6; align-self: flex-end; }
  .pl-quote__avatar { width: 30px; height: 30px; }
  /* flex and min-width matter: a flex item will not shrink below its content
     unless it is told it may, and the bubble would run off the screen. */
  .pl-quote__bubble {
    flex: 0 1 auto;
    min-width: 0;
    padding: 9px 13px;
    border-radius: 18px 18px 18px 6px;
    font-size: 14px;
    line-height: 20px;
  }
  .pl-quote__bubble span,
  .pl-quote--7 .pl-quote__bubble span {
    width: auto;
    max-width: 205px;
    white-space: normal;
  }
  /* 130 under a stacked list reads as a hole rather than as a break. */
  .pl-after-quotes { margin-top: 56px; }

  /* Four 40px figures do not sit in a row on a phone; two by two does. */
  .pl-setup { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .pl-setup__card { padding: 20px; }

  /* 104 under a headline that is now a third of its desktop size is a hole. */
  .pl-after-headline { margin-top: 48px; }

  /* The Problem block's three gaps are desktop distances — 279 of them is
     most of a phone screen of nothing. */
  .pl-problem        { margin-top: 96px; }
  .pl-problem__flow  { margin-top: 40px; }
  .pl-problem__count { margin-top: 32px; }
  .pl-count { font-size: 20px; }

  /* The four solution steps keep their phones at full size — they are 129
     wide, two fit a phone column — and go two by two with real gaps, since
     the plate's padding no longer separates them. */
  .pl-flow {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 32px 16px;
    padding: 28px 20px 32px;
  }

  /* The empty plates keep their ratio but stop being 489 tall on a phone,
     where that is most of the screen for something with nothing in it. */
  .pl-plate {
    aspect-ratio: auto;
    min-height: 200px;
    padding: 40px 24px;
  }
  .pl-plate--tall { aspect-ratio: auto; min-height: 240px; }
  .pl-plate__label { font-size: 20px; }

  /* Interviews. Three 40px figures and two 510 chat windows both need the
     full column on a phone, so each row becomes one. */
  .pl-findings { grid-template-columns: minmax(0, 1fr); }
  .pl-finding {
    min-height: 0;
    padding: 24px;
  }
  .pl-chats { grid-template-columns: minmax(0, 1fr); }
  /* 560 is most of a phone screen and leaves nothing above or below it to
     tell you the page continues. */
  .pl-chat { height: 440px; }
  .pl-chat__header { padding: 20px; }
  .pl-chat__log { padding: 20px; }

  .pl-points { grid-template-columns: minmax(0, 1fr); }
  .pl-point { padding: 24px; }
}

/* The phone is 251 of fixed art. Below ~330 of content it would touch the
   gutters, so it shrinks as a whole — transform, not width, so the screen
   inside keeps its offsets without a second set of numbers. */
@media (max-width: 360px) {
  .pl-phone {
    transform: scale(.85);
    transform-origin: top center;
    margin-bottom: -77px;   /* 513 * .15, reclaimed from the flow */
  }
}

@media (prefers-reduced-motion: reduce) {
  .case-petland * { animation: none !important; transition: none !important; }
}
