/* ============================================================
   GymXYZ — the few pieces the prototype got from the design
   system's React components (inline styles, not a stylesheet):
   Card, Avatar, and the login screen.
   Same rule as everywhere else: var(--*) only, never a literal.
   ============================================================ */

/* ---------- Card (design-system Card) ---------- */
.gx-card {
  position: relative;
  background: var(--surface-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.gx-card > .spark {
  position: absolute; inset-inline: 0; top: 0; height: 3px;
  background: var(--gradient-spark);
}

/* KPI subtitle — the prototype styles it inline. */
.gx-kpi .sub { font-size: var(--text-xs); color: var(--text-muted); margin-top: 4px; }

/* Delta tones. Status colours carry meaning and are never themed. */
.gx-tone-success { color: var(--color-success); }
.gx-tone-warning { color: var(--color-warning); }
.gx-tone-danger  { color: var(--color-danger); }
.gx-tone-brand   { color: var(--color-primary); }
.gx-tone-neutral { color: var(--text-muted); }

/* ---------- Avatar (design-system Avatar) ---------- */
.gx-avatar {
  display: inline-grid; place-items: center; flex: none;
  width: 34px; height: 34px;
  border-radius: var(--radius-circle);
  background: var(--azure-50);
  color: var(--azure-700);
  font-size: var(--text-xs);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  user-select: none;
}
.gx-avatar.sm { width: 30px; height: 30px; font-size: var(--text-2xs); }
.gx-avatar.md { width: 40px; height: 40px; font-size: var(--text-sm); }
.gx-avatar.lg { width: 56px; height: 56px; font-size: var(--text-xl); }
.gx-avatar.xl { width: 72px; height: 72px; font-size: var(--text-2xl); }

/* ---------- Quick actions on a mobile record ----------
   The prototype draws these as divs; here they are real buttons and links, so
   the browser's own chrome has to go. Behaviour, not decoration. */
.gx-m-circbtn { border: 0; padding: 0; background: none; font-family: inherit; text-decoration: none; }
.gx-m-circbtn[aria-disabled="true"] { opacity: .45; pointer-events: none; }

/* ---------- Coach card ----------
   The prototype draws the card as a div with an onClick; here it is a real
   button so the keyboard can reach it. Behaviour, not decoration. */
button.gx-coach-card { width: 100%; text-align: left; color: inherit; }

/* ---------- Drawer form layout ----------
   The prototype writes these two as inline styles on its Field / FieldRow
   helpers; here they are named so the markup stays readable. Layout only. */
.gx-form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-bottom: 14px; }
.gx-form-field { margin-bottom: 14px; }
@media (max-width: 560px) {
  .gx-form-row { grid-template-columns: 1fr; }
}

/* ---------- « Pointer » on a planning slot ----------
   The prototype draws an outline Button here. This is a link — it goes to the
   sheet's own address, so it has to be right-clickable and openable in a tab —
   which means undoing the anchor's chrome and borrowing the button's shape.
   Layout only; every value is a token. */
.gx-daypoint {
  display: inline-flex; align-items: center; gap: 6px;
  height: 30px; padding: 0 12px;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  background: var(--surface-card);
  color: var(--text-strong);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  text-decoration: none;
  white-space: nowrap;
}
.gx-daypoint:hover { background: var(--surface-sunken); }

/* ---------- Attendance sheet: the sticky action bar ----------
   mobile.css positions .gx-m-stickyfoot at bottom:0 with z-index 8, and
   .gx-m-tabbar at bottom:0 with z-index 9 — they land on top of each other.

   They do not collide in the prototype because its roster is a whole screen
   that replaces the tab bar. This shell keeps the tab bar on every sub-screen,
   as every other record does, so the bar is lifted clear of it instead.

   81px is the tab bar's measured height — 8px of padding, 53px of icon and
   label, 20px below — and the safe area is added on top because the tab bar
   reserves it too. Measured rather than derived: the first guess was 72 and the
   two bars overlapped by nine pixels, right where the thumb lands.

   Layout only, which is why it lives here rather than in the hand-off CSS. */
.gx-m-stickyfoot { bottom: calc(81px + env(safe-area-inset-bottom)); }

/* The body already reserves room for the tab bar; the sheet needs the action
   bar's height on top, or the last member on the roster sits underneath it. */
.gx-m-body:has(.gx-m-attendance) { padding-bottom: 178px; }

/* ---------- Login (design-system LoginScreen) ---------- */
.gx-login {
  min-height: 100vh;
  display: grid;
  grid-template-columns: 1fr 1fr;
}
.gx-login-brand {
  position: relative; overflow: hidden;
  background: var(--gradient-ink);
  color: var(--neutral-0);
  padding: var(--space-9);
  display: flex; flex-direction: column; justify-content: space-between;
}
.gx-login-brand::before {
  content: ""; position: absolute; inset: 0;
  background-image: radial-gradient(circle at 1px 1px, var(--surface-brand-soft) 1px, transparent 0);
  background-size: 26px 26px;
  opacity: .08;
}
.gx-login-brand > * { position: relative; }
.gx-login-brand .gx-wordmark,
.gx-login-brand .mark { color: var(--neutral-0); }
.gx-login-brand h2 {
  font-family: var(--font-display, var(--font-sans));
  font-size: calc(var(--text-3xl) * var(--display-title-scale, 1));
  font-weight: var(--display-weight, var(--weight-bold));
  letter-spacing: var(--display-ls, var(--tracking-tight));
  text-transform: var(--display-tr, none);
  color: var(--neutral-0);
  line-height: 1.2;
  margin: 0 0 14px;
}
.gx-login-brand p { color: var(--neutral-200); font-size: var(--text-lg); max-width: 38ch; }
.gx-login-brand .foot { font-size: var(--text-xs); color: var(--neutral-400); }

.gx-login-pane {
  background: var(--surface-page);
  display: flex; align-items: center; justify-content: center;
  padding: var(--space-7);
}
.gx-login-form {
  width: 100%; max-width: 360px;
  display: flex; flex-direction: column; gap: 18px;
}
.gx-login-form h1 {
  font-family: var(--font-display, var(--font-sans));
  font-size: calc(var(--text-2xl) * var(--display-title-scale, 1));
  font-weight: var(--display-weight, var(--weight-bold));
  letter-spacing: var(--display-ls, var(--tracking-tight));
  text-transform: var(--display-tr, none);
  color: var(--text-strong);
  margin: 0 0 6px;
}
.gx-login-form .lead { color: var(--text-muted); font-size: var(--text-sm); }
.gx-login-form .err {
  background: var(--color-danger-soft);
  color: var(--danger-700);
  border-radius: var(--radius-md);
  padding: 10px 12px;
  font-size: var(--text-sm);
}
.gx-login-form .field { display: flex; flex-direction: column; gap: 6px; }
.gx-login-form label {
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  color: var(--text-muted);
}

@media (max-width: 820px) {
  .gx-login { grid-template-columns: 1fr; }
  .gx-login-brand { display: none; }
}

/* ---------- Blazor's unhandled-error bar ----------
   Framework markup, styled by the project in the default template. This app
   dropped that stylesheet for the hand-off CSS, so the bar had no rule at all
   and sat visible at the bottom of every page — error or not.

   Hidden here, and dressed so the one time it does appear it looks like part of
   the product. Blazor reveals it by setting display:block inline, which wins
   over the rule below; the same is true of the reconnect UI, which this app
   replaces with its own ReconnectModal. */
#blazor-error-ui {
  display: none;
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  z-index: var(--z-toast);
  padding: 14px 46px 14px 18px;
  background: var(--color-danger-soft);
  color: var(--danger-700);
  border-top: 1px solid var(--color-danger);
  box-shadow: var(--shadow-md);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
}
#blazor-error-ui .reload {
  color: inherit;
  text-decoration: underline;
  margin-inline-start: 6px;
}
#blazor-error-ui .dismiss {
  position: absolute;
  top: 10px;
  inset-inline-end: 16px;
  cursor: pointer;
  font-size: var(--text-md);
  line-height: 1;
  padding: 4px;
}

/* ---------- Réglages save bar ---------- */
/* The prototype styles .gx-savebar as a plain card, while both hand-off
   documents call it "collante". Layout-only, so it lands here rather than in
   app.css: the panel above it can be long, and a save button that scrolls out
   of reach is a save button people stop finding. */
.gx-savebar-sticky {
  position: sticky;
  bottom: 0;
  z-index: 2;
}

/* ---------- "You asked for another space" notice ----------
   Shown above the screen when the address named a customer this account has no
   access to. A strip and not a modal: nothing is broken, they are simply not
   where they typed, and the screen underneath is theirs to use. */
.gx-elsewhere {
  display: flex; align-items: center; gap: 10px;
  margin-bottom: 16px; padding: 10px 14px;
  border: 1px solid var(--border-subtle); border-radius: var(--radius-md);
  background: var(--surface-sunken); color: var(--text-body);
  font-size: var(--text-sm);
}
.gx-elsewhere svg { flex: none; color: var(--text-muted); }
.gx-elsewhere b { color: var(--text-strong); font-weight: var(--weight-semibold); }

/* ---------- "Plus" sheet: keep the two columns inside the screen ---------- */
/* .gx-m-plusgrid is 1fr 1fr, and its items are grid items — so they carry the
   default min-width:auto and refuse to shrink below their longest word. On a
   375px screen a cell leaves 88px for the label while "Administration" needs
   110px, so the grid grew wider than the sheet and the whole thing scrolled
   sideways. The prototype has the same six labels and the same rule, so this is
   a hand-off gap rather than a deviation.

   Two layout-only rules. The tile becomes a query container, which both lets it
   shrink to its track and lets the label below ask how much room it actually
   has. Then the long wording gives way to the short one — "Abonnements" to
   "Abos", "Administration" to "Admin." — only on a tile too narrow for it.

   188px is where the longest label stops fitting: the tile spends 14px of
   padding either side, 38px of icon and a 12px gap before the text starts, and
   "Administration" needs 110px after that. Two columns on a 375px screen give
   167px a tile, so the short wording shows there; a wide phone or a tablet keeps
   the full one.

   A descendant and not a child: « Se déconnecter » posts, so its tile is wrapped
   in a form. The form is display:contents — the button is the grid item — but a
   child combinator reads the document, not the layout, so ">" stopped matching
   and the tile lost its container. The symptom was the long wording hyphenated
   over three lines while every other tile was on one. */
.gx-m-plusgrid .gx-m-plusitem {
  container-type: inline-size;
  min-width: 0;
}

.gx-m-plusitem .tt .t .short { display: none; }

@container (max-width: 187px) {
  .gx-m-plusitem .tt .t .long { display: none; }
  .gx-m-plusitem .tt .t .short { display: inline; }
}

/* « Se déconnecter » takes the whole foot of the grid. Not decoration: it is the
   only tile that is not a destination, the others come in pairs and a seventh
   would leave a hole beside it, and at half a track even the short wording broke
   over two lines while every neighbour sat on one.

   The rule lands on the button and not on the form around it: the form is
   display:contents, so the button is the grid item and grid-column belongs to
   the thing the grid actually places. */
.gx-m-plusgrid .gx-signout .gx-m-plusitem { grid-column: 1 / -1; }

/* Any label still too long for its tile wraps rather than pushing the grid
   sideways — a locale with longer words must not bring the overflow back. */
.gx-m-plusitem .tt .t {
  overflow-wrap: break-word;
  hyphens: auto;
}

/* ---------- Customer row (Administration) ----------
   The console's client list. The prototype has no drawing for it — it only ever
   shows one customer — so the row is assembled from pieces the hand-off does
   have: a .gx-listrow, and the .sw swatch of a .gx-theme-card.

   Layout only, as everywhere else: the swatch, the name and the caption all take
   their colours from the tokens, and each row carries its own data-theme so the
   swatch shows that customer's brand rather than the one being served. */
.gx-customer-row {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 2px 0;
  background: none;
  border: 0;
  text-align: left;
  font-family: inherit;
  cursor: pointer;
  border-radius: var(--radius-sm);
}

.gx-customer-row .sw {
  flex: none;
  width: 34px;
  display: flex;
  border-radius: var(--radius-sm);
  overflow: hidden;
  box-shadow: 0 0 0 1px rgba(12, 34, 54, .08);
}

.gx-customer-row .sw i { height: 34px; flex: 1; }

.gx-customer-row .main { flex: 1; min-width: 0; }

.gx-customer-row .t {
  display: block;
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
  color: var(--text-strong);
}

.gx-customer-row .s {
  display: block;
  font-size: var(--text-xs);
  color: var(--text-muted);
  margin-top: 2px;
}

.gx-customer-row.on .t { color: var(--color-primary); }

.gx-customer-row:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}
