/* =====================================================================
 * THE VISUAL POLISH BATCH -- items 15 (completion), 4 and 5.
 *
 * app/polish.py gates it; `polish_live` has no settings row, so it is OFF and
 * this file is not even requested while it is. Loaded AFTER night-polish-c.css
 * and therefore after every other sheet on the page, so a rule here beats the
 * one it corrects on order alone and needs no `!important`.
 *
 * ITEM 17 IS NOT IN HERE. It was built on 8 October and lives in
 * static/site/night-polish-c.css behind `night_polish_c`. One item, one home.
 * ITEM 25 IS NOT IN HERE either: it went live on 8 October inside "the
 * thirteen" and the ingredient columns already measure the Easy-Salsa style to
 * the pixel on all 172 published recipes. audit/polish/DIAGNOSIS.md has the
 * counts. Nothing to correct is nothing to write.
 *
 * SECTIONED BY ITEM. Every section says what was measured.
 * ===================================================================== */

/* ===================================================================== *
 * THE TWO COLOURS THIS BATCH USES, AND WHERE THEY COME FROM.
 *
 * The brief says "Brand has defined GRAY and GOLDEN tokens -- all colors below
 * come from those tokens, never hand-picked hex."
 *
 * GRAY EXISTS. `--card: #f7f7f7` (recipe-v3.css line 10) is the ground of every
 * content box on the recipe page -- the step cards, the comments card, the
 * embed blocks. It is used below by name and nothing is typed.
 *
 * GOLDEN DOES NOT EXIST, and that was checked rather than assumed: every custom
 * property declared in static/site/*.css, the seven theme tokens in
 * data/design-baseline.json (brand orange, brand orange darker, body text,
 * headings, soft background, success green, font) and Tom's own transcribed
 * drawings in design/drive/ -- there is no golden, no gold, no amber, no honey.
 * The warm colours this site owns are --cream #fffeec and --orange #f18032.
 *
 * SO THE GOLDEN IS DERIVED FROM TWO TOKENS AND NOT PICKED. It is 15% of the
 * brand orange in the approved cream, written as `color-mix()` so the
 * declaration literally reads the two custom properties -- change --orange in
 * the Look screen and this moves with it, which a hex could never do.
 *
 * 15% WAS MEASURED, NOT EYEBALLED. CIE76 dE, computed over the candidates:
 *
 *     mix      hex       dE from   dE from   dE from   contrast
 *                        the page  --cream   --card    with body ink
 *      6%    #fef6e1      11.71      3.80     11.35      7.42
 *     10%    #fef1d9      13.77      6.38     13.16      7.16
 *     15%    #fdebd0      16.58      9.64     15.76      6.83   <- chosen
 *     20%    #fce5c7      19.57     12.96     18.62      6.52
 *     30%    #fbd8b4      25.95     19.76     24.84      5.93
 *
 * and the two numbers that decided it:
 *
 *   THE REVIEWS CARD TODAY IS dE 2.56 FROM THE NUTRITION PANEL. That is below
 *   the distance at which two large flat grounds can be told apart at all,
 *   which is exactly the fault Tom is reporting.
 *
 *   THE NUTRITION PANEL IS dE 9.16 FROM THE PAGE. That is this site's own
 *   proven "this is a different block" distance -- the separation Tom already
 *   accepted when he approved the cream. 15% put the reviews card dE 9.64 from
 *   the nutrition panel: as different from nutrition as nutrition is from the
 *   page.
 *
 *   REVISION 2: TOM LOOKED AT 15% AND ASKED FOR 20%. So it is 20% -- dE 12.96
 *   from the nutrition panel, a third again as far apart as the floor the
 *   measurement argued for, and still 6.52:1 under the body ink and 12.61:1
 *   under the maroon headings. The 15% reasoning is kept above rather than
 *   rewritten: it is why the number could not be LOWER, and Tom's answer is
 *   why it is not merely that.
 *
 * AND IT STAYS READABLE. Body ink (#4e5155) on it is 6.83:1 and the maroon
 * headings are 13.21:1 -- both far past WCAG AA's 4.5:1, and better than the
 * 4.5 floor by enough that the 14px review meta text is safe too.
 *
 * THE @supports IS NOT DECORATION. `color-mix()` with `var()` inside is
 * substituted at COMPUTED-VALUE time, so a browser that does not know the
 * function does not fall back to an earlier declaration -- the property comes
 * out unset and the block loses its ground entirely. The plain value first is
 * the arithmetic above worked out, so both paths paint the same colour.
 * ===================================================================== */
:root{
  --golden: #fce5c7;
}
@supports (color: color-mix(in srgb, white 50%, black)){
  :root{
    --golden: color-mix(in srgb, var(--orange,#f18032) 20%, var(--cream,#fffeec) 80%);
  }
}

/* ===================================================================== *
 * ITEM 15, THE SECOND HALF -- one wrapper for every in-content ad, and the
 * 30px moved out of the clip onto the ad's own margin.
 *
 * WHAT WAS MEASURED FIRST, because the brief's premise and the page disagree.
 * Filled with the staging stub at 1440 on Žemlovka, 9 of 9 units already carry
 * `.ttc-ad__label` and 9 of 9 already measure 30px or more of painted air. The
 * in-content banners are NOT touching the content boxes and they are NOT
 * missing the label. The full table is in audit/polish/DIAGNOSIS.md.
 *
 * WHAT IS GENUINELY WRONG is the brief's other sentence -- "find WHY the
 * in-content placement skips the wrapper". It does. One page holds the same
 * 30px three different ways:
 *
 *     the top slot    an INLINE margin-top on the `.ttc-adtop` WRAPPER, in the
 *                     page whether the slot is enabled, disabled, filled or
 *                     collapsed. It cannot fail.
 *     nine others     a margin on the inner `.ttc-ad__box`, conditional on
 *                     `.is-filled` (which only ad-slots.js adds) AND on
 *                     night-polish-b.css (a switch). With that switch off the
 *                     same page measures 20px, not 30 -- measured on :8695.
 *     the sidebar     the same again, asymmetric, in its own rule.
 *
 * SO EVERY IN-CONTENT PLACEMENT NOW GOES THROUGH `.ttc-adbox` -- one wrapper,
 * emitted by adboxes.in_content(), carrying `data-ad-wrap="<slot>"` so a census
 * can count them. Eleven call sites in app/routes.py: the three recipe slots,
 * the in-step skinny one, the recipe foot, and the in-feed and foot slots on
 * the home page, the articles, the hub and the 46 category pages.
 *
 * THE WRAPPER ITSELF CONTRIBUTES NO BOX, and that is deliberate. `display:
 * contents` means it cannot move one pixel of the UNFILLED page -- which is the
 * page most readers get, because AdSense fills a minority of impressions -- and
 * an empty block wrapper would have been a self-collapsing box that let the two
 * neighbours' margins merge through it. The wrapper is structure, not spacing.
 *
 * THE SPACING GOES ON THE AD, AND THAT IS THE ONE REAL PIXEL CHANGE HERE.
 * Today the 30px is on `.ttc-ad__box`, INSIDE a `display: grid` container --
 * and a child's margin cannot collapse out of a grid formatting context, so it
 * ADDS to whatever the neighbour below already had. Measured, at 1440:
 *
 *     slot            air above   air below   why the below is not 30
 *     recipe_r1          30          63       div.kofi has 33px of its own
 *     recipe_r2          30          76       div.dirlabel has 46px
 *     recipe_r3          30          68       section.ttc-rel has 38px
 *     in-step skinny     30          30       a step card has none
 *     recipe_bottom      60          --       div.embed has 30px
 *
 * Moving the margin onto `.ttc-ad` itself puts it back in normal flow, where
 * an element's own margins DO collapse with its siblings'. The gap becomes
 * max(30, whatever the neighbour had) instead of 30 + neighbour: still never
 * below the 30px floor the item asks for, and no longer 76px in one place and
 * 30px in another. Nothing shrinks below 30 and nothing a neighbour already
 * asked for is taken away.
 *
 * AND IT TOUCHES NO SLOT ID, NO ADSENSE ATTRIBUTE AND NO DESK CONTRACT. Not one
 * declaration here names an `<ins>`, a `data-ad-slot`, a `data-ad-client` or a
 * unit id. tools/polish_gate.py proves it by comparing them byte for byte.
 * ===================================================================== */
/* AND THE SAME THING IS AN INLINE STYLE ON THE ELEMENT -- see the note at
   adboxes.in_content(). This rule is the one to read; the inline one is there
   because the wrapper's promise to contribute no box must survive this sheet
   being slow, blocked or missing, on a feed where it would otherwise become
   the flex item in place of the ad. */
.ttc-adbox{ display:contents }

/* THE FLOOR, on the ad's own margin so it collapses rather than adds. Still
   `.is-filled`, for round 96's reason: an unfilled slot is zero height on
   purpose and 30px above and below nothing is a 60px hole on every page where
   Google does not fill, which is most of them. */
.ttc-adbox > .ttc-ad.is-filled{ margin-block:30px }
/* and the box gives its own margin up, so the two do not add to 60. */
.ttc-adbox > .ttc-ad.is-filled .ttc-ad__box{ margin-block:0 }

/* ===================================================================== *
 * ITEM 4 -- "More recipes like this", from four text links to a gallery.
 *
 * THE SELECTION IS UNTOUCHED: same three tiers, same SQL, same 3-4 recipes,
 * same deterministic order. app/relatedrecipes.pick_rows() is the same walk it
 * always was over a SELECT that gained one column. This is appearance.
 *
 * THE GROUND IS THE BRAND GREY, BY NAME. `--card` is #f7f7f7, the ground of
 * every content box on this page -- the step cards, the comments card, the
 * embed blocks. The block used to sit on `--cream`, which measured dE 0.00 from
 * the nutrition panel: the two were literally the same colour, one above the
 * other. On grey it reads as a different kind of thing, which is what a gallery
 * at the foot of a recipe should be.
 *
 * THE CARDS ARE WHITE ON THAT GREY, AND THAT IS AN INVERSION OF THE LISTING
 * TILE RATHER THAN A DEPARTURE FROM IT. `article.card-v2` is #f8f8f8 on a white
 * page; here the container is the grey, so a #f8f8f8 card on it would be
 * invisible (dE 0.3). The relationship is kept and the two colours swap, which
 * is the only way to have both "brand-grey background" and cards you can see.
 * Everything else is the tile's own: `--r` 28px corners, the 395/370 photograph
 * box, the photograph bled to the card's top edge under rounded corners.
 *
 * THE WHOLE CARD IS ONE ANCHOR -- one hit target, one tab stop, one accessible
 * name. "See recipe" is a `<span>` styled as a button and not a second link to
 * the same address; see the note in app/relatedrecipes._gallery().
 *
 * NO LAYOUT SHIFT. The photograph box has a fixed `aspect-ratio`, so the space
 * is reserved before the lazy image arrives.
 *
 * AND THE SELECTOR CARRIES BOTH CLASSES ON PURPOSE. templates/recipe_v3.html
 * requests static/site/recipe-v3-related.css AFTER this sheet, and its
 * `.ttc-rel` rules are the same specificity as a lone `.ttc-rel--gallery` --
 * so source order would quietly hand the cream ground back. Two classes on the
 * element settles it with no `!important` and no <link> reordered.
 * ===================================================================== */
.ttc-rel.ttc-rel--gallery{
  background:var(--card,#f7f7f7);
  border:1px solid #e6e6e6;
  border-radius:var(--r-md,30px);
  margin-top:38px;
  padding:33px calc(var(--pad-r,56px) - 1px) 36px calc(var(--pad-l,56px) - 1px);
}
.ttc-rel.ttc-rel--gallery .ttc-rel__head{
  font-size:var(--nuthead-size,26px);
  font-weight:var(--nuthead-weight,700);
  color:var(--maroon,#51010e);
  margin:0 0 20px;
}
.ttc-rel__grid{
  list-style:none;
  margin:0;
  padding:0;
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(170px,1fr));
  gap:22px;
}
.ttc-relc{ margin:0; padding:0; display:flex }
.ttc-relc__a{
  display:flex;
  flex-direction:column;
  width:100%;
  background:var(--page,#fff);
  border-radius:var(--r,28px);
  overflow:hidden;                 /* the photograph takes the top corners */
  text-decoration:none;
  color:inherit;
  box-shadow:0 1px 3px rgba(0,0,0,.07);
  transition:box-shadow 160ms ease, transform 160ms ease;
}
.ttc-relc__a:hover,
.ttc-relc__a:focus-visible{
  box-shadow:0 6px 18px rgba(0,0,0,.13);
  transform:translateY(-2px);
}
.ttc-relc__a:focus-visible{
  outline:2px solid var(--maroon,#51010e);
  outline-offset:3px;
}
/* THE TILE'S OWN SHAPE: 395 wide by 370 of photograph, from cards-v2.css. */
.ttc-relc__shot{
  display:block;
  aspect-ratio:395 / 370;
  width:100%;
  background:var(--vars-tint-a,#efefef);
  overflow:hidden;
}
.ttc-relc__img{
  display:block;
  width:100%;
  height:100%;
  object-fit:cover;
}
/* A recipe whose photograph is not on disk gets a plain tinted panel rather
   than a broken image -- app/cards._card_image() returns '' and the markup
   carries no <img> at all. Round 38's blank white box, on purpose and tinted
   so it reads as "no picture" instead of "failed". */
.ttc-relc__shot.is-empty{ aspect-ratio:395 / 148 }
.ttc-relc__body{
  display:flex;
  flex-direction:column;
  gap:12px;
  flex:1 1 auto;
  padding:16px 18px 18px;
}
.ttc-relc__name{
  display:block;
  font-size:var(--small-size,15.5px);
  font-weight:700;
  line-height:1.35;
  color:var(--dark,#1d2327);
}
/* THE BUTTON AT THE BOTTOM OF EACH CARD. `margin-top:auto` is what puts it at
   the BOTTOM rather than under the name: four recipes have four different name
   lengths, and without it the buttons sit on four different lines. The colour
   is the accessible orange Tom chose on 8 October -- #b4531a, the one
   static/site/recipe-v3-related.css already uses and tools/zem_verify.py
   already asserts. --orange (#f18032) fails contrast as text. */
.ttc-relc__cta{
  display:inline-block;
  align-self:flex-start;
  margin-top:auto;
  padding:7px 14px;
  border:1px solid #b4531a;
  border-radius:999px;
  font-size:14px;
  font-weight:700;
  line-height:1.2;
  color:#b4531a;
  background:transparent;
}
.ttc-relc__a:hover .ttc-relc__cta,
.ttc-relc__a:focus-visible .ttc-relc__cta{
  background:#b4531a;
  color:#fff;
}
@media (max-width:1024px){
  .ttc-rel.ttc-rel--gallery{
    padding-left:calc(var(--pad-l,22px) - 1px);
    padding-right:calc(var(--pad-r,22px) - 1px);
  }
}
@media (max-width:600px){
  .ttc-rel.ttc-rel--gallery{ padding-top:24px; padding-bottom:24px;
                     border-radius:var(--r-md,22px) }
  /* TWO ACROSS ON A PHONE, NOT ONE. `auto-fit` with a 170px floor gives one
     column at 390 (the inner width is 306), and a single column of four cards
     is 1,100px of scrolling for a block nobody came for. Two is the listing
     page's own answer at this width. */
  .ttc-rel__grid{ grid-template-columns:repeat(2,minmax(0,1fr)); gap:14px }
  .ttc-relc__body{ padding:12px 12px 14px; gap:10px }
  .ttc-relc__cta{ padding:6px 11px; font-size:13px }
}
/* Print: a sheet of paper cannot be clicked, and four photographs of other
   recipes are four photographs of ink. The text version already does this. */
@media print{ .ttc-rel.ttc-rel--gallery{ display:none } }

/* ===================================================================== *
 * ITEM 5 -- the reviews card on the brand golden.
 *
 * TOKEN AND COLOUR ONLY. Not one rule here moves, resizes or re-spaces
 * anything: the selector is the one round 31 wrote and the declaration is the
 * one property it set.
 *
 * MEASURED BEFORE:  reviews #fffdf0   dE  2.56 from the nutrition panel
 *                                     dE  6.69 from the page
 *         AFTER:    reviews --golden  dE 12.96 from the nutrition panel
 *                                     dE 19.57 from the page
 *
 * THE COMMENTS CARD IS NOT TOUCHED and keeps `--card` #f7f7f7, which is the
 * whole point of round 31's design: the two blocks are told apart by their
 * ground, and now they are told apart from the nutrition panel as well.
 *
 * THE SELECTOR CARRIES `.ttc-reviews-ground`, so this still depends on
 * `reviews_ground_live` exactly as it did. Turning that switch off puts the
 * card back on grey whether or not this sheet is loaded -- the two switches
 * compose the way they always have.
 * ===================================================================== */
.ttc-v2.ttc-reviews-ground .embed#reviews{
  background:var(--golden,#fdebd0);
}

/* ===================================================================== *
 * REVISION 2, ITEM 3 -- the search bar centred in the GAP, not on the page.
 *
 * THE FAULT, MEASURED on the live header at four widths. All three boxes in
 * `header .top` are `position: absolute`: the logo at `left:0`, the socials
 * at `right:0`, and the form at `left:50%; margin-left:-17%` -- which centres
 * it on the CONTAINER. The logo and the socials are not the same width, so
 * the two gaps are not the same:
 *
 *     width    gap to the logo    gap to the icons    out by
 *      1920         207 px              306 px         99 px
 *      1440         159 px              235 px         76 px
 *      1280         139 px              215 px         76 px
 *      1100          31 px              123 px         92 px
 *
 * THE FIX IS THE STANDARD ABSOLUTE CENTRING: give the box a left, a right and
 * `margin-inline: auto`, and it centres itself in the span between them. The
 * span wanted is logo-right to icons-left, so `left` is the logo's width and
 * `right` is the icons' width -- two numbers no stylesheet can read, because
 * the logo's width is a background image's aspect ratio and the icons' is
 * however many there are. static/site/polish-search.js measures them and
 * writes the three properties; every declaration that uses them is here.
 *
 * THE FALLBACKS ARE THE THEME'S OWN VALUES, and that is the whole safety of
 * it: `50%`, `44rem` and `-17%` are what `header form` already declares, so a
 * blocked, failed or still-loading script leaves the bar exactly where it is
 * today. There is no state in which this breaks the header.
 *
 * >= 1070px ONLY. Below it the theme sets `width:auto; margin-left:0` and
 * stops centring the form at all, and below 700px it hides the form and the
 * icons outright. Both of those are untouched -- this rule cannot apply at a
 * width where there is nothing to centre.
 * ===================================================================== */
@media screen and (min-width: 1070px){
  header .top form{
    left:   var(--ttc-search-left,  50%);
    right:  var(--ttc-search-right, 44rem);
    margin-left:  var(--ttc-search-mx, -17%);
    margin-right: var(--ttc-search-mx, 0);
  }
}
