/* ALLIN MAKI · the collection (catalogue.html)
   Sits on top of tokens.css, base.css, components.css, sections.css and
   peru.css, so the page shares the banner, masthead, type and footer with the
   rest of the site. Everything here is the catalogue itself. */

:root {
  --ink-muted: rgba(0,0,0,.62);
  --heart:     #C0392B;
  --yes:       #2F6F5E;   /* a size this colour is made in */
  --yes-tint:  #E4EFEA;
  --no:        #B4695E;   /* a size this colour is not made in */
  --no-tint:   #F6E9E6;
  --warn:      #A8721E;
  /* two steps the site's scale does not carry, needed for the card body */
  --s-14: 14px;
  --s-18: 18px;
}

[hidden] { display: none !important; }
.muted { color: var(--ink-a60); }

/* ---- page head --------------------------------------------------------- */
.cat-head { padding-block: var(--s-56) var(--s-32); }
@media (min-width: 768px) { .cat-head { padding-block: var(--s-80) var(--s-40); } }
/* the opening copy on the left, the size chart in the whitespace on the right */
/* minmax(0,1fr) rather than the implicit auto track: the size chart has a
   row of nowrap cells, and an auto track lets their min-content push the
   whole page wider than the phone it is on. */
.cat-head__in { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--s-32); align-items: start; }
.cat-facts { min-width: 0; }
.cat-head__lead { display: grid; gap: var(--s-20); max-width: 780px; }
@media (min-width: 1040px) {
  .cat-head__in { grid-template-columns: minmax(0, 1fr) minmax(400px, 470px); gap: var(--s-48); }
  /* the column stretches to the height of the copy beside it, and the sheet
     rides along inside it: it pins under the masthead while you read, and lets
     go when the column runs out, which is level with the fleece bar */
  .cat-facts-col { align-self: stretch; }
  .cat-facts { position: sticky; top: calc(var(--pill-h) + var(--s-24)); }
}

/* ---- the size chart, as a factsheet ------------------------------------ */
.cat-facts {
  border: 1px solid var(--ink-a15); border-radius: var(--r-16);
  background: var(--white); padding: var(--s-20) var(--s-24) var(--s-16);
  display: grid; gap: var(--s-14);
}
.cat-facts__h { font-family: var(--font-mono); font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-muted); }
/* table-layout: fixed so the four columns stop negotiating with each other.
   They were auto, and the last column asked for 34% and nowrap at the same
   time; five chips at 9.5px plus their margins are wider than 34% of the card
   and a percentage cannot shrink a nowrap run, so the row rules and the LTD
   chip on the Small row ran out through the right edge of the card. */
.cat-facts table { width: 100%; table-layout: fixed; border-collapse: collapse; text-align: left; }
.cat-facts thead th {
  font-family: var(--font-mono); font-weight: 400; font-size: 9.5px; letter-spacing: .11em;
  text-transform: uppercase; color: var(--ink-muted);
  padding: 0 var(--s-10) var(--s-8) 0; border-bottom: 1px solid var(--ink-a15);
}
.cat-facts tbody th, .cat-facts tbody td {
  padding: var(--s-12) var(--s-10) var(--s-12) 0; border-bottom: 1px solid var(--ink-a10);
  font-size: 13px; line-height: 1.3; vertical-align: middle;
}
.cat-facts tbody tr:last-child th, .cat-facts tbody tr:last-child td { border-bottom: 0; }
.cat-facts tbody th { font-weight: 700; white-space: nowrap; }
/* the code sits beside the name rather than under it: one line per row keeps
   the whole sheet inside the whitespace it is filling */
.cat-facts tbody th span {
  font-family: var(--font-mono); font-weight: 400; font-size: 9.5px;
  letter-spacing: .1em; color: var(--ink-muted); margin-left: var(--s-6);
}
.cat-facts .num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; white-space: nowrap; }
.cat-facts .num span { color: var(--ink-muted); margin-left: var(--s-6); font-size: 11px; }
/* the collections a size is made in, as codes rather than names, so the column
   stays one line a row and the sheet keeps its air */
.cat-facts thead th:nth-child(1) { width: 20%; }
.cat-facts thead th:nth-child(2) { width: 30%; }
.cat-facts thead th:nth-child(3) { width: 14%; }
.cat-facts__where { width: 36%; }
/* The Rug row is the one value on the sheet that is two measurements, and it
   is the tightest: let the imperial half wrap rather than push the column. */
.cat-facts .num span { white-space: normal; }
/* And on a phone the name lets its code drop under it. One line a row is worth
   having and is not worth an overflow: the first column is 20 per cent, which
   is 82 pixels at 360, and the Spanish Rug row became "Alfombra RUG" at 88 the
   day the glossary stopped calling a rug a blanket. A name is a word somebody
   chose for a product and it will get longer again in German. */
@media (max-width: 480px) {
  .cat-facts tbody th { white-space: normal; }
  /* the code goes under the name rather than beside it. Letting the cell wrap
     is not enough on its own: the span follows the name with no space between
     them in the markup, so there is nowhere to break and the run stays
     "AlfombraRUG" whatever white-space says. */
  .cat-facts tbody th span { display: block; margin-left: 0; }
}
.cat-facts__tag {
  display: inline-block; font-family: var(--font-mono); font-size: 9.5px;
  letter-spacing: .1em; line-height: 1; color: var(--ink-a70);
  padding: 4px var(--s-6); margin: 0 3px 0 0; border-radius: var(--r-4);
  background: var(--ink-a05);
}
.cat-facts__key { letter-spacing: .06em; }
.cat-facts__key b { font-weight: 400; color: var(--ink-a70); }
.cat-facts__ask th b, .cat-facts__ask td { color: var(--ink-a60); }
.cat-facts__note { font-family: var(--font-mono); font-size: 10px; line-height: 1.5; letter-spacing: .04em; color: var(--ink-muted); }
/* On a narrow screen the collection list wraps to five lines a row and the
   sheet stops being a factsheet. Drop that column and say the same thing in
   one line under the table. */
@media (max-width: 700px) {
  .cat-facts { padding: var(--s-14) var(--s-16) var(--s-12); }
  .cat-facts thead th:last-child, .cat-facts tbody td:last-child { display: none; }
  .cat-facts__note--wide { display: none; }
  /* One line a row is the rule above, and at this width Spanish cannot keep it:
     "Tamano real XXL" wants 104px where the column gives 82 at 360 and 92 at
     390, so the code ran out through the side of the sheet. Only this row is
     long enough to wrap, and only in Spanish. */
  .cat-facts tbody th { white-space: normal; }
}
@media (min-width: 701px) { .cat-facts__note--narrow { display: none; } }
.cat-head .t-h1 { font-size: 40px; line-height: 1.03; letter-spacing: -0.02em; }
@media (min-width: 768px) { .cat-head .t-h1 { font-size: 64px; } }

/* the fleece run: the undyed shades as one bar, light to dark, which is the
   page's argument in a single line */
.cat-run { display: grid; gap: var(--s-8); margin-top: var(--s-8); }
.cat-run__bar { display: flex; height: 34px; border-radius: var(--r-8); overflow: hidden; }
.cat-run__bar i { flex: 1; }
.cat-run__lbl { display: flex; justify-content: space-between; font-family: var(--font-mono); font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-muted); }

/* ---- the jump strip and the favourites bar ----------------------------- */
/* deliberately not sticky: the site's banner and masthead already hold about
   130px of the screen, and a third sticky bar was covering the top of the
   cards as you scrolled past them */
.cat-bar { background: var(--tint); border-block: 1px solid var(--ink-a10); }
/* One row at every width. On a phone the bar used to be six jump links and a
   favourites line stacked into most of the first screen, so a buyer opening
   the collection saw the controls and not one alpaca. It is a dropdown and a
   heart now, and on a phone it is about as tall as a button. */
.cat-bar__in { display: flex; align-items: center; justify-content: space-between; gap: var(--s-10) var(--s-24); padding-block: var(--s-6); flex-wrap: wrap; }
@media (min-width: 900px) { .cat-bar__in { padding-block: var(--s-10); } }

.cat-filter { position: relative; display: inline-grid; align-items: center; min-width: 0; }
.cat-filter select {
  grid-area: 1 / 1; appearance: none; -webkit-appearance: none;
  min-height: 38px; padding: 0 var(--s-36) 0 var(--s-16);
  border: 1px solid var(--ink-a20); border-radius: var(--r-pill); background: var(--white);
  font: 500 14px/1 var(--font-body); color: var(--ink); cursor: pointer;
  max-width: 100%; transition: border-color var(--t-link);
}
.cat-filter select:hover { border-color: var(--ink-a40); }
.cat-filter select:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.cat-filter svg { grid-area: 1 / 1; justify-self: end; margin-right: var(--s-14); width: 14px; height: 14px; pointer-events: none; }
/* the page says which collection it is showing, so a filtered grid is never
   mistaken for the whole range */
.cat-bar:has(#cat-line option:checked:not([value="all"])) .cat-filter select { border-color: var(--ink); box-shadow: inset 0 0 0 1px var(--ink); }

/* .section is a grid, so the hidden attribute on its own does nothing */
#catalogue .cat-sec[hidden], #catalogue .peru-divider[hidden] { display: none; }

.cat-favbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-10); font-size: 14px; }
@media (max-width: 899px) {
  .cat-favbar { gap: var(--s-6); flex-wrap: nowrap; }
  /* the count says it with a heart; the word is for a screen with room */
  #fav-word, #fav-clear { display: none; }
  /* nothing to show only of until something is hearted */
  .cat-favbar[data-any="false"] #fav-only { display: none; }
}
.cat-favbar__n { display: inline-flex; align-items: center; gap: var(--s-8); font-family: var(--font-mono); font-size: 13px; white-space: nowrap; }
.cat-favbar__n svg { width: 15px; height: 15px; fill: var(--ink-a30); transition: fill var(--t-link); }
.cat-favbar[data-any="true"] .cat-favbar__n svg { fill: var(--heart); }
.cat-favbar button { font-size: 13px; padding: var(--s-6) var(--s-12); border-radius: var(--r-pill); border: 1px solid var(--ink-a20); transition: background-color var(--t-link); white-space: nowrap; }
.cat-favbar button:hover { background: rgba(0,0,0,.06); }
.cat-favbar button[aria-pressed="true"] { background: var(--ink); border-color: var(--ink); color: var(--white); }
.cat-favbar[data-any="false"] button { opacity: .45; }
.cat-favbar[data-any="false"] #fav-only { pointer-events: none; }

/* ---- a section --------------------------------------------------------- */
/* the pill, not the tall header: the collections dropdown on every page of the
   site now jumps straight into these sections, and by the time one lands the
   masthead has already collapsed */
.cat-sec { padding-block: var(--s-48) var(--s-56); scroll-margin-top: calc(var(--pill-h) + var(--s-16)); }
@media (min-width: 768px) { .cat-sec { padding-block: var(--s-64) var(--s-80); } }
.cat-sec__head { display: grid; gap: var(--s-12); max-width: 720px; margin-bottom: var(--s-32); }
@media (min-width: 768px) { .cat-sec__head { margin-bottom: var(--s-40); } }
/* Two columns from 1000, because the head was a 720px column of prose inside a
   1344px band six times over, and everything a buyer is scanning for was
   underneath it at twelve and thirteen pixels: the price band, the number of
   colourways, the note that says a line is a record rather than a range. They
   go in the second column, where they get weight from position rather than
   from a type change, and where they stop the stipple from being the only
   thing in the right half of every section opening. */
@media (min-width: 1000px) {
  .cat-sec__head {
    max-width: none;
    grid-template-columns: minmax(0, 720px) minmax(0, 1fr);
    /* explicit rows, because the second column spans all three and an auto row
       would otherwise absorb its extra height at the top and push the heading
       two hundred pixels down the page */
    grid-template-rows: auto auto 1fr;
    column-gap: var(--s-64); align-items: start;
  }
  .cat-sec__head > .t-eyebrow { grid-column: 1; grid-row: 1; }
  .cat-sec__head > .t-h2      { grid-column: 1; grid-row: 2; }
  .cat-sec__lede              { grid-column: 1; grid-row: 3; }
  .cat-sec__side              { grid-column: 2; grid-row: 1 / -1; }
}
/* The second column is one stack, not three items each taking a row whose
   height comes from the lede in the other half: that put a hundred and fifty
   pixels of nothing between the count and the note. */
.cat-sec__side { display: grid; gap: var(--s-12); align-content: start; }
.cat-sec__head .t-eyebrow { display: flex; align-items: center; gap: var(--s-8); color: var(--ink-muted); }
.cat-sec__lede { color: var(--ink-a70); }
.cat-sec__meta { font-family: var(--font-mono); font-size: 12px; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-muted); }
.cat-sec__meta b { font-weight: 500; color: var(--ink); }
.cat-sec__gap { color: var(--warn); }

/* the Peruvian dividers, quiet: the grid is the loud part of this page */
.peru-divider { --peru-scale: .8; --peru-ink: var(--fleece-sandstone, #BE9A70); opacity: .75; }

/* ---- the grid ---------------------------------------------------------- */
/* One square cell per colourway, all the same size, so the eye compares the
   fleece and not the frame. */
/* every implicit row the same height, and every card filling its row, so no
   card is a different size from any other */
.cat-grid { display: grid; gap: var(--s-12); grid-auto-rows: 1fr; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.cat-grid > .cat-card { height: 100%; }
@media (min-width: 700px) { .cat-grid { gap: var(--s-16); grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1000px) { .cat-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
/* A rug is 100 by 65, and it was being shown in a square cell alongside four
   size chips where the line has one size. Three landscape cells instead: the
   piece is the right shape, and eight over three leaves two cells over, which
   is the only way this line ever gets a filler. */
@media (min-width: 1000px) { #c-rugs .cat-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
#c-rugs .cat-card__photo { aspect-ratio: 100 / 65; }
/* The rug is in the bottom third of that frame, and cover crops from the
   centre, so the cell was mostly chair and floorboard. */
#c-rugs .cat-filler__media { object-position: 50% 88%; }

/* No frame at rest: the white card sits on parchment and the photograph is the
   edge. Hovering lifts it and draws a hairline in the colour of that fleece. */
.cat-card {
  position: relative;
  display: grid; grid-template-rows: auto 1fr; align-content: start;
  border-radius: var(--r-16); background: var(--white); overflow: hidden;
  box-shadow: 0 0 0 1px rgba(0,0,0,.05);
  transition: box-shadow .28s var(--ease-io), transform .28s var(--ease-io);
  /* the sheet sizes its type against this card's own width */
  container-type: inline-size;
}
@media (hover: hover) {
  .cat-card:hover { transform: translateY(-3px); box-shadow: 0 0 0 1.5px var(--c), 0 10px 26px rgba(70,58,0,.14); }
  .cat-card:hover .cw-frame[data-on="true"] img { transform: scale(1.035); }
}
.cat-card[data-fav-on="true"] { box-shadow: 0 0 0 1.5px var(--heart), 0 6px 18px rgba(192,57,43,.13); }
.cat-card:focus-within { box-shadow: 0 0 0 2px var(--ink); }

.cat-card__photo { position: relative; aspect-ratio: 1; background: var(--white); overflow: hidden; }

/* the slideshow: every size of this colour, stacked and crossfaded */
.cw-frame { position: absolute; inset: 0; display: block; opacity: 0; transition: opacity .5s var(--ease-io); }
.cw-frame[data-on="true"] { opacity: 1; }
.cw-frame img { width: 100%; height: 100%; object-fit: contain; transition: transform .5s var(--ease-io); }
.cat-dots { position: absolute; left: 50%; bottom: 10px; transform: translateX(-50%); display: flex; gap: 5px; opacity: 0; transition: opacity var(--t-link); z-index: 2; }
.cat-card[data-playing="true"] .cat-dots, .cat-card__photo:hover .cat-dots { opacity: 1; }
.cat-dots i { width: 5px; height: 5px; border-radius: var(--r-pill); background: var(--ink-a20); transition: background-color var(--t-link); }
.cat-dots i[data-on="true"] { background: var(--ink); }
@media (hover: none) { .cat-dots { opacity: 1; } }

/* Limited Edition has no photography yet, so the cell carries the two colours
   of the pattern as a gradient rather than a borrowed shot */
/* A cell with no photograph yet shows the fleece instead of a colour chip.
   Two layers: the macro crop of that shade from media/run, and the flat hex
   under it. If the crop is missing, as it is for the two-tone, the layer
   simply does not paint and the flat colour is what shows, so nothing has to
   know which crops exist. The label sits on a scrim along the bottom edge, the
   way a plate is captioned, rather than stamped across the middle, where it
   read as a broken image. */
.cat-swatch {
  position: absolute; inset: 0; display: grid; align-content: end;
  background: linear-gradient(150deg, var(--a) 0%, var(--a) 32%, var(--b) 68%, var(--b) 100%);
}
.cat-swatch img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* position, so the caption stacks over an absolutely positioned photograph
   instead of under it */
.cat-swatch__lbl { position: relative; }
.cat-swatch__lbl {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .1em; text-transform: uppercase;
  line-height: 1.6; color: rgba(255,255,255,.94);
  padding: var(--s-16) var(--s-12) var(--s-10);
  background: linear-gradient(to top, rgba(36,30,26,.62), rgba(36,30,26,0));
}
.cat-swatch__lbl i { display: block; font-style: normal; color: rgba(255,255,255,.66); }
/* A fleece crop standing in for one size among photographs. Its caption is
   lifted clear of the frame dots, which sit at the foot of the same box. */
.cw-frame--fleece .cat-swatch__lbl { padding-bottom: var(--s-24); }

/* the heart: outline at rest, red the moment a pointer is on it or it is saved */
.cat-heart {
  position: absolute; top: var(--s-8); right: var(--s-8); z-index: 3;
  width: 36px; height: 36px; border-radius: var(--r-pill); display: grid; place-items: center;
  background: rgba(255,255,255,.86); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  box-shadow: 0 1px 4px rgba(0,0,0,.12); transition: background-color var(--t-link);
}
.cat-heart svg { width: 20px; height: 20px; fill: none; stroke: var(--ink-a60); stroke-width: 1.6; transition: fill var(--t-link), stroke var(--t-link), transform var(--t-link); }
.cat-heart:hover { background: #fff; }
.cat-heart:hover svg, .cat-heart:focus-visible svg { fill: var(--heart); stroke: var(--heart); }
.cat-heart[aria-pressed="true"] svg { fill: var(--heart); stroke: var(--heart); }
@media (prefers-reduced-motion: no-preference) {
  .cat-heart:active svg { transform: scale(.82); }
  .cat-heart[aria-pressed="true"] svg { animation: catpop .28s cubic-bezier(.2,.8,.2,1); }
  @keyframes catpop { 0% { transform: scale(.7); } 60% { transform: scale(1.18); } 100% { transform: scale(1); } }
}

/* ---- the info sheet: a dark overlay over the whole card ------------------
   It covers the photograph and the body together, because the photograph on
   its own is too short for this much text. Type is sized in cqi, against the
   card's width, and js/catalogue.js shrinks --fs further if a card is still
   too small. The sheet is clipped, never scrolled: nothing may hide below a
   fold inside a card. */
.cat-sheet {
  position: absolute; inset: 0; z-index: 4;
  display: grid; align-content: center; overflow: hidden;
  padding: clamp(12px, 5cqi, 40px);
  background: rgba(30, 22, 16, .9);
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
  color: #fff; text-align: left;
  animation: catsheet .22s var(--ease-io);
  cursor: pointer;
}
@keyframes catsheet { from { opacity: 0; } to { opacity: 1; } }
/* a ceiling on the measure as well as on the type: a wide cell has room for
   60px text and a line 90 characters long, and neither is readable */
.cat-sheet__in { display: grid; gap: min(calc(clamp(5px, 2.2cqi, 15px) * var(--fs, 1)), 18px); max-width: 54ch; margin-inline: auto; width: 100%; }
.cat-sheet__nm {
  font-family: var(--font-display); font-weight: 800; letter-spacing: -.01em; line-height: 1.12;
  font-size: min(calc(clamp(15px, 6.4cqi, 30px) * var(--fs, 1)), 34px);
}
.cat-sheet__copy {
  line-height: 1.45; color: rgba(255,255,255,.87);
  font-size: min(calc(clamp(11px, 4.1cqi, 18px) * var(--fs, 1)), 20px);
}
.cat-sheet__kv {
  display: grid; gap: 2px; color: rgba(255,255,255,.87);
  padding-top: min(calc(clamp(5px, 2.1cqi, 13px) * var(--fs, 1)), 16px); border-top: 1px solid rgba(255,255,255,.22);
  font-size: min(calc(clamp(10px, 3.8cqi, 16px) * var(--fs, 1)), 18px);
}
.cat-sheet__kv b {
  font-family: var(--font-mono); font-weight: 400; letter-spacing: .1em; text-transform: uppercase;
  color: rgba(255,255,255,.6);
  font-size: min(calc(clamp(7px, 2.9cqi, 12px) * var(--fs, 1)), 12px);
}

/* the sizes with their price. Three columns on one line a size, so the block
   costs four lines rather than eight and the fit search keeps its type big. */
/* One grid for the whole list, and every row a subgrid of it. Each row used
   to be a grid of its own with auto columns, so the header sized its columns
   to the words HEIGHT and PER PIECE while the rows sized theirs to 15 cm and
   $10.90: nothing lined up, and on a phone the two header words ran into each
   other. Now the columns are measured once, across every row. */
.cat-sheet__price {
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto;
  row-gap: min(calc(clamp(3px, 1.2cqi, 8px) * var(--fs, 1)), 9px);
  column-gap: min(calc(clamp(10px, 4cqi, 20px) * var(--fs, 1)), 22px);
  padding-top: min(calc(clamp(5px, 2.1cqi, 13px) * var(--fs, 1)), 16px);
  border-top: 1px solid rgba(255,255,255,.22);
  list-style: none;
}
/* the price is what this sheet is for, so its rows are the biggest type on it
   after the name */
.cat-sheet__price li {
  grid-column: 1 / -1; display: grid; grid-template-columns: subgrid;
  align-items: baseline; color: rgba(255,255,255,.9);
  font-size: min(calc(clamp(14px, 5.2cqi, 21px) * var(--fs, 1)), 24px);
}
.cat-sheet__price i {
  font-style: normal; color: rgba(255,255,255,.55); justify-self: end;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: .82em;
}
.cat-sheet__price b {
  font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap;
  justify-self: end;
}
.cat-sheet__price-h {
  font-family: var(--font-mono); text-transform: uppercase; letter-spacing: .1em;
  color: rgba(255,255,255,.55);
  font-size: min(calc(clamp(8px, 2.7cqi, 11px) * var(--fs, 1)), 12px) !important;
}
.cat-sheet__price-h i, .cat-sheet__price-h b { font-size: inherit; font-weight: 400; color: inherit; }
/* On a card a phone's two-column grid makes, 146 to 173px wide, three columns
   and a price big enough to find do not fit on one line: Medium ran into
   32 cm. The height goes under the size instead, and the price takes both
   lines on the right. The header drops the word HEIGHT, because the
   centimetres now sit under the size they belong to. */
@container (max-width: 260px) {
  .cat-sheet__price { grid-template-columns: minmax(0, 1fr) auto; row-gap: min(calc(clamp(4px, 1.8cqi, 9px) * var(--fs, 1)), 10px); }
  .cat-sheet__price li > span { grid-column: 1; grid-row: 1; line-height: 1.1; }
  .cat-sheet__price li > i { grid-column: 1; grid-row: 2; justify-self: start; line-height: 1.1; }
  .cat-sheet__price li > b { grid-column: 2; grid-row: 1 / span 2; align-self: center; }
  .cat-sheet__price-h > i { display: none; }
  .cat-sheet__price-h > b { grid-row: 1; align-self: end; }
}
.cat-sheet__price li[data-out="true"] { color: rgba(255,255,255,.45); }
.cat-sheet__price li[data-out="true"] b { color: var(--no); font-weight: 400; }
.cat-sheet__fine {
  color: rgba(255,255,255,.55); line-height: 1.4;
  font-size: min(calc(clamp(9px, 3cqi, 12px) * var(--fs, 1)), 13px);
}
.cat-sheet__x {
  position: absolute; top: clamp(8px, 3cqi, 18px); right: clamp(8px, 3cqi, 18px);
  width: clamp(24px, 9cqi, 36px); height: clamp(24px, 9cqi, 36px);
  border-radius: var(--r-pill); display: grid; place-items: center;
  background: rgba(255,255,255,.14); color: #fff; transition: background-color var(--t-link);
}
.cat-sheet__x:hover { background: rgba(255,255,255,.26); }
.cat-sheet__x svg { width: 45%; height: 45%; }

.avail { display: inline-flex; gap: 3px; vertical-align: middle; margin-right: var(--s-6); }
.avail i { width: min(clamp(4px, 1.6cqi, 7px), 8px); height: min(clamp(4px, 1.6cqi, 7px), 8px); border-radius: var(--r-pill); background: rgba(255,255,255,.28); }
.avail i[data-on="true"] { background: #8FD3BC; }

/* ---- the card body ------------------------------------------------------ */
.cat-card__body { display: grid; gap: var(--s-12); padding: var(--s-14) var(--s-14) var(--s-18); align-content: start; }
/* Three tracks, the outer two the same fixed width, so the name is dead centre
   and always gets the whole middle. An auto middle column let the name be
   squeezed, which made it wrap differently from card to card and every card a
   slightly different height. */
/* The swatch and the name, centred together. The i moved onto the photograph:
   with a 26px column either side the name had about 78px on a phone, and
   Macchiato, Sandstone and Chocolate ran under the disc. */
.cat-card__top { display: flex; justify-content: center; align-items: center; gap: var(--s-8); min-width: 0; }
.cat-card__sw { flex: none; width: 15px; height: 15px; border-radius: var(--r-pill); box-shadow: inset 0 0 0 1px rgba(0,0,0,.12); }
/* two lines reserved whether the name needs them or not, so a card with a long
   name is exactly as tall as one with a short name */
.cat-card__nm {
  /* sized against the card, so the longest single word still fits a phone's
     two-column grid on one line */
  font-family: var(--font-display); font-weight: 800; font-size: clamp(15px, 10.5cqi, 19px); line-height: 1.15;
  letter-spacing: -.015em; text-align: center; min-width: 0;
  min-height: 2.3em; display: flex; align-items: center; justify-content: center;
}
@media (min-width: 700px) { .cat-card__nm { font-size: 20px; } }
/* The card declares container-type: inline-size, so the reserve can be
   conditional. No name in the catalogue wraps above 300px, and the longest are
   Mountain Wolf and Snow Leopard, so forty cards were each holding about 23px
   of air open for a second line that never comes, with the swatch dot and the
   info disc floating in it. */
@container (min-width: 300px) { .cat-card__nm { min-height: 1.15em; } }
/* the i: the heart's twin in the other top corner of the photograph. A dark
   disc rather than a white one, so the two corners are not mistaken for the
   same button. */
.cat-info {
  position: absolute; top: var(--s-8); left: var(--s-8); z-index: 3;
  width: 36px; height: 36px; border-radius: var(--r-pill);
  display: grid; place-items: center;
  background: var(--fleece-obsidian, #241E1A); color: #fff;
  box-shadow: 0 1px 4px rgba(0,0,0,.18);
  font-family: var(--font-display); font-size: 16px; font-weight: 800; line-height: 1;
  cursor: pointer; transition: background-color var(--t-link), transform var(--t-link);
}
.cat-info:hover { background: var(--fleece-walnut, #6E4A2E); transform: scale(1.08); }
.cat-card[data-sheet="true"] .cat-info { background: var(--accent); color: var(--ink); }

/* the sizes: centred, green where it is made, soft red where it is not.
   A pill with a photograph behind it is a button: hovering or tapping it holds
   the card on that size, and the pill marks itself while it is showing. */
.cat-card__sizes { display: flex; flex-wrap: wrap; align-content: center; justify-content: center; gap: 7px 8px; padding-block: var(--s-4) var(--s-6); min-height: 26px; }
/* below this the four pills wrap onto two rows, so reserve both and every card
   in the grid stays the same height */
@container (max-width: 302px) { .cat-card__sizes { min-height: 59px; } }
.cat-size {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .09em; text-transform: uppercase;
  padding: 5px var(--s-10); border-radius: var(--r-pill);
  background: var(--yes-tint); color: var(--yes);
  box-shadow: inset 0 0 0 1px transparent;
  transition: background-color var(--t-link), color var(--t-link), box-shadow var(--t-link);
}
.cat-size[data-out="true"] { background: var(--no-tint); color: var(--no); }
.cat-size[data-goto] { cursor: pointer; position: relative; }
/* The card sets its own min-height against this row, so the target grows
   over the chip rather than under it. Vertical only: the chips sit side by
   side and two overlapping targets would be worse than one small one. */
@media (max-width: 767px) {
  .cat-size[data-goto]::after { content: ""; position: absolute; inset: -6px 0; }
}
.cat-size[data-goto]:hover, .cat-size[data-goto]:focus-visible { box-shadow: inset 0 0 0 1px currentColor; }
.cat-size[data-showing="true"] { background: var(--yes); color: #fff; }
.cat-size[data-showing="true"][data-out="true"] { background: var(--no); color: #fff; }
.cat-size:not([data-goto]) { cursor: default; opacity: .72; }

/* ---- the filler cell ---------------------------------------------------
   Fills whatever the last row of a grid leaves empty. js/catalogue.js sets the
   span, because the column count moves with the viewport, and hides it at the
   widths where that row comes out even: no gap, no container. */
.cat-filler {
  position: relative; border-radius: var(--r-16); overflow: hidden;
  box-shadow: 0 0 0 1px rgba(0,0,0,.05);
  display: grid;
}
/* an author display beats the browser's own [hidden] rule, so say it here */
.cat-filler[hidden] { display: none; }
/* one row that fills the cell, so the picture can be 100% tall and the caption
   can sit on its bottom edge. minmax(0,1fr), not a plain 1fr: that keeps the
   picture's own height as the row minimum, so the row grows to the full frame
   and the caption falls out the bottom of the cell. */
.cat-filler--media { grid-template-rows: minmax(0, 1fr); background: #241E1A; }
.cat-filler__media { width: 100%; height: 100%; min-height: 0; object-fit: cover; grid-area: 1 / 1; display: block; }
.cat-filler--media .cat-filler__cap {
  grid-area: 1 / 1; align-self: end; display: grid; gap: var(--s-6);
  padding: var(--s-20) var(--s-18) var(--s-16);
  /* a scrim under the whole caption plus a soft fade above it, in pixels, so a
     caption that runs to eight lines in a narrow cell stays as readable as a
     two-line one in a wide cell */
  background: linear-gradient(rgba(24,17,12,0), rgba(24,17,12,.5) 56px),
              linear-gradient(rgba(24,17,12,.5), rgba(24,17,12,.88));
  color: #fff;
}
.cat-filler__eyebrow {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .12em; text-transform: uppercase;
  color: rgba(255,255,255,.72);
}
.cat-filler--media .cat-filler__copy { font-size: 13px; line-height: 1.45; color: rgba(255,255,255,.9); max-width: 46ch; }

/* the compliance cell is the one dark object in the grid, so it reads as a
   different kind of thing from a product */
.cat-filler--facts {
  background: var(--fleece-obsidian, #241E1A); color: #fff;
  align-content: center; gap: var(--s-12); padding: var(--s-24) var(--s-20);
}
.cat-filler--facts .cat-filler__eyebrow { color: rgba(255,255,255,.6); }
.cat-filler__h {
  font-family: var(--font-display); font-weight: 800; letter-spacing: -.015em; line-height: 1.12;
  font-size: clamp(18px, 3.4cqi, 27px); max-width: 20ch;
}
.cat-filler__std { display: flex; flex-wrap: wrap; gap: 6px; }
.cat-filler__std li {
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .05em;
  padding: 4px var(--s-8); border-radius: var(--r-4);
  background: rgba(143,211,188,.16); color: #8FD3BC;
}
.cat-filler--facts .cat-filler__copy { font-size: 13px; line-height: 1.5; color: rgba(255,255,255,.78); max-width: 44ch; }
@media (max-width: 699px) {
  .cat-filler--facts { padding: var(--s-16) var(--s-14); gap: var(--s-8); }
  .cat-filler--facts .cat-filler__copy, .cat-filler--media .cat-filler__copy { font-size: 12px; }
  .cat-filler__std li { font-size: 10px; padding: 3px var(--s-6); }
  .cat-filler--media .cat-filler__cap { padding: var(--s-14) var(--s-12) var(--s-12); }
}

/* ---- filtered to favourites -------------------------------------------- */
#catalogue[data-only-favs="true"] .cat-card:not([data-fav-on="true"]) { display: none; }
#catalogue[data-only-favs="true"] .cat-sec:not(:has(.cat-card[data-fav-on="true"])) { display: none; }
#catalogue[data-only-favs="true"] .cat-sec:not(:has(.cat-card[data-fav-on="true"])) + .peru-divider { display: none; }

/* ---- the closing band --------------------------------------------------- */
.cat-cta { background: var(--tint); padding-block: var(--s-64); }
@media (min-width: 768px) { .cat-cta { padding-block: var(--s-96); } }
.cat-cta__in { display: grid; gap: var(--s-24); justify-items: center; text-align: center; max-width: 640px; margin-inline: auto; }
/* the site's .btn stacks its children on a grid; this one carries an icon
   beside the label */
.cat-cta .btn { margin-inline: 0; grid-auto-flow: column; gap: var(--s-8); }
.cat-cta .btn svg { width: 16px; height: 14px; }

@media (prefers-reduced-motion: reduce) {
  .cat-card, .cw-frame, .cw-frame img, .cat-sheet { transition: none; animation: none; }
  .cat-card:hover { transform: none; }
}

/* A caveat, not a line of the lede. It gets the accent rule down its left
   side so it reads as an aside a buyer should finish before choosing a
   colour, and it stays inside the head's 720px measure. */
.cat-sec__note {
  margin: var(--s-4) 0 0; padding: var(--s-12) 0 var(--s-12) var(--s-16);
  border-left: 3px solid var(--accent);
  font-family: var(--font-body); font-size: 15px; line-height: 1.5;
  color: var(--ink-a70);
}
.cat-sec__note b { font-weight: 700; color: var(--ink); }


/* ---- The heart, explained before the grid --------------------------------
   The offset card: one fawn layer showing above the cream one, which is the
   only decoration on this page that is not a photograph or a fleece colour.
   --------------------------------------------------------------------------- */
.cat-how { padding-block: 0 var(--s-40); }
@media (min-width: 768px) { .cat-how { padding-block: 0 var(--s-56); } }

.how {
  position: relative; border-radius: var(--r-20);
  background: var(--accent); padding-top: 13px;
}
.how__in {
  border-radius: var(--r-20);
  background: var(--tint-card);
  padding: var(--s-24) var(--s-20);
  display: grid; gap: var(--s-20);
}
@media (min-width: 900px) {
  .how__in { padding: var(--s-32) var(--s-32) var(--s-28); grid-template-columns: minmax(0, 340px) minmax(0, 1fr); gap: var(--s-40); align-items: start; }
}
.how__lead { display: flex; gap: var(--s-16); align-items: flex-start; }
.how__mark {
  flex: 0 0 auto; width: 40px; height: 40px; display: grid; place-items: center;
  border-radius: var(--r-pill); background: var(--accent);
}
.how__mark svg { width: 20px; height: 20px; fill: var(--ink); }
/* a card title, not a section headline: at 38px it wraps to four lines in
   its own column and leaves the three steps stranded beside it */
.how__t { margin: var(--s-6) 0 0; font-size: clamp(21px, 2vw, 27px); line-height: 1.18; }

.how__steps {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: var(--s-16);
}
@media (min-width: 620px) { .how__steps { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-20); } }
.how__steps li { display: grid; gap: 5px; align-content: start; }
/* A step is a numbered disc, not a small grey character: at 11px in 40 per
   cent ink the numbers read as a footnote marker rather than as one, two,
   three. */
.how__n {
  display: grid; place-items: center; width: 26px; height: 26px; margin-bottom: 3px;
  border-radius: var(--r-pill); background: var(--paper);
  box-shadow: inset 0 0 0 1px var(--ink-a20);
  font-family: var(--font-mono); font-size: 12px; letter-spacing: 0;
  color: var(--ink);
}
.how__steps b { font-family: var(--font-body); font-weight: 700; font-size: 15px; }
.how__steps b i { font-style: normal; font-family: var(--font-mono); }
.how__steps small { font-size: 13.5px; line-height: 1.5; color: var(--ink-a70); }

/* ---- What a line costs, in its own head ----------------------------------- */
/* One row per size, not a dot-separated run. It was the smallest and faintest
   thing in a head that also carries a 54px heading, and the string is
   identical on three of the six lines, so the one line that is priced
   differently was the easiest to scroll past. */
.cat-sec__price { margin: 0; display: grid; gap: 0; }
.cat-sec__pr {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--s-12);
  align-items: baseline; padding-block: var(--s-8);
}
.cat-sec__pr + .cat-sec__pr {
  background-image: radial-gradient(circle, var(--ink-a20) 1px, transparent 1.1px);
  background-size: 8px 2px; background-repeat: repeat-x; background-position: left top;
}
.cat-sec__pr b {
  font-weight: 400; font-family: var(--font-mono); font-size: 12px;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-a60);
}
.cat-sec__pr i {
  /* The price is the answer this list exists to give, so it is read at a
     glance rather than found: two steps up in size and the only bold thing in
     the column. The size label beside it stays quiet on purpose. */
  font-style: normal; font-family: var(--font-mono); font-size: 19px; font-weight: 700;
  font-variant-numeric: tabular-nums; color: var(--ink);
}
@media (min-width: 620px) {
  .cat-sec__pr b {
    display: grid; grid-template-columns: max-content minmax(16px, 1fr);
    align-items: center; gap: var(--s-12);
  }
  .cat-sec__pr b::after {
    content: ""; height: 2px;
    background-image: radial-gradient(circle, var(--ink-a20) 1px, transparent 1.1px);
    background-size: 8px 2px; background-repeat: repeat-x;
  }
}
.cat-sec__price-fine {
  margin-top: var(--s-8);
  font-family: var(--font-body); font-size: 12.5px; letter-spacing: 0;
  /* the second column is where the watermark shows, so the smallest line in it
     cannot also be the palest */
  color: var(--ink-a60);
}

/* The fleece run, on the page it belongs to. The band itself is styled in
   css/landing.css, which this page loads; these are the two differences.
   Inside a section it needs room above and below, and it is not a link here
   because you are already on the colour card. */
/* the padding is not decoration: the shade names sit in it, and with it at
   zero they landed on top of the first and last squares */
.fleecerun--flat { margin: var(--s-12) 0 0; border-top: 0; padding-top: var(--s-20); cursor: default; }
.fleecerun--flat .fleecerun__mid { color: var(--ink-a55, var(--ink-a40)); }
/* The caps and the caption carried their own gutter because the strip used to
   run the full width of the section; inside the container that inset would put
   them 48px in from a strip that is already on the grid. */
.fleecerun--flat .fleecerun__cap, .fleecerun--flat .fleecerun__mid { padding-inline: 0; }
@media (min-width: 768px) { .fleecerun--flat { margin-top: var(--s-32); } }

/* The workshop still is a portrait frame rather than the square product
   crop, and it is film, so it gets a hairline to sit inside instead of
   dissolving into the white. */
.hero__shot--film img { border-radius: var(--r-4); }
