/* ROUND 32, JOB 32.9 items 4 and 5. THE FACE THE DRAWING WAS MADE IN.
   This file asked for Poppins in nine places and NOTHING ON THE SITE SERVED
   IT: no @font-face, no Google Fonts link, no file under static/, 0 of 232
   pages loading it. Every visitor fell through to `system-ui`, which at the
   same 700/17px reads heavier than Poppins -- Tom: "not sure if it is just
   too thick or different font but it is not same."

   It measured correct every time because THIS BUILD MACHINE has Poppins
   installed as a system font, so headless Chromium resolved it locally and
   getComputedStyle().fontFamily dutifully returned "Poppins". The gate and
   Tom were looking at two different fonts on two different machines.

   Poppins is SIL Open Font License 1.1, so serving it from the site is
   permitted -- and the licence TRAVELS WITH THE FONT, as the OFL requires:
   static/site/fonts/OFL.txt, beside the four .woff2 files, served at
   /site/fonts/OFL.txt. See also static/site/fonts/README-poppins.txt.
   Poppins (c) 2020 The Poppins Project Authors, Reserved Font Name "Poppins".
   `font-display: swap` on purpose: the card must be readable before the face
   arrives, and every element it sizes already carries width and height, so
   the swap does not move the layout. */
@font-face { font-family: Poppins; font-style: normal; font-weight: 400;
  font-display: swap; src: url("/site/fonts/poppins-400.woff2") format("woff2"); }
@font-face { font-family: Poppins; font-style: normal; font-weight: 500;
  font-display: swap; src: url("/site/fonts/poppins-500.woff2") format("woff2"); }
@font-face { font-family: Poppins; font-style: normal; font-weight: 600;
  font-display: swap; src: url("/site/fonts/poppins-600.woff2") format("woff2"); }
@font-face { font-family: Poppins; font-style: normal; font-weight: 700;
  font-display: swap; src: url("/site/fonts/poppins-700.woff2") format("woff2"); }

/* 19 SEPTEMBER 2026. THE TILE MOVES TO MONTSERRAT -- AND ONLY THE TILE.
   Tom has specified Montserrat for the card_v2 tile, per element, in three
   weights: 300 light, 400 regular, 700 bold. Every rule that asks for it
   below is inside `article.card-v2`, so the rest of the site is untouched and
   still Poppins -- which is why the four Poppins faces above stay exactly
   where they are rather than being replaced.

   ALL THREE WEIGHTS ARE SHIPPED, so the browser has a real face for each one
   and synthesises nothing. Round 32 found `font-weight: 800` being FAKED from
   700 on this very card while getComputedStyle reported "Poppins 800", so
   this is checked rather than assumed: each file's OS/2 usWeightClass was
   read with fontTools before it was copied -- 300, 400, 700 -- and
   tools/tile_font_41.py measures the PAINTED ink of each element and fails if
   a weight looks synthesised.

   Montserrat is SIL Open Font License 1.1, and the licence travels with the
   font as the OFL requires: static/site/fonts/OFL-Montserrat.txt, beside the
   three .woff2 files, served at /site/fonts/OFL-Montserrat.txt.
   Montserrat (c) 2011 The Montserrat Project Authors, Reserved Font Name
   "Montserrat". Provenance -- they are copied from the vendored theme's own
   copies, which carry no licence text at all -- is in
   static/site/fonts/README-montserrat.txt. */
@font-face { font-family: Montserrat; font-style: normal; font-weight: 300;
  font-display: swap; src: url("/site/fonts/montserrat-300.woff2") format("woff2"); }
@font-face { font-family: Montserrat; font-style: normal; font-weight: 400;
  font-display: swap; src: url("/site/fonts/montserrat-400.woff2") format("woff2"); }
@font-face { font-family: Montserrat; font-style: normal; font-weight: 700;
  font-display: swap; src: url("/site/fonts/montserrat-700.woff2") format("woff2"); }

/* =====================================================================
   ROUND 30, JOB 30.8 -- card_v2_live
   THE RECIPE / ARTICLE CARD.

   Reached only through `article.card-v2`, which app/cards.py puts on the
   article when `card_v2_live` is set. Off, not one declaration matches.

   THE SOURCE IS `New Recipe Thumbnail.jpg`, 395x555, which is the card at
   1:1 -- every number in the round's brief was measured off that file, so
   they are used here as given rather than re-derived from a scaled drawing.

   A RE-SKIN, NOT A NEW COMPONENT (README rule 6). The <article>, the
   .top / .image / .bottom structure, the grid, the breakpoints and the
   cards-per-row are untouched: everything below is expressed against the
   card's EXISTING width, never pinned to 395.
   ===================================================================== */

article.card-v2 {
  --c: 395;                       /* the width every ratio below was read at */
  --r: 28px;
  /* THE BADGES HANG OFF THE PHOTOGRAPH, NOT OFF THE CARD. In the 395x555
     source the NEW star and the diet pill sit 42px and 41px above the
     PICTURE's bottom edge, which is 370px down, not 555.
     AND THE ARITHMETIC IS EASIER THAN IT LOOKS. `.bottom` is positioned, so
     it -- not the article -- is what the badges inside it measure against,
     and `.bottom` starts exactly 23px ABOVE the photograph's bottom edge,
     because that is what its -23px margin means. So the photograph's bottom
     is at +23px inside `.bottom` at every card width, and each badge's top is
     23 - its own height - its gap. A constant, with no container query and
     nothing pinned to 395. Measured first: a `bottom:` against the article
     put the diet pill at y 678 on a 562px card, on top of the times row. */
  position: relative;
  border-radius: var(--r);
  box-shadow: 0 3px 16px rgba(0, 0, 0, .14);
  /* PHASE B, ITEM 2. THE CARD BODY IS GREY, NOT WHITE.
     MEASURED off New Recipe Thumbnail.jpg, which is the card at 1:1: every
     sample of the body below the photograph is (248,248,248) -- x=8, x=197
     and x=386 at y=410, 470 and 520 all agree, and the photograph dissolves
     to the same value by y=378. The build was #fff at every one of those
     points.
     #f7f7f7 AND NOT THE DRAWING'S 248: the site's own --card token is
     (247,247,247) and it is what every content box on the recipe page uses.
     One level apart is not a colour anyone can tell from another, and using
     the token means the card cannot drift away from the boxes beside it,
     which a hand-typed #f8f8f8 eventually would. Recorded in QUESTIONS.md so
     the choice is Tom's to overrule rather than mine to hide. */
  /* 19 SEPTEMBER: #f8f8f8, THE DRAWING'S OWN NUMBER.
     Yesterday this became #f7f7f7 -- the site's --card token -- and the note
     then said the drawing measures (248,248,248) and that one level apart was
     not a colour anyone could tell from another. Tom has chosen the drawing's
     number, so the drawing's number is what it is. It is a tile-local value
     on purpose: --card stays (247,247,247) for the content boxes on the
     recipe page, which are a different component and were not asked about. */
  background: #f8f8f8;
  overflow: hidden;
  /* MONTSERRAT, AND THE NOTE THAT USED TO BE HERE IS OVERRULED, NOT DELETED.
     Round 32 wrote, in this spot: "NOT Montserrat: line one is 307px of ink at
     a 13px ink height, and Montserrat 700 needs 16.4px to be that wide with
     ascenders far too short for it. Poppins 700 at 17px matches both, and
     matches the v3 recipe page." That was a measurement of which face best
     reproduced a JPEG at 17px, and it was honest. Tom has now specified
     Montserrat for the tile outright, with his own size and weight for every
     element -- which is a decision, and a decision beats a measurement of
     which face looks closest. Written down rather than quietly removed so
     nobody re-derives the old answer in six weeks and reverts this.
     THE REST OF THE SITE IS STILL POPPINS: this rule is inside
     `article.card-v2` and nothing outside the tile is touched. */
  font-family: Montserrat, system-ui, sans-serif;
}

/* ---- THE PHOTOGRAPH ----------------------------------------------------
   370 of the card's 395, and it runs 32px DEEPER than the visible picture,
   behind the name's first line. */
article.card-v2 .image {
  position: relative;
  aspect-ratio: 395 / 370;
  width: 100%;
  border-radius: var(--r) var(--r) 0 0;
  overflow: hidden;
}
article.card-v2 .image .img {
  display: block; width: 100%; height: 100%;
  background-size: cover; background-position: center;
}
/* THE GRADIENT IS AT THE BOTTOM, NOT THE TOP. Three rounds were lost looking
   for a dark scrim over the top; the top-right corner of the source measures
   255, pure white. The photograph DISSOLVES INTO THE CARD at the bottom. The
   five stops are the five luminances measured down the dark pan at the
   photograph's left edge, which should be constant and is not:
       y 288  L 86   0% white      y 300  149  36%     y 324  173  51%
       y 345  205  71%             y 370  248  100%
   They were not chosen. */
/* AND THE GRADIENT BOX IS THE BOTTOM 22.2% OF THE PHOTOGRAPH, not the whole
   of it. The five stops are percentages of the GRADIENT, and the five
   luminances were read at y 288, 300, 324, 345 and 370 of a 370px-tall
   picture -- so the gradient runs from y 288 to y 370, which is 82px, the
   last 22.2%. Placed at `inset: 0` instead, 15% of the stop list lands at
   y 55 and the whole photograph turns milky: measured on the first build,
   the dish was washed out from the top down. */
article.card-v2 .image::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0;
  /* ROUND 38, JOB 39.29 (a) AND RULE 0.6 -- THE PICTURE WINS, AND HERE IT
     CONTRADICTS THE CSS BESIDE IT.
     TTC-designs.css declares `height:85px` for this band. Its own five stops,
     which the README says were measured off the photograph and "were not
     chosen", put 0% white at y288 -- and the photograph box ends at y370, so
     the band the PICTURE describes is 370-288 = 82px.
     Built to the CSS's 85 (22.973%) and measured: y288 came back 9.8% white
     where the drawing says 0. Built to 82 (22.2%) it comes back 1.4%.
     So this stays at 22.2% and TOM IS TOLD THE CSS IS 3px OUT. */
  height: 22.2%; pointer-events: none;
  /* PHASE B, ITEM 2. THE SAME FIVE STOPS, IN THE CARD'S GREY.
     The photograph dissolves into the CARD, so when the card stopped being
     white the dissolve had to stop being white with it -- otherwise the
     picture fades to #fff and then meets #f7f7f7 in a hard line 82px down.
     NOTHING ELSE CHANGES. The five stops and the four positions are exactly
     as they were -- 0%, 15%, 44%, 70%, 100% at alphas 0, .36, .51, .71, 1 --
     because they are the five luminances measured down the dark pan at the
     photograph's left edge in the drawing and, as the note above says, they
     were not chosen. Only the colour those alphas are applied to moves. */
  /* 19 SEPTEMBER: the same five stops again, now in #f8f8f8. The photograph
     dissolves into the CARD, so the dissolve's colour follows the card's --
     otherwise the picture fades to one grey and meets another 82px down. The
     five stops and the four positions are untouched, for the third time:
     0%, 15%, 44%, 70%, 100% at alphas 0, .36, .51, .71, 1. */
  background: linear-gradient(180deg,
      rgba(248, 248, 248, 0) 0%,
      rgba(248, 248, 248, .36) 15%,
      rgba(248, 248, 248, .51) 44%,
      rgba(248, 248, 248, .71) 70%,
      #f8f8f8 100%);
}

/* ---- THE CHEF PILL, over the photograph -------------------------------- */
/* `.top` holds the chef pill and the flag, both of which are absolutely
   positioned over the photograph. Left in the flow it was 35.3px tall and
   pushed the picture down by that much, so the card measured 562.3 against
   the drawing's 555 and the photograph did not start at the card's own top
   edge. It keeps its markup and stops taking room. */
article.card-v2 > div.top {
  position: static; height: 0; min-height: 0; overflow: visible;
  padding: 0; margin: 0;            /* the theme gives it 19.97px of padding */
}
article.card-v2 .chef-label-holder {
  position: absolute; left: 21px; top: 19px; z-index: 3;
}
/* THE SPECIFICITY HAS TO CLEAR THE THEME'S OWN RULE. Measured: with
   `article.card-v2 .chef-label` the computed background came back
   rgba(0,0,0,0) -- the captured theme stylesheet sets it later in the head at
   the same specificity, and later wins. Naming the holder as well puts this
   one class ahead without an !important. */
/* TWO LINES BESIDE THE AVATAR, which is what the drawing shows and what a
   flex row could not give: `<strong>` and `<em>` are siblings of the avatar,
   so a row laid all three side by side, the pill ran off the card and the
   name sat on top of the picture. A 2x2 grid with the avatar spanning both
   rows keeps the theme's markup exactly as it is and stacks the two lines. */
article.card-v2 .chef-label-holder .chef-label {
  display: grid;
  grid-template-columns: 0 auto;
  grid-template-rows: auto auto;
  align-content: center;
  align-items: center;
  position: relative;
  column-gap: 0;              /* 32.9 item 3: the gap is on the text margin */
  height: 54px; width: max-content; max-width: 300px;
  border-radius: 27px; padding: 0 18px 0 5px;
  background: #e9e9e9; border: 0;
  box-shadow: 0 3px 10px rgba(0, 0, 0, .22);
  text-decoration: none;
}
/* FAULT 2. THE SYMBOL IN THE CHEF'S BUBBLE WAS NOT CENTRED.
   Measured before: the 44px avatar sat 5.0px ABOVE the 54px pill's vertical
   centre, because it spans both grid rows and the two text rows are not the
   same height -- `grid-row: 1/3` with the default `align-self: stretch` let it
   follow them. `align-self: center` puts it on the pill's own centre line, and
   `place-items: center` centres the chef symbol inside the 44px circle rather
   than letting the <img> sit top-left of it. Measured after: 0.0, 0.0. */
/* FAULT 2. THE AVATAR ON THE PILL'S OWN CENTRE LINE, DETERMINISTICALLY.
   Two goes at this with grid alignment both missed, in opposite directions --
   `align-self: center` alone left it 5.0px HIGH, and adding
   `align-content: center` overshot to 8.2px LOW -- because a row-spanning item
   in a fixed-height track group is centred against the tracks, not against the
   box, and the two do not coincide when the item is taller than the tracks.
   Taking it out of the flow removes the question: top 50% and a half-height
   translate is the pill's centre line by definition, at any pill height and
   whatever the two text lines do. Measured after: 0.0.
   `place-items: center` then centres the chef symbol inside its own circle,
   which is the second half of Tom's fault. Measured after: 0.0, 0.0. */
article.card-v2 .chef-label__img {
  position: absolute;
  left: 5px;
  top: 50%;
  transform: translateY(-50%);
  width: 44px; height: 44px; border-radius: 50%; overflow: hidden;
  display: grid; place-items: center;
}
article.card-v2 .chef-label__img img {
  width: 44px; height: 44px; display: block; object-fit: cover;
}
article.card-v2 .chef-label__img img {
  width: 44px; height: 44px; border-radius: 50%; display: block;
}
/* ROUND 32, JOB 32.9 item 3. THE TWO GAPS, MEASURED AGAINST THE DRAWING.
   TTC-designs.css section 01 gives `.card-chef{gap:10px}` between the avatar
   and the text, and `.card-chef-text em{margin-top:2px}` between the two
   lines. Measured in the build before this: the avatar ended at x=70 and the
   text began at x=84, a gap of 14, not 10; and `strong` ended at y=47.1 with
   `em` beginning at y=47.2, a gap of 0.1, not 2.
   The avatar is out of flow at left:5 inside a pill that starts at 21, so it
   spans 26..70 of the card; 10 past that is 80, which is 59 from the pill's
   content edge. `column-gap` is set to 0 here so the number below is the
   whole of the distance and there is only one place to change it. */
article.card-v2 .chef-label strong {
  grid-column: 2; grid-row: 1; align-self: end;
  margin-left: 54px;          /* the text begins at x=80: 26+44 avatar, +10 */
  /* ROUND 38, JOB 39.29 (a) / 39.23 (d). The spec: `.card-chef-text
     {font:400 13px/1.3;color:#6a6a6a}` with `b{font-weight:600;color:#1d2327}`.
     The name plays `b`, so it is 600 -- but the colour was #33322f and the
     line-height 1.15. Both to the spec. */
  /* TOM, 19 Sep: "From Tom the Chef": 12px, "Tom the Chef" weight 700.
     Was 600 13px. The colour is unchanged. */
  font: 700 12px/1.3 Montserrat; color: #1d2327; display: block; white-space: nowrap;
}
/* TOM, 19 Sep: the word "From" is the LIGHT weight, 300. It was 400, which
   is a weight we ship for Montserrat as well -- so this is a change of
   design, not a change of what is available. */
article.card-v2 .chef-label strong span { font-weight: 300; }
article.card-v2 .chef-label em {
  grid-column: 2; grid-row: 2; align-self: start;
  margin-left: 54px;
  margin-top: 2px;            /* the drawing's gap between the two lines */
  /* TOM, 19 Sep: "Published: <date>" is 10px regular. Was 10.5. */
  font: 400 10px/1.3 Montserrat; color: #8a8a8a; font-style: normal;
  display: block; white-space: nowrap;
}

/* ---- FAULT 1. THE FLAG: 48px circle, NO RING ---------------------------
   THE SELECTOR WAS WRONG AND NOTHING SAID SO. Round 30 styled `.flag,
   .nationality-flag`; app/cards.flag_html emits
       <span class="ttc-flag" data-nationality="american">
           <img src="/ttc-media/flags/american.svg" width="38" height="38">
   so not one declaration matched. The flag was in the markup the whole time,
   unstyled, 38px, sitting in the flow of a `.top` that this file had set to
   height:0 -- present to a grep, invisible to Tom. card_gate_30 never looked
   for it, which is exactly how it reported 0 of 27 on a card that was wrong.
   Measured after the fix: 48x48 at right 22, top 14, border 0, outline 0. */
article.card-v2 .ttc-flag,
article.card-v2 .flag,
article.card-v2 .nationality-flag {
  position: absolute; right: 22px; top: 19px; z-index: 3;
  /* AND THE THEME MOVES IT AGAIN AFTER THAT. `.ttc-flag` carries
     `transform: translateY(-24px)` in the theme's own stylesheet -- placed
     there for the old card, where the flag straddled the top edge. With
     `top:14px` set here the computed position measured y = -10 relative to the
     card, so the flag was drawn ten pixels ABOVE the card and clipped off by
     its `overflow: hidden`. Present in the DOM, present to a gate that asks
     whether it exists, and invisible to Tom -- which is the same shape of
     fault as the wrong selector above it. */
  transform: none;
  /* ROUND 32, JOB 32.9 item 1. OVERRULES the round-30 measurement of 48px at
     top 14. Tom, at 1:1: "Diameter = THE HEIGHT OF THE CHEF PILL (54px at the
     395 card), not 48px. Vertically in line with the pill, so the top of the
     card reads as one row."
     The pill is 54 high at top 19, so its centre is y=46. Measured before:
     the flag was 48 at top 14, centre y=38 -- eight pixels high and six
     pixels small. top:19 puts the two centres on the same line by
     construction, at any pill height. */
  width: 54px; height: 54px; border-radius: 50%;
  border: 0; outline: 0;
  box-shadow: 0 3px 10px rgba(0, 0, 0, .22);
  background-size: cover; background-position: center;
  overflow: hidden;
  display: block;
}
article.card-v2 .ttc-flag img {
  width: 54px; height: 54px; display: block; border-radius: 50%;
  object-fit: cover;          /* the SVG is 38px in the markup; the circle is 48 */
}

/* ---- NEW: a 62px star with ROUNDED points ------------------------------
   Drawn with a clip-path rather than an image: README rule 7 forbids drawing
   an ICON, and a star badge is the card's own shape, not an iconography
   choice. The rounding comes from `paint-order` on the stroke, which rounds
   every point without a second path. */
article.card-v2 .card-new,
article.card-v2 .new-badge {
  position: absolute; left: 20px; z-index: 3;
  top: -81px; bottom: auto;         /* 23 - 62 - 42 */
  width: 62px; height: 62px;
  display: grid; place-items: center;
  /* THIS BLOCK MATCHES NOTHING and is kept only because removing it is not
     this job. `card-new` is a class app/cards.py puts on the ARTICLE, and
     this selector asks for a DESCENDANT with that class; the badge the site
     actually draws is `.ttc-new` / `.ttc-new__word`, further down. The family
     moves with the rest so that no Poppins is left inside a tile that is
     meant to be Montserrat -- see QUESTIONS.md. */
  font: 700 12px/1 Montserrat; color: #33322f; letter-spacing: .02em;
  background: #ffff00;
  clip-path: polygon(50% 0%, 61.8% 35.5%, 100% 35.5%, 69% 57.5%,
                     80.9% 93%, 50% 71%, 19.1% 93%, 31% 57.5%,
                     0% 35.5%, 38.2% 35.5%);
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, .18));
}
article.card-v2.card-old .card-new,
article.card-v2.card-old .new-badge { display: none; }

/* ---- THE RING'S FOOT WAS BEING SHAVED OFF -----------------------------
   ROUND 38, JOB 39.23 (b). Tom saw the green ring cut flat along the bottom
   in round 37's own pictures, and he was right -- but nothing on the card
   was clipping it. Swept every card at seven viewport widths: not one icon
   overflows its <i>, its .card-time or its row, anywhere.
   THE CLIPPER IS THE <svg> ITSELF. A root <svg> has `overflow: hidden` by
   user-agent default, and these paths are drawn with their stroke's OUTER
   edge exactly on the viewBox boundary: a 16-radius circle centred at 16,16,
   translated by 2, stroke-width 4, on a 36 box -- outer edge 0 and 36 to the
   pixel. So the anti-aliased outer half-pixel is thrown away all the way
   round, and it reads as a flat cut where the curve runs horizontally, which
   is the bottom.
   MEASURED at device pixel ratio 4, ink read off the pixels:
       as built              ink 36.00px, bottom row 55 of 144 columns  38%
       with overflow visible ink 37.25px, bottom row  4 of 149 columns   3%
   The element's own box is 37x37 either way, so nothing moves and nothing
   reflows -- the ring simply stops being shaved. */
article.card-v2 .card-ring svg,
article.card-v2 .card-bars svg { overflow: visible; }

/* ---- THE DIET PILL: GREEN, not maroon ---------------------------------- */
article.card-v2 .card-diets {
  position: absolute; right: 22px; z-index: 3;
  top: -51px; bottom: auto;         /* 23 - 33 - 41 */
  height: 33px; border-radius: 17px; padding: 0 16px;
  max-width: 213px;
  display: inline-flex; align-items: center;
  background: #337907;
  /* TOM, 19 Sep: the diet pill is 12px BOLD. Was 600 13px. */
  font: 700 12px/1 Montserrat; color: #fff;
  /* RULE 4: one line, never wrapped, and the type never shrinks. The count is
     already reduced to three in app/cards.py, so this is the last rail. */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ---- THE BODY ---------------------------------------------------------- */
article.card-v2 .bottom {
  position: relative; z-index: 2;
  margin-top: -23px;              /* the name sits on the tail of the picture */
  /* ROUND 38, JOB 39.29 (a). The spec says `padding:0 23px 16px`. This was
     0 21px 18px -- 2px narrow on both sides and 2px deep at the foot. */
  padding: 0 23px 16px;
  background: transparent;
}
/* THE TITLE IS EXACTLY TWO LINES, ALWAYS. Fixed height, never min-height
   (README rule 3): a min-height lets a three-line name push the times row
   down and break the grid's own row alignment. */
article.card-v2 .bottom h2 {
  /* ROUND 38, JOB 39.29 (a). The spec says `margin:0` on .card-title and
     puts the 11px above the times row instead. This carried 14px below the
     title AND the times row carried 14 below itself, so the body ran 17px
     longer than the drawing between the title and the rule. */
  margin: 0;
  /* TOM, 19 Sep: 17px bold, and the 17 is not to be touched -- only the
     line-height may move if Montserrat needs it. Measured after the change:
     it does not. 31px x 2 is still 62, the name is still exactly two lines,
     and tools/tile_font_41.py fails if either stops being true. */
  font: 700 17px/31px Montserrat;
  height: 62px;                   /* 2 x 31, fixed */
  /* ROUND 38, JOB 39.29 (a), spec rule 3 -- "exactly two lines ALWAYS".
     The spec asks for the -webkit-box clamp and this was a plain overflow
     hidden, so a third line was cut mid-glyph instead of ellipsised. */
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
article.card-v2 .bottom h2 a { color: #1d2327; text-decoration: none; }

/* ---- THE TIMES ROW: spread, not evenly divided ------------------------- */
article.card-v2 .card-times {
  /* ROUND 38, JOB 39.29 (a). The spec: `height:37px;margin-top:11px`, and
     `.card-times>span{gap:8px}`. This had margin 0 0 14px and gap 10. */
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; margin: 11px 0 0;
  /* ROUND 32, JOB 32.9 item 5. TTC-designs.css gives
     `.card-times i{font:600 13px Poppins}`. Measured here before: weight 400.
     The label is the number beside each mark, so the weight is the whole of
     what Tom can see. */
  /* TOM, 19 Sep: the times numbers AND the difficulty "n/5" are 13px BOLD.
     Was 600. This rule is the one that sizes both -- the level label is the
     third `.card-time` in the same row. */
  font: 700 13px/1 Montserrat; color: #33322f;
}
article.card-v2 .card-time { display: inline-flex; align-items: center; gap: 8px; } /* 39.29(a): the spec says .card-times>span{gap:8px}, this was 9 */
/* THE SITE'S OWN SVG MARKS. The paths come from the `times()` macro in
   app/templates/recipe_v3.html; this only sizes and colours them, the way the
   recipe page's own stylesheet does. */
article.card-v2 .card-ring {
  width: 37px; height: 37px; flex: 0 0 37px;
  display: grid; place-items: center;
}
/* ROUND 32, JOB 32.9 item 9. The marks now carry the site's OWN geometry --
   a 36 viewBox with a 4 stroke, copied out of static/site/herobar-info.css --
   so the stroke width belongs to the path and must not be overridden here.
   What was here drew a 24 viewBox at 2.1, which is why the shapes did not
   match. Colour is driven through currentColor so one path serves both. */
article.card-v2 .card-ring { color: #fd7d23; }
article.card-v2 .card-ring.g { color: #44bb28; }
article.card-v2 .card-ring svg { width: 37px; height: 37px; display: block; }
/* ROUND 32, JOB 32.9 item 8. FILLED to the recipe's level, in the site's own
   orange, and drawn with the site's own asset -- five rects on a 43.509x32
   box, not a circle and four bars. The fill is set per rect in
   app/cards._bars_svg, because it depends on the level; this only sizes the
   box. The mark keeps the asset's own 43.509:32 ratio so the bars are not
   squashed, which the old 36x26 box did. */
article.card-v2 .card-bars {
  display: grid; place-items: center;
  width: 36px; height: 33px; flex: 0 0 36px;
}
article.card-v2 .card-bars svg { width: 36px; height: 26.5px; display: block; }


/* ---- THE RULE, THE STARS, THE COUNT, THE SHARE ------------------------- */
article.card-v2 .card-rating,
article.card-v2 .buttons {
  border-top: 1px solid #e0dedb;
}
/* The share squircle is 46px and sits on this row in the drawing, so the row
   is the taller of the two rather than the stars' own 20px: with a 35px row
   the 46px button hung 11px below the card's padding and over its corner. */
/* THE FOOT ROW. The rule is on it, the stars sit at the left, the share
   button at the right, and both are BELOW the rule because they are inside the
   element that carries it. `.card-foot` is drawn even when there is no rating,
   so the button always has a row to sit in. */
/* ROUND 38, JOB 39.29 (a). THE SPEC'S OWN NUMBERS.
   Section 01 gives `.card-rule{height:1px;background:#e0dedb;margin:14px 0}`
   and `.card-foot{display:flex;align-items:center;gap:14px;height:46px}`.
   The rule is drawn here as a border rather than an element -- that part is
   fine and my first delta table wrongly called .card-rule missing -- but the
   14px BELOW the rule was not there at all, and the gap was 10 where the spec
   says 14. */
article.card-v2 .card-rating .buttons,
article.card-v2 .card-foot .buttons { margin-left: auto; }
article.card-v2 .card-rating,
article.card-v2 .card-foot {
  display: flex; align-items: center; gap: 14px;
  /* ROUND 38, JOB 39.28 -- THE SEVEN PIXELS, LOCATED BY EDGE MATCHING.
     The spec says `.card-rule{margin:14px 0}`. Matching the drawing's
     horizontal edges to the build's puts the gap between the bottom of the
     times row and the rule at 21px in the DRAWING (y454 -> y475) and 14px in
     the build (y457 -> y471). That 7px is the whole of the difference between
     the spec's own arithmetic (548) and the picture (555).
     RULE 0.6: the picture wins. 14 above the rule becomes 21. */
  padding-top: 14px; margin-top: 21px; margin-bottom: 0;
  height: 46px; min-height: 46px;
  border-top: 1px solid #e0dedb;
  box-sizing: content-box;
}
article.card-v2.not-rated .card-foot { border-top: 1px solid #e0dedb; }
article.card-v2 .card-stars {
  display: inline-flex; gap: 3.5px; width: 114px; flex: 0 0 114px;
}
/* ROUND 32, JOB 32.9 item 6. Tom: "make them in exact shape like on the web,
   but of course orange instead of white... DO NOT DRAW A STAR."
   What was here DREW one -- a clip-path polygon with sharp points -- and the
   empty mark set `clip-path: none; border-radius: 3px`, so an unrated star
   rendered as a ROUNDED SQUARE. The mark is now the reviews block's own path
   (app/recipepage._STAR_PATH) emitted as SVG by app/cards._stars, given the
   same round-joined stroke that swells its points into lobes there. Only the
   colour differs, which is what Tom asked for. */
article.card-v2 .card-star {
  width: 20px; height: 20px; display: block; color: #fd7d23;
  background: none; clip-path: none;
}
article.card-v2 .card-star svg { width: 20px; height: 20px; display: block; }
article.card-v2 .card-star.is-empty {
  background: transparent; box-shadow: none;
  clip-path: none; border-radius: 0;
}
/* ROUND 38, JOB 39.29 (a). The spec: `.card-count{font:500 13px Poppins;
   color:#8e8b87;font-variant-numeric:tabular-nums}`. The weight was 400 and
   the digits were proportional, so the count jittered as it changed. */
/* TOM, 19 Sep: the review count ("325x") is 11px REGULAR. Was 500 13px.
   The tabular figures stay -- they are what stops the count jittering as it
   changes, and that is not a size question. */
article.card-v2 .card-count { font: 400 11px/1 Montserrat; color: #8e8b87;
  font-variant-numeric: tabular-nums; }
/* RULE 2: no rating means no stars AND NO COUNT. */
/* RULE 2: no rating means no stars AND no count -- but the FOOT ROW and its
   rule stay, because the share button lives on it. */
/* ROUND 38, TOM'S 39.29 (e) REPLACEMENT. THE STAR ROW IS VISIBLE.
   This was section 01's rule 2 -- "no rating means NO stars AND no count" --
   and Tom's instruction of 17 September supersedes it: "THE ROW IS VISIBLE.
   20px, four filled one outline, spanning exactly 114px, the same rounded
   points as the NEW badge. Round 37 turning it off is reverted."
   THE CSS IS STALE HERE. Noted in QUESTIONS.md so nobody reverts it. */
article.card-v2.not-rated .card-stars { display: inline-flex; }
article.card-v2.not-rated .card-count { display: inline; }

/* FAULT 6. THE SHARE BUTTON WAS ON THE WRONG SIDE AND CUT THE RULE.
   Measured before: `position:absolute; bottom:16px` put its top at y 469 while
   the foot row's 1px rule is at y 474 -- so the button sat 5px ABOVE the rule
   and interrupted it, and on a card with no rating row (no rule to sit under)
   it floated wherever the card happened to end.
   It is not positioned at all now: it is the last item of the foot row, which
   is a flex row with the stars at the left and `margin-left:auto` pushing the
   button to the right. That puts it BELOW the rule by construction, on every
   card, whether or not there is a rating. */
/* THE SPECIFICITY HAS TO CLEAR THE THEME'S OWN RULE, and measuring is how
   that was found: with `article.card-v2 .buttons` the computed position came
   back `absolute` and the button sat at x 101.8 in a foot row starting at
   99.7 -- at the LEFT, 5px above the rule. Naming the parent row puts this
   ahead without an !important. */
article.card-v2 .card-rating > .buttons,
article.card-v2 .card-foot > .buttons {
  position: static;
  margin-left: auto;
  inset: auto;
  border-top: 0; padding: 0;
  display: flex; align-items: center;
}
article.card-v2 .card-rating > .buttons > .icon-btn,
article.card-v2 .card-foot > .buttons > .icon-btn { margin: 0; }
/* ROUND 32, JOB 32.9 item 7. THE GLYPH COMES FROM THE SITE.
   Tom: the glyph is too small and the symbol is wrong -- and wrong in HIS
   drawing as well, so neither was the reference. The site's own mark is
   static/ch-assets/a/css/images/icons-button/share-black.svg: three nodes as
   RINGS, not filled dots, joined by two lines. TTC-designs.css gives the
   glyph at 21px in a 46px squircle.
   The theme was painting share-white.svg here at 1.8rem -- a white glyph on a
   #e5e5e5 ground, which is most of why it read as too small and wrong. */
/* THE SELECTOR CARRIES `.icon-btn` AS WELL, AND IT HAS TO.
   The theme ships `.icon-btn.icon-btn--share.icon-btn--grey{background-image:
   none}` -- three classes, specificity (0,3,0). The first version of this rule
   was `article.card-v2 .icon-btn--share`, which is (0,2,1) and LOSES on class
   count, so the glyph measured `background-image: none` while the size and the
   colour beside it applied: the rule was half-winning, which is the most
   confusing way for a cascade to fail. Naming `.icon-btn` makes it (0,3,1). */
article.card-v2 .icon-btn.icon-btn--share {
  width: 46px; height: 46px; border-radius: 17px;   /* a squircle */
  background-color: #e5e5e5;
  background-image: url("/ch-assets/a/css/images/icons-button/share-black.svg");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 21px auto;
  display: grid; place-items: center;
}
article.card-v2 .icon-btn.icon-btn--share:before,
article.card-v2 .icon-btn.icon-btn--share:after { content: none; }

/* ---- RULE 5: AN ARTICLE IS THE SAME CARD MINUS FOUR THINGS -------------
   diets, flag, difficulty and times. It is shorter by the times row, and
   that is correct -- it is not padded back out to match. */
article.card-v2.is-article .flag,
article.card-v2.is-article .nationality-flag,
article.card-v2.is-article .card-diets,
article.card-v2.is-article .card-times { display: none; }

/* ---- ROUND 32, JOB 32.9 item 10: THE "NEW" STAR ------------------------
   Tom: "The drawing's badge is a ROUNDED five-point star with the word NEW
   CENTRED inside it. The build's star is pointier and the word sits at the
   top-left edge."

   MEASURED OFF THE DRAWING, audit/designs/30/New Recipe Thumbnail.jpg, since
   the README says the picture is the target where it and the spec disagree
   (and they do: the spec says 62x62, the picture says 57x54):
       star bounding box   57 wide x 54 tall, at x=22
       fill                #ffff00, pure  (the build painted #ffe600)
       word centre         dx 0.0, dy +3.0 from the star's own centre

   The build before this: a 54x54 clip-path polygon with SHARP points, and the
   word 0.6px below centre -- because `.ttc-new__word` carries
   `transform: translateY(6%)` and 6% is taken from the WORD's own 10.3px
   height, not from the badge's 54. So the nudge was doing a twentieth of what
   it looks like it does.

   The points are rounded the way TTC-designs.css says to round them: a sharp
   5-point path given a same-colour round-joined stroke of 4.6 on a 22 viewBox.
   Scoped to `article.card-v2` so the recipe page's own hero badge is
   untouched by this round.  */
article.card-v2 .bottom { position: relative; }
article.card-v2 .ttc-new {
  /* ROUND 37, JOB 37.5, items 3, 5 and 7 -- AND THEY ARE ONE FAULT.
     The corrections document guessed that 3, 4, 5, 6 and 7 were probably a
     single fault at the photograph/body junction, and MEASURED, three of them
     are.
     This badge had no positioning at all, so it sat in normal flow at the top
     of .bottom and took its full 54px of vertical space: it pushed the recipe
     name down (item 7), it sat below the photograph instead of on it (item
     3), and it made the whole card 54px taller (item 5).
     THE ARITHMETIC IS EXACT. A card carrying the badge measured 395x607; the
     rated and unflagged cards, which have no badge, measured 395x553 against
     a drawing of 395x555. 607 - 553 = 54, the badge's own height.
     Out of flow, and placed so its foot lands on the photograph's lower edge:
     .bottom begins at y=347 with its -23px margin and the photograph ends at
     y=370, so -31px puts the badge wholly on the picture. */
  /* ROUND 38, JOB 39.23 (a). -31px WAS AN ARGUMENT, NOT A MEASUREMENT.
     Round 37 reasoned the star's foot should "land on the photograph's lower
     edge" and derived -31px from that sentence. Nobody looked at the drawing.
     MEASURED, in New Recipe Thumbnail.jpg at its own 395x555, by finding the
     yellow pixels: the star occupies x 22..78, y 275..329. Its foot is at
     329, which is 41px ABOVE the photograph's lower edge at 370 -- and
     Section 01 says `bottom:42px` inside `.card-photo`, which puts the foot
     at 328. THE SPEC AND THE DRAWING AGREE WITH EACH OTHER AND BOTH DISAGREE
     WITH THE BUILD, by 41px.
     That 41px is exactly what Tom photographed: the star sitting on top of
     the recipe name. `.bottom` begins at y=347, so a foot at 329 is
     329 - 54 - 347 = -72px. */
  position: absolute; left: 21px; top: -72px; z-index: 3;
  width: 57px; height: 54px;
  background: none;
  background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 22'><path d='M11.00 2.30 L12.95 8.31 L19.27 8.31 L14.16 12.03 L16.11 18.04 L11.00 14.32 L5.89 18.04 L7.84 12.03 L2.73 8.31 L9.05 8.31 Z' fill='%23ffff00' stroke='%23ffff00' stroke-width='4.6' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 57px 54px;
  clip-path: none;
  display: grid; place-items: center;
}
article.card-v2 .ttc-new__word {
  /* ROUND 37, JOB 37.5, item 3 -- "the word NEW is the wrong font".
     MEASURED, and it was: this asked for weight 800 and only 400, 500, 600
     and 700 are self-hosted. There is no Poppins 800 file anywhere on this
     machine, so the browser SYNTHESISED one by smearing 700 -- a fake bold,
     which is exactly the "not the same font" Tom can see and which
     getComputedStyle happily reports as "Poppins 800".
     It is set to the heaviest weight we actually serve. If the drawing really
     wants ExtraBold, poppins-800.woff2 has to be added first -- see
     QUESTIONS.md; a weight we do not ship is a weight the browser invents. */
  /* TOM, 19 Sep: the NEW badge word is 10px BOLD. Was 11px.
     THE 800 PROBLEM IS GONE RATHER THAN WORKED AROUND. The note above
     describes asking for weight 800 and getting a smeared 700 -- a fake bold
     that getComputedStyle happily called "Poppins 800". Tom's specification
     is 700, and Montserrat 700 is shipped, so this asks for a weight that
     exists and nothing is invented. */
  font: 700 10px/1 Montserrat; color: #1a2428; letter-spacing: .04em;
  /* the drawing's +3.0px, as pixels rather than a percentage of the word */
  transform: translateY(3px);
}

/* ROUND 38, JOB 39.12. THE AUTOMATIC "POPULAR" BADGE.
   Section 01 of TTC-designs.css has no POPULAR element: this is a piece Tom
   asked for that the drawing does not carry. Rather than invent a shape, it
   is the diet pill's shape at the other end of the same band -- same height,
   same radius, same type -- in the site's own orange so the two are never
   confused. Left, because the diet pill is right.
   It is won by views, at synchro, and it lasts seven days; none of that is
   decided here. See app/popular.py. */
/* PHASE B, ITEM 7. THE POPULAR BADGE IS GONE FROM THE PUBLIC CARD.
   Tom: "POPULAR badge: NOT on the public card. Admin-only, next to the
   recipe." app/cards.py no longer emits `.card-popular` at all, so the rules
   that styled it -- the pill, its position, and the 92px step it took when a
   card was also NEW -- have nothing left to match and are removed with it
   rather than left behind as dead weight. Popularity itself is unchanged:
   app/popular.py still decides it, and the admin Content list shows it as a
   `tag--popular` beside the recipe. */
