/* Netti — base application styles. Reads exclusively from tokens.css custom properties. */

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family: var(--font-body);
  font-weight: var(--font-weight-regular);
  font-size: var(--text-caption);
  color: var(--color-text);
  background: var(--color-bg);
}

/* Big display headings (page H1/greeting) stay light — the whisper-weight
 * editorial feel the size alone should carry. Card/section h3 titles get
 * the heavier weight instead, since at 18px "light" reads as thin rather
 * than elegant and titles need to anchor their card. */
h1, h2 {
  font-family: var(--font-heading);
  font-weight: var(--font-weight-light);
  letter-spacing: var(--tracking-heading);
  margin: 0 0 var(--spacing-16);
}

h3 {
  font-family: var(--font-heading);
  font-weight: var(--font-weight-semibold);
  letter-spacing: var(--tracking-heading);
  margin: 0 0 var(--spacing-16);
}

a {
  color: var(--color-accent);
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: color 0.15s ease;
}

/* Plain content links — the design doc's only stated hover rule ("active
   state may show a subtle color shift") applied here directly: a slightly
   lightened accent instead of a second color or an underline change. */
a:hover {
  color: color-mix(in srgb, var(--color-accent) 80%, white);
}

/* Primary entity name in a list row (e.g. the athlete name in a table) —
 * no underline, semibold, so it visually anchors the row instead of
 * reading at the same weight as everything around it. */
.entity-name {
  text-decoration: none;
  font-weight: var(--font-weight-semibold);
  font-size: 15px;
}

/* Reference link to another record's own page (an athlete/coach/group/court
   name shown inline elsewhere) — same accent color as a content link, but
   no underline. These show up densely (a whole roster of names in one
   card), where every one underlined reads as noise rather than the
   design doc's "sparingly, for the one or two most important links". */
.entity-link {
  text-decoration: none;
}

/* Quiets a secondary/repeated reference (a court name tacked onto a
   schedule line, one name among a whole roster) down to plain text color
   instead of the accent — same link, just not fighting for attention next
   to the one or two links per card that actually matter. Hover still
   confirms it's clickable via a color shift, just not into the accent
   (that's reserved for links that keep full accent color at rest). */
.entity-link-muted {
  color: var(--color-text-secondary);
}

.entity-link-muted:hover {
  color: var(--color-text);
}

/* Structural links (nav, card-as-link, buttons) opt out of the accent
   treatment via their own class/inline style — plain content links keep it,
   per the design system's "sparingly, for the one or two most important
   links per page" rule. */
.site-nav-logo,
.site-nav-pill a,
.btn,
.btn-ghost,
.card-link {
  text-decoration: none;
}

/* Whole-card and card-header links share this: no underline, inherited
   color by default, and a subtle color shift on hover — the design
   system's prescribed hover treatment for structural links ("active state
   may show a subtle color shift") instead of a shadow/elevation change. */
.card-link {
  color: inherit;
}

.card-link.kpi-numbered:hover h3,
.card-link.card-header-icon:hover h3 {
  color: var(--color-accent);
}

.stat-card.card-link {
  display: block;
}

/* Whole-card hover feedback — a background shift, not a shadow (the
   design system rules out elevation as a depth cue). Graphite-filled
   cards (.kpi-cta) darken slightly instead of going light. */
.card.card-link,
.stat-card.card-link {
  transition: background-color 0.15s ease;
}

.card.card-link:hover,
.stat-card.card-link:hover {
  background: var(--color-fog);
}

.card-link.kpi-cta:hover {
  background: #000000;
}

.container {
  max-width: var(--page-max-width);
  margin: 0 auto;
  padding: 0 var(--spacing-20);
}

.card {
  background: var(--color-canvas-white);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-signature);
  padding: var(--card-padding);
}

/* Dense utility card (detail-page forms, contact lists) — the doc's 40px
 * card padding is calibrated for spacious hero panels; small forms and
 * short lists inside that much padding read as "spread out" rather than
 * generous. Keeps the same surface/radius, just less air. */
.card-compact {
  padding: var(--spacing-20);
}

/* Featured content panels (list items that open into a detail page) are
   told apart from ordinary cards by surface color (Ash), not shape —
   every card shares the same asymmetric signature corner by default. */
.card-feature {
  background: var(--color-ash);
}

/* Data widget — white surface, floats with no shadow/border; needs an Ash
   band behind it for the surface contrast to read (see .surface-band). */
.stat-card {
  background: var(--color-canvas-white);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-signature);
  padding: var(--card-padding);
}

.surface-band {
  background: var(--color-ash);
  padding: var(--section-gap) 0;
}

.card-header-icon {
  display: flex;
  align-items: center;
  gap: var(--spacing-8);
  margin: 0 0 var(--spacing-16);
}

.card-header-icon svg {
  flex: none;
  color: var(--color-graphite);
}

.card-header-icon h3 {
  margin: 0;
}

/* One row in a card's primary list of records (members, entries, notes,
   contacts, etc). Gives each row a hairline divider instead of relying on
   margin alone — matches the divider already used for schedule/day blocks
   elsewhere. Last row drops the border so it doesn't double up against the
   card's own bottom edge. */
.list-row {
  margin: 0;
  padding: var(--spacing-8) 0;
  border-bottom: 1px solid var(--color-border);
}

.list-row:last-child {
  border-bottom: none;
}

/* Fallback for card titles where neither an icon nor a number makes
   sense (plain form cards: "new X" panels) — a small accent rule instead
   of leaving the title with no visual anchor at all. */
.card-title-rule {
  width: 32px;
  height: 2px;
  background: var(--color-accent);
  border: none;
  margin: 0 0 var(--spacing-12);
}

/* Numbered KPI tile — index + title + description/metric row. Shares
   .stat-card's surface/radius/padding so it reads as the same card family.
   Selector is fully qualified (not just .kpi-numbered) so it reliably
   beats .stat-card.card-link's own `display: block` below — two classes
   tie in specificity and lose to source order otherwise. That silent loss
   is exactly what broke this: .kpi-row's margin-top:auto bottom-alignment
   trick only means anything inside a real flex container — inside a block
   one it's a no-op, so the row just lands wherever normal flow puts it.
   Symptom: two KPI cards side by side whose numbers landed at different
   heights whenever one card had more content above the row (an eyebrow,
   a wrapping title) than the other. */
.stat-card.card-link.kpi-numbered {
  display: flex;
  flex-direction: column;
}

/* Decorative accent bar replacing the old "01/02/03/04" index numbers —
   roughly half the cap-height of --text-caption (14px), same spirit as
   .card-title-rule but a touch chunkier since it stands in for a number,
   not just a plain title underline. */
.kpi-index {
  display: block;
  width: 32px;
  height: 6px;
  border-radius: 2px;
  background: var(--color-accent);
  margin: 0 0 var(--spacing-8);
}

.kpi-cta .kpi-index {
  background: rgba(255, 255, 255, 0.6);
}

.kpi-numbered h3 {
  font-size: var(--text-subheading);
  margin: 0;
}

/* Bar + big metric share the top row — the number sits level with the
   accent bar instead of the title, so it reads as the card's headline;
   the title follows right after, close to the bar. */
.kpi-header-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: var(--spacing-8);
  margin-bottom: var(--spacing-8);
}

.kpi-header-row .kpi-index {
  margin-bottom: 0;
}

.kpi-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: var(--spacing-8);
  margin-top: auto;
}

.kpi-desc {
  font-size: var(--text-caption);
  color: var(--color-text-secondary);
  margin: 0;
}

.kpi-metric {
  font-family: var(--font-heading);
  letter-spacing: var(--tracking-heading);
  font-size: var(--text-heading-lg);
  line-height: 1;
  margin: 0;
  flex: none;
}

/* The one featured tile per row — reuses the Primary CTA Button treatment
   (Graphite fill, white text) at card scale, so it reads as "the
   different one" through color, matching every other card's shape. */
.kpi-cta {
  background: var(--color-graphite);
  color: var(--color-canvas-white);
}

.kpi-cta .kpi-desc {
  color: rgba(255, 255, 255, 0.75);
}

.kpi-cta .kpi-row {
  align-items: center;
}

.kpi-arrow {
  font-size: var(--text-subheading);
  line-height: 1;
}

.card-link.kpi-cta:hover h3 {
  color: var(--color-canvas-white);
}

.kpi-cta:hover .kpi-arrow {
  color: var(--color-accent);
}

.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-8);
  padding: 4px var(--spacing-12);
  border-radius: var(--radius-cards);
  font-size: var(--text-caption);
  font-weight: var(--font-weight-semibold);
}

.badge-success { background: color-mix(in srgb, var(--color-success) 12%, white); color: var(--color-success); }
.badge-warning { background: color-mix(in srgb, var(--color-warning) 12%, white); color: var(--color-warning); }
.badge-danger  { background: color-mix(in srgb, var(--color-danger) 12%, white); color: var(--color-danger); }
.badge-neutral { background: var(--color-ash); color: var(--color-text-secondary); }
.badge-accent  { background: color-mix(in srgb, var(--color-accent) 12%, white); color: var(--color-accent); }
.badge-tennis  { background: color-mix(in srgb, var(--color-accent-tennis) 12%, white); color: var(--color-accent-tennis); }
.badge-padel   { background: color-mix(in srgb, var(--color-accent-padel) 12%, white); color: var(--color-accent-padel); }

/* Small eyebrow label above a page H1 — the persistent
   "Ψηφιακή Γραμματεία · season" branding strip. */
.page-eyebrow {
  font-family: var(--font-eyebrow);
  font-weight: var(--font-weight-medium);
  letter-spacing: 0.04em;
  color: var(--color-accent);
  font-size: var(--text-caption);
  text-transform: uppercase;
  margin: 0 0 var(--spacing-8);
}

/* The eyebrow doubles as a "back to tournament" link on the public bracket
   and registration pages — plain uppercase micro-label look, no underline,
   same as it had as static text. */
a.page-eyebrow {
  display: inline-block;
  text-decoration: none;
}

/* Level/status filter row — same pill vocabulary as the nav container,
   with a Graphite-filled "selected" state matching the Primary CTA.
   Stays on one line and scrolls horizontally on narrow screens instead
   of wrapping (same pattern as .bracket) — wrapping pushed page content
   down unpredictably as pills were added/removed per page. */
.filter-pills {
  display: flex;
  flex-wrap: nowrap;
  gap: var(--spacing-8);
  padding: var(--spacing-20) 0;
  overflow-x: auto;
  scrollbar-width: none;
}

.filter-pills::-webkit-scrollbar {
  display: none;
}

.filter-pill {
  flex: none;
}

.filter-pill {
  display: inline-flex;
  padding: 6px var(--spacing-16);
  border-radius: var(--radius-nav-pills);
  background: var(--color-ash);
  color: var(--color-text);
  font-family: var(--font-heading);
  font-size: var(--text-caption);
  text-decoration: none;
  white-space: nowrap;
}

.filter-pill.is-active {
  background: var(--color-graphite);
  color: var(--color-canvas-white);
}

/* Quick-contact tags (call / Viber) next to a name in a table row. */
.contact-tag {
  display: inline-flex;
  align-items: center;
  padding: 3px var(--spacing-8);
  border-radius: var(--radius-cards);
  font-family: var(--font-body);
  font-size: 11px;
  font-weight: var(--font-weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.02em;
  text-decoration: none;
  margin-right: 6px;
  margin-bottom: var(--spacing-8);
}

/* Call/Viber get their own light functional tint (not the page accent) so
   they read as recognizable quick actions at a glance — a deliberate,
   narrow exception to the "no extra chromatic colors" rule, same
   precedent as the success/warning/danger status colors. */
.contact-tag-call {
  background: color-mix(in srgb, var(--color-success) 12%, white);
  color: var(--color-success);
}

.contact-tag-viber {
  background: color-mix(in srgb, #7360f2 12%, white);
  color: #7360f2;
}

.contact-tag-email {
  background: var(--color-fog);
  color: var(--color-text-secondary);
}

.contact-tag:hover {
  filter: brightness(1.1);
}

/* Financial status traffic-light dot — color plus a short text label, per
   the project's accessibility rule (never color alone). */
.status-dot {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--text-caption);
  color: var(--color-text-secondary);
}

.status-dot::before {
  content: '';
  width: 9px;
  height: 9px;
  border-radius: 50%;
  flex: none;
}

.status-dot.dot-success::before { background: var(--color-success); }
.status-dot.dot-warning::before { background: var(--color-warning); }
.status-dot.dot-danger::before { background: var(--color-danger); }

/* Row needing attention (e.g. a new registration awaiting placement) —
   the doc's Ivory wash, reserved for "featured/urgent" blocks. */
.row-attention td {
  background: var(--color-ivory);
}

.row-attention td:first-child {
  box-shadow: inset 3px 0 0 var(--color-accent);
}

/* td backgrounds paint over the <tr>, so the plain tr[data-href]:hover
   rule never shows on an ivory row — give it its own, slightly lighter,
   hover tone instead of losing the hover feedback entirely. */
tr[data-href].row-attention:hover td {
  background: color-mix(in srgb, var(--color-ivory) 85%, white 8%);
}

/* Buttons: uppercase + Geologica semibold reads more like a UI control at
 * small button sizes than the light weight used for big headings. */
.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-8);
  padding: 10px 20px;
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: var(--font-weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.02em;
  /* Scaled-down version of the card signature shape — 20px reads fine on
     a card, but on a ~40px-tall button it would swallow half the height. */
  border-radius: 10px 0 0 0;
  border: 1px solid var(--color-graphite);
  background: var(--color-graphite);
  color: var(--color-canvas-white);
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease;
}

/* Solid buttons darken slightly on hover — same "background shift, no
   shadow" language as the card hover treatment, not a separate rule. */
.btn:not(.btn-ghost):not(.btn-plain):hover {
  background: #000000;
}

.btn-ghost {
  background: transparent;
  color: var(--color-graphite);
}

/* Outlined buttons fill with a light background on hover, mirroring how
   whole cards get a background shift instead of a shadow/border change. */
.btn-ghost:hover {
  background: var(--color-fog);
}

/* Borderless button for dense repeated contexts (one per table row) where
   the standard bordered pill, repeated many times down a column, reads as
   visual noise rather than a set of distinct actions. */
.btn-plain {
  border: none;
  background: transparent;
  color: var(--color-accent);
}

.btn-plain:hover {
  color: color-mix(in srgb, var(--color-accent) 80%, white);
}

/* Icon-only button (nav logout) — square padding instead of the text
   pill's asymmetric horizontal padding, so it reads as a distinct control
   next to adjacent text buttons rather than an unlabeled version of one. */
.btn-icon {
  padding: 10px;
}

/* Plain back-navigation arrow above a show page's eyebrow — replaces a
   bulky "ΠΙΣΩ" button so the header's one visible button can be the page's
   real action (e.g. "Επεξεργασία") instead of competing with back nav. */
.back-link {
  display: inline-flex;
  color: var(--color-text-muted);
  margin: 0 0 var(--spacing-8);
}

.back-link:hover {
  color: var(--color-accent);
}

/* Tints native form-control chrome (checkboxes, radios, range, and the
   select dropdown's own highlight color in Chromium) to the accent orange
   instead of the OS/browser default blue — these controls are rendered by
   the OS, not our CSS, so accent-color is the only lever available. */
select, input[type="checkbox"], input[type="radio"], input[type="range"] {
  accent-color: var(--color-accent);
}

.field {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-8);
  margin-bottom: var(--spacing-16);
}

.field label {
  font-size: var(--text-caption);
  color: var(--color-text-secondary);
}

.field input,
.field select,
.field textarea {
  height: 42px;
  padding: 0 var(--spacing-12);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-cards);
  font-family: var(--font-body);
  font-size: 16px;
}

.field textarea {
  height: auto;
  padding: var(--spacing-12);
}

.field input:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 1px;
}

.error-message {
  color: var(--color-danger);
  font-size: var(--text-caption);
  margin-bottom: var(--spacing-16);
}

/* One-time flash shown to a viewer/demo account right after a write it
   attempted was intercepted (see Router::dispatch()) — sits above
   everything, including the nav, so it reads on every page regardless of
   what redirected here. */
.demo-notice {
  background: var(--color-graphite);
  color: var(--color-canvas-white);
  text-align: center;
  padding: var(--spacing-8) var(--spacing-20);
  font-size: var(--text-caption);
  font-weight: var(--font-weight-semibold);
  margin: 0;
}

.auth-shell {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-surface);
}

.auth-shell .card {
  width: 360px;
}

/* Public registration wizard (register/step{1,2,3}.php) — two-column
   layout (intro + step progress on the left, the actual form card on the
   right) instead of a single narrow stacked card, so a multi-field step
   doesn't read as sparse. Collapses to one column on mobile. */
.register-shell {
  min-height: 100vh;
  background: var(--color-surface);
  padding: var(--spacing-40) var(--spacing-20);
}

.register-shell-grid {
  max-width: 1080px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr 1.6fr;
  gap: var(--spacing-40);
  align-items: start;
}

@media (max-width: 720px) {
  .register-shell-grid {
    grid-template-columns: 1fr;
  }
}

.register-fields {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--spacing-16);
}

@media (max-width: 480px) {
  .register-fields {
    grid-template-columns: 1fr;
  }
}

/* Step 3 (consents) info cards — one per topic (regulation, GDPR,
   photo/video) instead of a single undifferentiated paragraph blob. */
.register-info-card {
  background: var(--color-surface);
  border-radius: var(--radius-cards);
  padding: var(--spacing-16);
  margin-bottom: var(--spacing-16);
}

.register-info-card h3 {
  font-size: var(--text-subheading);
  margin: 0 0 var(--spacing-8);
}

.register-info-card ul {
  margin: 0;
  padding-left: var(--spacing-20);
}

.register-info-card li {
  margin-bottom: var(--spacing-8);
}

.register-info-card li:last-child {
  margin-bottom: 0;
}

/* Each consent as its own tinted row instead of a plain checkbox+label
   line — easier to scan which ones are required vs optional. */
.consent-row {
  display: flex;
  align-items: flex-start;
  gap: var(--spacing-8);
  background: color-mix(in srgb, var(--color-accent) 6%, white);
  border-radius: var(--radius-cards);
  padding: var(--spacing-12) var(--spacing-16);
  margin-bottom: var(--spacing-8);
}

.consent-row input[type="checkbox"] {
  width: auto;
  height: auto;
  margin-top: 4px;
  flex-shrink: 0;
}

.consent-row label {
  margin: 0;
}

@media (max-width: 480px) {
  .register-fields {
    grid-template-columns: 1fr;
  }
}

/* Public landing page ("/") — same centered-card idea as .auth-shell, but
   in a column layout so a footer can sit pinned at the bottom of the
   viewport instead of being pushed off-screen below a 100vh center block. */
.landing-shell {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--color-surface);
}

.landing-shell-main {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}

.landing-footer {
  text-align: center;
  color: var(--color-text-muted);
  font-size: var(--text-caption);
  padding: var(--spacing-20) 0;
}

/* Discrete app-wide footer for every authenticated page. The margin-top
   is the breathing room below whatever content came before it — pages
   were ending abruptly right at the last card/table with no air. */
.app-footer {
  text-align: center;
  color: var(--color-text-muted);
  font-size: 12px;
  margin: var(--section-gap) 0 0;
  padding: var(--spacing-20) 0;
  border-top: 1px solid var(--color-border);
}

.search-bar {
  width: 100%;
  height: 48px;
  padding: 0 var(--spacing-16);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-nav-pills);
  font-size: 16px;
  font-family: var(--font-body);
}

/* Single-line filter bar: search grows, selects/button stay their
   natural width, wraps to a second line only if the viewport is tight. */
.filter-row {
  display: flex;
  gap: var(--spacing-8);
  align-items: center;
  flex-wrap: wrap;
  padding: 0 0 var(--spacing-20);
}

.filter-row .search-bar {
  flex: 1;
  min-width: 220px;
}

.filter-row select {
  height: 48px;
  border-radius: var(--radius-cards);
  border: 1px solid var(--color-border);
  flex: none;
}

/* Whole-element navigation: any [data-href] becomes clickable via the
   tiny script in app.js — table rows and cards alike. Cards get the same
   background-shift hover as .card-link; rows just tint. Applies
   site-wide — any future card/row just needs data-href. */
[data-href] {
  cursor: pointer;
}

tr[data-href]:hover {
  background: var(--color-fog);
}

.card[data-href]:hover,
.stat-card[data-href]:hover {
  background: var(--color-fog);
}

.site-nav {
  background: var(--color-canvas-white);
  border-bottom: 1px solid var(--color-border);
}

.site-nav-inner {
  max-width: var(--page-max-width);
  margin: 0 auto;
  padding: var(--spacing-12) var(--spacing-20);
  display: flex;
  align-items: center;
  gap: var(--spacing-20);
}

.site-nav-logo {
  font-family: var(--font-heading);
  font-size: var(--text-subheading);
  font-weight: var(--font-weight-regular);
  color: var(--color-graphite);
  text-decoration: none;
}

/* One unified bar background (the nav's own white) — items sit directly
   on it rather than floating inside a separate Ash pill container. Only
   the active item gets its own pill, so it's the thing that stands out. */
.site-nav-pill {
  display: flex;
  align-items: center;
  gap: var(--spacing-8);
  flex: 1;
}

.site-nav-pill a {
  text-decoration: none;
  font-family: var(--font-heading);
  font-size: 14px;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--color-graphite);
  padding: var(--spacing-8) var(--spacing-16);
  border-radius: var(--radius-nav-pills);
  transition: background-color 0.15s ease;
}

.site-nav-pill a.is-active {
  background: var(--color-ash);
  color: var(--color-graphite);
}

/* Not-yet-active nav items get the same light fill on hover, so the pill
   nav feels responsive before a click lands — skipped for the item
   that's already active since it's already filled. */
.site-nav-pill a:hover:not(.is-active) {
  background: var(--color-fog);
}

.site-nav-actions {
  display: flex;
  gap: var(--spacing-12);
  align-items: center;
}

.site-nav-inner form {
  margin: 0;
}

/* Least emphasis of the nav's right-side actions — plain text, no button
   chrome, same idea as a bare "sign out" link sitting apart from any
   filled/outlined action buttons. */
.site-nav-inner .btn-ghost {
  border: none;
  padding: var(--spacing-8) 0;
  color: var(--color-text-secondary);
}

.site-nav-inner .btn-ghost:hover {
  color: var(--color-graphite);
}

.site-nav-burger {
  display: none;
  background: none;
  border: none;
  padding: var(--spacing-8);
  margin-left: auto;
  color: var(--color-graphite);
  cursor: pointer;
}

/* Toggled to display:block by the shared [data-toggle] handler — stays
   plain block/block-children (no flex) so that generic toggle, which only
   ever sets 'block' or 'none', is enough to lay this out correctly. */
.site-nav-mobile {
  display: none;
  border-top: 1px solid var(--color-border);
  padding: 0 var(--spacing-20) var(--spacing-8);
}

.site-nav-mobile a,
.site-nav-mobile button {
  display: block;
  width: 100%;
  font-family: var(--font-heading);
  font-size: 14px;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  text-align: left;
  color: var(--color-graphite);
  text-decoration: none;
  background: none;
  border: none;
  border-bottom: 1px solid var(--color-border);
  padding: var(--spacing-12) 0;
  cursor: pointer;
}

.site-nav-mobile a.is-active {
  color: var(--color-accent);
}

.site-nav-mobile form {
  margin: 0;
}

.site-nav-mobile form button {
  border-bottom: none;
}

/* Same breakpoint as .workspace-grid's mobile collapse, so the whole
   layout (nav + page content) shifts to mobile shape together. */
@media (max-width: 720px) {
  .site-nav-pill,
  .site-nav-actions {
    display: none;
  }

  .site-nav-burger {
    display: inline-flex;
  }
}

.workspace-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--spacing-12) var(--spacing-20);
  padding: var(--spacing-20) 0;
  border-bottom: 1px solid var(--color-border);
}

.workspace-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--spacing-20);
  padding: var(--spacing-40) 0;
}

/* Per-page column counts are set inline (grid-template-columns) since they
   vary by content (2, 3, N courts...) — !important is needed here to win
   over that inline style at narrow widths. */
@media (max-width: 720px) {
  .workspace-grid {
    grid-template-columns: 1fr !important;
  }

  /* KPI/stat-card grids (small title + big number) stay multi-column and
     just reflow instead of stacking to one-per-row — unlike content-heavy
     grids, two of these side by side is still perfectly readable on a
     phone. Used by the athletes-page and dashboard KPI rows. */
  .workspace-grid.kpi-grid {
    grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)) !important;
  }
}

.empty-state {
  color: var(--color-text-muted);
  font-size: var(--text-caption);
}

/* Knockout bracket tree — connector lines drawn with plain CSS, no JS/SVG.
   Each round is a flex column; a round's matches are grouped into pairs
   (except the final), and each pair grows a "]"-shaped connector on its
   right edge reaching into the midpoint that lines up with the single
   match it feeds in the next round. */
.bracket {
  display: flex;
  align-items: stretch;
  gap: 48px;
  overflow-x: auto;
  padding: var(--spacing-20) 0;
}

.bracket-round {
  display: flex;
  flex-direction: column;
  min-width: 220px;
}

.bracket-round-matches {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  gap: var(--spacing-16);
}

.bracket-pair {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  gap: var(--spacing-16);
  position: relative;
}

.bracket-pair::after {
  content: '';
  position: absolute;
  top: 25%;
  bottom: 25%;
  right: -25px;
  width: 24px;
  border-top: 2px solid var(--color-border);
  border-right: 2px solid var(--color-border);
  border-bottom: 2px solid var(--color-border);
}

.bracket-round:last-child .bracket-match {
  margin: auto 0;
}

.bracket-match {
  background: var(--color-canvas-white);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-signature);
  padding: var(--spacing-12);
}

/* Tournament round columns (knockout staff view) — a 2-column grid so
   each screen shows two rounds side by side with room to breathe; extra
   rounds wrap to the next row below rather than requiring horizontal
   scroll. Collapses to a single column on mobile. */
.tournament-rounds {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--spacing-20);
}

@media (max-width: 720px) {
  .tournament-rounds {
    grid-template-columns: 1fr;
  }
}

/* Match row: pair pills in a fixed-width first column, so the
   schedule/score column lines up at the same x position on every row
   instead of drifting with each pill's own (variable) text width. */
.tournament-match-row {
  display: grid;
  grid-template-columns: 170px 1fr;
  gap: var(--spacing-12);
  align-items: flex-start;
}

.entry-pill {
  display: inline-block;
  padding: var(--spacing-8) var(--spacing-16);
  border-radius: var(--radius-nav-pills);
  background: var(--color-surface);
  font-weight: var(--font-weight-medium);
  text-transform: uppercase;
}

.entry-pill[draggable="true"] {
  cursor: grab;
}

.entry-pill[draggable="true"]:hover {
  filter: brightness(1.06);
}

.entry-pill.drag-over {
  outline: 2px dashed var(--color-accent);
  outline-offset: 2px;
}

/* Public tournament presentation page — the one public-facing screen in
 * the app that's meant to persuade a stranger to sign up, not just inform
 * a logged-in staffer, so it deliberately breaks from the plain admin look
 * (photography, full-bleed hero, dark sections) while staying inside
 * Netti's own tokens (Ember accent, Graphite dark surface, Geologica type)
 * instead of copying another club's exact palette.
 */
.tp-hero {
  position: relative;
  min-height: 50vh;
  display: flex;
  align-items: flex-end;
  overflow: hidden;
  background: var(--color-graphite);
  color: var(--color-canvas-white);
}

.tp-hero-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: saturate(0.9) brightness(0.8);
}

.tp-hero-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(32,32,32,0.15) 0%, rgba(32,32,32,0.6) 55%, rgba(32,32,32,0.97) 100%);
}

.tp-hero-nav {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 3;
  display: flex;
  align-items: center;
  gap: var(--spacing-12);
  padding: var(--spacing-16) var(--spacing-20);
}

.tp-hero-logo-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--color-canvas-white);
  padding: var(--spacing-8) var(--spacing-12);
  border-radius: var(--radius-cards);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
}

.tp-day-menu {
  background: var(--color-graphite);
  border-top: 1px solid rgba(255, 255, 255, 0.12);
}

.tp-day-menu-inner {
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-8);
  max-width: 1080px;
  margin: 0 auto;
  padding: var(--spacing-12) var(--spacing-20);
}

.tp-day-menu a {
  display: inline-flex;
  padding: 6px var(--spacing-16);
  border-radius: var(--radius-nav-pills);
  background: rgba(255, 255, 255, 0.1);
  color: var(--color-canvas-white);
  font-family: var(--font-eyebrow);
  font-size: var(--text-caption);
  text-decoration: none;
  white-space: nowrap;
}

.tp-day-menu a:hover {
  background: var(--color-accent);
}

.tp-hero-nav .club-name {
  font-family: var(--font-eyebrow);
  font-size: var(--text-caption);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-canvas-white);
}

.tp-hero-content {
  position: relative;
  z-index: 2;
  width: 100%;
  padding: var(--spacing-40) var(--spacing-20);
}

.tp-hero-inner,
.tp-section-inner {
  max-width: 1080px;
  margin: 0 auto;
}

.tp-hero-eyebrow {
  font-family: var(--font-eyebrow);
  font-size: var(--text-subheading);
  color: var(--color-accent);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.tp-hero-title {
  font-family: var(--font-heading);
  font-weight: var(--font-weight-semibold);
  letter-spacing: var(--tracking-display);
  line-height: var(--leading-display);
  font-size: clamp(2.6rem, 8vw, var(--text-display));
  margin: var(--spacing-8) 0 0;
}

.tp-hero-date {
  color: var(--color-accent);
  font-weight: var(--font-weight-semibold);
  font-size: var(--text-subheading);
  margin: var(--spacing-16) 0 0;
}

.tp-hero-card {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--spacing-24);
  background: var(--color-canvas-white);
  color: var(--color-text);
  border-radius: var(--radius-cards);
  padding: var(--spacing-16) var(--spacing-24);
  margin-top: var(--spacing-20);
}

.tp-hero-card strong {
  color: var(--color-accent);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.tp-hero-card-label {
  display: block;
  font-size: var(--text-caption);
  color: var(--color-text-secondary);
}

.tp-hero-card-value {
  font-weight: var(--font-weight-semibold);
}

.tp-hero-card .btn {
  background: var(--color-accent);
  border-color: var(--color-accent);
  margin-left: auto;
}

.tp-hero-card .btn:hover {
  filter: brightness(0.9);
}

.tp-section {
  padding: var(--spacing-60) var(--spacing-20);
}

.tp-section.dark {
  background: var(--color-graphite);
  color: var(--color-canvas-white);
}

.tp-section-title {
  font-family: var(--font-heading);
  font-weight: var(--font-weight-semibold);
  font-size: var(--text-heading-lg);
  margin: 0 0 var(--spacing-24);
}

.tp-category-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--spacing-20);
}

@media (max-width: 640px) {
  .tp-category-grid { grid-template-columns: 1fr; }
}

.tp-category-card {
  background: var(--color-steel);
  border-radius: var(--radius-signature);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.tp-category-card:hover {
  transform: translateY(-3px);
  box-shadow: 0 12px 24px rgba(0, 0, 0, 0.3);
}

.tp-category-body {
  padding: var(--spacing-24) var(--spacing-24) var(--spacing-24);
  display: flex;
  flex-direction: column;
  gap: var(--spacing-12);
  flex: 1;
}

.tp-category-body h3 {
  margin: 0;
  color: var(--color-canvas-white);
  font-size: var(--text-heading);
}

.tp-category-meta {
  font-size: var(--text-caption);
  font-family: var(--font-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-accent);
}

/* Wraps the card's 1-2 buttons (Ταμπλό always, Δήλωση Συμμετοχής while
   registration_open() allows it) — margin-top:auto lives here now, on the
   row itself, since with two buttons side by side neither individual .btn
   is a direct flex child of the column anymore. */
.tp-category-actions {
  display: flex;
  gap: var(--spacing-8);
  flex-wrap: wrap;
  margin-top: auto;
}

/* .btn-ghost's default graphite-on-transparent styling is illegible on
   this card's mid-grey background — same problem the dashboard's dark
   CTA card solved by overriding just the bits that need to invert. */
.tp-category-body .btn-ghost {
  color: var(--color-canvas-white);
  border-color: var(--color-canvas-white);
}

.tp-category-body .btn-ghost:hover {
  background: rgba(255, 255, 255, 0.12);
}

/* The card's one filled button is its primary CTA (join this category) —
   giving it the accent color instead of the default graphite makes it
   read as the clear next action next to the ghost "Ταμπλό" link, and
   puts the club's own color somewhere in the card instead of nowhere. */
.tp-category-body .btn:not(.btn-ghost) {
  background: var(--color-accent);
  border-color: var(--color-accent);
}

.tp-category-body .btn:not(.btn-ghost):hover {
  filter: brightness(0.9);
}

.tp-rules-text {
  font-size: var(--text-subheading);
  line-height: 1.7;
  color: var(--color-mist);
}

.tp-cta-banner {
  position: relative;
  overflow: hidden;
  min-height: 34vh;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
}

.tp-cta-banner-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: saturate(0.9) brightness(0.5);
}

.tp-cta-banner-scrim {
  position: absolute;
  inset: 0;
  background: rgba(32,32,32,0.5);
}

.tp-cta-banner-content {
  position: relative;
  z-index: 2;
  color: var(--color-canvas-white);
  padding: var(--spacing-20);
}

.tp-cta-banner-content h2 {
  font-family: var(--font-heading);
  font-weight: var(--font-weight-semibold);
  font-size: clamp(1.8rem, 5vw, var(--text-heading-lg));
  margin: var(--spacing-8) 0 var(--spacing-20);
}

.tp-footer {
  background: var(--color-graphite);
  color: var(--color-canvas-white);
  padding: var(--spacing-40) var(--spacing-20);
}

.tp-footer-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--spacing-16);
}

.tp-footer a {
  color: var(--color-canvas-white);
}

.tp-footer a:hover {
  color: var(--color-accent);
}

.tp-footer-copy {
  color: var(--color-mist);
  font-size: var(--text-caption);
}

/*
 * Per-tournament club theme overrides — scoped to a body class set by
 * TournamentController::CLUB_THEMES so only that tournament's public
 * pages (hero, dark sections, buttons, footer — all built on
 * --color-accent/--color-graphite) pick up the club's own colors. The
 * staff UI and every other tournament are unaffected since tokens.css
 * itself isn't touched.
 */
.tp-club-sythas {
  --color-accent: #3B8FE0;
  --color-graphite: #0E1B33;
}

.tp-club-sythas .tp-sponsors {
  background: var(--color-graphite);
  color: var(--color-canvas-white);
  --color-border: rgba(255, 255, 255, 0.3);
  --color-text-muted: rgba(255, 255, 255, 0.7);
}

.tp-club-korinthou {
  --color-accent: #E8821E;
  --color-graphite: #0E3A52;
}

.tp-club-korinthou .tp-sponsors {
  background: var(--color-graphite);
  color: var(--color-canvas-white);
  --color-border: rgba(255, 255, 255, 0.3);
  --color-text-muted: rgba(255, 255, 255, 0.7);
}
