/* ---------------------------------------------------------------------------
   Design language taken from twork-app.com, inverted to dark. Owner's call,
   asked for twice.

   What was measured off the reference in a real browser and carried over:
     - one sans for everything (they run Roboto body / Montserrat 900 display)
     - very heavy, very large headings; section headings centred
     - orange #FF9800 as the single accent, on buttons and figures
     - a filled accent button paired with an outlined one in the same colour
     - white cards on a tinted ground, 4px radius, 6px on buttons
     - a COOL grey neutral (#EEF1F3 ground, #54595F text), not a warm one

   Inverted rather than copied: their white cards on a light grey ground become
   raised cards on a darker ground, keeping the same cool cast so the dark
   version reads as the same family rather than a different product.

   TWO DELIBERATE DEVIATIONS, both measured, both failures if copied exactly:
     1. Their filled button is white text on that orange: 2.16:1. Ours puts the
        dark ground colour on it instead: 8.40:1. Same orange, readable.
     2. Their body text #54595F on #EEF1F3 is fine, but a straight inversion of
        their mid-grey would land under 4.5:1 here, so the two text greys were
        picked against these surfaces rather than flipped.

   Hebrew: Montserrat has no Hebrew at all, and Heebo IS Roboto's Hebrew sibling
   - same skeleton, same widths, with a 900 for the display line. One family,
   exactly as the reference does it.
--------------------------------------------------------------------------- */

@import url('https://fonts.googleapis.com/css2?family=Heebo:wght@400;500;700;900&display=swap');
/* Sora for the wordmark only. A geometric grotesque drawn for technical interfaces -
   near-circular O, flat terminals, wide counters - so PING reads as an instrument and
   not as a logotype. Deliberately NOT Inter or Space Grotesk, which are the two faces
   every generated page reaches for. */
@import url('https://fonts.googleapis.com/css2?family=Sora:wght@800&display=swap');

:root {
  /* Ground raised and the light end pushed further up, per the owner. Both moved in
     the same pass on purpose: lifting the ground alone would have flattened the page,
     since every contrast ratio here is measured against it. */
  --bg: #1A1E24;
  --card: #232830;
  --card-2: #2C323B;
  --well: #14171C;   /* recessed: chart tracks and inputs, still darker than the ground */
  --line: #3A424D;
  --hair: rgba(242, 245, 248, 0.10);

  --ink: #F2F5F8;
  --ink2: #B4BDC6;
  --muted: #9BA4AD;

  --accent: #FF9800;
  --accent-hi: #FFAD33;
  /* Pinned, NOT --bg: the button text has to stay dark enough for 8.40:1 on the
     orange, and it would have drifted up with the ground. */
  --on-accent: #14161A;

  /* Lifted with everything else. On the raised card-2 the old red measured 4.28:1
     and the old green and amber were close behind. Worst ratio on the page is now
     5.11:1. */
  --video: #5FD69C;
  --work: #E8BE5C;
  --browse: #B4BDC6;
  --poor: #F08A8A;

  --sans: Heebo, Roboto, system-ui, sans-serif;

  --r: 4px;        /* the reference's dominant radius */
  --r-btn: 6px;
  --page: 1120px;  /* their content column */
  --col: 720px;    /* reading column inside it */
}

* { box-sizing: border-box; }
html { color-scheme: dark; }
body {
  margin: 0; background: var(--bg); color: var(--ink);
  font: 400 16px/1.6 var(--sans);
  -webkit-font-smoothing: antialiased;
  padding-bottom: max(72px, env(safe-area-inset-bottom));
}

/* Their heading scale: h1 60/900, section heads ~45/900, lead 20.8. Tabular
   figures throughout so columns of readings line up without a second family. */
h1, h2, h3 { margin: 0; font-weight: 900; letter-spacing: -0.02em; line-height: 1.1; }
h1 { font-size: clamp(34px, 8.5vw, 58px); text-wrap: balance; }
h2 { font-size: clamp(26px, 6vw, 42px); }
h3 { font-size: 19px; font-weight: 700; letter-spacing: -0.01em; }
p { margin: 0; }
.n { font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }

.wrap { max-width: var(--page); margin: 0 auto; padding: 0 20px; }
.muted { color: var(--muted); }
.small { font-size: 14px; }
.hidden { display: none !important; }

/* --- header ------------------------------------------------------------- */

/* Sticky: the wordmark and the top edge stay put while the list scrolls. Not fixed -
   sticky keeps the header in the flow, so nothing underneath needs a matching offset,
   and the safe-area padding still applies on a notched phone. */
header.top {
  position: sticky; top: 0; z-index: 40;
  background: var(--card); border-bottom: 1px solid var(--hair);
  padding-top: env(safe-area-inset-top);
}
/* justify-content, not an auto margin on the logo: the wordmark carries dir="ltr" so
   ITS inline-start is the left edge, and margin-inline-start:auto there pushed the logo
   the wrong way. The row is RTL, so flex-end is the visual left. */
header.top .wrap { display: flex; align-items: center; justify-content: flex-end;
                   gap: 16px; padding: 16px 20px; }
.logo { display: inline-flex; align-items: center; gap: 9px; }
.logo .word {
  font-family: Sora, Heebo, system-ui, sans-serif;
  font-weight: 800; font-size: 22px; letter-spacing: -0.005em; line-height: 1;
}
/* The mark is orange and the word is not: one accent, spent on the thing that is the
   product's idea rather than on the letters.
   Sized in em off the cropped viewBox (aspect 1.656) so it tracks the wordmark: the
   drawn height lands just above the Hebrew letter height, which in Heebo is about
   0.7em - a mark matched to the letters rather than to the em box. */
.logo .mark { color: var(--accent); flex: none; height: 19px; width: 31.5px; }
.stats { margin-inline-start: auto; color: var(--muted); font-size: 13px; }

/* --- sections ----------------------------------------------------------- */

/* Their rhythm: full-bleed bands alternating ground and card, generous vertical
   padding, the column centred inside. */
.open { padding: 34px 0 30px; }
/* The column lives here rather than on <main>, so a tinted section can run edge to
   edge the way the reference's bands do. */
.open > .inner, .sec > .inner { max-width: var(--col); margin: 0 auto; padding-inline: 20px; }
.open .lead { font-size: clamp(17px, 4.2vw, 20.8px); color: var(--ink2); margin-top: 14px;
              text-wrap: balance; }


.sec { padding: 32px 0; }
/* The alternating band was removed (owner's call): the page is one ground now, and the
   only things lifted off it are the header and the cards. The class is kept because the
   markup uses it to mark the content sections. */
.sec.on-card { background: transparent; border-block: 0; }
/* Everything centres. Data rows keep their own internal alignment - a column of
   readings centred is a column nobody can scan. */
.sec > .inner { text-align: center; }
.sec > .inner > .sub { color: var(--ink2); margin: 12px auto 28px; max-width: 52ch; }
.sec > .inner .rows, .sec > .inner .card, .sec > .inner .log, .sec > .inner .hours,
.sec > .inner .opts, .sec > .inner label.radio, .sec > .inner details { text-align: start; }
.open.centred > .inner { text-align: center; }
.open.centred .lead, .open.centred .why { margin-inline: auto; max-width: 46ch; }

/* --- buttons ------------------------------------------------------------ */

button {
  font: 700 16px/1 var(--sans); border-radius: var(--r-btn);
  border: 2px solid transparent; min-height: 48px; padding: 14px 26px; cursor: pointer;
  transition: background-color .2s ease, border-color .2s ease, color .2s ease;
}
button:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }

.btn-primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.btn-primary:hover:not(:disabled) { background: var(--accent-hi); border-color: var(--accent-hi); }
.btn-primary:disabled { background: transparent; border-color: var(--line); color: var(--muted); cursor: not-allowed; }
/* The reference's second button: outlined, same accent, same size. */
.btn-accent-ghost { background: transparent; border-color: var(--accent); color: var(--accent); }
.btn-accent-ghost:hover { background: rgba(255, 152, 0, 0.12); }
.btn-ghost { background: transparent; border-color: var(--line); color: var(--ink2); }
.btn-ghost:hover { border-color: var(--ink2); color: var(--ink); }

/* Filter tabs. Pills, because they are a choice among three and not navigation. */
.citysearch { position: relative; max-width: 320px; margin: 0 auto 20px; }
.citysearch input { display: block; width: 100%; font: 700 15px var(--sans); color: var(--ink);
  background: var(--well); border: 2px solid var(--line); border-radius: var(--r);
  padding: 12px 14px; min-height: 48px; text-align: start; }
.citysearch input:focus-visible { outline: none; border-color: var(--accent); }
.cityhits { position: absolute; inset-inline: 0; top: calc(100% + 6px); z-index: 20;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r);
  max-height: 320px; overflow-y: auto; text-align: start; }
.cityhit { display: flex; align-items: baseline; gap: 10px; width: 100%; text-align: start;
  background: none; border: 0; border-radius: 0; border-bottom: 1px solid var(--hair);
  color: var(--ink); font-weight: 700; font-size: 15px; padding: 12px 14px; min-height: 48px; }
.cityhit:last-child { border-bottom: 0; }
.cityhit:hover { background: var(--card-2); }
.cityhit em { font-style: normal; margin-inline-start: auto; color: var(--muted);
              font-size: 12px; font-weight: 500; }

.tabs { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin-bottom: 22px; }
.tab { background: transparent; border: 2px solid var(--line); border-radius: 999px;
       color: var(--ink2); font-weight: 700; font-size: 14px; min-height: 42px; padding: 10px 18px; }
.tab:hover { border-color: var(--ink2); color: var(--ink); }
.tab.on { border-color: var(--accent); color: var(--accent); background: rgba(255, 152, 0, 0.1); }

/* Two secondary actions under the place name. */
.acts { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; margin-top: 16px; }
.act { display: inline-flex; align-items: center; gap: 8px; text-decoration: none;
       font-size: 14px; min-height: 44px; padding: 11px 16px; border-width: 1px; }
.act svg { width: 17px; height: 17px; flex: none; }
.act[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); }
.act[aria-pressed="true"] svg path { fill: var(--accent); }

/* How many people rated, at the end of the chip row it describes. */
/* Raised from 11.5px, per the owner: it sits on the same line as the chips now, and at
   that size it read as a footnote to them rather than as its own fact. */
.raters { flex-basis: 100%; margin-top: 8px; font-size: 14px; color: var(--muted); }

/* The primary action is a circle. A speed test's start control has been a big round
   button since Ookla's, so it reads as "press this" before anything is read - which is
   the whole point of pushing visitors into a measurement. */
.btn-round {
  width: clamp(150px, 42vw, 182px); aspect-ratio: 1; border-radius: 50%;
  background: var(--accent); border: 0; color: var(--on-accent);
  display: inline-flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px; padding: 0; margin-top: 42px; cursor: pointer;
  position: relative; isolation: isolate;
  /* A two-stop fill rather than a flat disc - lit from the top, the way a physical
     button is. Not a glow: nothing bleeds outside the circle. */
  background: linear-gradient(180deg, var(--accent-hi) 0%, var(--accent) 62%);
  transition: filter .2s ease;
  /* A halo pushed outward from the disc itself, chosen by the owner from the option
     set. It is a box-shadow and not an element, so nothing is added to the layout and
     the 26px it reaches cannot push the page sideways at any width. */
  animation: halo 2.6s ease-out infinite;
}
.btn-round b { font-size: clamp(24px, 6.4vw, 30px); font-weight: 900; letter-spacing: -0.025em;
               line-height: 1.15; text-align: center; }
.btn-round span { font-size: 13px; font-weight: 700; opacity: .72; }
.btn-round:hover { filter: brightness(1.08); }
/* `scale` rather than `transform`, so the press composes with the breathing
   animation instead of fighting it for the same property. */
.btn-round:active { scale: .96; }
.btn-round:focus-visible { outline: 3px solid var(--ink); outline-offset: 6px; }

@keyframes halo {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255, 152, 0, .55); }
  50%      { box-shadow: 0 0 0 26px rgba(255, 152, 0, 0); }
}

.under { margin-top: 14px; }
.btn-link { background: none; border: 0; color: var(--accent); font-weight: 700; font-size: 15px;
            text-decoration: underline; text-underline-offset: 5px; padding: 12px 16px; }
.btn-link:hover { color: var(--accent-hi); }

/* The push. It is the last thing under the button on purpose - the ask to contribute
   only lands after the visitor has seen what they get. */
.nudge { margin: 26px auto 0; max-width: 34ch; color: var(--ink2); font-size: 16px; font-weight: 500; }
.btn-row { display: flex; gap: 12px; margin-top: 26px; }
.btn-row button { flex: 1; }
.btn-back { min-height: 44px; padding: 10px 18px; font-size: 14px; border-width: 1px;
            margin-bottom: 22px; }

/* --- cards -------------------------------------------------------------- */

/* Their café list is a stack of white cards on the tinted ground. Same shape,
   raised instead of white. */
.card {
  background: var(--card); border: 1px solid var(--hair); border-radius: var(--r);
  padding: 20px; margin-bottom: 12px;
}
.sec.on-card .card { background: var(--card); }

/* --- live readout ------------------------------------------------------- */

/* Fixed, not tall: the measurement covers the header, the list and everything else for
   the twenty seconds it runs. Nothing on the page is worth reading while a number is
   moving, and a half-visible list behind it invites a scroll that interrupts nothing. */
#view-running:not(.hidden) {
  position: fixed; inset: 0; z-index: 60;
  display: flex; align-items: center; justify-content: center;
  background: var(--bg);
  background-image: radial-gradient(rgba(242, 245, 248, .055) 1.4px, transparent 1.4px);
  background-size: 23px 23px;
  padding: max(20px, env(safe-area-inset-top)) 20px max(20px, env(safe-area-inset-bottom));
}
.gwrap { width: 100%; max-width: 420px; text-align: center; }
.gphase { color: var(--ink2); font-size: 16px; font-weight: 700; letter-spacing: -0.01em;
          margin: 0 0 clamp(18px, 5vh, 34px); }

.dial { position: relative; width: min(78vw, 320px); margin: 0 auto; aspect-ratio: 1; }
/* The pool sits behind the dial and nothing else, so the arc reads as lit rather than
   the screen as washed. */
.dial::before {
  content: ""; position: absolute; inset: -12%;
  background: radial-gradient(circle, rgba(255, 152, 0, .18), transparent 62%);
  pointer-events: none;
}
.dial svg { position: relative; width: 100%; height: 100%; overflow: visible; }
.dial path { fill: none; stroke-width: 15; stroke-linecap: round; }
.dial .track { stroke: rgba(242, 245, 248, .10); }
.dial .fill {
  stroke: url(#garc);
  /* Set from JS as a fraction of the path's own length, so the arc geometry can change
     without the script having to know its new length. */
  stroke-dasharray: 1 1; stroke-dashoffset: 1;
  transition: stroke-dashoffset .25s linear;
  filter: drop-shadow(0 0 12px rgba(255, 152, 0, .35));
}
.dnum {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 4px;
}
.dnum .big { font-weight: 900; font-size: clamp(52px, 15vw, 84px); line-height: .92;
             letter-spacing: -0.05em; font-variant-numeric: tabular-nums; color: var(--accent); }
.dnum .unit { color: var(--muted); font-size: 15px; font-weight: 700; letter-spacing: .02em; }

.spark { display: flex; align-items: flex-end; gap: 2px; height: 56px;
         margin-top: clamp(20px, 5vh, 38px); }
.spark i { flex: 1 1 0; min-width: 2px; background: var(--line); height: 2px; border-radius: 1px;
           transition: height .12s linear, background-color .2s ease; }
.spark i.on { background: var(--accent); }
.steps { display: flex; gap: 8px; margin-top: clamp(18px, 4vh, 30px); }
.steps div { flex: 1; }
.steps span { display: block; height: 3px; background: var(--line); border-radius: 2px; }
.steps span > i { display: block; height: 100%; width: 0; background: var(--accent);
                  border-radius: 2px; transition: width .3s linear; }
.steps label { display: block; font-size: 13px; color: var(--muted); margin-top: 10px; font-weight: 600; }
.steps div[data-on="1"] label { color: var(--ink); }

/* --- readings ----------------------------------------------------------- */

.trio { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-top: 26px; }
.trio div { background: var(--card); border: 1px solid var(--hair); border-radius: var(--r);
            padding: 18px 16px; text-align: center; }
.trio b { display: block; font-weight: 900; font-size: clamp(26px, 7vw, 34px);
          letter-spacing: -0.03em; color: var(--accent); font-variant-numeric: tabular-nums; }
.trio span { display: block; font-size: 13px; color: var(--ink2); margin-top: 6px; }

/* The score on the place page: one large figure, its denominator, and which leg is
   holding it back - so the number never stands alone. */
.bigscore { display: flex; align-items: baseline; justify-content: center; gap: 10px;
            flex-wrap: wrap; margin-top: 14px; }
.bigscore b { font-size: clamp(46px, 13vw, 64px); font-weight: 900; letter-spacing: -0.05em;
              color: var(--accent); font-variant-numeric: tabular-nums; line-height: 1; }
.bigscore span { font-size: 15px; color: var(--ink2); font-weight: 700; }
.bigscore em { font-style: normal; font-size: 13px; color: var(--muted); }

.verdict { font-size: clamp(40px, 11vw, 56px); font-weight: 900; letter-spacing: -0.04em;
           color: var(--accent); font-variant-numeric: tabular-nums; }
.verdict small { font-size: 16px; font-weight: 700; color: var(--ink2); letter-spacing: 0; }
.verdict.video { color: var(--video); }
.verdict.work { color: var(--work); }
.verdict.browse { color: var(--browse); }
.verdict.poor { color: var(--poor); }
.why { color: var(--muted); font-size: 14px; margin-top: 10px; }

/* --- place cards -------------------------------------------------------- */

.rows { display: grid; gap: 12px; }
/* Actions live on the card now that the card no longer opens anything. */
.cardacts { display: flex; gap: 10px; align-items: center;
            margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--hair); }
.navbtn { display: inline-flex; align-items: center; gap: 8px; text-decoration: none;
  color: var(--ink2); background: transparent; border: 1px solid var(--line);
  border-radius: 999px; font-weight: 700; font-size: 14px; padding: 10px 16px;
  min-height: 44px; margin-inline-start: auto; }
.navbtn:hover { border-color: var(--accent); color: var(--accent); }
.navbtn svg { width: 17px; height: 17px; flex: none; }
.fav {
  width: 44px; height: 44px; min-height: 44px; padding: 0; border-radius: 999px;
  background: transparent; border: 1px solid var(--line); color: var(--muted);
  display: inline-flex; align-items: center; justify-content: center; flex: none;
}
.fav svg { width: 20px; height: 20px; }
@media (hover: hover) {
  /* Border only. Tinting the icon on hover left an un-favourited heart looking
     different from every other grey heart on the list right after it was switched
     off, which read as "it did not take". */
  .fav:hover { border-color: var(--muted); }
  .fav[aria-pressed="true"]:hover { border-color: var(--poor); color: var(--poor); }
}
.fav[aria-pressed="true"] { border-color: var(--poor); color: var(--poor); }
.fav[aria-pressed="true"] svg path { fill: var(--poor); }
/* Grid, not flex: the name and the score share the first row, and the chips take a
   full-width row of their own underneath. */
.place {
  --cardpad: 22px;
  display: block; width: 100%; text-align: start;
  background: var(--card); border: 1px solid var(--hair); border-radius: var(--r);
  padding: var(--cardpad) var(--cardpad) 18px; min-height: 96px;
  color: inherit; font-weight: 400; overflow: hidden;
}
/* Name and score on one line, sharing a baseline. They used to be two grid columns,
   and the score sank below the name on any card whose name column grew a line - which
   is most of them now that the card carries opening hours and freshness. */
.place .head { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; }
.place .head .nm { min-width: 0; }
.place .speed { margin-top: 4px; }
.place .meta.dim { opacity: .7; }
/* A removable card is a two-layer thing: the delete sits underneath and the content
   slides off it. The grid moves down to .placein so the layout above is untouched for
   every card that is not removable. */
.place.removable {
  display: block; padding: 0; overflow: hidden; position: relative; touch-action: pan-y;
}
.place.removable > .placein {
  display: block; padding: var(--cardpad) var(--cardpad) 18px; min-height: 96px;
  background: var(--card);   /* opaque: it is what hides the delete button when closed */
  will-change: transform;
}
.place.removable > .rowdel {
  position: absolute; inset-block: 0; inset-inline-start: 0; width: 96px;
  display: flex; align-items: center; justify-content: center;
  border: 0; border-radius: 0; background: var(--poor); color: #14161A;
  font-weight: 700; font-size: 15px; cursor: pointer;
}
.place.choice { cursor: pointer; transition: border-color .2s ease, background-color .2s ease; }
.sec.on-card .place { background: var(--card); }
.place.choice:hover { border-color: var(--accent); }
.place.choice:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
.place .col { display: block; }
.place .nm { display: block; font-weight: 700; font-size: 21px; letter-spacing: -0.02em; }
.place .meta { display: block; color: var(--muted); font-size: 13.5px; margin-top: 5px; }
.place .cap { display: block; font-size: 14px; font-weight: 500; margin-top: 4px; }
.place .score { white-space: nowrap; flex: none; }
.place .score { font-weight: 900; font-size: 36px; letter-spacing: -0.04em;
                color: var(--accent); font-variant-numeric: tabular-nums; line-height: 1.05; }
.place .score u { text-decoration: none; color: var(--muted); font-size: 13px; font-weight: 700;
                  margin-inline-start: 3px; letter-spacing: 0; }

/* Outlets and noise, on the card. Both chips always render - a missing one would read
   as "fine" when what it means is "nobody has said". */
/* Tightened so all three fit one row at 390px - three chips with the third alone on a
   second row read as an afterthought rather than as a set. Below ~360 they wrap, which
   is correct: three is more than a phone that narrow can line up. */
.chips { display: flex; flex-wrap: wrap; align-items: center;
         gap: 4px 0; margin-top: 16px; }

/* No pill behind each one. Three bordered capsules on a card that is itself a bordered
   panel was a box inside a box inside a box; the dot carries the separation instead. */
.chip { display: inline-flex; align-items: center; gap: 7px; font-size: 14.5px; font-weight: 700;
        color: var(--ink); white-space: nowrap; }
.chip + .chip::before {
  content: ""; width: 4px; height: 4px; border-radius: 999px;
  background: var(--muted); flex: none; margin-inline: 10px;
}
.chip svg { width: 17px; height: 17px; flex: none; color: var(--ink2); }
.chip.none { color: var(--muted); font-weight: 500; }
.chip.none svg { opacity: .55; }
/* A single report keeps the full text colour and loses only the icon's weight - with
   the pills gone there is no border left to thin. */
.chip.thin svg { opacity: .75; }
.place.choice.on { border-color: var(--accent); background: rgba(255, 152, 0, 0.08); }

.cap.video { color: var(--video); }
.cap.work { color: var(--work); }
.cap.browse { color: var(--browse); }
.cap.poor { color: var(--poor); }

.conf { display: inline-flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--muted); }
.conf s { text-decoration: none; display: flex; gap: 3px; }
.conf s i { width: 11px; height: 3px; border-radius: 2px; background: var(--line); }
.conf s i.f { background: var(--accent); }

/* --- hourly curve ------------------------------------------------------- */

.hours { display: grid; gap: 6px; }
.hour { display: grid; grid-template-columns: 82px 1fr auto; align-items: center; gap: 14px;
        min-height: 34px; }
.hour .lbl { font-size: 13px; color: var(--ink2); font-weight: 500; }
.hour .track { height: 10px; background: var(--well); border-radius: 5px; overflow: hidden; }

.hour .track i { display: block; height: 100%; background: var(--accent); border-radius: 5px; }
.hour .track i.video { background: var(--video); }
.hour .track i.work { background: var(--work); }
.hour .track i.browse { background: var(--browse); }
.hour .track i.poor { background: var(--poor); }
.hour .v { font-size: 13px; color: var(--ink2); font-variant-numeric: tabular-nums; font-weight: 500; }

/* --- log ---------------------------------------------------------------- */

.log > div { border-bottom: 1px solid var(--hair); }
.log > div:last-child { border-bottom: 0; }
.rowin { display: flex; gap: 14px; align-items: baseline; padding: 11px 0;
         font-size: 13.5px; background: var(--card); position: relative; z-index: 1; }
/* The row slides over the delete button, which sits underneath it. */
.logrow { position: relative; overflow: hidden; touch-action: pan-y; }
.rowdel { position: absolute; inset-block: 0; inset-inline-start: 0; width: 84px;
          border: 0; border-radius: 0; background: var(--poor); color: var(--bg);
          font-weight: 700; font-size: 13.5px; min-height: 0; padding: 0; }
.logrow .tag { font-size: 11px; font-weight: 700; color: var(--accent); }
.log time { color: var(--muted); font-variant-numeric: tabular-nums; }
.log .r { margin-inline-start: auto; color: var(--ink2); font-variant-numeric: tabular-nums; font-weight: 500; }

/* --- reported ----------------------------------------------------------- */

.said { display: grid; gap: 12px; }
.said div { display: flex; gap: 14px; align-items: baseline; }
.said b { font-weight: 700; font-size: 14px; min-width: 66px; }
.said em { font-style: normal; color: var(--muted); font-size: 13px; margin-inline-start: auto; }

/* --- form bits ---------------------------------------------------------- */

label.radio { display: flex; gap: 12px; align-items: center; min-height: 50px; padding: 13px 16px;
  border: 2px solid var(--line); border-radius: var(--r); margin-bottom: 10px; cursor: pointer;
  font-weight: 500; transition: border-color .2s ease, background-color .2s ease; }
label.radio:hover { border-color: var(--ink2); }
label.radio.on { border-color: var(--accent); background: rgba(255, 152, 0, 0.08); }
label.radio input { accent-color: var(--accent); width: 18px; height: 18px; }

.opts { display: grid; gap: 10px; margin-top: 14px; }
@media (min-width: 560px) { .opts { grid-template-columns: repeat(3, 1fr); } }
.opt { background: transparent; color: var(--ink2); border: 2px solid var(--line);
       border-radius: var(--r); font-weight: 500; font-size: 14.5px; padding: 13px 14px;
       text-align: center; min-height: 50px; }
.opt:hover { border-color: var(--ink2); color: var(--ink); }
.opt[aria-pressed="true"] { border-color: var(--accent); background: rgba(255, 152, 0, 0.08); color: var(--ink); }

input[type=text] { font: 400 16px var(--sans); width: 100%; padding: 13px 16px; min-height: 50px;
  border: 2px solid var(--line); border-radius: var(--r); background: var(--well); color: var(--ink); }
input[type=text]::placeholder { color: var(--muted); }
input[type=text]:focus-visible { outline: none; border-color: var(--accent); }
details > summary { color: var(--muted); font-size: 14px; cursor: pointer; min-height: 44px;
                    display: flex; align-items: center; }
details > summary:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }

.note { background: var(--card-2); border-inline-start: 4px solid var(--line);
        border-radius: var(--r); padding: 14px 16px; color: var(--ink2); font-size: 14px; }
.note.err { border-inline-start-color: var(--poor); color: var(--poor); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: .01ms !important; animation-duration: .01ms !important; }
  /* Stopped outright, not crushed to 0.01ms - an animation collapsed to one frame
     lands mid-cycle, which here would freeze a 26px orange halo permanently around
     the button. */
  .btn-round { animation: none !important; box-shadow: none !important; }
}
@media (max-width: 380px) {
  .hour { grid-template-columns: 66px 1fr auto; gap: 10px; }
  .trio { gap: 8px; }
  .trio div { padding: 14px 8px; }
  /* Vertical padding matches --cardpad so the photo, whose negative margin is
     derived from it, still meets the top edge exactly. */
  .place { --cardpad: 14px; padding: var(--cardpad) var(--cardpad) 16px; }
}


/* ---- the thank-you dialog ------------------------------------------------
   Sized to the sentence, not to the viewport: it holds one line of thanks and
   one button, so a full-screen sheet would be a lot of empty dark. */
#thanks, #confirm {
  border: 1px solid var(--line);
  border-radius: 18px;
  background: var(--card);
  color: var(--ink);
  padding: 26px 24px 22px;
  max-width: min(420px, calc(100vw - 40px));
  box-shadow: 0 24px 60px rgba(0, 0, 0, .45);
}
#thanks::backdrop, #confirm::backdrop { background: rgba(8, 11, 16, .72); }
#thanks p, #confirm p {
  margin: 0 0 20px;
  font-size: 17px;
  line-height: 1.55;
  text-wrap: pretty;
}
#thanks button { width: 100%; }
#thanks-share { display: inline-flex; align-items: center; justify-content: center;
                gap: 10px; margin-bottom: 10px; }
#thanks-share[hidden] { display: none; }
#thanks-share svg { width: 20px; height: 20px; flex: none; }
.dlg-row { display: flex; gap: 10px; }
.dlg-row button { flex: 1; }
.btn-danger {
  background: var(--poor); border: 1px solid var(--poor); color: #14161A;
  border-radius: 12px; font-weight: 700; font-size: 16px; min-height: 48px; cursor: pointer;
}
.btn-danger:hover { filter: brightness(1.08); }

/* The card the reader just checked into, so landing back on the list answers
   "did it save?" without a toast that disappears before they look. */
.place.justchecked { border-color: var(--accent); }
.youtag {
  display: inline-block;
  margin-inline-start: 8px;
  padding: 2px 8px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  color: var(--accent);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}

/* At 320 three chips cannot share a line, and a wrapped row would open with a dangling
   separator dot. One per line there, and the dots come off. */
@media (max-width: 344px) {
  .chips { flex-direction: column; align-items: flex-start; gap: 9px; }
  .chip + .chip::before { display: none; }
  .raters { margin-top: 3px; }
}


/* --- footer and the two static documents ---------------------------------- */
.foot { border-top: 1px solid var(--hair); margin-top: 40px; }
.foot .inner {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 20px;
  padding: 24px 20px calc(24px + env(safe-area-inset-bottom));
  max-width: 640px; margin-inline: auto;
  color: var(--muted); font-size: 13.5px;
}
.foot a { color: var(--ink2); text-decoration: none; border-bottom: 1px solid var(--line); }
.foot a:hover { color: var(--accent); border-bottom-color: var(--accent); }
.foot .attrib { margin-inline-start: auto; }
.foot .attrib a { border-bottom-color: var(--hair); }

/* .sec > .inner centres everything by default, which is right for the one-idea panels
   on the home page and wrong for a page of running text. */
.sec.doc > .inner { max-width: 640px; text-align: start; }
.sec.doc h2 { font-size: 19px; margin: 30px 0 10px; }
.sec.doc p, .sec.doc li { font-size: 16px; line-height: 1.72; color: var(--ink2); }
.sec.doc p { margin: 0 0 12px; }
.sec.doc ul { margin: 0 0 12px; padding-inline-start: 20px; }
.sec.doc li { margin-bottom: 9px; }
.sec.doc b { color: var(--ink); font-weight: 700; }
.sec.doc a { color: var(--accent); }
/* ⚠️ Two overrides the document pages need because they carry real links: the wordmark
   is an <a> on every page but the app, and .btn-primary inside .sec.doc was inheriting
   the accent link colour - amber text on an amber button, which rendered as an empty
   orange bar. */
a.logo { color: inherit; text-decoration: none; }
.sec.doc a.btn-primary { color: var(--on-accent); text-decoration: none; }
.sec.doc .btn-back { margin-bottom: 18px; }


/* --- the extra line under the name ----------------------------------------
   Opening hours, the best hour to come, freshness, and the venue's own wifi claim.
   Wraps rather than truncates: on a 320px card these can be two lines, and a card that
   is one line taller beats a fact cut in half. */
.place .extra {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; margin-top: 9px;
}
.place .extra:empty { display: none; }
.ochip {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 13px; font-weight: 700; letter-spacing: -0.01em;
}
.ochip::before { content: ""; width: 6px; height: 6px; border-radius: 999px; background: currentColor; }
.ochip.open { color: var(--video); }
.ochip.shut { color: var(--muted); }
.place .hint { font-size: 13px; color: var(--muted); }
/* A claim by the venue, not a measurement by anyone - said in the words and marked
   here in a lighter weight, so it never reads like a number we stand behind. */
.place .hint.claim { font-style: italic; }

/* The delete that a mouse can find. The swipe stays for phones; this is the same
   action with a target. */
.cardel, .cardedit, .cardshare {
  width: 44px; height: 44px; min-height: 44px; padding: 0; border-radius: 999px;
  background: transparent; border: 1px solid var(--line); color: var(--muted);
  display: inline-flex; align-items: center; justify-content: center; flex: none;
}
.cardel svg, .cardedit svg, .cardshare svg { width: 19px; height: 19px; }
@media (hover: hover) {
  .cardel:hover { border-color: var(--poor); color: var(--poor); }
  .cardedit:hover, .cardshare:hover { border-color: var(--accent); color: var(--accent); }
}


/* --- photos ---------------------------------------------------------------
   The picker on the check-in screen, and the shot on the card. */
.photopick { display: flex; flex-direction: column; gap: 14px; align-items: center; }
.photobtn { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; }
.photobtn svg { width: 20px; height: 20px; }
#photo-box { position: relative; width: 100%; max-width: 360px; }
#photo-prev {
  display: block; width: 100%; border-radius: 14px; border: 1px solid var(--line);
  background: var(--well);
}
.photodrop { position: absolute; inset-block-start: 10px; inset-inline-end: 10px;
             min-height: 36px; padding: 6px 14px; font-size: 14px;
             background: rgba(20, 23, 28, .82); }

/* On the card the photo is the first thing, edge to edge, with the top corners of the
   card. A fixed 16:9 box rather than the image's own shape: a column of cards whose
   heights depend on what somebody photographed does not read as a list. */
/* ⚠️ height:auto is load-bearing. The <img> carries width/height attributes for layout
   stability, and the UA stylesheet turns those into a used height that beats
   aspect-ratio - the photo rendered 870px tall until this line existed. */
.place .shot {
  display: block; height: auto;
  width: calc(100% + var(--cardpad) * 2);
  margin: calc(var(--cardpad) * -1) calc(var(--cardpad) * -1) 18px;
  aspect-ratio: 16 / 9; object-fit: cover;
  background: var(--well);
}


/* The photos you already added here, on the edit screen. A row that scrolls rather than
   a grid that reflows: there are usually one or two, and a grid of two looks like a grid
   with something missing. */
.myshots {
  display: flex; gap: 12px; overflow-x: auto; padding-bottom: 6px; margin-bottom: 18px;
  scrollbar-width: thin;
}
.myshot { position: relative; margin: 0; flex: none; width: 148px; }
.myshot img {
  display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
  border-radius: 12px; border: 1px solid var(--line); background: var(--well);
}
.shotdel {
  position: absolute; inset-block-start: 8px; inset-inline-end: 8px;
  width: 34px; height: 34px; min-height: 34px; padding: 0; border-radius: 999px;
  display: inline-flex; align-items: center; justify-content: center;
  background: rgba(20, 23, 28, .84); border: 1px solid var(--line); color: var(--ink);
  cursor: pointer;
}
.shotdel svg { width: 16px; height: 16px; }
@media (hover: hover) { .shotdel:hover { border-color: var(--poor); color: var(--poor); } }


/* --- the free-text note, and the two thumbs ------------------------------- */
#note-in {
  width: 100%; background: var(--well); color: var(--ink);
  border: 1px solid var(--line); border-radius: 12px; padding: 12px 14px;
  font: inherit; font-size: 16px; line-height: 1.5; resize: vertical; min-height: 84px;
}
#note-in:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }

/* What somebody wrote, on the card. Quiet and italic: it is one person's sentence, not
   a measurement, and it must not compete with the score above it. */
.pnote {
  margin: 12px 0 0; font-size: 15px; line-height: 1.55; color: var(--ink2);
  font-style: italic;
  border-inline-start: 2px solid var(--line); padding-inline-start: 12px;
}
.pnote .youtag { font-style: normal; }

.votes { display: inline-flex; gap: 6px; }
.vote {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 44px; padding: 0 12px; border-radius: 999px;
  background: transparent; border: 1px solid var(--line); color: var(--muted);
  font-weight: 700; font-size: 14px; font-variant-numeric: tabular-nums; cursor: pointer;
}
.vote svg { width: 18px; height: 18px; flex: none; }
.vote b { font-weight: 700; }
.vote b:empty { display: none; }
.vote[aria-pressed="true"].up { border-color: var(--video); color: var(--video); }
.vote[aria-pressed="true"].down { border-color: var(--poor); color: var(--poor); }
@media (hover: hover) {
  .vote:hover { border-color: var(--muted); }
  .vote[aria-pressed="true"].up:hover { border-color: var(--video); }
  .vote[aria-pressed="true"].down:hover { border-color: var(--poor); }
}
/* The action row has five things on it now; navigate keeps the far end and the rest
   pack from the start. Below 380 the row wraps rather than squeezing a 44px target. */
.cardacts { flex-wrap: wrap; row-gap: 10px; }

/* --- the crawler-readable city pages -------------------------------------- */
.seolist { list-style: none; margin: 0 0 8px; padding: 0; }
.seolist li { padding: 16px 0; border-bottom: 1px solid var(--hair); }
.seolist li:last-child { border-bottom: 0; }
.seolist .h { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; }
.seolist b { font-size: 18px; font-weight: 700; letter-spacing: -0.02em; color: var(--ink); }
.seolist .s { font-size: 24px; font-weight: 900; color: var(--accent);
              letter-spacing: -0.03em; font-variant-numeric: tabular-nums; flex: none; }
.seolist .s u { text-decoration: none; color: var(--muted); font-size: 12px; font-weight: 700;
                margin-inline-start: 2px; }
.seolist .u { font-size: 13px; color: var(--muted); flex: none; }
.seolist .m, .seolist .c { display: block; font-size: 14px; color: var(--muted); margin-top: 5px; }
.seolist .c { color: var(--ink2); font-weight: 600; }
#more-cities a { color: var(--ink2); text-decoration: none;
                 border-bottom: 1px solid var(--line); }
#more-cities a:hover { color: var(--accent); border-bottom-color: var(--accent); }

/* City links on the home page: a crawl path, and a shortcut for anyone who wants a list
   rather than a geolocation prompt. */
.citylinks {
  max-width: 640px; margin: 34px auto 0; padding: 0 20px;
  font-size: 13.5px; line-height: 2; color: var(--muted); text-align: center;
}
.citylinks span { color: var(--ink2); font-weight: 700; }
.citylinks a { color: var(--muted); text-decoration: none;
               border-bottom: 1px solid transparent; margin-inline: 5px; }
.citylinks a:hover { color: var(--accent); border-bottom-color: var(--accent); }
.citylinks:empty { display: none; }
/* Only under the list. They were rendering under the measurement and under the check-in
   too, because they sit outside the view sections. */
body:not([data-view="start"]) .citylinks,
body:not([data-view="start"]) .foot { display: none; }
