/* The city page, aligned with the native iOS city screen.
   ios/VegEats/Views/Native/CityScreen.swift and VenueCard.swift are the
   source of truth. Riley, 2026-10-10, recorded in CityScreen's own
   docstring: the web city page "doesn't feel up to par in terms of spacing
   and how clean everything is".

   LINKED FROM THE CITY PAGE ONLY, for the same reason venue.css is: the
   rules below reach `.vrow`, `.toolbar` and `footer`, and style.css is
   shared with the home page and the venue pages. It loads AFTER style.css
   so these win on equal specificity.

   VE's spacing scale, identical to the web's --s1..--s8:
   s1 4, s2 8, s3 12, s4 16, s5 24, s6 32, s7 48, s8 64. */

:root{--city-gutter:24px;--card-below:24px}

/* THE HEADER. `CityScreen.header`: the name at 34 Medium with -0.95
   kerning and 12 above it, the count sentence at 15.5 Book with 3pt line
   spacing and 8 above, then the chips with 16 above and 8 below. */
/* LESS AIR ABOVE THE NAME (Riley, 2026-10-13). style.css gives `.band` a
   64px top padding, and that was sized when a breadcrumb sat in it: the
   crumb's own 24px bottom margin meant the name never had 64px of nothing
   over it. The crumb left this header on the same day, so the padding was
   holding a gap for an element that no longer exists. 24 + the name's own
   12 puts it where the native screen has it. */
.band{padding:var(--s5) 0 var(--s2)}
.rankhead h1, h1.d-display{margin-top:12px;letter-spacing:-0.95px}

/* THE RANK ON THE LEFT, THE NAME ON THE RIGHT (Riley, 2026-10-13: "add a
   ranking tag next to it if it's in top 20 vegan us cities", then "that
   rank tag looks extremely cheap", then "i feel like the ranking should be
   on the left and the city name on the right").

   THIS IS /cities.html's OWN ROW. `.crow` there is a grid of a rank column
   and a name column in that order, so putting the rank first here makes
   the two pages agree rather than mirror each other.

   AND IT IS NOT A CHIP. The first version was a grey outlined capsule,
   which is the object the filter chips below it are, so a published
   finding was dressed as a control you can press -- and a bordered pill
   beside 60px display type reads as a browser widget that wandered in.
   style.css settled this on /cities.html and its comment is the argument:
   HappyCow centres that page on a photograph of the city, we have one
   photograph in this entire project and it is a field, so "the rank row is
   typographic: a numeral at the size a photograph would have been". No
   box, no fill. `.crank b` plus its small letterspaced label, which is the
   pair below.

   THE GRID IS ON `.band.ranked` ONLY. Most cities are not in the top
   twenty and three of the twenty have no page at all; a two-column header
   on an unranked city would hold an empty track and push the name off the
   margin for nothing. */
/* THE RANK COLUMN IS THE VENUE-COUNT COLUMN. `.hit-top` below is
   `72px minmax(0,1fr)` with an s4 gap, so using the same track puts the
   rank numeral exactly where every restaurant's vegan-mains count sits and
   the city name exactly where every restaurant name sits. A first pass
   gave the rank a 170px column of its own and the whole header hung 290px
   off a margin the sixty rows beneath it did not share, which reads as a
   layout fault rather than as a hierarchy.

   The same column also makes the point the page is making: that number is
   to the city what the number below it is to a restaurant. */
.band.ranked{display:grid;grid-template-columns:72px minmax(0,1fr);
  column-gap:var(--s4,16px);align-items:start}
.band.ranked .bandtext{min-width:0}
/* THE STATS RUN THE WHOLE WIDTH, FROM THE LEFT MARGIN (Riley, 2026-10-13:
   "i feel like the stats should be left aligned with the us rank"). Inside
   the name column they started 72px in, under the city name; across both
   tracks the first numeral sits directly under the rank numeral, which is
   the alignment the eye expects when both are numbers of the same city. */
/* THE CARD SPANS BOTH TRACKS. A grid child with no column takes auto
   placement, which here is the 72px RANK track: an earlier block landed
   there and drew 125px wide with its labels one word per line. */
.band.ranked .impcard{grid-column:1 / -1}
/* The numeral's cap sits on the name's. Both are the display face, so this
   is a ratio of their sizes, not a number found by nudging. */
/* CENTRED ON THE TWO LINES BESIDE IT (the 12px offsets the block's
   leading so the badge's middle meets the name-plus-claim middle, measured) (Riley, 2026-10-14: "the 11 us rank
   badge needs to move down so it's aligned with the center of these 2
   lines": the city name and "Best US city for vegans"). */
.band.ranked .crest{display:block;align-self:center;padding-top:12px;text-align:center;
  text-decoration:none}
.band.ranked .crest b{display:block;font-family:var(--serif,var(--font-brand));
  font-weight:600;font-size:38px;line-height:1;letter-spacing:-0.03em;
  font-variant-numeric:lining-nums tabular-nums;color:var(--accent,#3e5215)}
/* The label is `.hit-num span`'s treatment exactly -- 10px, 700, .13em,
   uppercase -- because it is the same object one level up. */
.band.ranked .crest span{display:block;margin-top:var(--s2,8px);
  font-family:var(--font-brand);font-size:10px;font-weight:700;
  letter-spacing:.13em;text-transform:uppercase;line-height:1.35;
  color:var(--ink-3,#6e7566)}
.band.ranked .crest:hover b{color:var(--ink,#1c1b19)}

/* THE CLAIM, under the name. A rank with no words is a number nobody can
   check, and the numeral alone in a 72px column cannot carry the sentence.
   The source follows it quieter, so the two read as a statement and its
   footnote rather than one long shout. */
.rankline{margin:6px 0 0;font-family:var(--font-brand);font-size:13px;
  font-weight:var(--font-weight-medium,500);letter-spacing:.01em;
  color:var(--ink-2,#3e5215)}
.rankline span{margin-left:8px;font-weight:var(--font-weight-book,400);
  color:var(--ink-3,#6e7566)}

@media (max-width:640px){
  /* The phone card takes `.hit-top` to a 48px track; the header follows it,
     for the same alignment reason. */
  /* THE RANK BLOCK IS ONE PIECE (lane DSN, Riley 2026-10-13: "the 1 us
     rank doesn't feel like 1 piece"). Number and label as close as a
     card's "88 / VEGAN MAINS" (13.5px ink to ink), the pair centred on the
     name plus subline; the rank column 16px from the name, like the count
     column from a restaurant name. */
  .band.ranked{grid-template-columns:48px minmax(0,1fr);column-gap:16px}
  .band.ranked .crest{padding-top:0}
  .band.ranked .crest b{font-size:26px}
  .band.ranked .crest span{font-size:9.5px;letter-spacing:.1em;margin-top:6.5px}
  /* The count column's 16px before the name is in style.css now (the
     shared card block), so the search card keeps the same gap. */
}

.cityintro, .rankhead p.lede{margin:8px 0 0;font-size:15.5px;line-height:1.55;
  color:var(--ink-body,#3a382f);max-width:62ch}

/* THE IMPACT CARD (Riley, 2026-10-13: "look at our ios app", "why didn't
   you make the graphic like the ones we use in the ios app", "don't show
   the 4,546 vegan mains / 921 restaurants / 19 fully vegan").

   THIS IS `impactCard` IN ios/VegEats/Views/Native/ProfileTabView.swift,
   carried over rather than reinterpreted: a card on the cream, a heading, a
   line of context, then one row per metric -- a 36px rounded-square badge
   filled with that metric's colour holding a white glyph, the sentence
   beside it with the number bold, and a bar under it.

   A CARD IS RIGHT HERE AND WAS WRONG BEFORE. An earlier pass put the three
   inventory numbers in filled tiles and they read as pasted in, because
   nothing else on this page is boxed. This is a different object: it is one
   panel carrying a self-contained argument, which is exactly what it is on
   the profile tab, and it is the only box on the page rather than three
   small ones competing with the venue rows.

   THE BAR IS PER-METRIC PROGRESS, NOT A COMPARISON BETWEEN ROWS. That is
   what makes four units barrable and it is what I got wrong twice: gallons
   are measured against the next gallons milestone, animals against animals
   (`nextMilestone` over `MILESTONES` in app/site/onboard_logic.js, with the
   ladder extended by decades for a city's grain). */
/* CONTAINER SPACING (Riley: "improve the container spacing"). The card had
   20px of padding against 16px between its rows, so the rows nearly touched
   its edge; 26/24 gives the block a margin of its own and lets the rows
   breathe without the card growing. */
.impcard{margin:24px 0 0;max-width:var(--measure,42em);padding:26px 28px 22px;
  border-radius:22px;background:var(--band,#f4f5f0)}
.imphead{margin:0;font-family:var(--font-brand);font-size:17px;
  font-weight:var(--font-weight-medium,500);color:var(--ink,#1c1b19)}
/* The city name and its possessive never break ("Gig / Harbor's"). */
.imphead .impcity{white-space:nowrap}
.impsub{margin:7px 0 0;font-family:var(--font-brand);font-size:13px;
  line-height:1.55;color:var(--ink-3,#6e7566);max-width:52ch}
.impsub b{font-weight:700;color:var(--ink-2,#3e5215)}
/* THE TILES (lane DSN, Riley 2026-10-13: "the icon tiles feel too big"):
   32px, glyph 16px, corners 10px, every screen; 32px between tiles, the
   first 20px under the heading. The figure's first ink lines up with its
   tile's top: the line box adds ~5.7px of leading above the glyphs, so the
   block moves up 5.5px. */
.improw{display:flex;align-items:flex-start;gap:14px;margin-top:20px}
.improw + .improw{margin-top:32px}
.impbadge{flex:0 0 auto;width:32px;height:32px;border-radius:10px;
  display:flex;align-items:center;justify-content:center;color:#fff}
.impbadge svg{width:16px;height:16px}
.impbody{flex:1 1 auto;min-width:0;padding-top:0;margin-top:-5.5px;
  position:relative}
.impbody p{margin:0;font-family:var(--font-brand);font-size:15px;
  line-height:1.4;color:var(--ink-2,#3e5215)}
.impbody b{font-weight:700;color:var(--ink,#1c1b19);
  font-variant-numeric:lining-nums tabular-nums}
/* THE BAR, WITH VEBar's END CAP. VEScaffold.swift draws "a thick white mark
   where the fill ends, as EcoGPT's bars have it", and squares the fill off
   under it so nothing of the rounded tip shows past the mark. Both halves
   are reproduced: the fill keeps its left radius only, and a 3px white rule
   sits on its right edge. */
/* 6px, fully rounded (Riley, 2026-10-13: 10px -> 6px). Overflow visible
   so the average-city notch stands 4px proud above and below. */
.impbar{position:relative;margin-top:8px;height:6px;border-radius:999px;
  overflow:visible;background:rgba(28,27,25,.13)}
.impbar i{display:block;height:100%;border-radius:999px 0 0 999px;
  position:relative}
.impbar i::after{content:"";position:absolute;top:0;right:0;bottom:0;
  width:2px;background:#fff;border-radius:1px}
/* THE AVERAGE CITY, as a tick through the track. Deliberately not a second
   fill: it marks a POSITION on the same scale, and a second bar would read
   as a second quantity. */
/* THE AVERAGE CITY, OPTION B (Riley picked it, 2026-10-13): a 3px ink
   notch at the median city's x, 4px proud of the bar above and below, the
   same x on every bar (fixed scale), and "Average city" said once,
   centred under the last bar's notch, 5px under its foot. */
.impbar u{position:absolute;top:-4px;bottom:-4px;width:3px;
  background:var(--ink-body,#1a1c16);opacity:.85;border-radius:2px}
.impavg{position:relative;height:15px;margin-top:9px}
.impavg span{position:absolute;top:0;font-family:var(--font-brand);
  font-size:11px;line-height:15px;color:var(--ink-3,#6e7566);white-space:nowrap}
.impavg span.centre{transform:translateX(-50%)}
.impnote{margin:18px 0 0;font-family:var(--font-brand);font-size:12px;
  line-height:1.55;color:var(--ink-3,#6e7566)}
/* One line (the marker line is gone; the caption says it). */
.impnote .impnote-l{display:block}
/* The legend swatch for the tick, drawn the same way it is drawn above. */
.impnote em{display:inline-block;width:2px;height:11px;margin-right:7px;
  border-radius:2px;background:var(--ink,#1c1b19);opacity:.42;
  vertical-align:-1px}
@media (max-width:640px){
  .impcard{padding:18px 18px 16px;border-radius:18px}
  .impbody p{font-size:14px}
  /* The card title on one line at 390; a long city name wraps, balanced. */
  .impcard .imphead{font-size:16px;text-wrap:balance}
  .impcard .impnote{font-size:11px}
}

/* TIGHTER ABOVE, LOOSER BELOW (Riley, 2026-10-13: "too much padding before
   the filters and not enough padding under the filters"). */
/* 10 above the chips was right when a line of text sat over them; under a
   card it read as the chips belonging to the card (Riley: "increase padding
   under the card"). 32 separates the two blocks, 26 still holds the chips
   off the first venue. */
.toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  margin:32px 0 26px;padding:0;border:0}
.toolbar .chips{display:flex;gap:8px;flex-wrap:wrap}
.toolbar .pill{font-size:13.5px;font-weight:var(--font-weight-medium,500);
  padding:8px 15px;border-radius:999px;background:#fff;
  border:1px solid var(--rule,#e3e3e0);color:var(--ink,#1c1b19);cursor:pointer}
.toolbar .pill[aria-pressed="true"]{background:var(--ink,#1c1b19);color:#fff;
  border-color:var(--ink,#1c1b19)}

/* THE CARD IS `.hit` NOW. style.css still carries the old city row as
   `.vrow{display:grid;grid-template-columns:130px minmax(0,1fr)}` and that
   sheet is shared, so it is not mine to delete; the article has two
   children now and inherited that grid put the whole venue header in a
   130px track with the dish list overlapping beside it. */
.rows{margin-top:0}
.vrow{display:block;padding:12px 0 var(--card-below);border:0}
.vrow[data-mains="0"] .hit-num b,
.vrow[data-mains="0"] .hit-num span{color:var(--ink-3,#6b6862);opacity:.65}
/* Only the word Closed takes the red; unknown hours keep the quiet grey,
   because unknown is not closed. */
.hit-line .open-shut{color:var(--nope-ink,#a4452a)}

/* THE FROST, the same object as the venue page's hours popup.
   DUPLICATED FROM venue.css ON PURPOSE. It cannot live in style.css: a
   Cloudflare cache rule gives that file a four-hour browser TTL which
   `_headers` does not override, so a change there reaches nobody until it
   expires. Both venue.css and this file are served no-cache. Twenty lines
   in two places beats a fix that cannot ship. */
.sd-frost{position:fixed;left:0;right:0;bottom:0;top:0;z-index:21;
  border-radius:14px 14px 0 0;background:rgba(255,255,255,.3);
  -webkit-backdrop-filter:blur(22px) saturate(1.6);
  backdrop-filter:blur(22px) saturate(1.6);
  -webkit-mask-image:
    linear-gradient(to bottom, transparent 0, #000 7px),
    linear-gradient(to right, transparent 0, #000 10px,
                    #000 calc(100% - 10px), transparent 100%);
  mask-image:
    linear-gradient(to bottom, transparent 0, #000 7px),
    linear-gradient(to right, transparent 0, #000 10px,
                    #000 calc(100% - 10px), transparent 100%);
  -webkit-mask-composite:source-in;mask-composite:intersect;
  animation:frostIn .22s ease-out}
.sd-frost.leaving{animation:frostOut .16s ease-in forwards}
@media (prefers-reduced-motion:reduce){
  .sd-frost,.sd-frost.leaving{animation:none}
}

/* NO RAIL. The native screen is one column: no minimap, no "nearby
   cities". `.with-rail` is a grid on desktop, so it is collapsed rather
   than left holding an empty second track. */
.with-rail{display:block;padding-bottom:0;gap:0}

footer{border-top:0;margin-top:32px;padding-top:0;font-size:12.5px;
  line-height:1.5;color:var(--ink-3,#6b6862)}

@media (max-width:700px){
  html:not(.embed) .shell:has(h1.d-display){
    padding-left:var(--city-gutter);padding-right:var(--city-gutter)}
  .shell,footer .shell{
    padding-left:var(--city-gutter);padding-right:var(--city-gutter)}
  footer{margin-top:18px}
}

/* A4's VISIBLE DATE and the list's H2. Its "Vegan food in" kicker and the
   answer paragraph under the city name are gone (Riley, 2026-10-13: the H1
   is the city name alone, as on the venue page). */
.band .updated-line{margin:8px 0 0;font-size:12.5px;line-height:1.4;
  color:var(--ink-3,#6b6862)}
.list-h{margin:0 0 4px;font-size:13px;line-height:1.4;
  font-weight:var(--font-weight-medium,500);letter-spacing:.06em;
  text-transform:uppercase;color:var(--ink-3,#6b6862)}

/* ======================================================================
   LANE DSN, THE SETTLED DESIGN (2026-10-13). docs/lanes/DSN-SETTLED.md
   has every value and who decided it; the -final previews are the
   reference these were measured against.
   ====================================================================== */

/* THE LIST AND THE MAP, A CENTRED PAIR (desktop, >=1100px). Riley: "the
   city page feels empty on the right side". The list is 600 -> 640 -> 700px
   across 1280 -> 1440 -> 1728, the map keeps 38% of the content between
   460 and 640px, 104px between them, the leftover to equal outer margins.
   The map is sticky 48px under the nav bar and 48px above the window's
   foot -- the same air the city name has under the bar. The bar's height
   is read from the page (citypage.js sets --city-bar), not typed in. */
@media (min-width:1100px){
  .shell.cx{max-width:none;margin:0 auto;display:grid;
    /* The two tracks and the gap are style.css's --pair-* (shared with the
       search page's list and map since lane SEARCHUI). */
    grid-template-columns:var(--pair-list) var(--pair-map);
    column-gap:var(--pair-gap);justify-content:center;align-items:start;
    padding-left:48px;padding-right:48px;box-sizing:border-box}
  .cx-r{--city-air:48px;position:sticky;
    top:calc(var(--city-bar,89px) + var(--city-air));
    height:calc(100vh - var(--city-bar,89px) - 2 * var(--city-air));
    margin-top:var(--city-air);border-radius:var(--r,14px);overflow:hidden;
    background:var(--band,#f4f5f0)}
  .cx-r #cmap{position:absolute;inset:0}
  .cx-r .cmap-foot{position:absolute;left:12px;bottom:12px;z-index:2;
    background:#fff;border-radius:999px;padding:7px 14px;font-family:var(--font-brand);
    font-size:13px;font-weight:var(--font-weight-medium,500);color:var(--ink,#3e5215);
    box-shadow:var(--shadow-sm);text-decoration:none}
  .cx-l .dwhy,.cx-l .hit-dishes,.cx-l .impcard{max-width:none}
  /* Hovering a card lights its pin; the name changes colour, no underline. */
  .hit.vrow.is-hot .hit-name a{color:var(--accent-deep,#2c3b0f)}
}
@media (max-width:1099px){ .cx-r{display:none} }

/* THE CARD'S DISH LIST, ITS "See all N vegan mains" LINK AND THE NAME'S
   LINK STATES MOVED TO style.css (lane SEARCHUI, 2026-10-14: Riley, "can
   you change how the search page looks so it's more like the results on
   the city pages?"). The search page draws the same card and now shares
   these rules rather than keeping a copy; see "THE VENUE CARD, SHARED BY
   THE CITY PAGE AND THE SEARCH PAGE" at the end of style.css. */

/* Read by screen readers and kept in the heading outline, not drawn. */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}

/* Riley 2026-10-15: no visible "Updated <date>" line; the date stays in the page's JSON-LD dateModified and the sitemap. */
.band .updated-line{display:none!important}
