/*
 * The app's own screens (Horarios, a day, Torneos, Campos, the sheets), on top
 * of styles.css, which holds what every page shares. Only the app (index.html)
 * loads this file, so the site and /search never pay for it.
 *
 * The system follows Playtomic's (studied on its App Store screens, v6.93.2, and
 * the tokens playtomic.com serves, 11 Oct 2026), in our brand:
 *  - Ink carries selection; colour carries action. A chosen day, party size or
 *    filter is filled with ink (Playtomic's navy, here forest black); the brand
 *    green is kept for what you can act on (book, see the rest, the open tab).
 *  - One scarce accent, gold, for what is special to the golfer: new
 *    tournaments, favourite stars, where now falls on today's daylight bar.
 *  - A grey ground under white surfaces with hairline edges; shadows for what
 *    floats (sheets, toasts, the proposal pill) and Horarios' fairway header;
 *    the filter bar and the tab bar float on frosted glass instead.
 *  - Pills for actions and filters, tiles for tee times, cards for places,
 *    circles for dates and badges.
 * Tokens are named by role (foreground, background, stroke) like Playtomic's
 * design system, Midas: never by the colour they happen to be.
 */

/* ------------------------------------------------------------ tokens */
/* The type (Figtree) and the shared tokens (foreground, backgrounds, strokes, action, accent, elevation, shape,
   motion) are every page's, in styles.css. These are the app's own. */
:root {
  /* The fairway: the one deep green panel (Horarios' header), striped like a mown fairway. */
  --fairway: #0f5a3d;
  --fairway-stripe: #126447;
  --on-fairway: #ffffff;
  /* 88 %: the header's quieter lines sit on a photo, not on a flat green (its e2e measures them). */
  --on-fairway-muted: rgb(255 255 255 / 0.88);
  /* What stays on screen: the Cápsula+ at the bottom (a 64 px pill 18 px off the edge); at the top the filter bar (a 44 px
     row with 6 px above and 4 below, under the safe area) and, from 960 px, the top bar above it. Stuck headings and
     scrolls stop under them. */
  /* The prototype's second chrome (--chrome-2): capitals on the felt, quieter than the words (a pane's kicker, a month,
     a tournament's weekday and month on its leaf). 74 % of the chrome. */
  --chrome-2: rgb(244 247 243 / 0.74);
  --tab-bar-height: 82px;
  --filter-bar-height: 54px;
  --top-bar-height: 0px;
}

/* ------------------------------------------------------------ the felt */
/* A+ (16 Oct 2026): the app is laid on felt, as a card table, with chrome words on it. The felt is the ground under
   everything and stays still while the screen scrolls over it; the hero's sky falls on its top as a faint blue wash
   that scrolls away with the screen. A grain keeps the green from banding on a large screen. */
/* The page's own ground is the felt's deepest green (an overscroll shows it); the body is transparent so #app's felt,
   painted beneath the screens, is what shows (the review of R1: a body colour covered it). */
html {
  background: var(--felt-deep);
}
body {
  background: transparent;
}
#app {
  display: flex;
  flex-direction: column;
  min-height: 100vh;

  background: linear-gradient(180deg, var(--sky-tint), rgb(150 192 232 / 0) 320px);
}
#app::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 .55 0'/></filter><rect width='100%' height='100%' filter='url(%23n)' opacity='.075'/></svg>"),
    radial-gradient(130% 70% at 50% 12%, var(--felt-glow) 0%, var(--felt) 52%, var(--felt-deep) 100%);
  background-color: var(--felt);
  pointer-events: none;
}
/* Every figure one width, as the prototype's screen sets them (its words inherit it): times, prices, counts and the
   chips line up. On every element, since a rule's font shorthand would otherwise reset it. */
#app,
#app * {
  font-variant-numeric: tabular-nums;
}
/* On the felt the roles are the felt's: chrome words, wells of light for tracks and quiet controls, chrome for what is
   chosen (ink on it), the lit green for action. Shadows fall darker, as on a table. */
#app {
  --fg: var(--on-felt);
  --fg-2: var(--on-felt-2);
  --fg-muted: var(--on-felt-muted);
  --fg-subtle: rgb(244 247 243 / 0.4);
  --ink: var(--on-felt);
  --on-ink: var(--paper-ink);
  --bg-1: var(--felt-well);
  --bg-2: var(--felt);
  --bg-3: var(--felt-well);
  --stroke: var(--felt-line);
  --stroke-strong: rgb(244 247 243 / 0.2);
  --action: var(--action-on-felt);
  --action-strong: var(--action-on-felt-strong);
  --action-tint: var(--action-on-felt-tint);
  --action-tint-strong: rgb(59 201 131 / 0.28);
  --warn: var(--warn-on-felt);
  --warn-tint: rgb(245 185 122 / 0.14);
  --danger: var(--danger-on-felt);
  --danger-tint: rgb(255 167 153 / 0.14);
  --elevation-1: 0 1px 1px rgb(0 0 0 / 0.22), 0 10px 20px -10px rgb(0 0 0 / 0.6);
  --elevation-2: 0 18px 36px -16px rgb(0 0 0 / 0.75);
  color: var(--fg);
}
/* Card stock on the felt: a tee time, a card, a club, a line that says why a day is empty. Each binds the roles back to paper's, on ivory; what sits inside reads as it always has. Zero specificity (:where), so a component's own colour
   still decides. Wells, chips and round tools stay the felt's. */
:where(#app)
  :where(
    .tee-time,
    .card,
    .club-card,
    .today-over,
    .day-state,
    .shared-tile,
    .info-line,
    .conditions,
    .tee-time-row,
    .banner,
    .rail-arrow
  ) {
  --fg: var(--paper-fg);
  --fg-2: var(--paper-fg-2);
  --fg-muted: var(--paper-fg-muted);
  --fg-subtle: var(--paper-fg-subtle);
  --ink: var(--paper-ink);
  --on-ink: var(--paper-on-ink);
  --bg-1: var(--card);
  --bg-2: var(--paper-bg-2);
  --bg-3: var(--paper-bg-3);
  --stroke: var(--paper-stroke);
  --stroke-strong: var(--paper-stroke-strong);
  --action: var(--paper-action);
  --action-strong: var(--paper-action-strong);
  --action-tint: var(--paper-action-tint);
  --action-tint-strong: var(--paper-action-tint-strong);
  --warn: var(--paper-warn);
  --warn-tint: var(--paper-warn-tint);
  --danger: var(--paper-danger);
  --danger-tint: var(--paper-danger-tint);
  color: var(--fg);
}
/* A golfer's own disc stays paper on the felt, light as the ball with their initial will be (R5). */
.brand-bar .account-button.signed-in {
  --action-tint: var(--paper-action-tint);
  --action-strong: var(--paper-action-strong);
}
/* The wordmark is chrome on the felt, beside its green tile. */
.brand-bar .brand {
  color: var(--on-felt);
}

/* ------------------------------------------------------------ layout */
/* The screens' column; a swipe's view of the next section (app/section-swipe.ts) is laid out as the screen will be. */
#view,
.preview-view {
  flex: 1;
  width: 100%;
  max-width: 640px;
  margin: 0 auto;
  padding: 0 16px calc(var(--tab-bar-height) + var(--safe-bottom) + 32px);
  outline: none;
}

/* A quiet line above each screen: the icon and the name, the area and the language on the right. */
.brand-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  max-width: 640px;
  margin: 0 auto;
  padding: calc(var(--safe-top) + 12px) 16px 2px;
}
.brand-tools {
  display: inline-flex;
  flex: 0 1 auto;
  align-items: center;
  gap: 6px;
  min-width: 0;
}
/* The area shown, as a pill that opens the area sheet: "📍 Madrid ▾". Same height and grey as ES | EN. */
.area-switch {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 3px;
  min-width: 0;
  max-width: 132px;
  height: 30px;
  padding: 0 7px 0 8px;
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--bg-3);
  color: var(--fg);
  font: 700 12px/1 var(--font);
  cursor: pointer;
}
.area-switch svg {
  width: 14px;
  height: 14px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.area-switch .caret {
  width: 12px;
  height: 12px;
  color: var(--fg-muted);
}
.area-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Last in the phone's bar, the account button takes the 16 px gutter to its right too: a tap in the phone's corner is
   its (Fitts). */
@media (max-width: 599px) {
  .brand-bar .account-button::after {
    inset: min(0px, (100% - 44px) / 2) -16px min(0px, (100% - 44px) / 2) 0;
  }
}
/* The area pill (36 px) takes a tap 44 px tall: a transparent ::after reaches above and below, never sideways, and
   stops short of what sits under the bar (checked at 360 and 390 px). */
.area-switch::after {
  content: "";
  position: absolute;
  inset: min(0px, (100% - 44px) / 2) 0;
}

/* A screen's title, its one line of status, and its one tool on the right. */
.screen-header {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 0 10px;
}
.screen-header h1 {
  margin: 0;
  font: 700 32px/1.1 var(--font-display);
  letter-spacing: -0.02em;
}
.subtitle {
  margin: 4px 0 0;
  font-size: 13px;
  line-height: 18px;
  color: var(--fg-muted);
}
.section-head {
  margin: 22px 0 10px;
  font: 700 17px/22px var(--font);
  letter-spacing: -0.005em;
  color: var(--fg);
}
.month-heading {
  margin: 28px 0 12px;
  font: 700 22px/28px var(--font-display);
  letter-spacing: -0.01em;
  text-transform: capitalize;
}

/* ------------------------------------------------------------ controls */
/* .icon-button itself is in styles.css, with the sheets whose ✕ it draws. */
/* A tool on its own: a white disc with a hairline. */
.icon-button.round {
  position: relative;
  width: 42px;
  height: 42px;
  border: 1px solid var(--stroke);
  background: var(--bg-1);
  box-shadow: var(--elevation-1);
}
.button {
  transition:
    transform 0.12s var(--ease),
    background 0.16s var(--ease),
    box-shadow 0.16s var(--ease);
}
.button.primary {
  box-shadow: 0 1px 2px rgb(12 94 63 / 0.25);
}
/* styles.css darkens it on any :hover, which a phone leaves on a tapped button; the app darkens it for a mouse only
   (the hover block, near the end). */
.button.primary:hover {
  background: var(--action);
}
.button.small {
  position: relative;
}
/* Controls drawn smaller than 44 px take a 44 px tap all the same, as the area pill does: a transparent ::after
   reaches past their edges, up to 44 px and no further, so it takes nothing from a neighbour 8 px away. Pills reach
   only above and below, never into the pill beside them. */
.segmented button::after,
.chip::after,
.button.small::after {
  content: "";
  position: absolute;
  inset: min(0px, (100% - 44px) / 2) 0;
}
.icon-button.round::after,
.club-card .star::after {
  content: "";
  position: absolute;
  inset: min(0px, (100% - 44px) / 2);
}

/* Two to four equal choices, the chosen one filled with ink: party size, holes, a week, a part of the day. */
.segmented {
  display: inline-grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  flex: none;
  gap: 2px;
  padding: 3px;
  border-radius: var(--radius-pill);
  background: var(--bg-3);
}
.segmented button {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 3px;
  min-width: 40px;
  min-height: 36px;
  padding: 0 10px;
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--fg-2);
  font: 600 14px/1 var(--font);
  white-space: nowrap;
  cursor: pointer;
  transition:
    background 0.18s var(--ease),
    color 0.18s var(--ease);
}
.segmented button[aria-pressed="true"] {
  background: var(--ink);
  color: var(--on-ink);
  box-shadow: 0 1px 3px rgb(16 36 27 / 0.25);
}
.segmented svg {
  width: 14px;
  height: 14px;
  fill: currentColor;
}
/* Full width: the week switch. */
.week-switch {
  display: grid;
  margin: 10px 0 2px;
}
/* Chosen, a later week scrolls up to the switch, which stops just under the filter bar. */
.week-switch {
  scroll-margin-top: calc(var(--top-bar-height) + var(--safe-top) + var(--filter-bar-height) + 8px);
}

/* Chips: a filter that says what it is set to. A chip that opens a sheet carries a caret; set, it turns ink. */
.chips {
  display: flex;
  gap: 8px;
  margin: 0 -16px;
  padding: 2px 16px 8px;
  overflow-x: auto;
  scrollbar-width: none;
}
.chips::-webkit-scrollbar {
  display: none;
}
.chip {
  position: relative;
  display: inline-flex;
  align-items: center;
  flex: none;
  gap: 6px;
  min-height: 40px;
  padding: 0 14px;
  border: 1px solid var(--stroke);
  border-radius: var(--radius-pill);
  background: var(--bg-1);
  color: var(--fg);
  font: 600 14px/1 var(--font);
  white-space: nowrap;
  cursor: pointer;
  transition:
    background 0.18s var(--ease),
    border-color 0.18s var(--ease),
    color 0.18s var(--ease),
    transform 0.12s var(--ease);
}
.chip:active {
  transform: scale(0.97);
}
.chip .icon {
  width: 16px;
  height: 16px;
  color: var(--fg-muted);
}
.chip .caret {
  width: 14px;
  height: 14px;
  margin: 0 -4px 0 -2px;
}
.chip[aria-pressed="true"],
.chip.is-set {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--on-ink);
}
.chip[aria-pressed="true"] .icon,
.chip.is-set .icon {
  color: currentColor;
}
/* A wrapping group of chips, for choices inside sheets. */
.choices {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 8px 0 16px;
}

/* The search's filters (A+, the prototype's .filters). On the week they lie on the felt under the hero and scroll with
   it, as the prototype's do; on a day they stick at the top, on felt glass reaching up under the phone's status bar,
   so the tee times never show through the chips. */
.filter-bar {
  position: sticky;
  top: calc(var(--top-bar-height) + var(--safe-top));
  z-index: 6;
  margin: 0 -16px;
  padding: 6px 0 4px;
}
.filter-bar::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: calc(-1 * var(--safe-top)) 0 0;
  background: rgb(7 42 29 / 0.82);
  box-shadow: 0 1px 0 rgb(255 255 255 / 0.06);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  transition: opacity var(--duration-quick) var(--ease);
}
/* On the week the filters scroll with the days, as the prototype's do (the mini-head stands in at the top, below). */
#view[data-screen="week"] .filter-bar {
  position: relative;
  top: auto;
}
#view[data-screen="week"] .filter-bar::before {
  content: none;
}
.filter-scroll {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0 16px;
  overflow-x: auto;
  scrollbar-width: none;
}
.filter-scroll::-webkit-scrollbar {
  display: none;
}
/* The party as golf balls (components/pickers.ts): white up to the party's size, small and dim after it, the count beside. */
.party-picker {
  display: flex;
  flex: none;
  align-items: center;
  gap: 0;
  min-height: 44px;
  /* The count's own 6 px close the pill at its end. */
  padding: 0 0 0 6px;
  border-radius: var(--radius-pill);
  background: rgb(255 255 255 / 0.07);
}
/* Each ball the prototype's size and nearly its place (30 px apart, against 26), each target 30 to 44 px wide with no
   gap between (the personas mis-tapped the 26 px ones). The pill stays the prototype's width, near enough (151 px
   against 143), so "€ Precio" is whole at 390 px. */
.party-picker button {
  position: relative;
  display: grid;
  place-items: center;
  width: 30px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-pill);
  background: none;
  cursor: pointer;
}
.party-picker i {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: rgb(255 255 255 / 0.28);
  transform: scale(0.38);
  transition: transform var(--duration-press) var(--spring-snap);
}
/* Between two balls each takes its own 30 px; the first reaches 14 px out past the pill's start (44 px in all), the last
   7 px into the count's room, short of the count itself. */
.party-picker button::after {
  content: "";
  position: absolute;
  inset: 0;
}
.party-picker button:first-child::after {
  left: -14px;
}
.party-picker button:last-of-type::after {
  right: -7px;
}
.party-picker button.in i {
  background: radial-gradient(circle at 34% 30%, #ffffff, #e2e8e4 70%, #c8d2cc);
  box-shadow: 0 2px 4px rgb(0 0 0 / 0.35);
  transform: none;
}
.party-picker button:active i {
  transform: scale(0.86);
}
/* The count, and a golfer beside it: what the balls count, with no word added to the prototype's. */
.party-count {
  display: inline-flex;
  align-items: center;
  gap: 1px;
  padding: 0 6px 0 0;
  font: 800 14px/1 var(--font);
  color: var(--on-felt);
}
.party-count svg {
  width: 11px;
  height: 11px;
  fill: currentColor;
  opacity: 0.75;
}
/* The holes, the price and the courses as felt chips (the prototype's .fpill); one set away from its default turns chrome. */
.filter-bar .chip {
  gap: 4px;
  min-height: 44px;
  padding: 0 10px 0 13px;
  border: 0;
  background: rgb(255 255 255 / 0.07);
  color: var(--on-felt);
  font: 700 14px/1 var(--font);
}
.filter-bar .chip .icon {
  width: 16px;
  height: 16px;
  color: currentColor;
  opacity: 0.75;
}
.filter-bar .chip .caret {
  margin: 0;
}
.filter-bar .chip.is-set {
  background: var(--on-felt);
  color: var(--paper-ink);
}
.filter-bar .chip.is-set .icon {
  opacity: 1;
}

/* ------------------------------------------------------------ badges, pills, tags */
.course-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px 3px 8px;
  border-radius: var(--radius-pill);
  background: var(--bg-2);
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
}
.course-pill::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--course);
}
.course-pill.plain::before {
  content: none;
}
.course-pill .club-badge {
  margin-left: -5px;
}
.tag {
  border-radius: var(--radius-pill);
  padding: 2px 9px;
}
.tag.new {
  background: var(--accent);
  color: var(--fg);
}

/* ------------------------------------------------------------ Horarios */
/* A+ (R2, 16 Oct 2026; the owner: "make a perfect copy of the prototype"): the week runs edge to edge, the hero
   full-bleed under the brand bar and the days on the felt below it. The values are the prototype's, ported as they are
   (ux/lanes/final/index.html: .hero, .hero-bar, .hero-main, .filters, .rail-sec, .tile). */
#view[data-screen="week"] {
  max-width: none;
  padding-inline: 0;
}
/* Under the hero, the week's column: the phone's gutter, a tablet's, and from 960 px the prototype's desktop window,
   1200 px with 44 px gutters. Rails reach past the gutters to the column's edges. */
.week-body {
  --week-gutter: var(--gutter);
  position: relative;
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 var(--week-gutter);
}
.week-body .filter-bar {
  margin-inline: calc(-1 * var(--week-gutter));
}
.week-body .filter-scroll {
  padding-inline: var(--week-gutter);
}

/* The hero: the area's own course with today's weather over it (components/hero-scene.ts), 302 px under the phone's
   status bar, the brand bar over its top (below), the date, the count and the weather over its foot. */
.hero {
  --hero-inset: max(var(--safe-top), 8px);
  position: relative;
  isolation: isolate;
  height: calc(302px + var(--hero-inset));
  overflow: hidden;
  /* No ground of its own: its foot fades into the felt under it (below), whatever the window's height. */
  background: transparent;
  color: var(--on-felt);
}
/* Until the photo has loaded: its own sky over its own ground, two colours of it, so the header never flashes green. */
/* Its last 56 px fade out over the felt beneath (fixed to the window, so the felt under the hero's foot differs with
   the window's height and the scroll): the prototype's "shadow" into the section below, never a line where they meet.
   At 390 × 844 the felt there is the prototype's, so it looks as it does there. */
.hero-backdrop {
  position: absolute;
  inset: 0;
  z-index: 0;
  -webkit-mask-image: linear-gradient(180deg, #000 calc(100% - 56px), transparent);
  mask-image: linear-gradient(180deg, #000 calc(100% - 56px), transparent);
  background: linear-gradient(
    180deg,
    var(--hero-sky, var(--felt)) 0%,
    var(--hero-sky, var(--felt)) 50%,
    var(--hero-ground, var(--felt)) 74%
  );
}
.hero-backdrop canvas,
.hero-backdrop img {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.6s var(--ease);
}
.hero-backdrop[data-ready] canvas,
.hero-backdrop[data-ready] img {
  opacity: 1;
}
/* The prototype's .hero-shade, as it is: the top darkened under the bar, a soft pool under the words at the lower
   left, and the foot running into the felt. Its contrast, measured in every weather and light by the app's e2e
   (hero-contrast.ts), is the words' own; where a line needs more, its text-shadow gives it, unseen. */
.hero-backdrop::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(90% 55% at 18% 72%, rgb(3 18 11 / 0.5), rgb(3 18 11 / 0) 70%),
    linear-gradient(180deg, rgb(3 18 11 / 0.5) 0%, rgb(3 18 11 / 0.08) 24%, rgb(3 18 11 / 0.22) 46%, rgb(5 28 19 / 0.8) 80%, #154437 100%);
}
/* The words' own shade, where a bright sky needs it (A+, R2's design QA: never a darker sky): a soft blur the size of
   each line, under the date, the count and the credit only, as dark as AA needs on the brightest photo and no more
   (hero-contrast.ts measures it in every weather). The eye reads it as the words' shadow. */
.hero-kicker,
.hero-photo {
  width: fit-content;
}
.hero-kicker::before,
.hero-photo::before,
.hero-numeral::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -7px -12px;
  border-radius: var(--radius-pill);
  background: rgb(3 18 11 / var(--words-shade));
  filter: blur(9px);
  pointer-events: none;
}
.hero-kicker {
  --words-shade: 0.4;
  position: relative;
}
/* The credit's shade hugs its letters (the re-check of R2: a wider blur read as a patch, darkening the sky round it by
   23 levels; this one by 3), at 4.9:1 or better in every weather. */
.hero-photo {
  --words-shade: 0.6;
}
.hero-photo::before {
  inset: -1px -4px;
  filter: blur(3px);
}
.hero-numeral::before {
  --words-shade: 0.26;
  inset: 8px -6px 0 -10px;
  border-radius: 40px;
  filter: blur(18px);
}
/* Whose course the photo is: under the bar, at the right. */
.hero-photo {
  position: absolute;
  z-index: 1;
  top: calc(var(--hero-inset) + 50px);
  right: 20px;
  margin: 0;
  color: #ffffff;
  font: 600 11px/1.35 var(--font);
  text-shadow:
    0 1px 6px rgb(0 0 0 / 0.6),
    0 0 2px rgb(3 18 11 / 0.7),
    0 0 6px rgb(3 18 11 / 0.6),
    0 0 12px rgb(3 18 11 / 0.4);
}
/* The date, the count and its line, over the hero's foot; the weather beside them, at the right. The count is sized
   from this box (a container), less the room the weather takes. */
.hero-main {
  position: absolute;
  z-index: 1;
  right: 20px;
  bottom: 34px;
  left: 20px;
  container-type: inline-size;
}
.hero-kicker {
  margin: 0;
  color: #ffffff;
  font: 800 12px/1 var(--font);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  /* The prototype's soft shadow, then a halo hugging the letters: 4.5:1 on a white sky, unseen as a shade. */
  text-shadow:
    0 1px 8px rgb(0 0 0 / 0.45),
    0 0 2px rgb(3 18 11 / 0.7),
    0 0 6px rgb(3 18 11 / 0.6),
    0 0 12px rgb(3 18 11 / 0.4);
}
/* The screen's one display numeral (A+): today's count in chrome, as large as its box allows beside the weather and
   never larger than the display size. kit/numeral-fit.ts measures how many ems its text is; the box's width, less the
   weather's 96 px, over that is the size that fits, less 4 % for the settle it lands with and its optical overhang. */
/* The numeral's slot, the same height in every state (the count, its loading shape, the words that take its place, or
   nothing), with what it holds at its foot: the date above sits where the prototype puts it whatever the hero says
   (R2's design QA: it moved by up to 122 px between states). 0.84 em of the display size and the count's margins. */
.hero-slot {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: calc(var(--text-display) * 0.84 + 18px);
}
/* Its own block (flow-root: the count's top margin stays inside it), so the halo lies exactly on the figures. */
.hero-numeral {
  position: relative;
  display: flow-root;
}
.hero-count,
.hero-count-halo {
  display: block;
  width: fit-content;
  /* The prototype's -4 px optical indent at the display size, as a share of the size so a fitted count keeps it. */
  margin: 12px 0 6px -0.032em;
  padding-right: 0.07em;
  font: 900 min(var(--text-display), calc((100cqi - 96px) / var(--numeral-ems, 3) * 0.96)) / 0.84 var(--font-display);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.06em;
  white-space: nowrap;
  transform-origin: 0 80%;
}
.hero-count {
  position: relative;
  /* Chrome: the face's gradient through the letters; its darkest band is the colour where clipping isn't possible. */
  color: var(--chrome-shade);
  background: var(--chrome-face);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
/* The count's halo, under it: the same figures, drawn only as their shadow. Its first layer is the prototype's own
   drop shadow (0 4px 18px, 35 %); the tighter ones under it hug the figures' edges, so the chrome keeps 3:1 over a
   white sky or a lit fog bank (hero-contrast.ts measures it in every weather) while the photo around keeps its light:
   the eye reads it as the numeral's shadow, never as a box or a pool behind it (the design QA's ask, R2). */
.hero-count-halo {
  position: absolute;
  top: 0;
  left: 0;
  color: transparent;
  text-shadow:
    0 4px 18px rgb(0 0 0 / 0.35),
    0 0 4px rgb(3 18 11 / 0.55),
    0 0 14px rgb(3 18 11 / 0.5),
    0 0 30px rgb(3 18 11 / 0.35);
  pointer-events: none;
  user-select: none;
}
/* It lands with a settle once, when the count first shows (a bounce, growing from its left edge, inside the fit's 4 %).
   A redraw while it settles carries the settle on from where it is (week-screen.ts sets the negative delay), so the
   numeral never restarts from nothing on a cold load (R1's blink). */
.hero-count.settling,
.hero-count-halo.settling {
  animation: numeral-settle var(--duration-land) var(--spring-bounce) both;
  animation-delay: var(--settle-delay, 0ms);
}
@keyframes numeral-settle {
  from {
    opacity: 0;
    transform: translateY(10px) scale(0.96);
  }
}
/* While today is first read: the numeral's shape, pressed into the photo's light. */
.hero-count-skeleton {
  display: block;
  width: min(220px, calc(100cqi - 96px));
  height: 92px;
  margin: 18px 0 8px;
  border-radius: 22px;
  background: linear-gradient(90deg, rgb(255 255 255 / 0.1) 0%, rgb(255 255 255 / 0.2) 50%, rgb(255 255 255 / 0.1) 100%);
  background-size: 200% 100%;
  animation: shimmer 1.2s ease-in-out infinite;
}
/* Today with nothing to count (over, or none free): the words in the numeral's place, as a title. */
.hero-headline {
  max-width: calc(100cqi - 96px);
  margin: 12px 0 8px;
  color: #ffffff;
  font: 800 28px/1.1 var(--font);
  letter-spacing: -0.02em;
  text-shadow: 0 1px 10px rgb(0 0 0 / 0.4);
  text-wrap: balance;
}
/* Under the count: a live dot, what it counts, and how fresh it is ("salidas libres · ahora"). */
.hero-sub {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  color: rgb(244 247 243 / 0.74);
  font: 650 15px/1.35 var(--font);
  text-shadow: 0 1px 6px rgb(0 0 0 / 0.3);
}
.hero-sep {
  margin: 0 -4px;
}
/* The freshness is the week's refresh: no chrome of its own, the line's words, and a tap 44 px tall. */
.hero-live {
  position: relative;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-shadow: inherit;
  white-space: nowrap;
  cursor: pointer;
}
.hero-live::after {
  content: "";
  position: absolute;
  inset: min(0px, (100% - 44px) / 2) -6px;
}
.hero-live[aria-disabled="true"] {
  cursor: default;
}
/* The live dot (week-screen.ts, liveDot): lit while the readings are under a minute old or being read, grey after. Its
   ring is a layer of its own that breathes by transform and opacity, so no frame repaints the line; the phase comes
   with the markup (--pulse-delay), so a redraw carries it on rather than starting it again. */
.live-dot {
  position: relative;
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--on-felt-muted);
}
.live-dot.lit {
  background: var(--action-on-felt);
}
.live-dot.lit::before {
  content: "";
  position: absolute;
  inset: -4px;
  border-radius: 50%;
  background: rgb(59 201 131 / 0.22);
}
.live-dot.breathing::before {
  animation: live-ring 2400ms ease-in-out var(--pulse-delay, 0ms) 2;
}
.live-dot.reading::before {
  animation: live-ring 1100ms ease-in-out var(--pulse-delay, 0ms) infinite;
}
@keyframes live-ring {
  50% {
    opacity: 0;
    transform: scale(1.375);
  }
}
/* Today's weather in the area, at the right, level with the count's foot. */
.hero-weather {
  position: absolute;
  z-index: 1;
  right: 20px;
  bottom: 42px;
  display: flex;
  margin: 0;
}
.hero-weather .weather-mark {
  gap: 6px;
  color: var(--on-felt);
  font: 750 20px/1 var(--font);
  text-shadow: 0 1px 8px rgb(0 0 0 / 0.35);
}
.hero-weather .weather-mark .icon {
  width: 28px;
  height: 28px;
}

/* The brand bar as A+ draws it (the prototype's .hero-bar): the mark and the name, the area on a glass pill and the
   golfer's ball, or Entrar in white. On Horarios it lies over the hero's photo, the hero reaching under it. */
.brand-bar {
  gap: 10px;
}
.brand-bar .brand {
  gap: 8px;
}
/* The mark alone (never the wordmark, which /search's and the site's bars draw as an image), hinted on 28 px
   (icon-28.svg): its squircle is in the file, so no radius of its own. */
.brand-bar .brand-mark {
  width: 28px;
  height: 28px;
}
.brand-bar .wordmark {
  letter-spacing: -0.02em;
}
.brand-tools {
  gap: 10px;
}
.area-switch {
  gap: 4px;
  max-width: 160px;
  height: 36px;
  padding: 0 10px 0 14px;
  background: rgb(255 255 255 / 0.16);
  color: var(--on-felt);
  font: 750 14px/1 var(--font);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}
.area-switch svg:not(.caret) {
  display: none;
}
.area-switch .caret {
  width: 16px;
  height: 16px;
  color: currentColor;
}
/* The golfer's M4 ball (R5: the owner's avatar, its own white ball on their colour), 32 px in a 40 px tap. Its gold
   ring, once earned, is drawn outside the 32 px (overflow visible), inside the tap. */
.brand-bar .account-button.signed-in {
  width: 40px;
  height: 40px;
  padding: 4px;
  background: none;
}
.brand-bar .account-button.signed-in .avatar {
  position: relative;
  width: 32px;
  height: 32px;
  filter: drop-shadow(0 2px 3px rgb(0 0 0 / 0.28));
}
/* A guest's Entrar: the bar's one white pill. */
.brand-bar .account-button:not(.signed-in) {
  height: 36px;
  padding: 0 14px;
  background: #ffffff;
  color: var(--paper-ink);
  font: 800 14px/1 var(--font);
}
/* Narrower phones keep the bar whole with the longest area ("Costa del Sol") beside Entrar, a step at a time: from
   389 px, where the area's name would be cut otherwise (shell.ts measures it and sets data-tight), the gaps close to 6 px; from 386
   px Entrar is its person on the white disc (the word stays for screen readers); from 345 px, where it must, the
   wordmark drops to 14 px and the area pill tightens. Measured with Figtree at the bar's sizes (16 Oct 2026): the brand 138 px,
   "Costa del Sol" on its pill 128 px, Entrar 72 px; "Madrid" fits whole at 320 px. */
@media (max-width: 389px) {
  .brand-bar[data-tight],
  .brand-bar[data-tight] .brand-tools {
    gap: 6px;
  }
}
@media (max-width: 386px) {
  .brand-bar .account-button:not(.signed-in) {
    width: 36px;
    padding: 0;
  }
  .brand-bar .account-button:not(.signed-in) .icon {
    display: block;
  }
  .brand-bar .account-button:not(.signed-in) .account-button-label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
  }
}
@media (max-width: 345px) {
  .brand-bar[data-tight] .wordmark {
    font-size: 14px;
  }
  .brand-bar[data-tight] .brand {
    gap: 6px;
  }
  .brand-bar[data-tight] .area-switch {
    gap: 2px;
    padding: 0 6px 0 9px;
  }
  .brand-bar[data-tight] .area-switch .caret {
    width: 14px;
    height: 14px;
  }
}
/* On a phone the bar is the prototype's: its ES | EN is at the top of the area sheet; a computer's top bar keeps it (R1). */
@media (max-width: 959px) {
  .brand-bar .language-switch {
    display: none;
  }
}
@media (max-width: 959px) {
  #app:has(> #view[data-screen="week"]) {
    position: relative;
  }
  /* No z-index on the bar itself: it would make a stacking context and take the Cápsula+ (fixed, inside it) down with
     it, under the filter bar. Its brand and tools rise over the hero one by one instead. */
  #app:has(> #view[data-screen="week"]) > .brand-bar {
    position: absolute;
    top: 0;
    right: 0;
    left: 0;
    max-width: none;
    padding: calc(max(var(--safe-top), 8px) + 2px) 16px 0;
  }
  #app:has(> #view[data-screen="week"]) > .brand-bar > :not(.capsule) {
    position: relative;
    z-index: 3;
    min-height: 40px;
  }
}

/* Saved searches, as a carousel: the next one peeks in from the right. */
.saved-searches .section-head {
  margin-top: 8px;
}
.carousel {
  display: flex;
  gap: 10px;
  margin: 0 -16px;
  padding: 0 16px 6px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: 16px;
  scrollbar-width: none;
}
.carousel::-webkit-scrollbar {
  display: none;
}
.carousel > * {
  flex: 0 0 min(84%, 330px);
  scroll-snap-align: start;
}
.carousel.single > * {
  flex-basis: 100%;
}
.saved-search {
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 6px 4px 6px 6px;
}
.saved-search-run {
  display: flex;
  flex: 1;
  align-items: center;
  gap: 12px;
  min-width: 0;
  padding: 4px;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.saved-search-run .grow {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.saved-search-run .grow b {
  font-size: 15px;
  line-height: 20px;
}
.saved-search-count {
  display: flex;
  flex: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 58px;
  height: 58px;
  border-radius: var(--radius-block);
  background: var(--action-tint);
  color: var(--action-strong);
}
.saved-search-count b {
  font: 700 24px/1 var(--font-display);
}
.saved-search-count small {
  margin-top: 3px;
  font-size: 11px;
  font-weight: 700;
}
/* A saved search whose next date is locked for a guest (ADR-0002): its count stays, on the grey ground, with the lock
   on the cell's corner. */
.saved-search-count {
  position: relative;
}
.saved-search-count.locked {
  background: var(--bg-2);
  color: var(--fg-2);
}
.saved-search-count .lock-glyph {
  position: absolute;
  top: -6px;
  right: -6px;
  width: 22px;
  height: 22px;
  padding: 4px;
  border-radius: 50%;
  background: var(--bg-1);
  box-shadow: 0 0 0 1px var(--stroke);
  color: var(--fg-2);
}
.saved-search-preview {
  margin: 12px 0;
}

/* Each day (the prototype's .rail-sec): a heading that opens the day, then its tee times running off the screen's edge. */
.days {
  margin-top: 0;
}
/* A week chosen at the foot comes up under the mini-head (a phone) or the top bar (a computer). */
.week-body .days,
.week-body .wk-skies {
  scroll-margin-top: calc(var(--top-bar-height) + max(var(--safe-top), 8px) + 48px);
}
.day-card {
  padding-top: 16px;
}
/* The heading: the day's name and date ("Mañana sáb 17"), "+3 nuevas" in gold when the club added tee times since the
   golfer's last look, then at the right its weather, its count and the way into the day. */
.day-head {
  position: relative;
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
}
.day-link {
  display: inline-flex;
  flex: 1;
  align-items: center;
  gap: 8px;
  min-width: 0;
  color: var(--on-felt);
  text-decoration: none;
}
/* The whole heading answers the tap, weather and count included. */
.day-link::after {
  content: "";
  position: absolute;
  inset: 0;
}
.day-link:focus-visible {
  outline: none;
}
.day-link:focus-visible::after {
  border-radius: 10px;
  outline: 2.5px solid #9df0c4;
  outline-offset: 2px;
}
.day-name {
  font: 780 21px/1.35 var(--font-display);
  letter-spacing: -0.02em;
  white-space: nowrap;
}
.day-date {
  color: rgb(244 247 243 / 0.58);
  font: 600 14px/1.35 var(--font);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.day-new {
  flex: none;
  padding: 4px 7px;
  border-radius: var(--radius-pill);
  background: var(--gold-sheen);
  color: var(--on-gold);
  font: 850 11px/1.35 var(--font);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}
.day-head .weather-mark {
  gap: 4px;
  color: rgb(244 247 243 / 0.74);
  font: 700 14px/1.35 var(--font);
}
.day-head .weather-mark .icon {
  width: 18px;
  height: 18px;
}
.day-more {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: 4px;
  margin-left: 6px;
  color: var(--on-felt);
}
.day-more b {
  font: 800 16px/1.35 var(--font);
}
.day-more .icon {
  width: 16px;
  height: 16px;
  color: rgb(244 247 243 / 0.58);
}
.day-more .spinning {
  color: var(--on-felt-muted);
}
/* The rail: tiles 108 px wide, 8 px apart, snapping to the gutter. A rail's last tile on screen is always cut by the
   edge, which says the rail goes on: at 360 px a 108 px fourth tile would start past the edge, so 350–374 px phones
   take 104 px tiles (at 320 px the third is cut, at 375–430 px the fourth). */
.tee-times-row {
  display: flex;
  gap: 8px;
  margin: 0 calc(-1 * var(--week-gutter, 16px));
  padding: 12px var(--week-gutter, 16px) 6px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: var(--week-gutter, 16px);
  scrollbar-width: none;
  overscroll-behavior-x: contain;
}
.tee-times-row::-webkit-scrollbar {
  display: none;
}
.tee-times-row .tee-time {
  flex: 0 0 108px;
  scroll-snap-align: start;
}
/* Under 375 px the words that take the count's place fit the numeral's slot in three lines at most, so the date keeps
   its place; and with nothing read (an empty slot, the line alone and long) the weather steps aside for it. */
@media (max-width: 374px) {
  .hero-headline {
    font-size: 24px;
  }
  .hero:has(.hero-slot:empty) .hero-weather {
    display: none;
  }
}
/* Under 375 px a heading with "+3 nuevas" has no room for the weather too: the count and the gold say more there (the
   forecast is the day's own, a tap away). */
@media (max-width: 374px) {
  .day-head:has(.day-new) .weather-mark {
    display: none;
  }
}
@media (min-width: 350px) and (max-width: 374px) {
  .tee-times-row .tee-time,
  .tile-skeleton {
    flex-basis: 104px;
  }
}
/* A day being read for the first time: blank tiles pressed into the felt, their lines shimmering, where its tee times
   will be. */
.rail-skeleton {
  display: flex;
  gap: 8px;
  margin: 0 calc(-1 * var(--week-gutter, 16px));
  padding: 12px var(--week-gutter, 16px) 6px;
  overflow: hidden;
}
.tile-skeleton {
  display: grid;
  flex: 0 0 108px;
  align-content: start;
  gap: 10px;
  height: 92px;
  padding: 13px 10px;
  border-radius: 16px;
  background: rgb(0 0 0 / 0.14);
  box-shadow:
    inset 0 2px 5px rgb(0 0 0 / 0.3),
    0 1px 0 rgb(255 255 255 / 0.05);
}
.tile-skeleton i {
  display: block;
  height: 12px;
  border-radius: 6px;
  background: linear-gradient(90deg, rgb(255 255 255 / 0.07) 0%, rgb(255 255 255 / 0.16) 50%, rgb(255 255 255 / 0.07) 100%);
  background-size: 200% 100%;
  animation: shimmer 1.2s ease-in-out infinite;
}
.tile-skeleton i:first-child {
  width: 62%;
  height: 18px;
}
.tile-skeleton i:nth-child(2) {
  width: 78%;
}
.tile-skeleton:nth-child(2) i {
  animation-delay: 0.1s;
}
.tile-skeleton:nth-child(3) i {
  animation-delay: 0.2s;
}
.tile-skeleton:nth-child(4) i {
  animation-delay: 0.3s;
}
/* A day with nothing to show says why, in one line where its tee times would be, pressed into the felt (an ivory card
   is a tee time to tap, so this is not one). */
.day-state,
.today-over {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 56px;
  margin: 12px 0 6px;
  padding: 0 16px;
  border: 0;
  border-radius: 16px;
  background: rgb(0 0 0 / 0.14);
  box-shadow:
    inset 0 2px 5px rgb(0 0 0 / 0.3),
    0 1px 0 rgb(255 255 255 / 0.05);
  color: var(--on-felt-2);
  font: 650 14px/1.35 var(--font);
}
.day-state .icon,
.today-over .icon {
  width: 18px;
  height: 18px;
}
.day-notes {
  margin: 6px 0 0;
}
.today-over {
  margin-top: 16px;
  text-decoration: none;
}
.today-over .day-name {
  color: var(--on-felt);
  font-size: 17px;
}
.today-over .icon {
  color: var(--on-felt-muted);
}
/* After the week's last day: the switch to the next two weeks. */
.week-switch {
  margin-top: 28px;
}

/* A date past the strip's fifteen days (reached by the week switch or a link), shown after an ellipsis. */
.strip-gap {
  align-self: center;
  flex: none;
  padding-top: 18px;
  color: var(--fg-subtle);
  font-weight: 700;
}

/* The wall (A+, R4; ADR-0002, components/locked-day.ts and banderin.ts): the prototype's M1 to M4, its values ported as
   they are. Nothing here is gold; the green is the action's. */

/* The locked week as day skies (the prototype's .wk-skies, from lane B): each day's tint its forecast at 10:00, its
   height its real count against the busiest locked day (presentation/day-sky.ts), the week's total over them. */
.wk-skies {
  position: relative;
  margin-top: 22px;
  padding: 18px 0 10px;
}
.tb-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding: 0 16px;
}
.tb-head .cap {
  color: rgb(244 247 243 / 0.74);
  font: 800 12px/1 var(--font);
  letter-spacing: 0.09em;
  text-transform: uppercase;
}
.tb-total {
  color: rgb(244 247 243 / 0.74);
  font: 650 14px/1.35 var(--font);
}
.tb-total b {
  display: inline-block;
  color: var(--on-felt);
  font-size: 20px;
  font-weight: 850;
  line-height: 1;
  letter-spacing: -0.02em;
}
.skies {
  display: flex;
  align-items: flex-end;
  gap: 6px;
  padding: 18px 16px 22px;
}
.skycol {
  display: flex;
  flex: 1;
  flex-direction: column;
  align-items: center;
  gap: 7px;
  min-width: 0;
  padding: 0;
  border: 0;
  border-radius: 14px;
  background: none;
  color: var(--on-felt);
  font: inherit;
  container-type: inline-size;
  cursor: pointer;
}
.skycol.quiet {
  cursor: default;
}
.sc-bar {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  width: 100%;
  height: var(--h);
  padding-top: 10px;
  overflow: hidden;
  border-radius: 14px;
  background: var(--g);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.3),
    inset 0 -18px 24px -18px rgb(0 0 0 / 0.25),
    0 12px 20px -12px rgb(0 0 0 / 0.7);
  transform-origin: 50% 100%;
  transition: transform var(--duration-press) var(--spring-snap);
}
.skycol:active .sc-bar {
  transform: scale(0.96);
}
/* A day still being read: the shortest sky, its number to come, breathing as the app's skeletons do. */
.sc-bar.reading {
  animation: shimmer-fade 1.2s ease-in-out infinite alternate;
}
@keyframes shimmer-fade {
  to {
    opacity: 0.55;
  }
}
/* A day with nothing to open: its sky, dimmed. */
.skycol.quiet:not(:has(.reading)) .sc-bar {
  opacity: 0.55;
}
/* 14 px as drawn; a narrow sky (seven to a 320 px phone) takes its number down rather than past its edges. */
.sc-n {
  color: #fff;
  font: 850 clamp(8px, 26cqi, 14px) / 1 var(--font);
  letter-spacing: -0.01em;
  text-shadow: 0 1px 3px rgb(0 0 0 / 0.3);
}
.sc-bar .icon {
  width: 18px;
  height: 18px;
  flex: none;
  color: #fff;
}
/* The weekday at 64 % chrome, not the prototype's 58 %: 10.5 px capitals keep 4.5:1 on the felt (R3's rule). */
.sc-wd {
  color: rgb(244 247 243 / 0.64);
  font: 800 10.5px/1 var(--font);
  letter-spacing: 0.06em;
}
.sc-d {
  margin-top: -3px;
  font: 780 15px/1 var(--font);
}
.sc-flash,
.dc-flash {
  position: absolute;
  pointer-events: none;
  opacity: 0;
}
.sc-flash {
  inset: 0;
  background: linear-gradient(180deg, rgb(255 255 255 / 0.7), rgb(255 255 255 / 0));
}
.tb-cta {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  padding: 0 16px;
}
.tb-cta .cta {
  width: 100%;
}
.locked-week-empty {
  margin: 0 16px;
}
/* A computer (the prototype draws none): the week's column already has its gutters, and a sky is a tile's width
   (132 px), not a fifth of the window, the button under them at its own width. */
@media (min-width: 960px) {
  .wk-skies :is(.tb-head, .skies, .tb-cta) {
    padding-right: 0;
    padding-left: 0;
  }
  .wk-skies .tb-head {
    justify-content: flex-start;
    gap: 24px;
  }
  .skies {
    gap: 8px;
  }
  .skycol {
    flex: 0 1 132px;
  }
  .tb-cta {
    align-items: flex-start;
  }
  .tb-cta .cta {
    width: auto;
    min-width: 262px;
  }
  .locked-week-empty {
    margin: 0;
  }
}
/* The wall's one green button (the prototype's .cta), on the week and on a locked day. */
:is(.tb-cta, .lock-foot) .cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 56px;
  padding: 0 30px;
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--action-on-felt);
  color: #03170d;
  font: 800 17px/1.2 var(--font);
  letter-spacing: -0.01em;
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.45),
    inset 0 -2px 0 rgb(0 0 0 / 0.14),
    0 14px 30px -14px rgb(59 201 131 / 0.75);
  cursor: pointer;
  transition: transform var(--duration-press) var(--spring-snap);
}
:is(.tb-cta, .lock-foot) .cta:active {
  transform: scale(0.96);
}
:is(.tb-cta, .lock-foot) .fine {
  margin: 0;
  color: rgb(244 247 243 / 0.64);
  font: 550 13px/1.35 var(--font);
}

/* A locked date in the strip: a little day sky, dimmed (the prototype's .chip), 30 × 38 over the date's place; its
   number is the chip's, the date's own hidden under it until the reveal lights it away (banderin.ts marks it gone). */
.sky-chip {
  position: absolute;
  inset: -2px 2px;
  display: grid;
  place-items: center;
  border-radius: 11px;
  background: linear-gradient(rgb(4 24 16 / 0.26), rgb(4 24 16 / 0.26)), var(--g);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.3),
    0 3px 8px -2px rgb(0 0 0 / 0.5);
  color: #fff;
  font: 820 14.5px/1 var(--font);
  text-shadow: 0 1px 3px rgb(0 0 0 / 0.35);
}
.day-pill[aria-current="date"] .sky-chip {
  box-shadow:
    0 0 0 2.5px var(--on-felt),
    0 3px 8px -2px rgb(0 0 0 / 0.5);
}
.day-pill .day:has(> .sky-chip:not(.gone)) {
  background: transparent;
  color: transparent;
}
.dc-flash {
  top: 50%;
  left: 50%;
  width: 56px;
  height: 56px;
  margin: -28px 0 0 -28px;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgb(255 255 255 / 0.9), rgb(255 255 255 / 0));
}

/* A locked day under its count: the real day on the felt. Ghost tiles are pressed into the felt, one per real tee time
   (up to the grid's first rows), the size of the tiles they stand for. */
.lock-stage {
  position: relative;
}
.ghost-tile {
  display: block;
  height: 92.2px;
  border-radius: 16px;
  background: rgb(0 0 0 / 0.17);
  box-shadow:
    inset 0 2px 5px rgb(0 0 0 / 0.38),
    inset 0 -1px 0 rgb(255 255 255 / 0.05),
    0 1px 0 rgb(255 255 255 / 0.06);
  pointer-events: none;
}
/* A friend's tee time on a locked day: the one real tile, as the link showed it, its lock where the places would be. */
.shared-cap {
  margin: 22px 4px -8px;
  color: rgb(244 247 243 / 0.74);
  font: 800 12px/1.35 var(--font);
  letter-spacing: 0.09em;
  text-transform: uppercase;
}
.shared-tile {
  margin: 0;
}
.shared-tile .lock-glyph {
  width: 14px;
  height: 14px;
  color: var(--paper-fg-muted);
}
/* The count's side while locked: a blank ball a course (never which), the price waiting for the day to open. */
.cs-balls {
  display: flex;
}
.cs-ball {
  width: 22px;
  height: 22px;
  margin-left: -7px;
  border-radius: 50%;
  background:
    radial-gradient(circle at 30% 26%, rgb(255 255 255 / 0.75), rgb(255 255 255 / 0) 38%),
    radial-gradient(circle at 72% 80%, rgb(0 20 10 / 0.2), rgb(0 0 0 / 0) 58%), #fff;
  box-shadow:
    0 0 0 1.5px #cfd6d1,
    0 2px 5px rgb(0 0 0 / 0.28);
}
.cs-ball:first-child {
  margin-left: 0;
}

/* The Banderín: the pin in the cup. Only the pole and the flag take the gesture (touch-action there alone); the rest
   of the felt scrolls. Placed from the grid by banderin.ts, never at fixed pixels. */
.cand {
  position: absolute;
  inset: 0;
  z-index: 5;
  pointer-events: none;
}
.pin-cup {
  position: absolute;
  width: 56px;
  height: 20px;
  margin: -10px 0 0 -28px;
  border-radius: 50%;
  background: radial-gradient(ellipse 50% 60% at 50% 70%, #010604 0 62%, #06140d 100%);
  box-shadow:
    inset 0 3px 0 -1px #e9efec,
    inset 0 5px 4px -2px rgb(0 0 0 / 0.6),
    0 14px 18px -8px rgb(0 0 0 / 0.5);
  pointer-events: none;
}
.cup-ring {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 52px;
  height: 20px;
  margin: -10px 0 0 -26px;
  border-radius: 50%;
  box-shadow: 0 0 0 2px rgb(240 255 246 / 0.9);
  opacity: 0;
}
.pin {
  position: absolute;
  width: 90px;
  pointer-events: none;
  will-change: transform;
}
.pole {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 4px;
  border-radius: 2px;
  background: linear-gradient(90deg, #8e9a94, #ffffff 45%, #c4cec9 70%, #7f8b85);
  box-shadow: 2px 0 4px rgb(0 0 0 / 0.3);
}
/* The idle cue: three waves, under 5 s (WCAG 2.2.2), then still. */
.flag {
  position: absolute;
  top: 2px;
  left: 3px;
  width: 86px;
  height: 56px;
  overflow: visible;
  transform-origin: 0 50%;
  animation: wave 1.6s ease-in-out 3;
}
@keyframes wave {
  0%,
  100% {
    transform: skewY(0deg) scaleX(1);
  }
  50% {
    transform: skewY(-5deg) scaleX(0.93);
  }
}
.pin.taut .flag {
  animation: none;
}
.pin-hit {
  position: absolute;
  border-radius: 22px;
  pointer-events: auto;
  touch-action: none;
  cursor: grab;
}
.pin-hint {
  position: absolute;
  display: flex;
  align-items: center;
  gap: 4px;
  color: var(--action-on-felt-strong);
  font: 800 12px/1 var(--font);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  pointer-events: none;
}
.pin-hint .icon {
  width: 16px;
  height: 16px;
  stroke-width: 2.2;
}
/* The foot: the pin's instant twin over a fade to the deep felt, held at the screen's foot over the ghosts as the
   prototype's is (sticky, above the tab bar), so a short phone still sees it. */
.lock-foot {
  position: sticky;
  bottom: calc(var(--tab-bar-height, 0px) + var(--safe-bottom));
  z-index: 6;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  gap: 12px;
  height: 156px;
  margin: 0 calc(-1 * var(--day-gutter, 16px));
  padding: 0 16px 32px;
  background: linear-gradient(180deg, rgb(7 42 29 / 0), rgb(7 42 29 / 0.9) 40%, var(--felt-deep));
  pointer-events: none;
}
.lock-foot > * {
  pointer-events: auto;
}
.lock-foot .cta {
  min-width: 262px;
}
/* A computer has no tab bar to hold it over and its ghosts end within the window: the foot sits under them in the
   column, with no fade (one would end in a band across the window's felt). */
@media (min-width: 960px) {
  .lock-stage .lock-foot {
    position: static;
    height: auto;
    margin: 0;
    padding: 32px 0 8px;
    background: none;
  }
}
/* The reveal's own layer (banderin.ts): the pin, the ghosts fading and the flag in flight, over the day drawn open. */
.unlock-layer {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 35;
  width: 0;
  height: 0;
  pointer-events: none;
}
/* While the reveal plays, a tap anywhere skips it, and only that (banderin.ts swallows its click). */
.unlock-catch {
  position: fixed;
  inset: 0;
  z-index: 36;
}
.unlock-layer .ghost-tile {
  position: absolute;
}
.flagfly {
  position: absolute;
  z-index: 41;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  color: #03170d;
  pointer-events: none;
  will-change: transform;
}
.flagfly b {
  font: 900 15px/1 var(--font);
  letter-spacing: -0.5px;
}

/* ------------------------------------------------------------ tee times */
/* A tee time (A+, the prototype's .tile): an ivory card, its time as the hero, the club's ball and short name under
   it, then the price and the places free in words ("2 libres"). Gold for new since the golfer's last look, silver for
   the day's cheapest, each with its tab over the top edge. */
.tee-time {
  position: relative;
  display: grid;
  align-content: start;
  gap: 7px;
  min-width: 0;
  padding: 11px 8px 10px 10px;
  border: 0;
  border-radius: 16px;
  background: var(--card);
  box-shadow:
    inset 0 1px 0 #ffffff,
    0 1px 1px rgb(0 0 0 / 0.22),
    0 10px 20px -10px rgb(0 0 0 / 0.6);
  color: var(--paper-fg);
  font: inherit;
  line-height: 1.35;
  text-align: left;
  cursor: pointer;
  transition: transform var(--duration-press) var(--spring-snap);
}
.tee-time:active {
  transform: scale(0.96);
}
.tee-time .time {
  display: block;
  height: 1em;
  font: 820 22px/1 var(--font);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}
.tee-time-club {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  color: var(--paper-fg-2);
  font: 680 12.5px/1.35 var(--font);
  letter-spacing: -0.005em;
  white-space: nowrap;
}
/* A long name ends in an ellipsis, never wraps: the tile keeps its height and the rail its line. */
.club-name {
  overflow: hidden;
  text-overflow: ellipsis;
}
.tee-time-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 4px;
  min-height: 16px;
}
.tee-time .price {
  color: var(--paper-fg);
  font: 780 13.5px/1.35 var(--font);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.free-places {
  margin-left: auto;
  color: var(--paper-action-strong);
  font: 800 12px/1.35 var(--font);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
  white-space: nowrap;
}
/* The club's badge printed on a golf ball, ringed in the club's colour and lit from the top left. */
.club-ball {
  position: relative;
  display: inline-grid;
  flex: none;
  place-items: center;
  width: 17px;
  height: 17px;
  overflow: hidden;
  border-radius: 50%;
  background: #ffffff;
  box-shadow:
    0 0 0 1.5px var(--course, #cfd6d1),
    0 2px 5px rgb(0 0 0 / 0.28);
}
/* The whole badge at 90 % of the ball, as search.css prints it (badge-ball.ts's BADGE_SHARE). */
.club-ball .club-badge {
  width: 90%;
  height: 90%;
  max-width: none;
  border-radius: 0;
  background: none;
  box-shadow: none;
  object-fit: contain;
}
.club-ball::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background:
    radial-gradient(circle at 30% 26%, rgb(255 255 255 / 0.75), rgb(255 255 255 / 0) 38%),
    radial-gradient(circle at 72% 80%, rgb(0 20 10 / 0.2), rgb(0 0 0 / 0) 58%);
  pointer-events: none;
}
.ball-dot {
  width: 45%;
  height: 45%;
  border-radius: 50%;
  background: var(--course);
}
/* The tab over the top edge, centred: "Nueva" in gold, "Mejor precio" in silver. */
.tee-time-tag {
  position: absolute;
  z-index: 3;
  top: -8px;
  left: 50%;
  padding: 3px 7px;
  border-radius: var(--radius-pill);
  font: 850 9.5px/1.1 var(--font);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  pointer-events: none;
  transform: translateX(-50%);
}
.tee-time.silver {
  background: linear-gradient(128deg, #eef2f3 0%, #ffffff 30%, #d9e0e2 55%, #f8fafa 78%, #e4e9ea 100%);
}
.tee-time.silver .tee-time-tag {
  background: var(--silver-sheen);
  box-shadow: 0 1px 2px rgb(0 0 0 / 0.3);
  color: var(--on-silver);
}
.tee-time.gold {
  background: linear-gradient(128deg, #fff6da 0%, #fffdf5 32%, #f7e3a2 58%, #fff9e8 100%);
  box-shadow:
    inset 0 0 0 1.5px rgb(201 154 18 / 0.55),
    0 1px 1px rgb(0 0 0 / 0.22),
    0 10px 20px -10px rgb(0 0 0 / 0.6);
}
.tee-time.gold .tee-time-tag {
  background: var(--gold-sheen);
  box-shadow: 0 1px 2px rgb(0 0 0 / 0.3);
  color: var(--on-gold);
}
/* Finishing after dark: the card pressed back into a well, its time quieter, as the day's legend says. */
.tee-time.late:not(.gold, .silver) {
  background: #e9ece6;
  box-shadow: inset 0 0 0 1px rgb(16 36 27 / 0.08);
}
.tee-time.late .time {
  color: var(--paper-fg-muted);
}
/* The end of a day's rail: the rest of the day, behind a lit green arrow, on the felt. */
.tee-time.more {
  align-content: center;
  justify-items: center;
  gap: 2px;
  background: rgb(255 255 255 / 0.07);
  box-shadow: none;
  color: var(--on-felt);
  text-align: center;
  text-decoration: none;
}
.more-arrow {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--action-on-felt);
  color: #03170d;
}
.more-arrow .icon {
  width: 18px;
  height: 18px;
}
.more-count {
  font: 800 17px/20px var(--font-display);
}
.more-label {
  color: var(--on-felt-muted);
  font-size: 12px;
  font-weight: 650;
}

/* A course's tee times on a day: tiles at least 72 px wide, three or four to a row on a phone; six from 600 px (every
   screen size, below), so the twelve shown before "see more" fill whole rows at every width. */
.tee-times {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));
  gap: 8px;
  margin: 14px 0 4px;
}
/* Without a club to name, a tile stacks, centred: the time, the price, the places free in words (R3 lays the day out
   in A+; until then its tiles are the week's cards, a size smaller). */
.tee-times .tee-time {
  justify-items: center;
  gap: 6px;
  padding: 10px 4px 9px;
  text-align: center;
}
.tee-times .tee-time .time {
  font-size: 19px;
}
.tee-times .tee-time-foot {
  flex-direction: column;
  gap: 2px;
}
.tee-times .free-places {
  margin-left: 0;
}

/* ------------------------------------------------------------ a day */
/* A+ (R3, 16 Oct 2026; the owner: "make a perfect copy of the prototype"): the prototype's M9, its values ported as
   they are (ux/lanes/final/index.html: .d-top, .dstrip, .count-block, .grid, .more). On a phone the day starts under
   the status bar, as the prototype's does: the brand bar steps aside (its area and account wait on Horarios, the area
   also in the search field), the Cápsula+ stays. The felt is the prototype's alone: no sky's wash without a hero. */
@media (max-width: 959px) {
  #app:has(> #view[data-screen="day"]) {
    position: relative;
  }
  #app:has(> #view[data-screen="day"]) > .brand-bar {
    position: absolute;
    top: 0;
    right: 0;
    left: 0;
    height: 0;
    padding: 0;
  }
  #app:has(> #view[data-screen="day"]) > .brand-bar > :not(.capsule) {
    display: none;
  }
  #view[data-screen="day"] {
    padding-top: max(var(--safe-top), 8px);
  }
}
#app:has(> #view[data-screen="day"]) {
  background: none;
}
/* The day's gutter: the phone's 16 px, a tablet's 24; the header and the strip reach past it to the screen's edge. */
#view[data-screen="day"] {
  --day-gutter: var(--gutter);
  padding-inline: var(--day-gutter);
}
#view[data-screen="day"] .filter-bar {
  margin-inline: calc(-1 * var(--day-gutter));
}
#view[data-screen="day"] .filter-scroll {
  gap: 8px;
  padding-inline: var(--day-gutter);
  scroll-padding-inline: var(--day-gutter);
}
/* The header (the prototype's .d-top): back, the day's name with its month quieter, and its weather at the right. */
.back-header {
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: 52px;
  margin: 0 calc(-1 * var(--day-gutter, 16px));
  padding: 4px var(--day-gutter, 16px) 0 calc(var(--day-gutter, 16px) - 8px);
}
.day-back {
  display: grid;
  flex: none;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  color: var(--on-felt);
  transition: transform var(--duration-press) var(--spring-snap);
}
.day-back:active {
  transform: scale(0.96);
}
.day-back .icon {
  width: 22px;
  height: 22px;
  stroke-width: 1.75;
}
/* The day's area over its title (the prototype's caption: 12 px 800 capitals), which opens the area's sheet. Caption and
   title share the header's 52 px with room to spare. */
.day-heading {
  display: flex;
  flex: 1;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
  min-width: 0;
}
.day-area {
  position: relative;
  display: flex;
  max-width: 100%;
  padding: 0;
  border: 0;
  background: none;
  color: rgb(244 247 243 / 0.74);
  font: 800 12px/1 var(--font);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
}
.day-area span {
  overflow: hidden;
  text-overflow: ellipsis;
}
/* A 44 px tap, reaching above it and down over the title, which takes none. */
.day-area::after {
  content: "";
  position: absolute;
  inset: -16px 0;
}
.back-header .day-title {
  align-self: stretch;
  min-width: 0;
  margin: 0;
  color: var(--on-felt);
  font: 800 22px/1.35 var(--font);
  letter-spacing: -0.025em;
  text-wrap: nowrap;
}
/* A long name beside the weather on a narrow phone ("Wednesday 21 Oct" at 320 px) steps down until it fits (day-screen.ts
   measures it), rather than running under the weather. */
.back-header .day-title[data-tight] {
  font-size: 19px;
}
/* The month a step quieter (the prototype's 58 % chrome, at 64 % so it keeps 4.5:1 where the felt's glow is brightest). */
.day-title span {
  color: rgb(244 247 243 / 0.64);
  font-weight: 650;
}
.day-weather {
  margin: 0;
}
.day-weather .weather-mark {
  gap: 6px;
  color: rgb(244 247 243 / 0.74);
  font: 750 16px/1.35 var(--font);
}
.day-weather .weather-mark .icon {
  width: 22px;
  height: 22px;
  stroke-width: 1.75;
}

/* The count (the prototype's .count-block): the day's free tee times as the screen's one chrome numeral, fitted to what
   the words beside it leave (kit/numeral-fit.ts measures its ems), and those words at its foot, right-aligned. Its
   slot keeps the display size's height in every state, so the grid under it never moves. */
.day-count {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px;
  /* As tall as a three-figure count fitted to the row (the prototype's 124 px at 390, 98 at 320), in every state. */
  min-height: min(var(--text-display), calc((100vw - 2 * var(--day-gutter, 16px)) * 0.3464));
  margin-top: 10px;
  padding: 0 4px;
}
.day-count-slot {
  flex: 1;
  min-width: 0;
  align-self: stretch;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  container-type: inline-size;
}
.day-numeral {
  display: block;
  width: fit-content;
  height: 1em;
  /* The prototype's -6 px optical indent at the display size, as a share of the size so a fitted count keeps it. */
  margin-left: -0.048em;
  padding-right: 0.07em;
  font: 900 min(var(--text-display), calc(100cqi / var(--numeral-ems, 3) * 0.96)) / 1 var(--font-display);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.06em;
  white-space: nowrap;
  color: var(--chrome-shade);
  background: var(--chrome-face);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  transform-origin: 20% 80%;
}
/* It lands with a settle once, when the count first shows, as Horarios' does (day-screen.ts carries it across redraws). */
.day-numeral.settling {
  animation: numeral-settle var(--duration-land) var(--spring-bounce) both;
  animation-delay: var(--settle-delay, 0ms);
}
/* While the day is first read: the numeral's shape, pressed into the felt. */
.day-count-skeleton {
  display: block;
  width: min(200px, 100cqi);
  height: 96px;
  margin-bottom: 10px;
  border-radius: 22px;
  background: linear-gradient(90deg, rgb(255 255 255 / 0.07) 0%, rgb(255 255 255 / 0.15) 50%, rgb(255 255 255 / 0.07) 100%);
  background-size: 200% 100%;
  animation: shimmer 1.2s ease-in-out infinite;
}
/* Nothing to count: the words in the numeral's place, as a title. */
.day-count-words {
  margin: 0 0 14px;
  color: var(--on-felt);
  font: 800 24px/1.15 var(--font);
  letter-spacing: -0.02em;
  text-wrap: balance;
}
/* Beside it (the prototype's .count-side): what it counts in capitals (15 px there, as its spans are), the courses, and
   the lowest price on a silver pill. */
.count-side {
  display: flex;
  flex: none;
  flex-direction: column;
  align-items: flex-end;
  gap: 7px;
  padding-bottom: 14px;
  text-align: right;
}
.count-side > span {
  color: rgb(244 247 243 / 0.74);
  font: 650 15px/1.35 var(--font);
}
/* The first word is the day's refresh: no chrome of its own, a tap 44 px tall. */
.day-summary {
  position: relative;
  padding: 0;
  border: 0;
  background: none;
  color: rgb(244 247 243 / 0.74);
  font: 650 15px/1 var(--font);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  cursor: pointer;
}
.day-summary::after {
  content: "";
  position: absolute;
  inset: -14.5px -8px;
}
.day-summary[aria-disabled="true"] {
  cursor: default;
}
.count-side .count-from {
  padding: 4px 9px;
  border-radius: var(--radius-pill);
  background: var(--silver-sheen);
  color: #2a3a33;
  font: 800 13px/1.35 var(--font);
}

/* The tee times (the prototype's .grid): three to a row on a phone, 16 px between rows (room for a tile's tab) and 7 px
   across, each the week's tile with its club. Four from 600 px, six on a computer: twelve fill whole rows at every size. */
.day-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px 7px;
  padding-top: 22px;
}
.day-grid .tee-time {
  width: 100%;
}
.day-grid .tile-skeleton {
  height: 92.2px;
}
/* Under 360 px three tiles would be 91 px, too narrow for "125 € 4 libres" (the prototype's grid runs off a 320 px
   screen there): two to a row, 141 px each. */
@media (max-width: 359px) {
  .day-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (min-width: 600px) {
  .day-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 16px 8px;
  }
  .day-strip .day-pill {
    flex-basis: calc(100% / 12);
  }
}
/* A computer: the week's column (R2's desktop window: 1200 px, 44 px gutters, 132 px tiles), so opening a day moves
   nothing sideways; eight tiles to a row (sixteen before "Ver las N"), the filters on one row, and the count's words
   beside their numeral rather than across the window. */
@media (min-width: 960px) {
  #view[data-screen="day"] {
    --day-gutter: 44px;
    max-width: 1200px;
  }
  .day-grid {
    grid-template-columns: repeat(8, minmax(0, 1fr));
  }
  .day-strip .day-pill {
    flex-basis: calc(100% / 15);
  }
  .day-count {
    justify-content: flex-start;
    column-gap: 32px;
  }
  .day-count-slot {
    flex: 0 1 auto;
    container-type: normal;
  }
  /* Room past its last figure for the settle's overshoot, inside its own slot. */
  .day-numeral {
    margin-right: 0.05em;
    font-size: var(--text-display);
  }
  .count-side {
    align-items: flex-start;
    text-align: left;
  }
}
/* "Ver las 410": the rest of the day, on a well of light under the grid. */
.day-see-all {
  display: flex;
  align-items: center;
  gap: 4px;
  min-height: 44px;
  margin: 18px auto 0;
  padding: 0 18px;
  border: 0;
  border-radius: var(--radius-pill);
  background: rgb(255 255 255 / 0.08);
  color: var(--on-felt);
  font: 800 15px/1.35 var(--font);
  cursor: pointer;
  transition: transform var(--duration-press) var(--spring-snap);
}
.day-see-all:active {
  transform: scale(0.96);
}
.day-see-all .icon {
  width: 16px;
  height: 16px;
}
/* The filters lie on the felt until they stick at the top; then they take their felt glass (day-screen.ts marks it). */
#view[data-screen="day"] .filter-bar:not([data-stuck])::before {
  opacity: 0;
}
/* Under the dates, before what they count (the design QA of R3): date, filters, the count, its tee times. The count
   then sits on its grid exactly as the prototype's does. */
#view[data-screen="day"] .day-strip + .filters-from + .filter-bar {
  margin-top: -2px;
  margin-bottom: 6px;
}
.info-line {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin: 6px 0 10px;
  padding: 10px 12px;
  border: 1px solid var(--stroke);
  border-radius: var(--radius-block);
  background: var(--bg-1);
  font-size: 13px;
  line-height: 18px;
  color: var(--fg-2);
}
.info-line .icon {
  width: 18px;
  height: 18px;
  color: var(--fg-muted);
}
.info-line.concern {
  border-color: transparent;
  background: var(--warn-tint);
  color: var(--warn);
}
.info-line.concern .icon {
  color: currentColor;
}
/* A day's conditions, folded to one line: the weather in brief (a warning in its colour) and sunset, with a caret. Unfolded,
   the full forecast, what it means for a round, and the day's light from sunrise to sunset. */
.conditions {
  margin: 6px 0 4px;
  border: 1px solid var(--stroke);
  border-radius: var(--radius-card);
  background: var(--bg-1);
  box-shadow: var(--elevation-1);
}
.conditions-toggle {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: 48px;
  padding: 10px 14px 10px 16px;
  border: 0;
  border-radius: inherit;
  background: none;
  color: var(--fg-2);
  font: 500 14px/20px var(--font);
  text-align: left;
  cursor: pointer;
}
.conditions-toggle .sky {
  display: grid;
  flex: none;
  place-items: center;
  font-size: 20px;
  line-height: 20px;
  color: var(--fg-muted);
}
.conditions-toggle .sky .icon {
  width: 20px;
  height: 20px;
}
.conditions-brief {
  flex: 1;
  min-width: 0;
}
.conditions-brief b {
  font-weight: 700;
  color: var(--warn);
}
.conditions-sunset {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: 4px;
  font-size: 13px;
  font-weight: 600;
  color: var(--fg-muted);
}
.conditions-sunset .icon {
  width: 17px;
  height: 17px;
}
.conditions-caret {
  flex: none;
  width: 18px;
  height: 18px;
  color: var(--fg-muted);
  transition: transform 0.2s var(--ease);
}
.conditions.open .conditions-caret {
  transform: rotate(180deg);
}
.conditions-detail {
  padding: 0 16px 12px;
}
.conditions-weather {
  margin: 0;
  font-size: 13px;
  line-height: 18px;
  color: var(--fg-2);
}
.conditions-hint {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin: 8px 0 0;
  padding: 8px 10px;
  border-radius: var(--radius-tile);
  background: var(--bg-2);
  font-size: 13px;
  line-height: 18px;
  color: var(--fg-2);
}
.conditions-hint .icon {
  width: 17px;
  height: 17px;
  color: var(--fg-muted);
}
.daylight-track {
  position: relative;
  height: 10px;
  margin: 30px 2px 8px;
  border-radius: var(--radius-pill);
  background: linear-gradient(90deg, #f4dca2 0%, #e2f1e7 16%, #cfe8da 50%, #e2f1e7 84%, #f1c9a3 100%);
}
/* The last start that still finishes before dark: a flag on its pin, the holes on the pennant. */
.daylight-flag {
  position: absolute;
  bottom: 5px;
  left: var(--at);
  width: 2px;
  height: 26px;
  border-radius: 1px;
  background: var(--fg);
}
.daylight-flag b {
  position: absolute;
  top: 0;
  left: 2px;
  padding: 1px 5px 1px 4px;
  border-radius: 0 4px 4px 0;
  background: var(--action);
  color: var(--on-ink);
  font-size: 10px;
  font-weight: 800;
  line-height: 13px;
}
.daylight-now {
  position: absolute;
  top: 50%;
  left: var(--at);
  width: 14px;
  height: 14px;
  border: 3px solid var(--bg-1);
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 1px 3px rgb(16 36 27 / 0.3);
  transform: translate(-50%, -50%);
}
.daylight-ends {
  display: flex;
  justify-content: space-between;
  margin: 0;
  font-size: 12px;
  font-weight: 600;
  color: var(--fg-muted);
}
.daylight-ends > span {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.daylight-ends .icon {
  width: 16px;
  height: 16px;
}
.daylight-note {
  margin: 6px 0 0;
  font-size: 13px;
  line-height: 18px;
  color: var(--fg-2);
}

/* The days ahead (the prototype's .dstrip): the weekday in capitals over the number, the chosen one ink on a chrome
   disc; nine to a phone's width, the rest a scroll away. The month is in the title above, so the strip says it only to
   a screen reader. */
.day-strip {
  display: flex;
  margin: 0 calc(-1 * var(--day-gutter, 16px));
  padding: 6px calc(var(--day-gutter, 16px) - 8px) 4px;
  overflow-x: auto;
  scroll-padding-inline: 8px;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
}
.day-strip::-webkit-scrollbar {
  display: none;
}
/* Relative, so the month read to screen readers stays inside the strip it scrolls in, not past the page's edge. */
.day-pill {
  position: relative;
  display: flex;
  flex: 0 0 calc(100% / 9);
  flex-direction: column;
  align-items: center;
  gap: 6px;
  min-height: 62px;
  color: var(--on-felt);
  text-decoration: none;
  scroll-snap-align: end;
}
/* The weekday at the prototype's 58 % chrome, at 64 % so 10.5 px capitals keep 4.5:1 under the felt's glow. */
.day-pill .weekday {
  color: rgb(244 247 243 / 0.64);
  font: 800 10.5px/1.35 var(--font);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.day-pill .day {
  position: relative;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  margin: 3px 0;
  border-radius: 50%;
  font: 780 15px/1.35 var(--font);
  transition:
    background var(--duration-quick) var(--ease),
    color var(--duration-quick) var(--ease);
}
.day-pill[aria-current="date"] .day {
  background: var(--on-felt);
  color: var(--paper-ink);
}
.day-pill[aria-current="date"] .weekday {
  color: var(--on-felt);
}
/* Cards: white on the ground with a hairline; a list card splits its rows with hairlines. */
.card {
  border: 1px solid var(--stroke);
  border-radius: var(--radius-card);
  background: var(--bg-1);
  box-shadow: var(--elevation-1);
}
.card.padded {
  padding: 16px;
}
/* Campos' "about": what the app does and doesn't, each led by its label in ink. */
.about b {
  color: var(--fg);
}
/* Clip, not hidden, where the browser can: it rounds the rows' corners the same way without becoming the scroller
   that the hour headings would stick to (they would never stick). */
.card.list {
  overflow: hidden;
  overflow: clip;
}
.card.list > * + * {
  border-top: 1px solid var(--stroke);
}
.stack > * + * {
  margin-top: 12px;
}
/* A course on the day: its mark, its name over how far it is (and a note when one sets it apart), its lowest price; then
   its tee times. */
.course-block {
  padding: 14px 14px 10px;
}
.course-head {
  display: flex;
  align-items: center;
  gap: 12px;
}
.course-head .name {
  display: block;
  font-size: 16px;
  font-weight: 700;
  line-height: 21px;
}
.course-head .meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 2px 10px;
  margin-top: 2px;
  font-size: 13px;
  line-height: 18px;
  color: var(--fg-muted);
}
.course-head .meta .buggy.included {
  color: var(--action-strong);
  font-weight: 600;
}
.from-price {
  display: flex;
  flex: none;
  flex-direction: column;
  align-items: flex-end;
  padding: 6px 10px;
  border-radius: var(--radius-tile);
  background: var(--action-tint);
  color: var(--action-strong);
  line-height: 1.1;
}
.from-price small {
  font-size: 11px;
  font-weight: 600;
}
.from-price b {
  font-size: 17px;
}
.course-name-button {
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.show-more {
  margin-top: 2px;
}
.show-more .icon {
  width: 16px;
  height: 16px;
}
/* Why a course shows nothing, in one line, with what can be done about it. */
.state-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 10px;
  margin-top: 12px;
  padding: 10px 12px;
  border-radius: var(--radius-block);
  background: var(--bg-2);
  font-size: 14px;
  line-height: 19px;
  color: var(--fg-muted);
}
.state-text {
  display: inline-flex;
  align-items: flex-start;
  gap: 8px;
}
.state-text .icon {
  width: 18px;
  height: 18px;
}
.status {
  font-weight: 600;
}
.status.down {
  color: var(--danger);
}
.course-block.quiet {
  box-shadow: none;
}
.legend {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 12px 0 0;
}
.legend .icon {
  width: 16px;
  height: 16px;
}
/* ------------------------------------------------------------ weather */
/* A forecast badge: symbol, top temperature, rain chance when it matters. */
.weather {
  display: inline-flex;
  flex: none;
  align-items: baseline;
  gap: 3px;
  font-size: 14px;
  font-weight: 600;
  color: var(--fg-muted);
  white-space: nowrap;
}
.weather small {
  font-size: 12px;
}
.weather.concern {
  color: var(--warn);
}
/* A+'s forecast mark (presentation/weather.ts, weatherMark): the sky as a line glyph and the top temperature, sized by
   where it sits (a day's heading, the hero), in the words' own colour. */
.weather-mark {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: 4px;
  white-space: nowrap;
}
.weather-mark .icon.sky {
  stroke-width: 1.75;
}
/* A day to watch out for keeps the words' colour, as the prototype draws every sky: the warning is in its name. */
.weather-mark.concern .icon {
  color: inherit;
}
/* Four equal days, however long one day's figures are: on a narrow phone the rain chance drops to its own line. */
.forecast-row {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px;
  margin: 8px 0;
}
.forecast-day {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 10px 4px;
  border-radius: var(--radius-block);
  background: var(--bg-2);
}
.forecast-day .weather {
  flex-wrap: wrap;
  justify-content: center;
}

/* ------------------------------------------------------------ booking */
/* A tee time's sheet (A+, R3; the prototype's M9 sheet, its values ported as they are: .sheet, .sh-photo, .sh-club,
   .sh-when, .sh-time, .facts, .dl, .sh-party, .sh-acts, .sh-foot). On the tray's paper, 36 px corners, the photos
   172 px tall under them, with no grabber (a swipe down still closes it). */
/* Every figure one width, as on the prototype's screen ("1/4", the facts, the total). */
.sheet:is(.booking-sheet, .invitation-sheet),
.sheet:is(.booking-sheet, .invitation-sheet) * {
  font-variant-numeric: tabular-nums;
}
.sheet.booking-sheet {
  --tray: #f6f6f1;
  padding: 0;
  border-radius: 36px 36px 0 0;
  background: var(--tray);
  box-shadow: 0 -10px 40px rgb(0 0 0 / 0.35);
}
/* On a phone it slides up on the glide spring, 380 ms (a computer's dialog keeps its own fade). */
@media (max-width: 959px), (max-height: 619px) {
  .sheet.booking-sheet {
    transition: transform 380ms var(--spring-glide);
  }
  .sheet.invitation-sheet {
    transition: transform 420ms var(--spring-glide);
  }
}
@media (min-width: 960px) and (min-height: 620px) {
  .sheet.booking-sheet,
  .sheet.invitation-sheet {
    border-radius: 36px;
  }
}
.booking-sheet .sheet-body {
  padding-bottom: 0;
}
.booking-sheet .grabber {
  display: none;
}
.sheet.booking-sheet .sheet-close {
  top: 12px;
  right: 12px;
  width: 44px;
  height: 44px;
  background: rgb(0 0 0 / 0.38);
  color: #ffffff;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.sheet.booking-sheet .sheet-close .icon {
  width: 22px;
  height: 22px;
  stroke-width: 1.75;
}
.photo-header.booking {
  margin: 0;
}
.photo-header.booking::before,
.photo-header.booking::after {
  content: none;
}
.photo-header.booking .photo-strip {
  height: 172px;
}
/* "1/4" on a dark pill (the prototype's .sh-count); a lone photo keeps its icon on a disc. */
.photo-header.booking .photo-count:has([data-photo-at]) {
  right: 14px;
  height: auto;
  padding: 4px 9px;
  background: rgb(0 0 0 / 0.45);
  font: 750 12px/1.35 var(--font);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
.photo-header.booking .photo-count:has([data-photo-at]) .icon {
  display: none;
}
.booking-main {
  padding: 0 20px 8px;
}
/* The club: its ball on the photos' lower edge (58 px, ringed in its colour and in the tray), its name beside it. */
.booking-club {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: flex-start;
  gap: 14px;
  margin-top: 14px;
}
.booking-club.on-photos {
  margin-top: -28px;
  /* It overlaps the photos' lower edge: taps there still reach the photos and their count. */
  pointer-events: none;
}
.booking-club .club-ball {
  width: 58px;
  height: 58px;
  box-shadow:
    0 0 0 2.5px var(--course, #cfd6d1),
    0 0 0 6px var(--tray),
    0 6px 14px rgb(0 0 0 / 0.25);
}
.booking-club .grow {
  display: flex;
  flex-direction: column;
  min-width: 0;
  padding-top: 36px;
}
.booking-club:not(.on-photos) .grow {
  padding-top: 8px;
}
.booking-club b {
  font: 800 19px/1.1 var(--font);
  letter-spacing: -0.02em;
}
.booking-club small {
  margin: 2px 0 1px;
  color: var(--paper-fg-muted);
  font: 550 14px/1.35 var(--font);
}
/* The day in capitals, its weather at the right (15 px, as the prototype's spans are). */
.booking-when {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  /* The weather's 22 px line, with or without a forecast, so the time below keeps its place. */
  min-height: 22px;
  margin-top: 20px;
}
.booking-date {
  color: var(--paper-fg-muted);
  font: 750 15px/1 var(--font);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  white-space: nowrap;
}
.booking-weather {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-width: 0;
  color: var(--paper-fg);
  font: 750 15px/1.35 var(--font);
  white-space: nowrap;
}
.booking-weather .icon {
  width: 22px;
  height: 22px;
  stroke-width: 1.75;
}
.booking-weather > span[aria-hidden] {
  overflow: hidden;
  text-overflow: ellipsis;
}
.booking-weather.concern {
  color: var(--paper-warn);
}
/* The time: the sheet's one numeral, ink, fitted to the sheet's width (kit/numeral-fit.ts). */
.sheet .booking-title {
  margin: 6px 0 0;
  container-type: inline-size;
}
.booking-time {
  display: block;
  width: fit-content;
  /* The prototype's -4 px optical indent at 100 px. */
  margin-left: -0.04em;
  padding-right: 0.07em;
  color: var(--paper-fg);
  font: 900 min(100px, calc(100cqi / var(--numeral-ems, 3) * 0.95)) / 0.85 var(--font-display);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.06em;
  white-space: nowrap;
  transform-origin: 0 80%;
}
/* The facts in a well: the price per player, the places free in green, the holes. */
.booking-facts {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  margin: 18px 0 0;
  padding: 13px 0;
  border-radius: 20px;
  background: #e9ece6;
}
.booking-facts > div {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}
.booking-facts > div + div {
  box-shadow: -1px 0 0 rgb(16 36 27 / 0.07);
}
.booking-facts dd {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  margin: 0;
  padding: 0 4px;
  text-align: center;
}
.booking-facts b {
  font: 820 19px/1.1 var(--font);
  letter-spacing: -0.02em;
}
.booking-facts .free {
  color: var(--paper-action);
}
.booking-facts dd span {
  color: var(--paper-fg-muted);
  font: 600 12.5px/1.35 var(--font);
}
/* The day's light (only where the round may end near or after sunset): sunrise's blue to sunset's orange, the dark
   striped after sunset, the round outlined in ink over it. */
.booking-light {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 16px;
}
.light-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.light-head span {
  color: var(--paper-fg-muted);
  font: 800 12px/1 var(--font);
  letter-spacing: 0.09em;
  text-transform: uppercase;
}
.light-head b {
  font: 780 14px/1.35 var(--font);
}
.light-bar {
  position: relative;
  height: 14px;
  overflow: hidden;
  border-radius: 7px;
  background: linear-gradient(90deg, #eaf2f7 0%, #f3ebd3 45%, #f6d3a0 75%, #e8946a 100%);
}
.light-bar i {
  position: absolute;
  top: 0;
  bottom: 0;
}
.light-dark {
  right: 0;
  background: repeating-linear-gradient(135deg, #29384f 0 4px, #3a4b66 4px 8px);
}
.light-set {
  width: 2px;
  margin-left: -1px;
  background: #e8946a;
}
.light-bar .light-round {
  top: 2px;
  bottom: 2px;
  border-radius: 5px;
  box-shadow: inset 0 0 0 2px var(--paper-fg);
}
.light-axis {
  position: relative;
  height: 14px;
  color: var(--paper-fg-muted);
  font: 700 12px/1.35 var(--font);
}
.light-axis span {
  position: absolute;
  top: 0;
  white-space: nowrap;
}
.light-axis .light-length {
  transform: translateX(52px);
}
/* The players: those already in as grey balls, the group as rings in a mint capsule, white balls once in. */
.booking-party {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-top: 14px;
}
.party-words {
  display: flex;
  flex-direction: column;
  min-width: 0;
  color: var(--paper-fg-muted);
}
.party-title {
  font: 800 12px/1 var(--font);
  letter-spacing: 0.09em;
  text-transform: uppercase;
}
.party-words small {
  margin-top: 5px;
  font: 600 12.5px/1 var(--font);
}
.party-words small + small {
  line-height: 1.35;
}
.party-spots {
  display: flex;
  flex: none;
  align-items: center;
  gap: 2px;
}
.spot-taken,
.spot {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
}
.spot-taken i {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: radial-gradient(circle at 34% 30%, #e3e8e5, #c3ccc7 70%, #aeb9b3);
}
.spot-group {
  display: flex;
  padding: 0 1px;
  border-radius: var(--radius-pill);
  background: #d9f0e2;
}
.spot {
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.spot i {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  box-shadow: inset 0 0 0 2.5px var(--paper-action);
  color: var(--paper-fg);
  font: normal 850 12px/1 var(--font);
  transition: transform var(--duration-press) var(--spring-snap);
}
.spot.on i {
  background: radial-gradient(circle at 34% 30%, #ffffff, #eef2ef 62%, #cad4ce);
  box-shadow:
    0 0 0 1.5px rgb(16 36 27 / 0.14),
    0 3px 6px rgb(0 0 0 / 0.22);
}
.spot:active i {
  transform: scale(0.86);
}
.spot[aria-disabled="true"] {
  cursor: default;
}
.spot[aria-disabled="true"] i {
  box-shadow: inset 0 0 0 2.5px rgb(18 122 82 / 0.35);
}
/* Gone: the group's rings and balls quiet, choosing nothing. */
.party-spots.gone .spot-group {
  background: #e9ece6;
}
.party-spots.gone .spot i {
  background: none;
  box-shadow: inset 0 0 0 2.5px rgb(16 36 27 / 0.18);
  color: var(--paper-fg-muted);
}
/* The way there and the invitation, as words beside their icons; the proposal a round tool after them. */
.booking-acts {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 4px;
}
.booking-act {
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding: 0 14px 0 10px;
  border: 0;
  border-radius: var(--radius-pill);
  background: none;
  color: var(--paper-fg-2);
  font: 700 14px/1.35 var(--font);
  text-decoration: none;
  cursor: pointer;
  transition: transform var(--duration-press) var(--spring-snap);
}
.booking-act:active,
.booking-propose:active {
  transform: scale(0.96);
}
.booking-act .icon,
.booking-propose .icon {
  width: 20px;
  height: 20px;
  stroke-width: 1.75;
  color: var(--paper-action);
}
.booking-propose {
  display: grid;
  flex: none;
  place-items: center;
  width: 44px;
  height: 44px;
  margin-left: auto;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  cursor: pointer;
  transition: transform var(--duration-press) var(--spring-snap);
}
.booking-propose[aria-pressed="true"] {
  background: #d9f0e2;
}
/* How fresh the reading is, and checking it again: one quiet line. */
.booking-check {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 6px 0 0;
  color: var(--paper-fg-muted);
  font: 500 13px/17.5px var(--font);
}
.booking-check > span {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.booking-check .icon {
  width: 16px;
  height: 16px;
}
/* Drawn on the line's 18 px; its tap reaches 44 px tall through a transparent ::after, as the app's small controls do. */
/* "Comprobar" in ink-2, not the action's green, which is the footer's. */
.check-now {
  position: relative;
  flex: none;
  margin-left: auto;
  padding: 0 4px;
  border: 0;
  background: none;
  color: var(--paper-fg-2);
  font: 600 13px/17.5px var(--font);
  cursor: pointer;
}
.check-now::after {
  content: "";
  position: absolute;
  inset: -13.25px 0;
}
.booking-fine {
  margin: 6px 0 0;
  color: var(--paper-fg-muted);
  font: 500 12px/1.4 var(--font);
}
/* The total beside the club's page, pinned (the prototype's .sh-foot). */
.booking-sheet .sheet-footer {
  margin: 8px -20px -8px;
  padding: 12px 16px max(32px, calc(12px + var(--safe-bottom))) 22px;
  border-top: 0;
  background: rgb(246 246 241 / 0.96);
  box-shadow: 0 -1px 0 rgb(16 36 27 / 0.07);
}
.booking-sheet .footer-total {
  gap: 3px;
  line-height: 1;
}
.booking-sheet .footer-total small {
  color: var(--paper-fg-muted);
  font: 800 11px/1 var(--font);
  letter-spacing: 0.09em;
  text-transform: uppercase;
}
.booking-sheet .footer-total b {
  font: 850 26px/1 var(--font);
  letter-spacing: -0.03em;
}
.book {
  display: inline-flex;
  flex: 1;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 56px;
  padding: 0 16px;
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--paper-action);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.25),
    0 10px 22px -12px rgb(18 122 82 / 0.9);
  color: #ffffff;
  font: 800 15.5px/1.35 var(--font);
  letter-spacing: -0.01em;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: transform var(--duration-press) var(--spring-snap);
}
.book:active {
  transform: scale(0.97);
}
.book .icon {
  width: 18px;
  height: 18px;
  stroke-width: 1.75;
}
.book.soft {
  background: #e9ece6;
  box-shadow: none;
  color: var(--paper-fg);
}
/* Under 360 px the prototype's row and footer would wrap ("Cómo / llegar", the button's words on two lines): the acts
   close up, and the footer's total and button step down a size, so each keeps one line. */
@media (max-width: 359px) {
  .booking-acts {
    gap: 2px;
  }
  .booking-act {
    gap: 6px;
    padding: 0 8px 0 6px;
  }
  .booking-sheet .footer-bar {
    gap: 10px;
  }
  .booking-sheet .footer-total b {
    font-size: 22px;
  }
  .booking-sheet .book {
    gap: 4px;
    padding: 0 8px;
    font-size: 14px;
  }
  .booking-sheet .book .icon {
    width: 14px;
    height: 14px;
  }
}
/* The invitation (A+, the prototype's poster, .pwrap): the card the friend is sent, its one step under it, then the
   way back. The sheet's grabber, no ✕ ("Volver" is the way out, as Escape, the scrim and a swipe down are). */
.sheet.invitation-sheet {
  padding: 14px 16px 0;
  border-radius: 36px 36px 0 0;
  background: #f6f6f1;
  box-shadow: 0 -10px 40px rgb(0 0 0 / 0.35);
}
.invitation-sheet .sheet-top {
  height: 5px;
  margin-bottom: 12px;
}
.invitation-sheet .grabber {
  margin: 0 auto;
  background: rgb(16 36 27 / 0.18);
}
.invitation-sheet .sheet-close {
  display: none;
}
.invitation-sheet .sheet-body {
  padding-bottom: calc(30px + var(--safe-bottom));
}
/* A computer's dialog: round at every corner, as the tee time's (this rule comes after the shape above). */
@media (min-width: 960px) and (min-height: 620px) {
  .sheet.invitation-sheet {
    border-radius: 36px;
  }
}
.invitation {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
}
.poster {
  position: relative;
  width: 100%;
  height: 470px;
  overflow: hidden;
  border-radius: 30px;
  background: var(--felt-deep);
  box-shadow: 0 22px 40px -22px rgb(0 0 0 / 0.7);
  color: #ffffff;
}
.poster img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.poster-shade {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    180deg,
    rgb(3 18 11 / 0.4) 0%,
    rgb(3 18 11 / 0) 26%,
    rgb(4 30 20 / 0.35) 48%,
    rgb(6 36 24 / 0.94) 78%,
    var(--felt-deep)
  );
}
.poster-club {
  position: absolute;
  top: 16px;
  left: 16px;
  display: flex;
  align-items: center;
  gap: 10px;
  font: 800 16px/1.35 var(--font);
  text-shadow: 0 1px 6px rgb(0 0 0 / 0.5);
}
.poster-club .club-ball {
  width: 38px;
  height: 38px;
}
.poster-main {
  position: absolute;
  right: 20px;
  bottom: 22px;
  left: 20px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  container-type: inline-size;
}
/* The time in chrome, fitted to the card (5 % kept for the beat it lands with), its soft shadow under it. */
.poster-time {
  display: block;
  width: fit-content;
  margin-left: -0.045em;
  padding-right: 0.07em;
  color: var(--chrome-shade);
  background: var(--chrome-face);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  font: 900 min(112px, calc(100cqi / var(--numeral-ems, 3) * 0.95)) / 0.84 var(--font-display);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.06em;
  white-space: nowrap;
  filter: drop-shadow(0 4px 18px rgb(0 0 0 / 0.35));
  transform-origin: 0 80%;
}
.poster-when {
  color: rgb(244 247 243 / 0.74);
  font: 700 16px/1.35 var(--font);
}
/* 44 px whatever it holds, so the time above never moves with the group (rings or none). */
.poster-spots {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  margin-top: 6px;
}
.poster-spots i {
  display: grid;
  flex: none;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  font-style: normal;
}
.poster-spots .spot-taken {
  background: radial-gradient(circle at 34% 30%, rgb(255 255 255 / 0.55), rgb(255 255 255 / 0.3));
}
.poster-spots .spot-in {
  position: relative;
  background: radial-gradient(circle at 50% 50%, #ffffff 0 55%, #eef1ee 100%);
  box-shadow:
    0 0 0 1.5px #ffffff,
    0 2px 5px rgb(0 0 0 / 0.28);
  color: var(--paper-fg);
  font: 850 14.3px/1 var(--font);
}
.spot-left {
  display: flex;
  gap: 8px;
  padding: 5px;
  border-radius: var(--radius-pill);
  background: rgb(59 201 131 / 0.22);
}
.spot-left i {
  box-shadow: inset 0 0 0 2.5px var(--action-on-felt-strong);
}
.poster-spots b {
  margin-left: 6px;
  color: var(--action-on-felt-strong);
  font: 850 22px/1.35 var(--font);
  letter-spacing: -0.02em;
}
.invitation .book {
  flex: none;
  width: 100%;
}
.invitation-back {
  min-height: 44px;
  padding: 0 20px;
  border: 0;
  border-radius: var(--radius-pill);
  background: #e9ece6;
  color: var(--paper-fg);
  font: 750 15px/1.35 var(--font);
  cursor: pointer;
}
.invitation .booking-fine {
  margin: 0;
  font: 550 13px/1.35 var(--font);
}
/* It arrives as the prototype's does: the card lands tilted and settles, the time beats once, the rings to fill pop in. */
.invitation-sheet.open .poster {
  animation: poster-land 650ms var(--spring-bounce) 120ms backwards;
}
.poster-time.settling {
  animation: numeral-beat 360ms ease-out 220ms;
}
.invitation-sheet.open .spot-left i {
  animation: ring-in 520ms var(--spring-bounce) calc(420ms + var(--at, 0) * 90ms) backwards;
}
@keyframes poster-land {
  from {
    transform: scale(0.9) rotate(-2deg);
  }
}
@keyframes numeral-beat {
  30% {
    transform: scale(1.045);
    filter: drop-shadow(0 4px 18px rgb(0 0 0 / 0.35)) brightness(1.22);
  }
}
@keyframes ring-in {
  from {
    opacity: 0;
    transform: scale(0.3);
  }
}
.check-result {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 8px;
  padding: 13px 14px;
  border-radius: var(--radius-block);
  font-weight: 700;
  animation: rise 0.28s var(--ease-out) both;
}
.check-result.ok {
  background: var(--action-tint);
  color: var(--action-strong);
}
.check-result.gone {
  background: var(--danger-tint);
  color: var(--danger);
}
.check-result.unknown {
  background: var(--warn-tint);
  color: var(--warn);
}
.hand-off {
  margin-top: 10px;
  padding: 12px 14px;
  border: 1px dashed var(--stroke-strong);
  border-radius: var(--radius-block);
  background: var(--bg-2);
  font-size: 14px;
  line-height: 20px;
}
.hand-off-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 10px;
}

/* ============================================================ R6a: Torneos and Campos (A+) */
/* The prototype's two other panes (ux/lanes/final, .pn-head, .trow, .ccard), their values ported as they are. Both
   screens open with the same head: the area in capitals over the title, and the pane's count as its chrome numeral at
   the right, fitted to the room the words leave (kit/numeral-fit.ts) and settling once as it first shows. */
.pane-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 4px 18px;
}
/* The words keep their width and the numeral yields (the prototype's rule), down to a third of the row: a long kicker
   ("Costa del Sol · actualizado hace 3 h") wraps rather than squeezing the count to nothing at 320 px. */
.pane-head-words {
  flex: 0 1 auto;
  min-width: 0;
}
/* The prototype's kicker is a <p> at 12 px with its 1 em margins (12 px over and under, the title's 8 collapsing into
   them): the words stand 70 px tall, so the title sits 44 px under the head's top. A 1.2 line, for a kicker that wraps,
   takes its 2.4 px out of those margins. */
.pane-kicker {
  margin: 10.8px 0;
  color: var(--chrome-2);
  font: 800 12px/1.2 var(--font);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  text-wrap: balance;
}
/* The area, as a button in the kicker's own type, its tap 44 px tall (reaching up, and down over the title, which takes
   none), as a day's area is. */
.pane-area {
  position: relative;
  display: inline-block;
  max-width: 100%;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-align: left;
  text-transform: inherit;
  cursor: pointer;
}
.pane-area::after {
  content: "";
  position: absolute;
  inset: -16px 0;
}
.pane-title {
  margin: 8px 0 0;
  color: var(--on-felt);
  font: 820 34px/1 var(--font);
  letter-spacing: -0.035em;
}
.pane-count-slot {
  display: flex;
  flex: 1 0 30%;
  align-items: flex-end;
  justify-content: flex-end;
  align-self: stretch;
  min-width: 0;
  container-type: inline-size;
}
/* 76 px where it fits, less 5 % for the settle (which grows leftward, from the right edge it is pinned to). */
.pane-count {
  display: block;
  width: fit-content;
  padding-right: 0.07em;
  font: 900 min(76px, calc(100cqi / var(--numeral-ems, 3) * 0.95)) / 0.85 var(--font-display);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.06em;
  white-space: nowrap;
  color: var(--chrome-shade);
  background: var(--chrome-face);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  transform-origin: 100% 80%;
}
.pane-count.settling {
  animation: numeral-settle var(--duration-land) var(--spring-bounce) both;
}
/* While the list is first read: the numeral's shape, pressed into the felt. */
.pane-count-skeleton {
  display: block;
  width: min(72px, 100cqi);
  height: 58px;
  border-radius: 18px;
  background: linear-gradient(90deg, rgb(255 255 255 / 0.07) 0%, rgb(255 255 255 / 0.15) 50%, rgb(255 255 255 / 0.07) 100%);
  background-size: 200% 100%;
  animation: shimmer 1.2s ease-in-out infinite;
}
.pane-note {
  margin: 16px 4px 0;
  color: var(--on-felt-muted);
  font: 550 13px/1.4 var(--font);
}

/* On a phone the panes start under the status bar, as the prototype's do (.pn-scroll): the brand bar steps aside as on
   a day (R3), its area in the search field's chip (ES | EN at the top of the area sheet) and the account on Horarios;
   the Cápsula+ stays. A swipe's view of a pane lands as the pane will. The felt is the prototype's alone: no sky. */
@media (max-width: 959px) {
  #app:has(> #view:is([data-screen="tournaments"], [data-screen="courses"])) {
    position: relative;
  }
  #app:has(> #view:is([data-screen="tournaments"], [data-screen="courses"])) > .brand-bar {
    position: absolute;
    top: 0;
    right: 0;
    left: 0;
    height: 0;
    padding: 0;
  }
  #app:has(> #view:is([data-screen="tournaments"], [data-screen="courses"])) > .brand-bar > :not(.capsule),
  .swipe-preview-page:has(> .preview-view:is([data-screen="tournaments"], [data-screen="courses"])) > .brand-bar {
    display: none;
  }
  /* The prototype's .pn-scroll: 58 px under a 50 px status bar. */
  :is(#view, .preview-view):is([data-screen="tournaments"], [data-screen="courses"]) {
    padding-top: calc(var(--safe-top) + 8px);
  }
}
#app:has(> #view:is([data-screen="tournaments"], [data-screen="courses"])) {
  background: none;
}

/* ------------------------------------------------------------ tournaments */
/* Each tournament a row of card stock (the prototype's .trow): its day as a leaf of felt, its name over the club's ball
   and the format, the fee at the right. A new one is gold with its ribbon, as a new tee time is. Under it, the
   registration as a tinted strip with its one action and the calendar or the tournament's page (the prototype's example
   rows have no registration to show; it is what a golfer comes to Torneos for). */

.pane-month {
  margin: 24px 4px 12px;
  color: var(--chrome-2);
  font: 800 12px/1 var(--font);
  letter-spacing: 0.09em;
  text-transform: uppercase;
}
.spaced {
  margin-bottom: 10px;
}
.card.tournament {
  position: relative;
  border: 0;
  border-radius: 20px;
  background: var(--card);
  box-shadow:
    inset 0 1px 0 #ffffff,
    0 10px 20px -10px rgb(0 0 0 / 0.6);
}
.card.tournament.new {
  background: linear-gradient(128deg, #fff6da 0%, #fffdf5 32%, #f7e3a2 58%, #fff9e8 100%);
  box-shadow:
    inset 0 0 0 1.5px rgb(201 154 18 / 0.55),
    0 10px 20px -10px rgb(0 0 0 / 0.6);
}
.tournament-ribbon {
  position: absolute;
  z-index: 3;
  top: -8px;
  right: 14px;
  padding: 3px 7px;
  border-radius: var(--radius-pill);
  background: var(--gold-sheen);
  box-shadow: 0 1px 2px rgb(0 0 0 / 0.3);
  color: var(--on-gold);
  font: 850 9.5px/1.1 var(--font);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  pointer-events: none;
}
.tournament-body {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 16px 12px 12px;
}
/* The prototype's 54 × 58 leaf, with the weekday over the day (a golfer plans by it; the example data had none). */
.date-tile {
  display: flex;
  flex: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 54px;
  min-height: 58px;
  padding: 6px 0;
  border-radius: 15px;
  background: var(--felt);
  color: var(--on-felt);
}
.date-tile-weekday,
.date-tile-month {
  color: var(--chrome-2);
  font: 800 11px/1.2 var(--font);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.date-tile-weekday {
  font-size: 10px;
}
.date-tile-day {
  margin: 1px 0;
  font: 880 24px/1 var(--font);
  letter-spacing: -0.03em;
}
.tournament-main {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}
.tournament-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0;
  font-size: 12px;
  font-weight: 800;
  line-height: 18px;
}
/* A long name takes two lines, then an ellipsis: the row never grows a third. */
.tournament-name {
  display: -webkit-box;
  margin: 0;
  overflow: hidden;
  color: var(--paper-fg);
  font: 800 16px/1.25 var(--font);
  letter-spacing: -0.01em;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.tournament-club {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  margin: 0;
  color: var(--paper-fg-2);
  font: 650 13px/1.35 var(--font);
}
.tournament-club > span {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tournament-club .club-ball {
  width: 18px;
  height: 18px;
}
.tournament-details {
  margin: -2px 0 0;
  color: var(--paper-fg-muted);
  font: 600 12.5px/1.35 var(--font);
}
.tournament-fee {
  flex: none;
  color: var(--paper-fg);
  font: 820 17px/1 var(--font);
  white-space: nowrap;
}
/* The registration: its moment, tinted by how soon, and the one thing to do about it. The words keep at least 150 px:
   on a narrow phone the button drops under them, to the right, rather than squeezing them into broken lines. */
/* Tinted by how soon, across the card's foot. */
.registration {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 10px;
  padding: 8px 8px 8px 16px;
  border-radius: 0 0 20px 20px;
  font-size: 13px;
  line-height: 18px;
}
.registration > .icon {
  width: 20px;
  height: 20px;
}
.registration .grow {
  display: flex;
  flex: 1 1 150px;
  flex-direction: column;
  min-width: 0;
  padding: 3px 0;
}
.registration b {
  font-size: 14px;
  text-wrap: balance;
}
.registration small {
  font-size: 12px;
  font-weight: 500;
  text-wrap: balance;
}
.registration.soon {
  background: var(--warn-tint);
  color: var(--warn);
}
.registration.open {
  background: var(--action-tint);
  color: var(--action-strong);
}
.registration.closed,
.registration.unknown {
  background: rgb(16 36 27 / 0.04);
  box-shadow: inset 0 1px 0 rgb(16 36 27 / 0.06);
  color: var(--fg-muted);
}
/* The tools, then the one action at the far right, where the thumb is; on a narrow row they drop under the words. */
.registration-acts {
  display: flex;
  flex: none;
  align-items: center;
  gap: 2px;
  margin-left: auto;
}
.registration-acts .icon-button {
  color: var(--fg-2);
}
.registration-acts .button {
  margin-left: 6px;
}
/* From 360 px the strip is one line (the review of R6a: rows were 2.6 times the prototype's): the words take what the
   tools and the action leave, the tone's icon steps aside (the tint carries it), and the tools draw 36 px wide with
   their tap still 44 px through a transparent ::after (10 px apart, so two tools' taps never meet). Below 360 px the action drops under the words, as before. */
@media (min-width: 360px) {
  .registration {
    flex-wrap: nowrap;
    gap: 8px;
  }
  .registration > .grow {
    flex: 1 1 0;
  }
  .registration > .icon {
    display: none;
  }
  .registration-acts {
    gap: 10px;
  }
  .registration-acts .icon-button {
    position: relative;
    width: 36px;
    min-width: 36px;
  }
  .registration-acts .icon-button::after {
    content: "";
    position: absolute;
    inset: 0 -4px;
  }
  .registration-acts .button {
    margin-left: 0;
  }
}
/* One the golfer can't enter: pressed back into a well, its name quieter. Never transparency, which would fail contrast. */
.card.tournament.ineligible {
  background: #e9ece6;
  box-shadow: inset 0 0 0 1px rgb(16 36 27 / 0.08);
}
.tournament.ineligible .tournament-name {
  color: var(--paper-fg-muted);
}
/* A row being read: about the height of one with its strip, on the felt. */
.skeleton.tournament-skeleton {
  height: 136px;
  margin-bottom: 10px;
  border-radius: 20px;
}

/* ------------------------------------------------------------ Campos */
/* The clubs two to a row (three from 600 px), each the prototype's .ccard: its cover photo 88 px tall, the club's ball
   on the photo's edge ringed in its colour and in the card, then its short name, its town and the drive. The whole card
   opens the club; the star on the photo keeps it first. */
.club-cards {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
  margin: 0;
}
@media (min-width: 600px) {
  .club-cards {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}
.club-card {
  position: relative;
  overflow: hidden;
  border-radius: 20px;
  background: var(--card);
  box-shadow: 0 10px 20px -10px rgb(0 0 0 / 0.6);
  transition: transform var(--duration-press) var(--spring-snap);
}
.club-card:active {
  transform: scale(0.98);
}
.club-card-photo {
  height: 88px;
  overflow: hidden;
  background: radial-gradient(circle at 50% 40%, #17694a, #0a3a28);
}
.club-card-photo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition:
    opacity 0.35s var(--ease),
    transform 0.4s var(--ease);
}
.club-card-photo img.loaded {
  opacity: 1;
}
.club-card > .club-ball {
  position: absolute;
  z-index: 1;
  top: 64px;
  left: 10px;
  width: 38px;
  height: 38px;
  box-shadow:
    0 0 0 2px var(--course, #cfd6d1),
    0 0 0 4px var(--card),
    0 4px 10px rgb(0 0 0 / 0.25);
  pointer-events: none;
}
.club-card .course-name-button {
  display: flex;
  flex-direction: column;
  gap: 2px;
  width: 100%;
  min-height: 44px;
  padding: 20px 12px 12px;
  color: var(--paper-fg);
}
/* The name's button reaches over the whole card, so a tap anywhere on it opens the club. */
.club-card .course-name-button::after {
  content: "";
  position: absolute;
  inset: 0;
}
.club-card .title,
.club-card .subtitle {
  display: block;
  max-width: 100%;
  margin: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.club-card .title {
  font: 800 15px/1.3 var(--font);
}
.club-card .subtitle {
  color: var(--paper-fg-muted);
  font: 600 12.5px/1.35 var(--font);
}
.club-card-drive {
  margin-top: 4px;
  color: var(--paper-fg-2);
  font: 750 13px/1.35 var(--font);
}
.club-card .star {
  position: absolute;
  z-index: 2;
  top: 6px;
  right: 6px;
  width: 40px;
  height: 40px;
  background: rgb(255 255 255 / 0.92);
  box-shadow: 0 2px 6px rgb(0 0 0 / 0.2);
}
.star {
  color: var(--paper-fg-subtle);
}
.star[aria-pressed="true"] {
  color: var(--accent-strong);
}
.star[aria-pressed="true"] .icon {
  fill: var(--accent);
}

/* A club's sheet is a tee time's (the booking section above): its photos, the club's ball on their edge, the facts in a
   well; these are what only a club's sheet has. Two facts, so two columns. */
.course-sheet-title {
  margin: 0;
  color: var(--paper-fg);
  font: 800 19px/1.1 var(--font);
  letter-spacing: -0.02em;
}
.booking-facts.course-facts {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
.course-sheet .course-layout {
  margin: 16px 0 0;
  color: var(--paper-fg-2);
  font: 500 15px/1.45 var(--font);
}
.course-sheet .footer-bar .booking-act {
  flex: none;
}

@media (prefers-reduced-motion: reduce) {
  .pane-count.settling,
  .pane-count-skeleton,
  .skeleton.tournament-skeleton {
    animation: none !important;
  }
  .club-card,
  .club-card-photo img {
    transition: none !important;
  }
}
/* With reduced transparency the star's disc is opaque. */
@media (prefers-reduced-transparency: reduce) {
  .club-card .star {
    background: #ffffff;
  }
}
/* ============================================================ end of R6a */

/* ------------------------------------------------------------ banners & empty states */
.banner {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin: 4px 0 12px;
  padding: 12px 14px;
  border-radius: var(--radius-block);
  background: var(--bg-1);
  font-size: 14px;
}
.banner.danger {
  background: var(--danger-tint);
  color: var(--danger);
}
.banner .icon {
  width: 18px;
  height: 18px;
}
.empty {
  padding: 40px 20px 28px;
  text-align: center;
  color: var(--fg-muted);
}
.empty-mark {
  display: grid;
  place-items: center;
  width: 64px;
  height: 64px;
  margin: 0 auto 14px;
  border-radius: 50%;
  background: var(--action-tint);
  color: var(--action-strong);
}
.empty-mark .icon {
  width: 30px;
  height: 30px;
}
.empty h1,
.empty h2 {
  margin: 0 0 6px;
  font: 700 21px/26px var(--font-display);
  color: var(--fg);
}
.empty p {
  margin: 0 auto 16px;
  max-width: 34ch;
  font-size: 14px;
  line-height: 20px;
}
/* A tournament card being read: about the height of one with its registration strip. */
.skeleton {
  height: 190px;
  border-radius: var(--radius-card);
  background: linear-gradient(90deg, var(--bg-1) 0%, var(--bg-3) 50%, var(--bg-1) 100%);
  background-size: 200% 100%;
  animation: shimmer 1.2s ease-in-out infinite;
}
@keyframes shimmer {
  from {
    background-position: 100% 0;
  }
  to {
    background-position: -100% 0;
  }
}

/* ------------------------------------------------------------ the admin's dashboard */
/* #/admin (screens/admin-screen.ts, presentation/admin-report.ts): the owner's anonymous totals. A+ (R6b): the top is
   the approved prototype's scoreboard (moment 7, lane C on the felt), its values ported as they are: visits × the share
   that tap through, then booking taps, their product, as the screen's one chrome numeral. Chrome for what is chosen and
   for the north star, the lit green for the rate that makes it and for what went up, grey for what went down, gold
   never. The charts and tables below stay ivory cards. Numbers in tabular figures; 28 px between sections. */
.admin {
  --admin-gap: 28px;
}
/* The prototype's title: 30 px, 820, tight. */
.admin .screen-header {
  position: relative;
  gap: 8px;
}
.admin .screen-header h1 {
  font: 820 30px/1.05 var(--font-display);
  letter-spacing: -0.035em;
}
/* ⓘ beside the title, as the prototype's .adm-top, so the subtitle keeps the row's width. */
.admin-title {
  display: flex;
  align-items: center;
  gap: 2px;
}
.admin-title .admin-about {
  margin: -6px 0;
}
.admin-about[aria-expanded="true"] {
  background: var(--felt-well);
}
/* The disclaimer, behind ⓘ (the prototype's .info-pop): an ivory note under the header's right end, over the board. */
.admin-note {
  position: absolute;
  top: calc(100% - 6px);
  left: 0;
  z-index: 5;
  max-width: min(320px, 100%);
  margin: 0;
  padding: 10px 14px;
  border-radius: 14px;
  background: var(--card);
  color: var(--paper-ink);
  font-size: 14px;
  font-weight: 650;
  line-height: 20px;
  box-shadow: 0 10px 24px -10px rgb(0 0 0 / 0.6);
}
.admin-note[hidden] {
  display: none;
}
.admin .screen-header .button[aria-disabled="true"] {
  opacity: 0.55;
}
/* The periods: the prototype's .seg, the whole column wide, the chosen one chrome with ink on it. */
.admin-range {
  display: grid;
  margin: 8px 0 12px;
  padding: 4px;
  background: rgb(255 255 255 / 0.07);
}
.admin-range button {
  min-height: 40px;
  font-weight: 750;
  color: var(--on-felt-2);
}
.admin-body > * + * {
  margin-top: var(--admin-gap);
}
.admin-body > .admin-today + * {
  margin-top: 12px;
}
.admin-body > .admin-hero + .admin-kpis {
  margin-top: 24px;
}
.admin-body.switched {
  animation: admin-fade 150ms var(--ease);
}
@keyframes admin-fade {
  from {
    opacity: 0.35;
  }
}
.admin h2 {
  margin: 0 0 12px;
  font: 700 17px/22px var(--font);
  letter-spacing: -0.005em;
}
.admin h3 {
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  line-height: 18px;
  color: var(--fg-muted);
}
.admin-today {
  margin: 0;
  padding: 9px 12px;
  border-radius: var(--radius-tile);
  background: var(--bg-3);
  font-size: 13px;
  line-height: 18px;
  font-variant-numeric: tabular-nums;
  color: var(--fg-2);
}

/* A change against the period before: up in green, down in grey (a fall is not a fault). */
.delta {
  display: inline-flex;
  align-items: center;
  padding: 3px 8px;
  border-radius: var(--radius-pill);
  font-size: 13px;
  font-weight: 700;
  line-height: 16px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  vertical-align: middle;
}
.delta.up,
.delta.new {
  background: var(--action-tint);
  color: var(--action-strong);
}
.delta.down,
.delta.same {
  background: var(--bg-3);
  color: var(--fg-2);
}
.versus {
  margin: 4px 0 0;
  font-size: 12px;
  line-height: 16px;
  color: var(--fg-muted);
}

/* The scoreboard (the prototype's .score): two factors, the line naming their product, the product and its change. */
.admin-hero {
  margin-top: 22px;
}
.score-factors {
  /* The figures are sized from the board's width, not the factor's: a size container can't be a subgrid. */
  container-type: inline-size;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  grid-template-rows: auto auto auto;
  column-gap: 8px;
}
/* Each factor lies on the board's three rows (label, figure, foot), so the figures line up when one label wraps on a
   narrow phone. */
.factor {
  display: grid;
  grid-column: 1;
  grid-row: 1 / span 3;
  grid-template-rows: subgrid;
  align-content: start;
  row-gap: 8px;
  min-height: 96px;
  margin: 0;
  padding: 14px 14px 16px;
  border-radius: 22px;
  background: rgb(0 0 0 / 0.26);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.06);
}
.factor-label,
.kpi h3 {
  font-size: 11px;
  font-weight: 800;
  line-height: 1;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--on-felt-2);
}
/* The prototype's 38 px where it fits; a 320 px phone's narrower factor takes "12.345" whole at about 29 px (3.4 em
   is the widest figure in Figtree 880 at this tracking, with its % or its thousands' dot). A factor's content is half
   the board, less the two 8 px gaps and the × (about 22 px), less its 28 px of padding. */
.factor-value {
  justify-self: start;
  width: fit-content;
  font: 880 min(38px, calc(((100cqi - 38px) / 2 - 28px) / 3.4)) / 1 var(--font-display);
  letter-spacing: -0.04em;
  white-space: nowrap;
  color: var(--chrome-shade);
  background: var(--chrome-face);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
/* The rate is what the golfer's tap makes: the lit green, ink on it. */
.factor.rate {
  grid-column: 3;
  background: var(--action-on-felt);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.45),
    0 14px 30px -16px rgb(59 201 131 / 0.7);
}
.factor-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 8px;
}
.factor-foot:empty {
  display: none;
}
.factor-foot .versus {
  flex-basis: 100%;
  margin: 0;
}
.factor-foot .sparkline {
  flex-basis: 100%;
}
.factor.rate .factor-label,
.factor.rate .factor-value {
  color: var(--on-action-on-felt);
  background: none;
  -webkit-text-fill-color: currentColor;
}
.factor-times {
  grid-column: 2;
  grid-row: 1 / span 3;
  align-self: center;
  font-size: 34px;
  font-weight: 900;
  color: var(--on-felt);
}
/* "Pasos a reservar" between two rules, as the prototype's = line. Its words at the felt's muted chrome (the
   prototype's 58 % chrome measured under 4.5:1 at the glow; the eye can't tell them apart). */
.score-eq {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 18px 0 0;
  font-size: 14px;
  font-weight: 800;
  line-height: 1.2;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--on-felt-muted);
}
.admin .score-eq h2 {
  margin: 0;
  font: inherit;
  letter-spacing: inherit;
  color: inherit;
}
.score-sign {
  font-size: 18px;
  letter-spacing: 0;
}
.score-eq::before,
.score-eq::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--felt-line);
}
/* The product and, at its right foot, its change: the numeral takes what the change leaves, never more than the
   display size (kit/numeral-fit.ts measures its ems; 4 % kept for its settle and optical overhang). */
.score-product {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px;
  margin-top: 12px;
}
.hero-value {
  flex: 1;
  min-width: 0;
  margin: 0;
  container-type: inline-size;
}
.hero-number {
  display: block;
  width: fit-content;
  margin-left: -0.048em;
  padding-right: 0.07em;
  font: 900 min(var(--text-display), calc(100cqi / var(--numeral-ems, 3) * 0.96)) / 1 var(--font-display);
  letter-spacing: -0.06em;
  white-space: nowrap;
  color: var(--chrome-shade);
  background: var(--chrome-face);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  transform-origin: 20% 80%;
}
.hero-number.settling {
  animation: numeral-settle var(--duration-land) var(--spring-bounce) both;
}
.score-side {
  display: flex;
  flex: none;
  flex-direction: column;
  align-items: flex-end;
  gap: 8px;
  max-width: 31%;
  padding-bottom: 16px;
  text-align: right;
}
.score-side .delta {
  padding: 6px 11px;
  font-size: 16px;
  font-weight: 850;
  line-height: 1.2;
}
.score-side .versus {
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--on-felt-muted);
}
.admin-hero .chart-axis,
.admin-hero .chart-top,
.hero-legend {
  color: var(--on-felt-muted);
}
.admin-hero .chart-axis {
  margin-top: 8px;
  font-weight: 650;
}
.admin-hero .chart {
  margin-top: 20px;
}
.admin-hero .chart-plot {
  height: 112px;
}
.hero-legend {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 6px 0 0;
  font-size: 12px;
}

/* The sub-KPIs: sign-ups and lock taps (visits lead the equation, so they are shown once), wells pressed into the
   felt as the prototype's visits factor, side by side at every width. */
.admin-kpis {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}
.kpi {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 14px 14px 16px;
  border-radius: 22px;
  background: rgb(0 0 0 / 0.26);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.06);
}
.kpi-value {
  width: fit-content;
  margin: 8px 0 0;
  font: 880 30px/1.1 var(--font-display);
  letter-spacing: -0.03em;
  color: var(--chrome-shade);
  background: var(--chrome-face);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
.kpi-change {
  margin: 6px 0 0;
  min-height: 22px;
}
.sparkline {
  position: relative;
  display: block;
  height: 32px;
  margin-top: auto;
  padding-top: 10px;
  box-sizing: content-box;
}
.sparkline svg {
  display: block;
  width: 100%;
  height: 32px;
  overflow: visible;
}
.spark-line,
.spark-ghost {
  fill: none;
  vector-effect: non-scaling-stroke;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.spark-line {
  stroke: var(--ink);
  stroke-width: 1.5;
}
.spark-ghost {
  stroke: var(--stroke-strong);
  stroke-width: 1.5;
  stroke-dasharray: 3 3;
}
.spark-dot {
  position: absolute;
  width: 4px;
  height: 4px;
  margin: 8px 0 0 -2px;
  border-radius: 50%;
  background: var(--ink);
}
.skeleton-hero,
.skeleton-tile {
  border-radius: var(--radius-card);
  background: linear-gradient(90deg, var(--bg-1) 0%, var(--bg-3) 50%, var(--bg-1) 100%);
  background-size: 200% 100%;
  animation: shimmer 1.2s ease-in-out infinite;
}
.skeleton-hero {
  height: 300px;
  margin-bottom: 12px;
}
.skeleton-tile {
  height: 150px;
  border: 0;
  box-shadow: none;
}

/* Charts (kit/chart.ts). */
.chart {
  margin: 0;
}
.chart-plot {
  position: relative;
  height: 160px;
  margin-top: 22px;
}
.chart-plot svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}
.chart-top {
  position: absolute;
  top: -20px;
  left: 0;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--fg-muted);
}
.chart-grid,
.chart-base,
.chart-line,
.chart-ghost {
  vector-effect: non-scaling-stroke;
}
.chart-grid {
  stroke: var(--stroke);
  stroke-width: 1;
}
.chart-base {
  stroke: var(--stroke-strong);
  stroke-width: 1;
}
.chart-bar {
  fill: var(--ink);
}
.chart-green .chart-bar {
  fill: var(--action);
}
.chart-line {
  fill: none;
  stroke: var(--ink);
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.chart-ghost {
  fill: none;
  stroke: var(--stroke-strong);
  stroke-width: 1.5;
  stroke-dasharray: 3 3;
}
.chart-area {
  fill: rgb(16 36 27 / 0.06);
}
.chart-green .chart-line {
  stroke: var(--action);
}
.chart-green .chart-area {
  fill: var(--action-tint);
}
/* The scoreboard's weeks, on the felt (the tone keeps its v1 name): chrome bars, the period's own brighter, as the
   prototype's .bars. */
.chart-on-ink .chart-grid {
  stroke: var(--felt-line);
}
.chart-on-ink .chart-base {
  stroke: rgb(244 247 243 / 0.3);
}
.chart-on-ink .chart-bar {
  fill: rgb(244 247 243 / 0.32);
}
.chart-on-ink .chart-bar.emphasis {
  fill: rgb(244 247 243 / 0.88);
}
.chart-on-ink .chart-ghost {
  stroke: rgb(244 247 243 / 0.6);
}
.chart-hit {
  fill: transparent;
}
.chart-axis {
  display: flex;
  justify-content: space-between;
  margin-top: 6px;
  font-size: 12px;
  color: var(--fg-muted);
}
.chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 16px;
  margin: -4px 0 0;
  font-size: 12px;
  color: var(--fg-muted);
}
.chart-legend > span {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.legend-line,
.legend-dash {
  display: inline-block;
  width: 16px;
  height: 0;
  border-top: 2px solid var(--action);
}
.legend-dash {
  border-top: 2px dashed var(--stroke-strong);
}
.hero-legend .legend-dash {
  border-top-color: rgb(255 255 255 / 0.6);
}

/* Scrubbing the visits (kit/chart-scrub.ts): the page keeps its vertical scroll. */
.chart-scrub {
  touch-action: pan-y;
  cursor: crosshair;
  border-radius: 6px;
}
.chart-cursor {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--fg-muted);
  pointer-events: none;
}
.chart-dot {
  position: absolute;
  width: 8px;
  height: 8px;
  margin: -4px 0 0 -4px;
  border: 2px solid var(--bg-1);
  border-radius: 50%;
  background: var(--action);
  box-sizing: content-box;
  transform: translate(-2px, -2px);
  pointer-events: none;
}
.chart-tip {
  position: absolute;
  top: -30px;
  padding: 4px 8px;
  border-radius: var(--radius-pill);
  background: var(--ink);
  color: var(--on-ink);
  font-size: 12px;
  font-weight: 600;
  line-height: 16px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  pointer-events: none;
}

/* The wall: a sentence, then pairs of bars, with the wall in ink and without it outlined. */
.wall-verdict {
  margin: 0 0 14px;
  font-size: 17px;
  font-weight: 600;
  line-height: 24px;
}
.wall-pair + .wall-pair {
  margin-top: 14px;
}
.wall-pair h3 {
  margin-bottom: 6px;
}
.wall-row {
  display: grid;
  grid-template-columns: minmax(70px, auto) 1fr 36px;
  align-items: center;
  gap: 10px;
  margin-top: 6px;
  font-size: 13px;
}
.wall-label {
  color: var(--fg-2);
  white-space: nowrap;
}
.wall-track {
  display: block;
  height: 20px;
}
.wall-bar {
  display: block;
  width: max(4px, calc(var(--share) * 100%));
  height: 100%;
  border-radius: 4px;
}
.wall-bar.on {
  background: var(--ink);
}
.wall-bar.off {
  background: var(--bg-3);
  box-shadow: inset 0 0 0 1px var(--stroke-strong);
}
.wall-value {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

/* The funnel: two measured steps as stepped bars, the rate between them, sign-ups apart. */
.funnel-step {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 6px 12px;
  font-size: 15px;
  font-weight: 600;
}
.funnel-count {
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.funnel-bar {
  grid-column: 1 / -1;
  display: block;
  height: 28px;
}
.funnel-bar span {
  display: block;
  width: max(4px, calc(var(--share) * 100%));
  height: 100%;
  border-radius: 6px;
  background: var(--ink);
}
.funnel-rate {
  margin: 8px 0;
}
.step-chip {
  display: inline-block;
  padding: 3px 10px;
  border-radius: var(--radius-pill);
  background: var(--bg-3);
  font-size: 13px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--fg-2);
}
.funnel-apart {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 4px 12px;
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--stroke);
  font-size: 15px;
  font-weight: 600;
}
.funnel-apart .admin-hint {
  grid-column: 1 / -1;
  font-weight: 400;
}

/* Sources: initials, name, count, change, and a thin bar under them. */
.source-list {
  margin: 0;
  padding: 0;
  list-style: none;
}
.source-row {
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 4px 10px;
  min-height: 40px;
  padding: 6px 0;
  font-size: 14px;
}
.source-row + .source-row {
  border-top: 1px solid var(--stroke);
}
.source-mark {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--bg-3);
  font-size: 10px;
  font-weight: 700;
  color: var(--fg-2);
}
.source-name {
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.source-count {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.source-change:empty {
  display: none;
}
.source-bar {
  grid-column: 2 / -1;
  display: block;
  height: 6px;
  border-radius: 3px;
  background: var(--bg-3);
  overflow: hidden;
}
.source-bar span {
  display: block;
  width: calc(var(--share) * 100%);
  height: 100%;
  border-radius: 3px;
  background: var(--ink);
}

/* More data, closed: pages and locks by surface. */
.admin-more summary {
  display: flex;
  align-items: center;
  min-height: 44px;
  font: 700 17px/22px var(--font);
  cursor: pointer;
}
.admin-more > section + section {
  margin-top: 12px;
}
.admin-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
  line-height: 18px;
}
.admin-table th,
.admin-table td {
  padding: 10px 0;
  text-align: left;
  vertical-align: top;
}
.admin-table th + th,
.admin-table td {
  padding-left: 12px;
}
.admin-table thead th {
  font-size: 12px;
  font-weight: 600;
  color: var(--fg-muted);
  vertical-align: bottom;
}
.admin-table tbody tr {
  border-top: 1px solid var(--stroke);
}
.admin-table tbody th {
  font-weight: 600;
}
.admin-table .number {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.admin-hint {
  margin: 10px 0 0;
  font-size: 13px;
  line-height: 18px;
  color: var(--fg-muted);
}
.admin-hint.flush {
  margin-bottom: 0;
}
.admin-hint.flush-top {
  margin-top: 0;
}

/* The first paint only (admin-screen.ts): lines draw in, bars grow. */
.first-paint .chart-plot svg,
.first-paint .sparkline svg {
  animation: admin-draw 600ms var(--ease-out) both;
}
.first-paint .chart-bar {
  transform-box: fill-box;
  transform-origin: bottom;
  animation: admin-grow 400ms var(--ease-out) both;
}
@keyframes admin-draw {
  from {
    clip-path: inset(0 100% 0 0);
  }
  to {
    clip-path: inset(0 0 0 0);
  }
}
@keyframes admin-grow {
  from {
    transform: scaleY(0);
  }
}

/* ------------------------------------------------------------ small things */
.footnote {
  margin-top: 22px;
  line-height: 18px;
}
.inline-link {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  color: var(--action-strong);
  font-weight: 600;
  text-decoration: none;
}
.inline-link .icon {
  width: 15px;
  height: 15px;
}
.save-search[aria-pressed="true"] .icon {
  fill: currentColor;
  color: var(--action);
}
.plain-list {
  margin: 8px 0 12px;
  padding-left: 18px;
}
.nowrap {
  white-space: nowrap;
}

/* ------------------------------------------------------------ sheets */
/* The sheet, its scrim and the toast are in styles.css, shared with /search; the app's sheets add these. */
.sheet .section-head {
  margin: 20px 0 8px;
  font-size: 15px;
}
/* The one next step, pinned to the bottom of a sheet, with what it costs when it costs something. */
.sheet-footer {
  position: sticky;
  bottom: 0;
  z-index: 2;
  margin: 18px -20px calc(-22px - var(--safe-bottom));
  padding: 12px 20px calc(12px + var(--safe-bottom));
  border-top: 1px solid var(--stroke);
  background: rgb(255 255 255 / 0.96);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}
.footer-bar {
  display: flex;
  align-items: center;
  gap: 14px;
}
.footer-bar .button {
  min-height: 50px;
  font-size: 16px;
}
.footer-total {
  display: flex;
  flex: none;
  flex-direction: column;
  line-height: 1.15;
}
.footer-total small {
  font-size: 12px;
  color: var(--fg-muted);
}
.footer-total b {
  font-size: 22px;
}
.sheet-footer > .button {
  margin-top: 6px;
}
.course-layout {
  margin: 0 0 10px;
  font-size: 14px;
  line-height: 20px;
  color: var(--fg-2);
}
.checklist {
  display: grid;
  gap: 8px;
  margin: 14px 0 6px;
  padding: 0;
  list-style: none;
  font-size: 14px;
  line-height: 20px;
}
.checklist li {
  display: flex;
  align-items: center;
  gap: 10px;
}
.checklist .icon {
  width: 18px;
  height: 18px;
  color: var(--action);
}
.checklist .off {
  color: var(--fg-muted);
}
.checklist .off .icon {
  color: var(--fg-subtle);
}
/* Links in a centred row, each a 44 px tap: rows that wrap touch but never overlap. */
.link-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0 18px;
  margin: 6px 0 0;
}
.link-row .inline-link {
  min-height: 44px;
}
/* A sheet's buttons stacked under its text (a saved search's). */
.actions {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 16px;
}
/* Rows to pick from: a mark, a name over a detail, a check when chosen (Playtomic's list item). */
.option-list,
.area-list {
  overflow: hidden;
  border: 1px solid var(--stroke);
  border-radius: var(--radius-card);
}
.option-list > * + *,
.area-list > * + * {
  border-top: 1px solid var(--stroke);
}
.option,
.area-list .area-option {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 58px;
  padding: 10px 16px 10px 14px;
  border: 0;
  background: var(--bg-1);
  color: var(--fg);
  font: 400 15px/20px var(--font);
  text-align: left;
  cursor: pointer;
  transition: background 0.16s var(--ease);
}
.option .grow {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.option small {
  font-size: 12px;
  line-height: 17px;
  color: var(--fg-muted);
}
.option-mark {
  display: grid;
  flex: none;
  place-items: center;
  width: 32px;
  height: 32px;
}
.option-mark.all {
  border-radius: 50%;
  background: var(--bg-3);
  color: var(--fg-2);
}
.option-mark.all .icon {
  width: 18px;
  height: 18px;
}
.option-check {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  flex: none;
  border: 1.5px solid var(--stroke-strong);
  border-radius: 50%;
  color: transparent;
}
.option-check .icon {
  width: 15px;
  height: 15px;
  stroke-width: 2.6;
}
.option[aria-pressed="true"],
.area-list .area-option[aria-pressed="true"] {
  background: var(--action-tint);
}
.option[aria-pressed="true"] .option-check {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--on-ink);
}
.area-list .area-option .icon {
  color: var(--action);
}

/* ------------------------------------------------------------ a club's photos */
/* At the top of a sheet, edge to edge under its rounded corners: the club's photos in a row that snaps one by one,
   on the fairway's green while they load (components/photo-gallery.ts). */
.photo-header {
  position: relative;
  margin: -6px -20px 0;
  background:
    radial-gradient(120% 90% at 100% 0%, rgb(255 255 255 / 0.1), transparent 60%),
    repeating-linear-gradient(118deg, var(--fairway) 0 34px, var(--fairway-stripe) 34px 68px);
}
/* Shade at the top and the bottom, so the grabber, the ✕ and the count read on a white sky or a bright green. */
.photo-header::before,
.photo-header::after {
  content: "";
  position: absolute;
  right: 0;
  left: 0;
  z-index: 1;
  pointer-events: none;
}
.photo-header::before {
  top: 0;
  height: 72px;
  background: linear-gradient(rgb(6 14 10 / 0.34), transparent);
}
.photo-header::after {
  bottom: 0;
  height: 64px;
  background: linear-gradient(transparent, rgb(6 14 10 / 0.3));
}
.photo-strip {
  display: flex;
  height: clamp(176px, 50vw, 236px);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}
.photo-strip::-webkit-scrollbar {
  display: none;
}
.photo-strip:focus-visible,
.viewer-strip:focus-visible {
  outline: 3px solid var(--action);
  outline-offset: -3px;
}
.photo {
  flex: 0 0 100%;
  scroll-snap-align: start;
  scroll-snap-stop: always;
  cursor: zoom-in;
}
.photo img,
.viewer-photo img {
  opacity: 0;
  transition: opacity 0.35s var(--ease);
}
.photo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.photo img.loaded,
.viewer-photo img.loaded {
  opacity: 1;
}
.photo-count {
  position: absolute;
  right: 12px;
  bottom: 12px;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 30px;
  padding: 0 11px 0 9px;
  border: 0;
  border-radius: var(--radius-pill);
  background: rgb(10 20 15 / 0.62);
  color: #ffffff;
  font: 700 13px/1 var(--font);
  font-variant-numeric: tabular-nums;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  cursor: pointer;
}
/* The count looks small but takes a 44 px tap, reaching up into the photo. */
.photo-count::after {
  content: "";
  position: absolute;
  inset: -8px -6px -6px;
}
.photo-count .icon {
  width: 16px;
  height: 16px;
}
/* A club with one photo has nothing to count: the icon alone, on a disc that still opens the viewer. */
.photo-count:not(:has([data-photo-at])) {
  width: 30px;
  padding: 0;
  justify-content: center;
}
.photo-count:not(:has([data-photo-at]))::after {
  inset: -8px -7px -6px;
}
/* For a mouse: arrows on the photos' sides while the pointer is over them. */
.photo-step {
  position: absolute;
  top: 50%;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgb(255 255 255 / 0.92);
  box-shadow: var(--elevation-2);
  color: var(--fg);
  opacity: 0;
  cursor: pointer;
  transform: translateY(-50%);
  transition: opacity 0.18s var(--ease);
}
.photo-step.left {
  left: 12px;
}
.photo-step.right {
  right: 12px;
}
.photo-step .icon {
  width: 18px;
  height: 18px;
}
.photo-header:hover .photo-step {
  opacity: 1;
}
.photo-header[data-at-start] .photo-step.left,
.photo-header[data-at-end] .photo-step.right {
  visibility: hidden;
}
/* A sheet that opens on photos: the grabber and the ✕ float over them. */
.sheet:has(.photo-header) .sheet-top {
  position: absolute;
  inset: 0 0 auto;
  z-index: 3;
  height: 0;
}
.sheet:has(.photo-header) .grabber {
  position: absolute;
  top: 8px;
  left: 50%;
  margin: 0;
  background: rgb(255 255 255 / 0.9);
  box-shadow: 0 1px 4px rgb(0 0 0 / 0.25);
  transform: translateX(-50%);
}
.sheet:has(.photo-header) .sheet-close {
  top: 12px;
  right: 12px;
  background: rgb(10 20 15 / 0.5);
  color: #ffffff;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

/* The viewer: the photos full screen on near-black, one at a time, with the club's name, the count, the credit and
   the photos in small to jump between, as Google Maps shows a place's. */
.photo-viewer {
  width: 100%;
  max-width: none;
  height: 100%;
  max-height: none;
  margin: 0;
  padding: 0;
  overflow: hidden;
  border: 0;
  background: rgb(8 12 10);
  color: #ffffff;
}
.photo-viewer[open] {
  display: grid;
  grid-template-rows: auto 1fr auto;
  animation: viewer-in 0.24s var(--ease-out);
}
.photo-viewer::backdrop {
  background: transparent;
}
@keyframes viewer-in {
  from {
    opacity: 0;
  }
}
/* Clear of a notch and rounded corners on a phone held sideways, as the arrows are. */
.viewer-top {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: calc(var(--safe-top) + 8px) max(12px, env(safe-area-inset-right, 0px)) 8px max(20px, env(safe-area-inset-left, 0px));
}
.viewer-title {
  display: flex;
  flex: 1;
  flex-direction: column;
  min-width: 0;
  margin: 0;
  font-size: 13px;
  line-height: 18px;
  color: rgb(255 255 255 / 0.72);
}
.viewer-title b {
  overflow: hidden;
  font-size: 16px;
  line-height: 22px;
  color: #ffffff;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.viewer-close {
  background: rgb(255 255 255 / 0.12);
  color: #ffffff;
}
.viewer-strip {
  display: flex;
  min-height: 0;
  overflow-x: auto;
  overscroll-behavior: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}
.viewer-strip::-webkit-scrollbar {
  display: none;
}
.viewer-photo {
  position: relative;
  flex: 0 0 100%;
  margin: 0;
  scroll-snap-align: center;
  scroll-snap-stop: always;
}
/* The whole photo, as large as the space allows, never cropped. */
.viewer-photo img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.viewer-step {
  position: fixed;
  top: 50%;
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgb(255 255 255 / 0.14);
  color: #ffffff;
  cursor: pointer;
  transform: translateY(-50%);
}
.viewer-step.left {
  left: max(16px, env(safe-area-inset-left, 0px));
}
.viewer-step.right {
  right: max(16px, env(safe-area-inset-right, 0px));
}
.viewer-step[disabled] {
  visibility: hidden;
}
.viewer-step:hover {
  background: rgb(255 255 255 / 0.24);
}
/* The arrows are for a mouse; a finger swipes. */
@media (hover: none) {
  .photo-step,
  .viewer-step {
    display: none;
  }
}
.viewer-foot {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 8px 16px calc(var(--safe-bottom) + 14px);
}
.viewer-thumbs {
  display: flex;
  gap: 8px;
}
.viewer-thumb {
  width: 56px;
  height: 44px;
  padding: 0;
  overflow: hidden;
  border: 2px solid transparent;
  border-radius: 8px;
  background: rgb(255 255 255 / 0.08);
  opacity: 0.55;
  cursor: pointer;
  transition:
    opacity 0.18s var(--ease),
    border-color 0.18s var(--ease);
}
.viewer-thumb img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.viewer-thumb[aria-current="true"] {
  border-color: #ffffff;
  opacity: 1;
}
.viewer-credit {
  margin: 0;
  font-size: 12px;
  color: rgb(255 255 255 / 0.6);
}

/* ------------------------------------------------------------ the group's proposal */
/* Above the tab bar on every screen once it holds a tee time: ink, so it reads as the golfer's own thing. */
.proposal-pill {
  position: fixed;
  bottom: calc(var(--tab-bar-height) + var(--safe-bottom) + 12px);
  left: 50%;
  z-index: 19;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 46px;
  padding: 0 20px 0 16px;
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--ink);
  box-shadow: var(--elevation-2);
  color: var(--on-ink);
  font: 700 15px/1 var(--font);
  cursor: pointer;
  transform: translateX(-50%);
  animation: pill-in 0.32s var(--ease-out) both;
}
.proposal-pill .icon {
  width: 19px;
  height: 19px;
}
.proposal-pill:active {
  transform: translateX(-50%) scale(0.96);
}
@keyframes pill-in {
  from {
    opacity: 0;
    transform: translateX(-50%) translateY(12px);
  }
}
body.has-proposal #toast {
  bottom: calc(var(--tab-bar-height) + var(--safe-bottom) + 70px);
}
body.has-proposal #view {
  padding-bottom: calc(var(--tab-bar-height) + var(--safe-bottom) + 90px);
}
ol.option-list {
  margin: 12px 0 0;
  padding: 0;
  list-style: none;
}
.proposal-list .option {
  gap: 10px;
  padding-right: 4px;
  cursor: default;
}
.option-number {
  display: grid;
  flex: none;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--ink);
  color: var(--on-ink);
  font-size: 12px;
  font-weight: 800;
}

/* ES | EN at the top of the area sheet (components/area-sheet.ts), its label in both languages, so whoever reads no
   Spanish finds it where the area pill (named for both) leads. */
.sheet-language {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 44px;
  margin: 0 0 8px;
}
.sheet-language-label {
  color: var(--fg-muted);
  font: 700 13px/1.35 var(--font);
}
.sheet-language .language-switch button {
  min-width: 44px;
  height: 32px;
  font-size: 13px;
}

/* The week's mini-head (week-screen.ts; the prototype's .mini-head): once the hero has gone by (140 px), felt glass at
   the top with the mark, "Horarios", the area and the account, under the phone's status bar. A cut under reduced
   motion; solid felt under reduced transparency; a phone's only (a computer's top bar stays). */
.mini-head-from {
  position: absolute;
  top: 140px;
  left: 0;
  width: 1px;
  height: 1px;
  pointer-events: none;
}
.mini-head {
  position: fixed;
  z-index: 18;
  top: 0;
  right: 0;
  left: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: max(var(--safe-top), 8px) calc(16px + var(--safe-right)) 8px calc(16px + var(--safe-left));
  background: rgb(7 42 29 / 0.82);
  color: var(--on-felt);
  opacity: 0;
  pointer-events: none;
  transform: translateY(-8px);
  transition:
    opacity 0.2s,
    transform 0.2s;
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
}
.mini-head.on {
  opacity: 1;
  pointer-events: auto;
  transform: none;
}
.mini-head img {
  width: 24px;
  height: 24px;
  border-radius: 7px;
}
.mini-head b {
  font: 800 17px/1.35 var(--font);
  letter-spacing: -0.02em;
}
.mini-area {
  margin-right: auto;
  color: rgb(244 247 243 / 0.58);
  font: 650 14px/1.35 var(--font);
}
/* The golfer's M4 ball (28 px; R5, its own ground) or a guest's Entrar, the bar's own actions. */
.mini-ball {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  filter: drop-shadow(0 2px 3px rgb(0 0 0 / 0.28));
  cursor: pointer;
}
.mini-enter {
  min-height: 36px;
  padding: 0 14px;
  border: 0;
  border-radius: var(--radius-pill);
  background: #ffffff;
  color: var(--paper-ink);
  font: 800 14px/1 var(--font);
  cursor: pointer;
}
@media (prefers-reduced-transparency: reduce) {
  .mini-head {
    background: var(--felt-deep);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
}
@media (min-width: 960px) {
  .mini-head,
  .mini-head-from {
    display: none;
  }
}

/* ------------------------------------------------------------ the Cápsula+ */
/* The sections and search (index.html's .capsule, app/capsule.ts), as the panel approved them on 16 Oct 2026. On a
   phone: a pill floating 18 px over the bottom edge (and its safe area), the three tabs with their words always, and a
   round search button beside it. The pill is solid felt under its words, never glass: the words keep 7:1 over
   whatever scrolls beneath, with nothing to blur on every frame. A lens of light marks the open tab (no flag: the
   owner took it off). */
.capsule {
  position: fixed;
  z-index: 20;
  left: calc(14px + var(--safe-left));
  right: calc(14px + var(--safe-right));
  bottom: calc(18px + var(--safe-bottom));
  display: flex;
  gap: 10px;
  height: 64px;
  /* Its own layer in a section change (the pager, below): the screens slide under it while it stays. */
  view-transition-name: capsule;
}
.tab-bar {
  position: relative;
  display: flex;
  flex: 1;
  min-width: 0;
  padding: 4px;
}
.tab-pill,
.search-open-disc {
  position: absolute;
  inset: 0;
  border-radius: 32px;
  background: linear-gradient(180deg, #124632, #062217);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.2),
    inset 0 0 0 1px rgb(255 255 255 / 0.08),
    0 18px 36px -16px rgb(0 0 0 / 0.8);
  transform-origin: 50% 100%;
  transition: transform var(--duration-shift) var(--spring-glide);
}
.search-open-disc {
  border-radius: 50%;
}
/* The lens: glass over the open tab, placed by its offsetLeft and width (never a number fixed for 390 px). */
.tab-lens-track {
  position: absolute;
  inset: 4px;
  pointer-events: none;
  transform-origin: 50% 100%;
  transition: transform var(--duration-shift) var(--spring-glide);
}
.tab-lens {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  border-radius: 28px;
  background: linear-gradient(180deg, rgb(255 255 255 / 0.2), rgb(255 255 255 / 0.07));
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.6),
    inset 0 0 0 1px rgb(214 224 218 / 0.28),
    0 4px 14px -4px rgb(0 0 0 / 0.45);
  transform-origin: 0 50%;
}
.tab-bar a {
  position: relative;
  z-index: 1;
  display: grid;
  flex: 1;
  place-items: center;
  min-width: 44px;
  border-radius: 28px;
  color: #c9d4ce;
  font: 750 12.5px/1 var(--font);
  letter-spacing: -0.005em;
  text-decoration: none;
}
/* The prototype's 12.5 px, stepped down only for a word that wouldn't fit its tab (app/capsule.ts measures). */
.tab-label {
  font-size: calc(12.5px * var(--label-fit, 1));
  /* The prototype's line box (its screen's 1.35), so the icon and the word sit where it puts them. */
  line-height: 1.35;
  white-space: nowrap;
}
.tab-bar a[aria-current="page"] {
  color: #ffffff;
}
.tab-in {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  transition:
    transform var(--duration-shift) var(--spring-glide),
    scale var(--duration-press) var(--spring-snap);
}
.tab-bar svg,
.search-open svg {
  width: 24px;
  height: 24px;
  flex: none;
  overflow: visible;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.9;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* The icons' moving parts (app/capsule.ts plays them once when their tab opens). */
.tab-clock-hand {
  transform-box: view-box;
  transform-origin: 12px 12px;
}
.tab-cup {
  transform-box: view-box;
  transform-origin: 12px 9px;
}
.tab-cup-shine {
  opacity: 0;
  stroke-width: 1.6;
}
.tab-flag-cloth {
  fill: currentColor;
  fill-opacity: 0.3;
  transform-box: fill-box;
  transform-origin: 0 50%;
}
.search-open {
  position: relative;
  display: grid;
  flex: none;
  place-items: center;
  width: 64px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: #ffffff;
  cursor: pointer;
}
.search-open svg {
  position: relative;
  transition:
    transform var(--duration-shift) var(--spring-glide),
    scale var(--duration-press) var(--spring-snap);
}
.tab-bar a:active .tab-in,
.search-open:active svg {
  scale: 0.94;
}
.tab-bar a:focus-visible,
.search-open:focus-visible {
  outline: 2.5px solid #9df0c4;
  outline-offset: 2px;
  border-radius: 28px;
}
.search-open:focus-visible {
  border-radius: 50%;
}
/* Scrolled down: the pill shrinks in height only, by transforms. Every tab keeps its box (the tap, its x, its width),
   the words stay, and only the felt under them and their glyphs dip, so nothing a thumb aims at moves. */
.capsule.mini .tab-pill {
  transform: scaleY(0.8);
}
.capsule.mini .tab-lens-track {
  transform: scaleY(0.78);
}
.capsule.mini .tab-in {
  transform: translateY(6px) scale(0.95);
}
.capsule.mini .search-open-disc {
  transform: scale(0.8);
}
.capsule.mini .search-open svg {
  transform: translateY(6px);
}
/* Once, the first time on a phone: what to type, over the search button. */
.search-hint {
  position: absolute;
  right: 0;
  bottom: calc(100% + 12px);
  z-index: 3;
  display: flex;
  flex-direction: column;
  gap: 1px;
  margin: 0;
  padding: 9px 13px 10px;
  border-radius: 16px;
  background: var(--card);
  color: var(--paper-fg-muted);
  font: 650 12.5px/1.25 var(--font);
  white-space: nowrap;
  pointer-events: none;
  box-shadow: 0 12px 26px -12px rgb(0 0 0 / 0.7);
  animation: hint-in var(--duration-shift) var(--spring-glide) 400ms backwards;
}
.search-hint b {
  color: var(--paper-fg);
  font-size: 14px;
  font-weight: 800;
}
.search-hint::after {
  content: "";
  position: absolute;
  right: 26px;
  bottom: -6px;
  width: 12px;
  height: 12px;
  border-radius: 2px;
  background: var(--card);
  transform: rotate(45deg);
}
@keyframes hint-in {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
}
/* The search field: over the pill once the button opens it (a phone), always in the top bar (960 px and up). Ivory,
   with the area's chip under the thumb and a real plan as the placeholder. */
.search-field {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  gap: 4px;
  margin: 0;
  padding: 7px 6px 7px 7px;
  visibility: hidden;
}
.capsule.searching .search-field {
  visibility: visible;
}
.capsule.searching .tab-bar,
.capsule.searching .search-open {
  visibility: hidden;
}
.search-field-ground {
  position: absolute;
  inset: 0;
  border-radius: 32px;
  background: var(--card);
  box-shadow:
    inset 0 1px 0 #ffffff,
    0 18px 36px -14px rgb(0 0 0 / 0.8);
  transform-origin: 100% 50%;
}
.search-field:focus-within .search-field-ground {
  box-shadow:
    inset 0 1px 0 #ffffff,
    0 0 0 2.5px var(--paper-action),
    0 18px 36px -14px rgb(0 0 0 / 0.8);
}
.search-field > :not(.search-field-ground) {
  position: relative;
}
.search-area {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: 2px;
  max-width: 45%;
  min-height: 48px;
  padding: 0 8px 0 14px;
  border: 0;
  border-radius: 25px;
  background: var(--paper-bg-3);
  color: var(--paper-fg);
  font: 780 14px/1 var(--font);
  cursor: pointer;
}
.search-area {
  position: relative;
}
/* A 44 px tap where the chip is drawn 40 px tall (the top bar), above and below only. */
.search-area::after {
  content: "";
  position: absolute;
  inset: min(0px, (100% - 44px) / 2) 0;
}
.search-area-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.search-area .caret,
.search-glass,
.search-close svg {
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.search-area .caret {
  width: 16px;
  height: 16px;
}
.search-glass {
  width: 20px;
  height: 20px;
  margin-left: 2px;
  color: var(--paper-action);
}
/* Where even the short plan wouldn't show whole, the magnifier makes room for it (app/capsule.ts). */
.search-field.tight .search-glass {
  display: none;
}
.search-field.tight .search-area {
  padding: 0 4px 0 12px;
}
.search-input {
  flex: 1;
  min-width: 0;
  height: 48px;
  /* The browser's own padding, which the prototype's field keeps: its plan starts 2 px in. */
  padding: 1px 2px;
  border: 0;
  background: none;
  color: var(--paper-fg);
  /* 16 px: iOS zooms into a smaller field. */
  font: 600 16px/1 var(--font);
  outline: none;
  appearance: none;
}
.search-input::placeholder {
  color: var(--paper-fg-muted);
  opacity: 1;
}
/* ✕ closes the field; the browser's own clear button would be a second ✕ beside it. */
.search-input::-webkit-search-cancel-button {
  appearance: none;
}
.search-close {
  display: grid;
  flex: none;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--paper-fg);
  cursor: pointer;
}
.search-close svg {
  width: 22px;
  height: 22px;
}
.search-area:focus-visible,
.search-close:focus-visible {
  outline: 2.5px solid var(--paper-action);
  outline-offset: 2px;
}
/* First in the Tab order, shown only while focused: past the bars, onto the screen's first tee time. */
.skip-link {
  position: fixed;
  top: calc(8px + var(--safe-top));
  left: calc(16px + var(--safe-left));
  z-index: 60;
  min-height: 44px;
  padding: 0 16px;
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--card);
  color: var(--paper-fg);
  font: 800 14px/1 var(--font);
  opacity: 0;
  transform: translateY(-200%);
  pointer-events: none;
}
.skip-link:focus-visible {
  opacity: 1;
  transform: none;
  pointer-events: auto;
  outline: 2.5px solid var(--paper-action);
}
/* A swipe between sections (app/section-swipe.ts): the screen, its bar's words and tools follow the finger, and the next
   section's real screen comes in beside them, in a layer of its own (inert), as the prototype drags its panes. */
/* Its layers move by their own translate (app/section-swipe.ts), so a move restyles nothing else; the preview's layout
   and paint are its own. */
.swipe-preview {
  position: fixed;
  inset: 0;
  z-index: 15;
  overflow: hidden;
  pointer-events: none;
  contain: layout paint;
}
.swipe-preview-page {
  position: absolute;
  inset: 0 0 auto;
}
@media (max-width: 959px) {
  /* Sideways drags are the swipe's (app/section-swipe.ts), but only at the page's own scale: pinch-zoomed in, a
     sideways finger pans the page, as it should. Rows that scroll sideways keep theirs, being scrollers. */
  #view.swipeable {
    touch-action: pan-y pinch-zoom;
  }
  /* Mid-turn the finger lands on the turn's picture, not the screen: the page itself leaves sideways drags to the swipe
     then too, so one begun right after a tap still swipes. */
  :root[data-turn]:has(#view.swipeable) {
    touch-action: pan-y pinch-zoom;
  }
}
/* A change of section on a phone (app/pager.ts animates the turn, and takes the taps the browser gives the page
   mid-turn): the bar is its own layer and stays, its lens gliding live. */
::view-transition-group(capsule) {
  animation: none;
}
::view-transition-old(capsule) {
  display: none;
}
::view-transition-new(capsule) {
  animation: none;
}
::view-transition-old(root),
::view-transition-new(root) {
  mix-blend-mode: normal;
  animation: none;
}
/* Less transparency asked for: the bar is flat felt, and nothing on it is glass. A locked day's foot turns solid
   sooner, so its button never sits on ghosts showing through. */
@media (prefers-reduced-transparency: reduce) {
  .lock-foot {
    background: linear-gradient(180deg, rgb(7 42 29 / 0), var(--felt-deep) 24%);
  }
  .tab-pill,
  .search-open-disc {
    background: #0a3424;
  }
  .tab-lens {
    background: #1d5a43;
  }
  .filter-bar {
    background: var(--felt);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  #view[data-screen="day"] .filter-bar:not([data-stuck]) {
    background: none;
  }
  /* A day's stuck filters, flat felt; the tee time's ✕ a solid disc (the prototype's own fallback), its footer opaque. */
  .filter-bar::before {
    background: var(--felt-deep);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  .sheet.booking-sheet .sheet-close {
    background: rgb(0 0 0 / 0.55);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  .booking-sheet .sheet-footer {
    background: #f6f6f1;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
}

/* ------------------------------------------------------------ feedback */
.pull-indicator {
  --pull: 0px;
  --turn: 0deg;
  position: fixed;
  top: calc(var(--safe-top) - 40px);
  left: 50%;
  z-index: 30;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--bg-1);
  box-shadow: var(--elevation-2);
  opacity: 0;
  pointer-events: none;
  transform: translate(-50%, var(--pull)) rotate(var(--turn));
}
/* Pulled down from the top: a golf ball, its dimples turning as it comes; ringed in green once letting go refreshes. */
.pull-indicator::before {
  content: "";
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background:
    radial-gradient(circle at 32% 28%, rgb(255 255 255 / 0.95) 0 18%, transparent 46%),
    radial-gradient(circle, rgb(16 36 27 / 0.16) 0 1.1px, transparent 1.6px) 0 0 / 7px 7px,
    radial-gradient(circle, rgb(16 36 27 / 0.12) 0 1.1px, transparent 1.6px) 3.5px 3.5px / 7px 7px,
    #f7f8f6;
}
.pull-indicator.ready {
  box-shadow:
    0 0 0 3px var(--action),
    var(--elevation-2);
}
.pull-indicator.refreshing::before {
  animation: spin 0.9s linear infinite;
}

/* ------------------------------------------------------------ motion */
/* A screen's first paint rises into place, day by day; redraws after it (every minute, every reading) stay still. */
@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
}
#view[data-entering] :is(.day-card, .today-over, .course-block, .saved-searches, .card.list) {
  animation: rise 0.42s var(--ease-out) both;
}
/* Torneos' and Campos' cards are dealt in on a screen's first paint as the prototype's enter() deals them: each rises
   8 px out of an 8 px blur, 420 ms on the glide spring, 60 ms after the one before; the first six in the page's order
   (router.ts marks them data-dealt, with their place as --deal, since tournaments sit in months), the rest simply
   there. A turn of section deals nothing: the cards come with the pane, sharp from its first frame (app/pager.ts). */
@keyframes card-deal {
  from {
    opacity: 0;
    transform: translateY(8px);
    filter: blur(8px);
  }
}
#view[data-entering] [data-dealt] {
  animation: card-deal 420ms var(--spring-glide) calc(var(--deal, 0) * 60ms) backwards;
}
/* Reduced motion is at the very end of the file, so it also wins over the transitions declared for larger screens. */

/* ------------------------------------------------------------ every screen size */
/* Titles break into even lines ("Sábado / 17 oct", never "Sábado 17 / oct") when a narrow phone wraps them. */
h1,
h2 {
  text-wrap: balance;
}

/* Up to 345 px (a 320 px phone, small Androids, or a larger one with its text zoomed): the day's title balances, and
   the sheet's one button keeps its words on one line. The bar's own steps are with the bar, above. */
@media (max-width: 345px) {
  .language-switch button {
    min-width: 30px;
    padding: 0 6px;
  }
  .footer-bar {
    gap: 10px;
  }
  .footer-bar .button {
    padding: 0 14px;
    font-size: 15px;
  }
  .footer-total b {
    font-size: 20px;
  }
}

/* A short window held sideways (a landscape tablet, a short laptop window, a phone on its side): the photos shrink
   with the window's height, so the sheet under them keeps room to read. Up to 520 px tall they are 150 px, as before. */
@media (max-height: 700px) and (orientation: landscape) {
  .photo-strip {
    height: clamp(150px, 30vh, 236px);
  }
}

/* Up to 619 px tall on its side, a sheet's pinned step takes one row, so most of the sheet stays readable. From
   620 px a wide window shows the sheet as a 560 px dialog (below), too narrow for the step on one row. */
@media (max-height: 619px) and (orientation: landscape) {
  .sheet-footer {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 12px;
    padding-top: 8px;
    padding-bottom: calc(8px + var(--safe-bottom));
  }
  .sheet-footer .footer-bar {
    flex: 1;
  }
  .footer-bar .button {
    min-height: 44px;
  }
  /* The booking sheet's link beside its footer bar keeps its own width; a footer's only button takes the row. */
  .sheet-footer > .button {
    flex: none;
    width: auto;
    margin-top: 0;
  }
  .sheet-footer > .button:only-child {
    flex: 1;
  }
}

/* A phone on its side (520 px tall or less: a 375–430 px phone held sideways): a slimmer tab bar with the words beside
   the icons, a sheet nearly as tall as the screen, and a photo viewer whose photo gets the height (the count and the
   arrows are enough to move between photos). */
@media (max-height: 520px) and (orientation: landscape) {
  /* The pill drops to 52 px and 8 px off the edge, its words beside the icons. */
  :root {
    --tab-bar-height: 60px;
  }
  .capsule {
    bottom: calc(8px + var(--safe-bottom));
    height: 52px;
  }
  .search-open {
    width: 52px;
  }
  .tab-in {
    flex-direction: row;
    gap: 8px;
  }
  .viewer-thumbs {
    display: none;
  }
  .viewer-top {
    padding-top: 6px;
    padding-bottom: 4px;
  }
}

/* A tablet held upright: the pill keeps a phone's width in the middle, as iPadOS groups its tabs, not stretched to the
   far edges of a wide screen. */
@media (min-width: 600px) and (max-width: 959px) {
  .capsule {
    left: max(calc(14px + var(--safe-left)), calc(50% - 260px));
    right: max(calc(14px + var(--safe-right)), calc(50% - 260px));
  }
}

/* A computer window narrower than the prototype's 1200 px: the tabs' icons step aside before the search box gets too
   narrow for a whole plan (the words stay; nothing else changes). */
@media (min-width: 960px) and (max-width: 1199px) {
  .tab-bar svg {
    display: none;
  }
}

/* The narrowest phones: the area's chip keeps to a third of the field, so the plan beside it shows whole. */
@media (max-width: 359px) {
  .search-area {
    max-width: 34%;
  }
}

/* From 600 px (a tablet, or a phone on its side): a course's tee times six to a row, so the twelve shown before "see
   more" make two full rows. (Campos' columns are R6a's, with its cards.) */
@media (min-width: 600px) {
  .tee-times {
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }
}

@media (min-width: 700px) {
  .brand-bar {
    padding-top: 24px;
  }
  /* In the centred column, rows that scroll sideways fade at the column's edges instead of being cut by them: on the
     left only what has scrolled past the row's 16 px padding fades, so nothing fades at rest. */
  .tee-times-row,
  .filter-scroll,
  .chips,
  .carousel,
  .day-strip {
    mask-image: linear-gradient(to right, transparent, #000 16px, #000 calc(100% - 40px), transparent);
  }
}

/* A computer, or a tablet on its side: the sections move to the top, as on Playtomic's web, in a bar that stays
   while the page scrolls; the column widens to show more tee times per row; and sheets open as dialogs in the middle
   of the screen, since nothing is within a thumb's reach of the bottom edge. */
@media (min-width: 960px) {
  :root {
    --tab-bar-height: 0px;
    /* Stuck things (the filter bar, an hour's heading) stop under the top bar, not behind it. */
    --top-bar-height: 76px;
  }
  #app {
    overflow-x: clip;
  }
  /* The home's guides follow the view's column; "#view +" outranks their own 640 px, which comes later in the file. */
  #view,
  #view + .home-guides {
    max-width: 860px;
  }
  /* The top bar as the prototype draws it (ux/lanes/final, 1200 px): across the window, 76 px tall, 28 px in from
     each edge; the brand, the tabs on their 400 px felt pill, then the 440 x 50 search box with the area's chip, then
     ES | EN (the prototype has none; the app keeps it, small) and the account. It is clear felt over the screen at
     rest, and takes the felt's deepest green once the page scrolls under it (app/capsule.ts's data-scrolled), so the
     words stay readable over what passes. */
  .brand-bar {
    position: sticky;
    top: 0;
    z-index: 25;
    display: flex;
    align-items: center;
    gap: 14px;
    max-width: none;
    height: var(--top-bar-height);
    padding: 0 28px;
  }
  .brand-bar::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background: rgb(7 42 29 / 0.94);
    opacity: 0;
    transition: opacity var(--duration-quick) var(--ease);
  }
  .brand-bar[data-scrolled]::before {
    opacity: 1;
  }
  .brand-bar .brand {
    flex: none;
    gap: 8px;
    letter-spacing: -0.02em;
  }
  .brand-bar .wordmark {
    letter-spacing: inherit;
  }
  .brand-bar .brand-mark {
    width: 28px;
    height: 28px;
  }
  .capsule {
    display: contents;
  }
  .search-open,
  .search-hint,
  .search-close,
  .brand-tools .area-switch {
    display: none;
  }
  /* The prototype has no ES | EN: it is re-homed in the room the prototype leaves between the tabs and the search
     box, so the box and the account keep the prototype's places. Its Tab stop stays among the tools'. */
  .brand-tools {
    display: contents;
  }
  /* The tools keep their size; the tabs' pill and the search box give room when the window is narrow. */
  .brand-tools .language-switch {
    order: 1;
    flex-shrink: 0;
    margin-left: auto;
  }
  .search-field {
    order: 2;
  }
  .brand-tools .account-button {
    order: 3;
    flex-shrink: 0;
  }
  .tab-bar {
    flex: 0 1 400px;
    height: 52px;
    min-width: 0;
  }
  .tab-pill {
    background: linear-gradient(180deg, rgb(18 70 50 / 0.94), rgb(6 34 23 / 0.96));
    box-shadow:
      inset 0 1px 0 rgb(255 255 255 / 0.16),
      inset 0 0 0 1px rgb(255 255 255 / 0.07),
      0 18px 36px -16px rgb(0 0 0 / 0.75);
  }
  .tab-lens {
    background: linear-gradient(180deg, rgb(255 255 255 / 0.24), rgb(255 255 255 / 0.1));
    box-shadow:
      inset 0 1px 0 rgb(255 255 255 / 0.4),
      inset 0 -1px 0 rgb(0 0 0 / 0.15),
      0 4px 14px -4px rgb(0 0 0 / 0.45);
  }
  .tab-bar a {
    min-width: 48px;
    color: rgb(244 247 243 / 0.74);
    font-size: 14.5px;
  }
  .tab-label {
    font-size: calc(14.5px * var(--label-fit, 1));
  }
  .tab-in {
    flex-direction: row;
    gap: 8px;
  }
  .tab-bar svg {
    width: 20px;
    height: 20px;
  }
  .search-field {
    position: relative;
    inset: auto;
    flex: 0 1 440px;
    min-width: 0;
    height: 50px;
    padding: 0 20px 0 6px;
    gap: 10px;
    visibility: visible;
  }
  .search-field-ground {
    border-radius: 25px;
    box-shadow: 0 14px 28px -16px rgb(0 0 0 / 0.8);
  }
  .search-field:focus-within .search-field-ground {
    box-shadow:
      0 0 0 2.5px var(--paper-action),
      0 14px 28px -16px rgb(0 0 0 / 0.8);
  }
  .search-area {
    min-height: 38px;
    border-radius: 24px;
  }
  .search-glass {
    margin-left: 0;
  }
  .search-input {
    height: 44px;
    font-size: 15.5px;
  }
  /* The week on a computer, as the prototype's desktop window: the hero 330 px from the window's top, under the top
     bar (which lies on its photo until the page scrolls, R1's data-scrolled); the words 44 px into the 1200 px column,
     the numeral up to 128 px; the rails' tiles 132 px wide. */
  .week-body {
    --week-gutter: 44px;
  }
  .hero {
    height: 330px;
    margin-top: calc(-1 * var(--top-bar-height));
  }
  .hero-main {
    right: calc(max(0px, (100% - 1200px) / 2) + 44px);
    bottom: 30px;
    left: calc(max(0px, (100% - 1200px) / 2) + 44px);
  }
  .hero-slot {
    min-height: calc(128px * 0.84 + 20px);
  }
  .hero-count,
  .hero-count-halo {
    margin: 12px 0 8px -0.032em;
    font-size: min(128px, calc((100cqi - 96px) / var(--numeral-ems, 3) * 0.96));
  }
  .hero-count-halo {
    margin-bottom: 0;
  }
  .hero-weather {
    right: calc(max(0px, (100% - 1200px) / 2) + 44px);
    bottom: 38px;
  }
  .hero-photo {
    top: calc(var(--top-bar-height) + 8px);
    right: calc(max(0px, (100% - 1200px) / 2) + 44px);
  }
  .tee-times-row .tee-time,
  .tile-skeleton {
    flex-basis: 132px;
  }
  /* A mouse can't scroll a row sideways: on a wide screen the filters all show, wrapping if they must. */
  .filter-scroll {
    flex-wrap: wrap;
    overflow: visible;
    mask-image: none;
  }
  .proposal-pill {
    bottom: 28px;
  }
  body.has-proposal #toast {
    bottom: 88px;
  }
}
/* The arrows a mouse uses to move a row sideways (kit/rail-arrows.ts), one pair that follows the pointer. */
.rail-arrow {
  position: fixed;
  z-index: 5;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  padding: 0;
  border: 1px solid var(--stroke);
  border-radius: 50%;
  background: var(--bg-1);
  box-shadow: var(--elevation-2);
  color: var(--fg);
  cursor: pointer;
  transform: translateY(-50%);
}
.rail-arrow.right {
  transform: translate(-100%, -50%);
}
.rail-arrow[hidden] {
  display: none;
}
.rail-arrow .icon {
  width: 18px;
  height: 18px;
}
.rail-arrow:hover {
  border-color: var(--stroke-strong);
}

/* A mouse or trackpad: what can be clicked says so when the pointer is on it. Only here, so a tap never leaves a
   hover look behind, and never in the colours of what is chosen (ink) or pressed. */
@media (hover: hover) and (pointer: fine) {
  .chart-hit:hover {
    fill: rgb(16 36 27 / 0.06);
  }
  .chip:not([aria-pressed="true"], .is-set):hover,
  .action-tile:not([aria-pressed="true"]):hover,
  .icon-button.round:hover {
    border-color: var(--stroke-strong);
  }
  .action-tile:not([aria-pressed="true"]):hover,
  :is(button, a).option:not([aria-pressed="true"]):hover,
  .area-list .area-option:not([aria-pressed="true"]):hover,
  .today-over:hover {
    background: var(--bg-2);
  }
  .tee-time:not(.more):hover {
    border-color: var(--action);
  }
  .tee-time.more:hover {
    background: var(--action-tint-strong);
  }
  .conditions-toggle:hover .conditions-caret {
    color: var(--fg);
  }
  .button.primary:hover {
    background: var(--action-strong);
  }
  .button.soft:hover {
    background: var(--action-tint-strong);
  }
  .button.ghost:hover {
    background: var(--action-tint);
  }
  .day-link:hover .day-name,
  .saved-search-run:hover .grow b,
  .course-block .course-name-button:hover {
    text-decoration: underline;
    text-decoration-thickness: 2px;
    text-underline-offset: 4px;
  }
  .inline-link:hover {
    text-decoration: underline;
    text-underline-offset: 3px;
  }
  .segmented button:not([aria-pressed="true"]):hover,
  .language-switch button:not([aria-pressed="true"]):hover,
  .tab-bar a:not([aria-current="page"]):hover {
    color: #ffffff;
  }
  .area-switch:hover,
  .search-area:hover {
    background: var(--stroke);
  }
  .search-area:hover {
    background: var(--paper-stroke);
  }
  .day-pill:not([aria-current="date"]):hover .day {
    border-color: var(--stroke-strong);
  }
  .day-pill.is-today:not([aria-current="date"]):hover .day {
    border-color: var(--action-strong);
  }
  .saved-search .icon-button:hover,
  .proposal-list .icon-button:hover,
  .registration-acts .icon-button:hover {
    background: var(--bg-3);
  }
  /* On photos and on the fairway: a darker or a lighter glass. */
  .sheet:has(.photo-header) .sheet-close:hover,
  .photo-count:hover {
    background: rgb(10 20 15 / 0.75);
  }
  .viewer-close:hover {
    background: rgb(255 255 255 / 0.22);
  }
  .viewer-thumb:not([aria-current="true"]):hover {
    opacity: 0.8;
  }
  /* The proposal is always ink, so pointed at it lightens a shade instead. */
  .proposal-pill:hover {
    background: color-mix(in srgb, var(--ink) 86%, #ffffff);
  }
  .club-card:hover {
    box-shadow: var(--elevation-2);
  }
  .club-card:hover .club-card-photo img {
    transform: scale(1.03);
  }
  .club-card .star:hover {
    background: #ffffff;
  }
  .club-card .star:not([aria-pressed="true"]):hover {
    color: var(--fg-2);
  }
  .home-guides .pill-links a:hover {
    background: var(--action-tint-strong);
  }
  .home-guides .link-row a:hover {
    text-decoration: underline;
  }
}

/* ------------------------------------------------------------ the home's guides */
/*
 * After <main id="view">, where the app never draws (the build puts it there from src/site/pages/info-pages.ts,
 * homeShellContent): what the app does in a line, the area guides and the rest of the site. A search engine that runs
 * the app reads it too; on 12 Oct 2026 a render of the home with /api/ blocked, as robots.txt asks, showed only the
 * unloaded week, because the router drew over what the build had put inside the view. Its words are Spanish (the English
 * home is /en), so it shows before the app starts and under Horarios in Spanish; every other screen stays as it was.
 */
.home-guides {
  display: none;
  width: 100%;
  max-width: 640px;
  margin: 0 auto;
  padding: 8px 16px calc(var(--tab-bar-height) + var(--safe-bottom) + 32px);
}
html[lang="es"] #view:not([data-screen]) + .home-guides,
html[lang="es"] #view[data-screen="week"] + .home-guides {
  display: block;
}
/* Before the app starts the view is empty: the guides sit under the brand bar, not at the foot of the window. */
#view:not([data-screen]) {
  flex: none;
  padding-bottom: 0;
}
/* Under Horarios the guides end the page, so they, not the week, keep clear of the tab bar and the proposal pill. */
html[lang="es"] #view[data-screen="week"]:has(+ .home-guides) {
  padding-bottom: 0;
}
body.has-proposal .home-guides {
  padding-bottom: calc(var(--tab-bar-height) + var(--safe-bottom) + 90px);
}
/* A hairline after the week's last footnote: the screen is over, and this is the way on. */
#view[data-screen="week"] + .home-guides::before {
  content: "";
  display: block;
  height: 1px;
  margin: 16px 0 20px;
  background: var(--stroke);
}
.home-guides h2 {
  margin: 0 0 6px;
  font: 700 17px/22px var(--font);
  letter-spacing: -0.005em;
  color: var(--fg);
}
.home-guides .lede {
  margin: 0;
  font-size: 14px;
  line-height: 20px;
  color: var(--fg-muted);
}
.home-guides h3 {
  margin: 20px 0 8px;
  font: 700 12px/16px var(--font);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--fg-muted);
}
.home-guides ul {
  display: flex;
  flex-wrap: wrap;
  margin: 0;
  padding: 0;
  list-style: none;
}
/* The area guides as green pills, drawn 40 px tall; a transparent ::after takes the tap to 44 px, short of the next row. */
.home-guides .pill-links {
  gap: 8px;
}
.home-guides .pill-links a {
  position: relative;
  display: inline-flex;
  align-items: center;
  height: 40px;
  padding: 0 14px;
  border-radius: var(--radius-pill);
  background: var(--action-tint);
  color: var(--action-strong);
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
}
.home-guides .pill-links a::after {
  content: "";
  position: absolute;
  inset: -2px 0;
}
.home-guides .pill-links .muted {
  margin-left: 4px;
  color: var(--action-strong);
  font-weight: 500;
}
/* The rest of the site, quieter: a row of text links, each 44 px tall, from the left like the rest of the block (the
   course sheet's .link-row is centred). */
.home-guides .link-row {
  justify-content: flex-start;
  gap: 0 18px;
}
.home-guides .link-row a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--action-strong);
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
}

/* ------------------------------------------------------------ reduced motion */
/* Last in the file, so it wins over every animation and transition above, the dialogs' from 960 px included. */
@media (prefers-reduced-motion: reduce) {
  .skeleton,
  .tile-skeleton,
  .skeleton-hero,
  .skeleton-tile,
  .admin-body.switched,
  .first-paint .chart-plot svg,
  .first-paint .sparkline svg,
  .first-paint .chart-bar,
  .spinning,
  .check-result,
  .proposal-pill,
  .photo-viewer[open],
  .search-hint,
  .live-dot::before,
  .hero-count.settling,
  .hero-count-halo.settling,
  .day-numeral.settling,
  .day-count-skeleton,
  .poster-time.settling,
  .hero-number.settling,
  .invitation-sheet.open .poster,
  .invitation-sheet.open .spot-left i,
  .hero-count-skeleton,
  .pull-indicator::before,
  #view[data-entering] *,
  .flag,
  .sc-bar.reading {
    animation: none !important;
  }
  .hero-backdrop canvas,
  .hero-backdrop img,
  .photo img,
  .viewer-photo img,
  .club-card,
  .club-card-photo img,
  .tee-time,
  .sc-bar,
  .chip,
  .segmented button,
  .tab-pill,
  .search-open-disc,
  .tab-lens-track,
  .tab-in,
  .search-open svg,
  .mini-head,
  .party-picker i,
  .filter-bar::before,
  .sheet.booking-sheet,
  .sheet.invitation-sheet,
  .spot i,
  .day-pill .day {
    transition: none;
  }
}
