/*
 * Sayd Portal — design tokens lifted verbatim from docs/04-app-ux-motion.md §1–§2 so the
 * portal, the app and the pitch deck read as one product.
 * ~32 screens of forms and tables: no build step, no component framework, just this.
 *
 * RTL-first. Every directional rule uses logical properties (inline-start/end), never
 * left/right — the portal is Arabic-native, not a mirrored LTR design.
 */

/* ── Type ──────────────────────────────────────────────────────────────────────────
 * Cairo ships as a self-hosted variable font (wght 200–1000) rather than a Google Fonts
 * link: the portal runs on the club's own box and must render correctly with no egress.
 * Before this, both families were named in font-family but neither was ever loaded, so
 * every screen fell back to the system Arabic face.
 */

@font-face {
  font-family: 'Cairo';
  src: url('/assets/fonts/cairo-var.woff2') format('woff2-variations'),
       url('/assets/fonts/cairo-var.woff2') format('woff2');
  font-weight: 200 1000;
  font-style: normal;
  font-display: swap;
}

:root {
  /* Brand — docs/04 §1 */
  --ink: #07142B;
  --ink-2: #0C2247;
  --navy: #123566;
  --navy-soft: #1B4A8C;
  --gold: #C9A227;
  --gold-2: #E8CC6A;
  --sky: #3E8CE0;
  --mint: #16B981;
  --rose: #E0556B;
  --paper: #FFFFFF;
  --paper-2: #F7F8FB;
  --paper-3: #EFF2F7;
  --line: #E3E8F0;
  --txt: #0E1A2B;
  --txt-2: #4A5A72;
  /* docs/04 §1 lists --txt-3 as #7C8AA0. That is 3.5:1 on white and 3.1:1 on --paper-3,
     below WCAG AA for body text, and it carries most of the portal's secondary copy —
     table headers, hints, member numbers, KPI labels. Darkened to the lightest value
     that clears 4.5:1 on the darkest surface it is used on; still visibly the third step
     down from --txt-2. */
  --txt-3: #636E80;

  /* --sky is reserved as series-1 and validated for CVD in docs/04 §2, so it is left
     alone; text links get their own darker step because #3E8CE0 is 3.5:1 on white. */
  --link: #2F6DB0;

  /* Reserved status colours — never reused as a series colour. These are the fill, dot
     and border values from docs/04 §1, unchanged. */
  --good: #0ca30c;
  --warning: #fab219;
  --serious: #ec835a;
  --critical: #d03b3b;

  /* …and the text steps of the same hues. `good` is 3.4:1 as text on white and `critical`
     4.2:1 on its own tint, so status *text* uses these. Same hue, same meaning, readable
     — and every status still ships with an icon and a label, never colour alone. */
  --good-text: #077007;
  --warning-text: #8a5c00;
  --serious-text: #a3421a;
  --critical-text: #b02f2f;

  /* Categorical series — fixed order, hard cap 3, never cycled (docs/04 §2) */
  --series-1: #3E8CE0;
  --series-2: #C9A227;
  --series-3: #16B981;

  /* Sequential ramp (magnitude), one hue, light → dark */
  --seq-1: #cde2fb;
  --seq-2: #9ec5f4;
  --seq-3: #6da7ec;
  --seq-4: #3987e5;
  --seq-5: #2a78d6;
  --seq-6: #256abf;
  --seq-7: #184f95;

  /* Brand override point — set per-club from the branding screen, which writes
     --brand-primary into the document head. It used to be emitted and then referenced by
     nothing, so the colour an admin picked never appeared anywhere in the portal.
     `--brand-soft` is the hover/active step derived from it; the literal fallback keeps
     the navy default on engines without color-mix(). */
  --brand-primary: #123566;
  --brand-soft: #1B4A8C;
  --brand-soft: color-mix(in oklab, var(--brand-primary) 82%, white);
  --brand-tint: rgba(18, 53, 102, 0.08);
  --brand-tint: color-mix(in oklab, var(--brand-primary) 10%, transparent);

  /* Radii + shadows */
  --r-s: 8px;
  --r-m: 14px;
  --r-l: 22px;
  --r-xl: 32px;
  --sh-s: 0 1px 2px rgba(7, 20, 43, 0.06), 0 1px 1px rgba(7, 20, 43, 0.04);
  --sh-m: 0 4px 12px rgba(7, 20, 43, 0.08), 0 2px 4px rgba(7, 20, 43, 0.04);
  --sh-l: 0 12px 32px rgba(7, 20, 43, 0.12), 0 4px 8px rgba(7, 20, 43, 0.04);

  /* 4px base grid */
  --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px;
  --s-5: 20px; --s-6: 24px; --s-8: 32px; --s-10: 40px;

  /* Type scale */
  --t-xs: 11.5px; --t-sm: 12.5px; --t-md: 13.5px; --t-base: 14px;
  --t-lg: 16px;   --t-xl: 18px;   --t-2xl: 22px;  --t-hero: 52px;

  /* Motion — docs/04 §4.2. Durations and curves are tokens so nothing is eyeballed. */
  --e-out: cubic-bezier(0.16, 1, 0.3, 1);
  --e-out-cubic: cubic-bezier(0.215, 0.61, 0.355, 1);
  --e-in-out-cubic: cubic-bezier(0.645, 0.045, 0.355, 1);
  --e-back: cubic-bezier(0.34, 1.56, 0.64, 1);
  --t-instant: 90ms;
  --t-quick: 160ms;
  --t-base-d: 240ms;
  --t-move: 320ms;
  --t-expressive: 480ms;
  --stagger: 50ms;

  --sidebar-w: 252px;
  --content-max: 1560px;
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: 'IBM Plex Sans Arabic', 'Cairo', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  background: var(--paper-2);
  color: var(--txt);
  direction: rtl;
  font-size: var(--t-base);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

h1, h2, h3, h4 { font-family: 'Cairo', 'IBM Plex Sans Arabic', sans-serif; margin: 0 0 var(--s-2); color: var(--ink); line-height: 1.35; }
h1 { font-size: var(--t-2xl); font-weight: 700; letter-spacing: -0.01em; }
h2 { font-size: var(--t-xl); font-weight: 700; }
h3 { font-size: 15px; font-weight: 600; }
p { margin: 0 0 var(--s-3); color: var(--txt-2); }
a { color: var(--link); text-decoration: none; }
a:hover { text-decoration: underline; }

/* One visible focus treatment for the whole portal. Keyboard users get a ring on
   everything; pointer users never see it. */
:focus-visible {
  outline: 2px solid var(--sky);
  outline-offset: 2px;
  border-radius: 4px;
}
.sidebar :focus-visible { outline-color: var(--gold-2); }

.skip-link {
  position: absolute;
  inset-inline-start: -9999px;
  top: var(--s-2);
  z-index: 60;
  background: var(--ink);
  color: #fff;
  padding: var(--s-2) var(--s-4);
  border-radius: var(--r-s);
  font-size: var(--t-md);
  font-weight: 600;
}
.skip-link:focus { inset-inline-start: var(--s-4); text-decoration: none; }

/* ── Shell ─────────────────────────────────────────────────────────────────────── */

.shell { display: flex; min-height: 100vh; }

.sidebar {
  width: var(--sidebar-w);
  flex-shrink: 0;
  background: var(--ink);
  color: #fff;
  padding: var(--s-5) 0 var(--s-8);
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: rgba(255,255,255,.18) transparent;
}
.sidebar::-webkit-scrollbar { width: 8px; }
.sidebar::-webkit-scrollbar-thumb { background: rgba(255,255,255,.16); border-radius: 8px; }

.sidebar__brand {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: 0 var(--s-5) var(--s-5);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  margin-bottom: var(--s-4);
}
.sidebar__brand img { width: 34px; height: 34px; border-radius: var(--r-s); object-fit: cover; flex-shrink: 0; }
.sidebar__brand strong { font-family: 'Cairo', sans-serif; font-size: 16px; font-weight: 800; line-height: 1.35; }

.nav-group { padding: 0 var(--s-3); margin-bottom: var(--s-5); }
.nav-group__label {
  font-family: 'Cairo', sans-serif;
  font-size: 12px; color: rgba(255,255,255,0.66);
  padding: 0 var(--s-2) var(--s-2); letter-spacing: .04em; font-weight: 700;
}

/* Light-on-dark optically thins a typeface, and Arabic loses more than Latin does — the
   thin joins and diacritics are the first thing to go. Cairo is a variable font here, so
   the sidebar takes a genuinely heavier cut (600, 700 when active) at a slightly larger
   size, rather than the body weight the rest of the portal uses on white.
   `letter-spacing` is deliberately untouched: tracking breaks Arabic letter joining. */
.nav-link {
  position: relative;
  display: flex; align-items: center; gap: var(--s-3);
  padding: 10px var(--s-3); border-radius: var(--r-s);
  color: rgba(255,255,255,0.86);
  font-family: 'Cairo', 'IBM Plex Sans Arabic', sans-serif;
  font-size: 14.5px; font-weight: 600; line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  transition: background var(--t-quick) var(--e-out-cubic), color var(--t-quick) var(--e-out-cubic);
}
.nav-link:hover { background: rgba(255,255,255,0.09); text-decoration: none; color: #fff; }

/* Exactly one link is active — it is matched on the request path, not on a section key
   shared by half a dozen screens (which used to light all of them at once). */
.nav-link.is-active { background: var(--brand-soft, var(--navy-soft)); color: #fff; font-weight: 700; }
.nav-link.is-active::before {
  content: '';
  position: absolute;
  inset-inline-start: 0; top: 50%;
  transform: translateY(-50%);
  width: 3px; height: 18px;
  border-radius: 0 3px 3px 0;
  background: var(--gold);
}
.nav-link__count {
  margin-inline-start: auto;
  background: rgba(255,255,255,.14); color: #fff;
  font-size: 11px; font-weight: 700; line-height: 1;
  padding: 3px 6px; border-radius: 999px;
  font-variant-numeric: tabular-nums;
}
.nav-link__count--alert { background: rgba(208,59,59,.9); }

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.topbar {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-4);
  padding: var(--s-3) var(--s-6); background: var(--paper);
  border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 20;
}
/* Anchored to the end of the bar (the left corner, in RTL) so it stays put whether or
   not the drawer toggle is showing. */
.topbar__user { display: flex; align-items: center; gap: var(--s-3); font-size: 13px; color: var(--txt-2); margin-inline-start: auto; }
.topbar__name { font-weight: 600; color: var(--txt); }

.nav-toggle {
  display: none;
  align-items: center; justify-content: center;
  width: 40px; height: 40px; flex-shrink: 0;
  background: transparent; border: 1px solid var(--line);
  border-radius: var(--r-s); cursor: pointer; color: var(--txt);
}
.nav-toggle:hover { background: var(--paper-2); }
.nav-toggle svg { width: 18px; height: 18px; }

.nav-scrim {
  display: none;
  position: fixed; inset: 0; z-index: 30;
  background: rgba(7, 20, 43, 0.45);
  animation: fadeIn var(--t-move) var(--e-out-cubic);
}

/* The one place a max-width is set. It is centred, so a 2560px monitor shows a centred
   workspace instead of everything jammed against the sidebar with a dead half-screen. */
.content {
  padding: var(--s-6) var(--s-6) 72px;
  width: 100%;
  max-width: var(--content-max);
  margin-inline: auto;
  flex: 1;
}
/* Tables and reports earn the whole width; opt in per screen. */
.content--wide { max-width: none; }

.page-header { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: var(--s-5); gap: var(--s-4); flex-wrap: wrap; }
.page-header__actions { display: flex; gap: var(--s-2); flex-wrap: wrap; align-items: center; }

.breadcrumb { display: flex; align-items: center; gap: var(--s-2); font-size: var(--t-sm); color: var(--txt-3); margin-bottom: var(--s-2); }
.breadcrumb a { color: var(--txt-3); }
.breadcrumb a:hover { color: var(--navy); }

/* ── Cards & KPIs ──────────────────────────────────────────────────────────────── */

.card { background: var(--paper); border-radius: var(--r-m); box-shadow: var(--sh-s); padding: var(--s-5); border: 1px solid var(--line); transition: transform var(--t-base-d) var(--e-out-cubic), box-shadow var(--t-base-d) var(--e-out-cubic); }
.card + .card { margin-top: var(--s-4); }
.card:hover { transform: translateY(-2px); box-shadow: var(--sh-m); }
.card--flat:hover { transform: none; box-shadow: var(--sh-s); }
.card__head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-3); margin-bottom: var(--s-4); }
.card__head h3 { margin: 0; }

.grid { display: grid; gap: var(--s-4); }
.grid--kpi { grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }

.kpi {
  position: relative; overflow: hidden;
  padding: var(--s-5); border-radius: var(--r-m); background: var(--paper);
  box-shadow: var(--sh-s); border: 1px solid var(--line);
  transition: transform var(--t-base-d) var(--e-out-cubic), box-shadow var(--t-base-d) var(--e-out-cubic);
  /* The figures size against the tile, not the viewport: a six-figure total in a
     four-across KPI row otherwise runs the currency straight off the card edge, and no
     single fixed size is safe for both 800.00 and 1,234,567.89. */
  container-type: inline-size;
}
.kpi:hover { transform: translateY(-2px); box-shadow: var(--sh-m); }
.kpi__label { font-size: var(--t-sm); color: var(--txt-3); margin-bottom: var(--s-1); }
.kpi__value {
  font-family: 'Cairo', sans-serif; font-size: 30px; font-size: clamp(21px, 9.5cqi, 30px);
  font-weight: 700;
  color: var(--ink); font-variant-numeric: tabular-nums; line-height: 1.25;
  display: flex; align-items: baseline; gap: 4px; min-width: 0;
}
/* The currency rides alongside the figure at a smaller size instead of being part of it,
   so a six-digit total does not push "ج.م" onto a second line. */
.kpi__unit { font-size: 0.46em; font-weight: 600; color: var(--txt-3); white-space: nowrap; }
.kpi__delta { font-size: 12px; margin-top: var(--s-1); display: flex; align-items: center; gap: var(--s-1); }
.kpi__delta.is-up { color: var(--good-text); }
.kpi__delta.is-down { color: var(--critical-text); }
.kpi__delta.is-flat { color: var(--txt-3); }
.kpi__foot { margin-top: var(--s-3); }

/* The lead KPI carries the hero figure (docs/04 §2: "the lead number as a hero figure
   ≥48px"). One number per screen gets this — the rest stay at 30px or the hierarchy
   collapses. */
.kpi--hero { grid-column: span 1; }
.kpi--hero .kpi__value { font-size: var(--t-hero); font-size: clamp(30px, 14cqi, var(--t-hero)); letter-spacing: -0.02em; }
/* Gold is the brand's "premium moment" accent (docs/04 §1). A wash in the far corner
   from the label, anchored to the card so the gradient has no visible edge — the RTL
   inline-end corner is the left one, which is why the origin is 0 0. */
.kpi--hero::after {
  content: '';
  position: absolute; inset: 0;
  background: radial-gradient(circle at 0 0, rgba(201, 162, 39, .13), transparent 42%);
  pointer-events: none;
}

/* ── Charts (docs/04 §2) ───────────────────────────────────────────────────────────
 * Hand-rolled SVG, no charting library: the portal has no build step and must work on a
 * box with no internet, and the form vocabulary here is small and fixed by the doc —
 * sparkline, line, column, horizontal bar, meter. No pies, no donuts, no radar.
 */

.chart { position: relative; }
.chart svg { display: block; width: 100%; height: auto; overflow: visible; }
.chart__grid line { stroke: var(--line); stroke-width: 1; }
.chart__axis { fill: var(--txt-3); font-size: 11px; font-family: inherit; }
.chart__label { fill: var(--txt-2); font-size: 11.5px; font-family: inherit; font-variant-numeric: tabular-nums; }
/* The direct label sits over the series' own area fill, so it carries a surface-coloured
   halo painted behind the glyphs rather than relying on the fill being light enough. */
.chart__label--strong {
  fill: var(--txt); font-weight: 700;
  paint-order: stroke fill; stroke: var(--paper); stroke-width: 3.5px; stroke-linejoin: round;
}

/* Values and labels wear text tokens, never the series colour (docs/04 §2 mark specs). */
.chart__line { fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.chart__marker { stroke: var(--paper); stroke-width: 2; }
.chart__area { opacity: .12; }

/* Columns and bars grow from the baseline. transform only — never height (docs/04 §4.7). */
.chart__col, .chart__bar { transform-origin: var(--grow-origin, bottom); }
.chart__col rect, .chart__bar rect { rx: 4; }

.chart-anim .chart__col { animation: growY var(--t-expressive) var(--e-out-cubic) both; animation-delay: calc(var(--i, 0) * var(--stagger)); }
.chart-anim .chart__bar { animation: growX var(--t-expressive) var(--e-out-cubic) both; animation-delay: calc(var(--i, 0) * var(--stagger)); }
.chart-anim .chart__line { animation: drawLine 900ms var(--e-out-cubic) both; }
/* Its own keyframe rather than the generic fadeIn: `fill-mode: both` freezes the
   animation's final value, so ending on `opacity: 1` would override the .12 on the class
   and leave the area a solid slab of series colour. */
.chart-anim .chart__area { animation: areaIn 700ms var(--e-out-cubic) both; animation-delay: 260ms; }
.chart-anim .chart__marker { animation: popIn var(--t-base-d) var(--e-back) both; animation-delay: calc(700ms + var(--i, 0) * 40ms); }

@keyframes growY { from { transform: scaleY(0); } to { transform: scaleY(1); } }
@keyframes growX { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes drawLine { from { stroke-dashoffset: var(--len, 1000); } to { stroke-dashoffset: 0; } }
@keyframes popIn { from { opacity: 0; transform: scale(.4); } to { opacity: 1; transform: scale(1); } }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes areaIn { from { opacity: 0; } to { opacity: .12; } }

/* Hover layer: crosshair + tooltip on lines, per-mark tooltip on bars (docs/04 §2). */
.chart__hit { fill: transparent; cursor: crosshair; }
.chart__crosshair { stroke: var(--txt-3); stroke-width: 1; stroke-dasharray: 3 3; opacity: 0; pointer-events: none; }
.chart__hover-dot { opacity: 0; pointer-events: none; }
.chart.is-hovering .chart__crosshair, .chart.is-hovering .chart__hover-dot { opacity: 1; }
.chart__col:hover rect, .chart__bar:hover rect { filter: brightness(1.08); }

.chart-tip {
  position: absolute; z-index: 10;
  transform: translate(50%, -100%);
  background: var(--ink); color: #fff;
  padding: var(--s-2) var(--s-3); border-radius: var(--r-s);
  font-size: var(--t-sm); line-height: 1.5; white-space: nowrap;
  box-shadow: var(--sh-m); pointer-events: none;
  opacity: 0; transition: opacity var(--t-quick) var(--e-out-cubic);
}
.chart-tip.is-visible { opacity: 1; }
.chart-tip__value { font-weight: 700; font-variant-numeric: tabular-nums; }
.chart-tip__label { color: rgba(255,255,255,.7); font-size: var(--t-xs); }

.chart-legend { display: flex; flex-wrap: wrap; gap: var(--s-3); font-size: var(--t-sm); color: var(--txt-2); }
.chart-legend__item { display: inline-flex; align-items: center; gap: 6px; }
.chart-legend__dot { width: 9px; height: 9px; border-radius: 3px; flex-shrink: 0; }

/* The sparkline that belongs on every KPI tile per docs/04 §2 but was computed and then
   never rendered. */
.spark { display: block; width: 100%; height: 34px; overflow: visible; }
.spark__line { fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

/* A ratio against a limit is a meter, not a donut (docs/04 §2). */
.meter { display: flex; flex-direction: column; gap: 6px; }
.meter__head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-2); font-size: var(--t-sm); color: var(--txt-2); }
.meter__value { font-family: 'Cairo', sans-serif; font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; }
.meter__track { height: 10px; background: var(--paper-3); border-radius: 999px; overflow: hidden; }
.meter__fill {
  height: 100%; border-radius: 999px; background: var(--sky);
  transform-origin: right center; /* RTL: the meter fills from the start edge */
  animation: growX 700ms var(--e-out-cubic) both;
}
.meter__fill--good { background: var(--good); }
.meter__fill--warning { background: var(--warning); }
.meter__fill--critical { background: var(--critical); }
.meter__scale { display: flex; justify-content: space-between; font-size: var(--t-xs); color: var(--txt-3); font-variant-numeric: tabular-nums; }

/* A chart's obligatory table view (docs/04 §2 accessibility). */
.chart-table-toggle { background: none; border: none; padding: 0; color: var(--link); font: inherit; font-size: var(--t-sm); cursor: pointer; }
.chart-table-toggle:hover { text-decoration: underline; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ── Motion: entrance + polish ────────────────────────────────────────────────── */

.fade-in-up {
  animation: fadeInUp var(--t-expressive) var(--e-out-cubic) both;
  animation-delay: calc(var(--stagger-i, var(--stagger, 0)) * 1ms);
}
/* Views set `--stagger:N` as a plain integer; keep the historical contract working. */
[style*="--stagger"].fade-in-up { animation-delay: calc(var(--stagger) * 55ms); }

@keyframes fadeInUp {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Loading placeholder for panels that hydrate asynchronously. */
.skeleton {
  position: relative;
  overflow: hidden;
  background: var(--paper-3);
  border-radius: var(--r-s);
  color: transparent !important;
}
.skeleton::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.55), transparent);
  animation: skeletonSweep 1.4s ease-in-out infinite;
}
@keyframes skeletonSweep {
  from { transform: translateX(-100%); }
  to   { transform: translateX(100%); }
}

@media (prefers-reduced-motion: reduce) {
  .fade-in-up, [style*="--stagger"].fade-in-up { animation: none; opacity: 1; transform: none; }
  .card, .kpi, .nav-link { transition: none; }
  .card:hover, .kpi:hover { transform: none; }
  .skeleton::after { animation: none; }
  .chart-anim .chart__col,
  .chart-anim .chart__bar,
  .chart-anim .chart__line,
  .chart-anim .chart__area,
  .chart-anim .chart__marker,
  .meter__fill { animation: none; opacity: 1; transform: none; stroke-dashoffset: 0; }
  .nav-scrim, .drawer { animation: none; }
}

.bar-track { height: 6px; background: var(--paper-3); border-radius: 4px; overflow: hidden; margin-top: var(--s-2); }
.bar-fill { height: 100%; background: var(--sky); border-radius: 4px; transform-origin: right center; animation: growX var(--t-expressive) var(--e-out-cubic) both; }
@media (prefers-reduced-motion: reduce) { .bar-fill { animation: none; } }

/* ── Tables ────────────────────────────────────────────────────────────────────── */

.table-wrap { overflow-x: auto; background: var(--paper); border-radius: var(--r-m); box-shadow: var(--sh-s); border: 1px solid var(--line); }
table { width: 100%; border-collapse: collapse; font-size: var(--t-md); }
thead th {
  text-align: right; padding: var(--s-3) var(--s-4); background: var(--paper-2);
  color: var(--txt-3); font-weight: 600; font-size: 12px; white-space: nowrap;
  border-bottom: 1px solid var(--line);
}

/* The table view that every chart ships with (docs/04 §2). Sits inside a card, so it
   drops the card chrome the standalone tables carry. */
.table-mini { width: 100%; margin-top: var(--s-3); font-size: var(--t-sm); border-collapse: collapse; }
.table-mini th { text-align: right; padding: 5px var(--s-2); color: var(--txt-3); font-weight: 600; background: transparent; border-bottom: 1px solid var(--line); white-space: nowrap; }
.table-mini td { padding: 5px var(--s-2); border-bottom: 1px solid var(--paper-3); }
.table-mini tr:last-child td { border-bottom: none; }
tbody td { padding: 11px var(--s-4); border-bottom: 1px solid var(--paper-3); vertical-align: middle; }
tbody tr:last-child td { border-bottom: none; }
tbody tr { transition: background var(--t-instant) linear; }
tbody tr:hover { background: var(--paper-2); }
tbody tr.is-clickable { cursor: pointer; }
tbody tr.is-clickable:focus-visible { background: rgba(62,140,224,.08); outline: 2px solid var(--sky); outline-offset: -2px; }
.table-empty { padding: var(--s-10) var(--s-5); text-align: center; color: var(--txt-3); }
.num { font-variant-numeric: tabular-nums; }

.th-sort { color: var(--txt-3); font-weight: 600; }
.th-sort:hover { color: var(--navy); text-decoration: none; }
.th-sort.is-active { color: var(--navy); }
.th-sort__arrow { font-size: 9px; }

.row-actions { display: flex; gap: 6px; justify-content: flex-end; flex-wrap: nowrap; }
.row-actions form { display: inline; }

/* ── Badges ────────────────────────────────────────────────────────────────────── */

.badge { display: inline-flex; align-items: center; gap: 5px; padding: 3px 9px; border-radius: 999px; font-size: 12px; font-weight: 600; white-space: nowrap; }
.badge__icon { font-size: 8px; }
/* The reserved status hues stay exactly as docs/04 §1 defines them for fills, dots and
   borders. Badge *labels* sit on a 10–14% tint of their own hue, where the pure hue is
   3.0:1 (good) and 4.2:1 (critical), so the text takes a darker step of the same hue.
   The icon+label pairing from View::badge() still carries the meaning either way. */
.badge--good { background: rgba(12,163,12,0.1); color: var(--good-text); }
.badge--warning { background: rgba(250,178,25,0.14); color: var(--warning-text); }
.badge--serious { background: rgba(236,131,90,0.14); color: var(--serious-text); }
.badge--critical { background: rgba(208,59,59,0.1); color: var(--critical-text); }
.badge--neutral { background: var(--paper-3); color: var(--txt-2); }
.badge--gold { background: rgba(201,162,39,0.15); color: #8a5c00; }
.badge--info { background: rgba(62,140,224,0.1); color: var(--navy); }

/* ── Forms ─────────────────────────────────────────────────────────────────────── */

label { display: block; font-size: var(--t-sm); color: var(--txt-2); margin-bottom: 5px; font-weight: 600; }
.field { margin-bottom: var(--s-3); }
input, select, textarea {
  width: 100%; padding: 9px var(--s-3); border: 1px solid #DCE1EA; border-radius: var(--r-s);
  font-family: inherit; font-size: var(--t-md); background: var(--paper); color: var(--txt);
  transition: border-color var(--t-quick) var(--e-out-cubic), box-shadow var(--t-quick) var(--e-out-cubic);
}
input:hover:not(:disabled), select:hover:not(:disabled), textarea:hover:not(:disabled) { border-color: #C4CCDA; }
input:focus, select:focus, textarea:focus { outline: none; border-color: var(--sky); box-shadow: 0 0 0 3px rgba(62,140,224,0.15); }
input:disabled, select:disabled, textarea:disabled { background: var(--paper-2); color: var(--txt-3); cursor: not-allowed; }
textarea { resize: vertical; min-height: 80px; }
.field-row { display: flex; gap: var(--s-3); flex-wrap: wrap; }
.field-row > .field { flex: 1; min-width: 160px; }
.checkbox-row { display: flex; align-items: center; gap: var(--s-2); }
.checkbox-row input { width: auto; }
.checkbox-row label { margin: 0; font-weight: 500; }
.hint { font-size: var(--t-xs); color: var(--txt-3); margin-top: var(--s-1); }
.error-text { font-size: var(--t-xs); color: var(--critical-text); margin-top: var(--s-1); }

/* Segmented radio group — four attendance marks per player need to be one tap on a
   phone at poolside, with a target well over 48px, not four loose radio dots. */
.segmented { display: inline-flex; background: var(--paper-2); border: 1px solid var(--line); border-radius: 999px; padding: 3px; gap: 2px; }
.segmented__opt { position: relative; margin: 0; }
.segmented__opt input {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0; margin: 0; cursor: pointer;
}
.segmented__opt span {
  display: block; padding: 7px var(--s-3); border-radius: 999px;
  font-size: var(--t-sm); font-weight: 600; color: var(--txt-2);
  white-space: nowrap; text-align: center; min-width: 62px;
  transition: background var(--t-quick) var(--e-out-cubic), color var(--t-quick) var(--e-out-cubic);
}
.segmented__opt input:hover + span { background: rgba(7,20,43,.05); }
.segmented__opt input:focus-visible + span { outline: 2px solid var(--sky); outline-offset: 1px; }
/* Selected marks are filled with their status hue. Where white on that hue falls under
   4.5:1 the fill takes a darker step (present) or the label goes dark (late, excused) —
   the coach reads these at arm's length in sunlight. */
.segmented__opt input:checked + span { background: var(--paper); box-shadow: var(--sh-s); color: var(--ink); }
.segmented__opt input:checked + span.is-present { background: #0a890a; color: #fff; }
.segmented__opt input:checked + span.is-late { background: var(--warning); color: #4a3200; }
.segmented__opt input:checked + span.is-excused { background: var(--serious); color: #3d1d0b; }
.segmented__opt input:checked + span.is-absent { background: var(--critical); color: #fff; }

/* ── Buttons ───────────────────────────────────────────────────────────────────── */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 9px var(--s-4); border-radius: var(--r-s); font-size: var(--t-md); font-weight: 600;
  border: 1px solid transparent; cursor: pointer; font-family: inherit;
  transition: background var(--t-quick) var(--e-out-cubic), transform var(--t-instant) var(--e-out-cubic), box-shadow var(--t-quick) var(--e-out-cubic);
}
.btn:active:not([disabled]) { transform: translateY(1px); }
.btn--primary { background: var(--brand-primary, var(--navy)); color: #fff; }
.btn--primary:hover { background: var(--brand-soft, var(--navy-soft)); text-decoration: none; box-shadow: var(--sh-m); }
.btn--gold { background: var(--gold); color: var(--ink); }
.btn--gold:hover { background: var(--gold-2); text-decoration: none; }
.btn--danger { background: var(--critical); color: #fff; }
.btn--danger:hover { background: #b83232; text-decoration: none; }
.btn--ghost { background: transparent; color: var(--brand-primary, var(--navy)); border-color: #DCE1EA; }
.btn--ghost:hover { background: var(--paper-2); text-decoration: none; border-color: #C4CCDA; }
.btn--sm { padding: 5px 11px; font-size: var(--t-sm); }
.btn--lg { padding: 13px var(--s-6); font-size: 15px; }
.btn--block { width: 100%; }
.btn[disabled] { opacity: .5; cursor: not-allowed; }
@media (prefers-reduced-motion: reduce) { .btn { transition: none; } .btn:active { transform: none; } }

/* ── Tabs & pills ──────────────────────────────────────────────────────────────── */

.tabs { display: flex; gap: var(--s-1); border-bottom: 1px solid var(--line); margin-bottom: var(--s-5); flex-wrap: wrap; }
.tab { padding: 9px var(--s-4); font-size: 13px; font-weight: 600; color: var(--txt-3); border-bottom: 2px solid transparent; transition: color var(--t-quick) var(--e-out-cubic), border-color var(--t-quick) var(--e-out-cubic); }
.tab.is-active { color: var(--brand-primary, var(--navy)); border-color: var(--brand-primary, var(--navy)); }
.tab:hover { text-decoration: none; color: var(--brand-primary, var(--navy)); }

.filters { display: flex; gap: var(--s-3); flex-wrap: wrap; align-items: flex-end; margin-bottom: var(--s-4); }
.filters .field { margin-bottom: 0; min-width: 160px; }

/* A filter bar that reads as one control surface rather than inputs floating on the page. */
.filters--carded {
  background: var(--paper); border: 1px solid var(--line); border-radius: var(--r-m);
  padding: var(--s-4); box-shadow: var(--sh-s);
}

/* ── Alerts & flashes ──────────────────────────────────────────────────────────── */

/* APP_ENV=demo only — slim always-visible strip above the shell. */
.demo-banner { background: rgba(250,178,25,0.15); color: #8a5c00; border-bottom: 1px solid rgba(250,178,25,0.35); text-align: center; padding: 5px var(--s-4); font-size: var(--t-sm); font-weight: 600; letter-spacing: 0.2px; }

.alert { padding: var(--s-3) var(--s-4); border-radius: var(--r-s); margin-bottom: var(--s-4); font-size: var(--t-md); }
.alert--good { background: rgba(12,163,12,0.08); color: #0a7a0a; border: 1px solid rgba(12,163,12,0.2); }
.alert--warning { background: rgba(250,178,25,0.1); color: #8a5c00; border: 1px solid rgba(250,178,25,0.25); }
.alert--critical { background: rgba(208,59,59,0.08); color: var(--critical-text); border: 1px solid rgba(208,59,59,0.2); }
.alert--info { background: rgba(62,140,224,0.08); color: var(--navy); border: 1px solid rgba(62,140,224,0.2); }

.smart-alert {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-4); border-radius: var(--r-m); background: var(--paper);
  border: 1px solid var(--line); border-inline-start: 3px solid var(--txt-3);
  box-shadow: var(--sh-s);
  transition: transform var(--t-base-d) var(--e-out-cubic), box-shadow var(--t-base-d) var(--e-out-cubic);
}
.smart-alert:hover { transform: translateY(-1px); box-shadow: var(--sh-m); }
.smart-alert--warning { border-inline-start-color: var(--warning); }
.smart-alert--critical { border-inline-start-color: var(--critical); }
.smart-alert--serious { border-inline-start-color: var(--serious); }
.smart-alert--info { border-inline-start-color: var(--sky); }
.smart-alert__icon {
  flex-shrink: 0; width: 34px; height: 34px; border-radius: 50%;
  display: grid; place-items: center; font-size: 13px; font-weight: 700;
}
.smart-alert--warning .smart-alert__icon { background: rgba(250,178,25,.16); color: #8a5c00; }
.smart-alert--critical .smart-alert__icon { background: rgba(208,59,59,.12); color: var(--critical-text); }
.smart-alert--serious .smart-alert__icon { background: rgba(236,131,90,.16); color: #a3421a; }
.smart-alert--info .smart-alert__icon { background: rgba(62,140,224,.12); color: var(--navy); }
.smart-alert__body-wrap { flex: 1; min-width: 0; }
.smart-alert__title { font-weight: 700; margin-bottom: 2px; font-size: var(--t-md); }
.smart-alert__body { font-size: var(--t-sm); color: var(--txt-2); }
.smart-alert__action { flex-shrink: 0; }
@media (prefers-reduced-motion: reduce) { .smart-alert { transition: none; } .smart-alert:hover { transform: none; } }

/* ── Auth pages ────────────────────────────────────────────────────────────────── */

/* Two panels: the club's identity on one side, the task on the other. A single centred
   box on a flat gradient is the default every admin template ships with; the crest, the
   gold rule and the brand wall are what make this look like *this* club's portal. */
.auth-shell {
  min-height: 100vh;
  display: grid;
  grid-template-columns: minmax(420px, 1fr) minmax(0, 1.1fr);
  background: var(--paper);
}

.auth-brand {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column; justify-content: space-between;
  padding: var(--s-10) clamp(var(--s-6), 5vw, 64px);
  /* Solid colour first: the `background` shorthand below resets background-color to
     transparent, so without this the white text sits on the white page behind it
     wherever the gradients do not paint (forced-colors mode, print, older engines). */
  background-color: var(--ink);
  background-image:
    radial-gradient(120% 90% at 100% 0, rgba(201,162,39,.22), transparent 55%),
    radial-gradient(90% 70% at 0 100%, rgba(62,140,224,.20), transparent 60%),
    linear-gradient(155deg, var(--ink) 0%, var(--ink-2) 55%, var(--navy) 100%);
  color: #fff;
}
/* A slow gold sweep across the panel — the "premium moment" accent from docs/04 §1,
   used once, quietly, rather than sprinkled over the whole screen. */
.auth-brand::after {
  content: '';
  position: absolute; inset: -40% -10%;
  background: linear-gradient(115deg, transparent 42%, rgba(232,204,106,.10) 50%, transparent 58%);
  animation: authSweep 9s ease-in-out infinite;
  pointer-events: none;
}
@keyframes authSweep {
  0%, 100% { transform: translateX(-18%); opacity: .5; }
  50%      { transform: translateX(18%);  opacity: 1; }
}

.auth-brand__mark { display: flex; align-items: center; gap: var(--s-4); position: relative; z-index: 1; }
.auth-brand__mark img { width: 64px; height: 64px; border-radius: var(--r-m); object-fit: cover; box-shadow: var(--sh-l); }
.auth-brand__mark strong { font-family: 'Cairo', sans-serif; font-size: 21px; font-weight: 800; line-height: 1.35; }

.auth-brand__body { position: relative; z-index: 1; max-width: 30ch; }
.auth-brand__body h2 {
  font-family: 'Cairo', sans-serif; color: #fff;
  font-size: clamp(26px, 3.2vw, 40px); font-weight: 800; line-height: 1.3;
  margin: 0 0 var(--s-4);
}
.auth-brand__rule { width: 56px; height: 3px; border-radius: 3px; background: var(--gold); margin-bottom: var(--s-4); }
.auth-brand__body p { color: rgba(255,255,255,.76); font-size: var(--t-lg); margin: 0; line-height: 1.75; }

.auth-brand__foot { position: relative; z-index: 1; color: rgba(255,255,255,.5); font-size: var(--t-sm); }

.auth-form { display: flex; align-items: center; justify-content: center; padding: var(--s-8) var(--s-6); }
.auth-card {
  width: 100%; max-width: 400px;
  animation: fadeInUp var(--t-expressive) var(--e-out-cubic) both;
}
.auth-card__logo { display: none; }
.auth-card h1 { font-size: 26px; margin-bottom: 6px; }
.auth-card__lede { color: var(--txt-2); font-size: var(--t-lg); margin-bottom: var(--s-6); }
.auth-card .field { text-align: right; margin-bottom: var(--s-4); }
.auth-card label { font-size: var(--t-md); }
.auth-card input { padding: 12px var(--s-4); font-size: 15px; }
.auth-card .btn { width: 100%; margin-top: var(--s-2); padding: 13px; font-size: 15px; }
.auth-card__hint { margin-top: var(--s-5); font-size: var(--t-sm); color: var(--txt-3); text-align: center; }

@media (max-width: 900px) {
  .auth-shell { grid-template-columns: 1fr; }
  /* The brand wall collapses to a header band rather than disappearing — on a phone the
     crest is still how staff know they are on the right portal. */
  .auth-brand { padding: var(--s-6); gap: var(--s-4); }
  .auth-brand__body, .auth-brand__foot { display: none; }
  .auth-brand__mark img { width: 46px; height: 46px; }
  .auth-brand__mark strong { font-size: 17px; }
  .auth-form { padding: var(--s-8) var(--s-5) var(--s-10); }
}

@media (prefers-reduced-motion: reduce) {
  .auth-card { animation: none; }
  .auth-brand::after { animation: none; }
}

.error-shell { min-height: 100vh; display: flex; align-items: center; justify-content: center; background: var(--paper-2); padding: var(--s-5); }
.error-card { text-align: center; max-width: 440px; }
.error-card .code { font-family: 'Cairo', sans-serif; font-size: 56px; font-weight: 800; color: var(--navy); }

/* ── Misc ──────────────────────────────────────────────────────────────────────── */

.muted { color: var(--txt-3); }
.small { font-size: 12px; }
.mono { font-variant-numeric: tabular-nums; direction: ltr; unicode-bidi: isolate; }
.divider { border: none; border-top: 1px solid var(--line); margin: var(--s-5) 0; }
.pill-list { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.stack { display: flex; flex-direction: column; gap: var(--s-3); }
.stack--tight { gap: var(--s-2); }
.section-title { font-size: 13px; font-weight: 700; color: var(--txt-2); letter-spacing: .03em; margin: var(--s-6) 0 var(--s-3); display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-3); }
.section-title:first-child { margin-top: 0; }
.section-title__aside { font-weight: 500; font-size: var(--t-sm); color: var(--txt-3); }

/* An empty state is a moment, not a centred grey sentence (docs/04 §4.6). */
.empty-state { text-align: center; padding: 56px var(--s-5); color: var(--txt-3); }
.empty-state__art { width: 64px; height: 64px; margin: 0 auto var(--s-4); display: grid; place-items: center; border-radius: 50%; background: var(--paper-3); color: var(--txt-3); }
.empty-state__art svg { width: 28px; height: 28px; }
.empty-state__title { font-family: 'Cairo', sans-serif; font-size: var(--t-lg); font-weight: 700; color: var(--txt-2); margin-bottom: 6px; }
.empty-state__body { font-size: var(--t-md); color: var(--txt-3); max-width: 46ch; margin: 0 auto var(--s-4); }
.empty-state--allclear .empty-state__art { background: rgba(201,162,39,.14); color: var(--gold); animation: shimmer 2.8s ease-in-out infinite; }
@keyframes shimmer { 0%, 100% { box-shadow: 0 0 0 0 rgba(201,162,39,.35); } 50% { box-shadow: 0 0 0 12px rgba(201,162,39,0); } }
@media (prefers-reduced-motion: reduce) { .empty-state--allclear .empty-state__art { animation: none; } }

.pagination { display: flex; gap: 6px; margin-top: var(--s-4); justify-content: center; flex-wrap: wrap; }
.pagination a, .pagination span { padding: 6px 11px; border-radius: var(--r-s); font-size: var(--t-sm); border: 1px solid var(--line); }
.pagination a:hover { background: var(--paper-2); text-decoration: none; }
.pagination .is-active { background: var(--brand-primary, var(--navy)); color: #fff; border-color: var(--brand-primary, var(--navy)); }

/* A chart with nothing in it should say so, not draw an empty axis or a flat line along
   the baseline — which reads as "zero every month" rather than "no data yet". */
.chart-empty {
  display: grid; place-items: center; text-align: center;
  min-height: 140px; padding: var(--s-5);
  color: var(--txt-3); font-size: var(--t-md);
  border: 1px dashed var(--line); border-radius: var(--r-m);
  background: var(--paper-2);
}

/* ── Record detail pages ───────────────────────────────────────────────────────────
 * Every list row in the portal opens a record page, and a record page shows everything
 * the system holds about that record plus its history. These are the shared parts.
 */

/* Label/value pairs. The whole point is that no stored field is hidden, so this wraps
   into as many columns as fit rather than forcing a fixed two-column shape. */
.datalist { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: var(--s-4) var(--s-5); }
.datalist__item { min-width: 0; }
.datalist__label { font-size: var(--t-sm); color: var(--txt-3); margin-bottom: 2px; }
.datalist__value { font-size: var(--t-base); color: var(--txt); font-weight: 600; overflow-wrap: anywhere; }
.datalist__value--empty { color: var(--txt-3); font-weight: 400; }

/* Identity strip at the top of a record page. */
.record-head { display: flex; align-items: flex-start; gap: var(--s-4); flex-wrap: wrap; }
.record-head__avatar {
  width: 64px; height: 64px; border-radius: 50%; object-fit: cover; flex-shrink: 0;
  background: var(--paper-3); display: grid; place-items: center;
  font-family: 'Cairo', sans-serif; font-weight: 700; font-size: 22px; color: var(--txt-3);
}
.record-head__main { flex: 1; min-width: 220px; }
.record-head__title { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; margin-bottom: 2px; }
.record-head__title h1 { margin: 0; }
.record-head__meta { color: var(--txt-2); font-size: var(--t-md); display: flex; gap: var(--s-2); flex-wrap: wrap; align-items: center; }
.record-head__meta .sep { color: var(--txt-3); }

/* In-page section nav for long record pages. */
.anchor-nav {
  display: flex; gap: var(--s-1); flex-wrap: wrap;
  border-bottom: 1px solid var(--line); margin: var(--s-5) 0 var(--s-5);
  position: sticky; top: 57px; z-index: 10;
  background: var(--paper-2); padding-top: var(--s-2);
}
.anchor-nav a {
  padding: 8px var(--s-3); font-size: var(--t-md); font-weight: 600;
  color: var(--txt-2); border-bottom: 2px solid transparent; white-space: nowrap;
}
.anchor-nav a:hover { color: var(--brand-primary, var(--navy)); text-decoration: none; }
.anchor-nav a.is-active { color: var(--brand-primary, var(--navy)); border-color: var(--brand-primary, var(--navy)); }
.anchor-nav__count { font-size: var(--t-xs); color: var(--txt-3); font-variant-numeric: tabular-nums; margin-inline-start: 3px; }
/* Anchor targets clear the two stacked sticky bars. */
.record-section { scroll-margin-top: 120px; }

/* History rail — status changes, audit entries, anything that happened in order. */
.timeline { position: relative; padding-inline-start: var(--s-5); }
.timeline::before {
  content: ''; position: absolute; inset-block: 6px 6px; inset-inline-start: 5px;
  width: 2px; background: var(--line);
}
.timeline__item { position: relative; padding-bottom: var(--s-4); }
.timeline__item:last-child { padding-bottom: 0; }
.timeline__item::before {
  content: ''; position: absolute;
  inset-inline-start: calc(-1 * var(--s-5) + 1px); top: 6px;
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--paper); border: 2px solid var(--txt-3);
}
.timeline__item--good::before { border-color: var(--good); }
.timeline__item--warning::before { border-color: var(--warning); }
.timeline__item--critical::before { border-color: var(--critical); }
.timeline__item--info::before { border-color: var(--sky); }
.timeline__when { font-size: var(--t-sm); color: var(--txt-3); font-variant-numeric: tabular-nums; }
.timeline__what { font-weight: 600; font-size: var(--t-md); }
.timeline__who { font-size: var(--t-sm); color: var(--txt-2); }

/* A compact figure inside a record section (not the dashboard KPI row). */
.stat-row { display: flex; flex-wrap: wrap; gap: var(--s-5); }
.stat { min-width: 110px; }
.stat__label { font-size: var(--t-sm); color: var(--txt-3); }
.stat__value { font-family: 'Cairo', sans-serif; font-size: 20px; font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; }

@media (max-width: 1024px) { .anchor-nav { top: 0; } }

/* ── Coach screens (roster, evaluations) ───────────────────────────────────────────
 * Used only when a coach is signed in — staff with a portal role see these screens
 * inside the normal shell, with the sidebar and a way back.
 */

.coach-topbar {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-3);
  padding: var(--s-3) var(--s-4); background: var(--ink); color: #fff;
  position: sticky; top: 0; z-index: 20;
}
.coach-topbar strong { font-family: 'Cairo', sans-serif; font-size: 15px; }
.coach-content { padding: var(--s-4) var(--s-4) 96px; max-width: 760px; margin: 0 auto; }

.roster-player {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  background: var(--paper); border: 1px solid var(--line); border-radius: var(--r-m);
  box-shadow: var(--sh-s);
  transition: border-color var(--t-quick) var(--e-out-cubic), box-shadow var(--t-quick) var(--e-out-cubic);
}
.roster-player:hover { border-color: #D3DBE7; box-shadow: var(--sh-m); }
.roster-player__avatar {
  width: 40px; height: 40px; border-radius: 50%; flex-shrink: 0;
  object-fit: cover; background: var(--paper-3);
  display: grid; place-items: center;
  font-family: 'Cairo', sans-serif; font-weight: 700; font-size: var(--t-md); color: var(--txt-3);
}
.roster-player__id { flex: 1; min-width: 0; }
.roster-player__name { font-weight: 600; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.roster-player__meta { font-size: var(--t-sm); color: var(--txt-3); margin-top: 1px; }
.roster-player__marks { flex-shrink: 0; }

/* One evaluation criterion: score box, its ceiling, and a live bar of the score against
   that ceiling — the same horizontal-bar form the member's app shows, so the coach sees
   what the parent will see while typing. */
.criterion + .criterion { margin-top: var(--s-3); }
.criterion__row { display: flex; align-items: center; gap: var(--s-3); }
.criterion__input { width: 84px; flex-shrink: 0; text-align: center; font-variant-numeric: tabular-nums; }
.criterion__max { font-size: var(--t-sm); color: var(--txt-3); flex-shrink: 0; }
.criterion__track { flex: 1; min-width: 60px; height: 8px; background: var(--paper-3); border-radius: 999px; overflow: hidden; }
.criterion__fill {
  height: 100%; width: 0; border-radius: 999px; background: var(--seq-4);
  transition: width var(--t-base-d) var(--e-out-cubic), background var(--t-base-d) linear;
}
@media (prefers-reduced-motion: reduce) { .criterion__fill { transition: none; } }

/* The action row at the end of a form. Deliberately *not* sticky: on a long form it
   would hover over the textarea being typed into. Only the roster, where the whole task
   is scanning a list, gets the pinned variant below. */
.form-actions {
  margin-top: var(--s-4);
  padding: var(--s-3) var(--s-4);
  background: var(--paper);
  border: 1px solid var(--line); border-radius: var(--r-m);
  box-shadow: var(--sh-s);
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); flex-wrap: wrap;
}

/* Save bar pinned to the bottom: the coach's thumb never leaves the mark column. */
.roster-savebar {
  position: sticky; bottom: 0; z-index: 15;
  margin-top: var(--s-4);
  padding: var(--s-3) var(--s-4);
  background: rgba(255,255,255,.92);
  backdrop-filter: blur(8px);
  border: 1px solid var(--line); border-radius: var(--r-m);
  box-shadow: var(--sh-l);
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); flex-wrap: wrap;
}
.roster-savebar__counts { display: flex; gap: var(--s-3); flex-wrap: wrap; font-size: var(--t-sm); }
.roster-count { display: inline-flex; align-items: center; gap: 5px; color: var(--txt-2); font-variant-numeric: tabular-nums; }
.roster-count__dot { width: 8px; height: 8px; border-radius: 3px; }

@media (max-width: 640px) {
  .roster-player { flex-wrap: wrap; }
  .roster-player__marks { width: 100%; }
  .segmented { width: 100%; }
  .segmented__opt { flex: 1; }
  .segmented__opt span { min-width: 0; padding: 10px 6px; }
}

/* ── Responsive ────────────────────────────────────────────────────────────────────
 * Below 1024px the sidebar becomes a drawer. Previously it was simply `display:none`,
 * which left the portal with no navigation at all on a tablet or phone.
 */

@media (max-width: 1024px) {
  .nav-toggle { display: inline-flex; }

  .sidebar {
    position: fixed; inset-block: 0; inset-inline-start: 0;
    z-index: 40; width: min(84vw, 300px);
    transform: translateX(100%);
    transition: transform var(--t-move) var(--e-in-out-cubic);
    box-shadow: var(--sh-l);
    visibility: hidden;
  }
  [dir="ltr"] .sidebar { transform: translateX(-100%); }

  .shell.is-nav-open .sidebar { transform: translateX(0); visibility: visible; }
  .shell.is-nav-open .nav-scrim { display: block; }

  body.is-nav-locked { overflow: hidden; }

  .content { padding: var(--s-4) var(--s-4) 64px; }
  .topbar { padding: var(--s-3) var(--s-4); }
}

@media (prefers-reduced-motion: reduce) {
  .sidebar { transition: none; }
}

@media (max-width: 560px) {
  :root { --t-hero: 38px; }
  .page-header { gap: var(--s-3); }
  .page-header__actions { width: 100%; }
  .kpi { padding: var(--s-4); }
  .topbar__user span:not(.badge) { display: none; }
  .topbar__user .topbar__name { display: inline; }
}

@media print {
  .sidebar, .topbar, .nav-toggle, .demo-banner, .page-header__actions,
  .roster-savebar, .form-actions, .skip-link { display: none !important; }
  .content { max-width: none; padding: 0; }
  .card, .table-wrap, .kpi { box-shadow: none; border-color: #ccc; break-inside: avoid; }
}

/* ── Audit diff viewer (P32) ──────────────────────────────────────────────────── */

.diff-table { width: 100%; margin-top: var(--s-2); font-size: 12px; border-collapse: collapse; }
.diff-table th { text-align: right; padding: 5px var(--s-2); color: var(--txt-3); font-weight: 600; background: transparent; border-bottom: 1px solid var(--paper-3); }
.diff-table td { padding: 5px var(--s-2); border-bottom: 1px solid var(--paper-3); vertical-align: top; }
.diff-table tr:last-child td { border-bottom: none; }
.diff-cell--old { background: rgba(208,59,59,0.08); color: var(--critical-text); text-decoration: line-through; text-decoration-color: rgba(208,59,59,0.4); }
.diff-cell--new { background: rgba(12,163,12,0.08); color: var(--good-text); }
.diff-row--added .diff-cell--old, .diff-row--removed .diff-cell--new { text-decoration: none; color: var(--txt-3); background: transparent; }

/* ── Wizards (P33) ────────────────────────────────────────────────────────────────
 * Guided multi-step operations. Nothing here is written until the preview gate has
 * been seen and confirmed, so the chrome makes "where am I / what happens next /
 * what is about to change" answerable at a glance.
 */

.wizard-card { display: block; padding: var(--s-5); border-radius: var(--r-m); background: var(--paper); border: 1px solid var(--line); box-shadow: var(--sh-s); transition: transform var(--t-base-d) var(--e-out-cubic), box-shadow var(--t-base-d) var(--e-out-cubic), border-color var(--t-quick) linear; height: 100%; }
.wizard-card:hover { transform: translateY(-2px); box-shadow: var(--sh-m); text-decoration: none; border-color: #D3DBE7; }
.wizard-card__icon { width: 38px; height: 38px; border-radius: var(--r-s); display: grid; place-items: center; font-size: 18px; background: var(--brand-tint); margin-bottom: var(--s-3); }
.wizard-card__title { font-family: 'Cairo', sans-serif; font-weight: 700; font-size: 15px; color: var(--ink); margin-bottom: 4px; }
.wizard-card__desc { font-size: var(--t-sm); color: var(--txt-2); line-height: 1.6; }
.wizard-card--danger .wizard-card__icon { background: rgba(208,59,59,.1); }

/* Progress rail. Steps already answered stay clickable-looking (they are reachable
   with the back button) so the sequence never feels like a trap. */
.wizard-rail { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-bottom: var(--s-5); }
.wizard-rail__step { display: flex; align-items: center; gap: var(--s-2); padding: 7px var(--s-3); border-radius: 999px; font-size: var(--t-sm); font-weight: 600; color: var(--txt-3); background: var(--paper-3); }
.wizard-rail__step.is-done { background: rgba(12,163,12,.1); color: var(--good-text); }
.wizard-rail__step.is-current { background: var(--brand-primary, var(--navy)); color: #fff; }
.wizard-rail__num { display: grid; place-items: center; width: 18px; height: 18px; border-radius: 50%; background: rgba(255,255,255,.25); font-size: 11px; font-variant-numeric: tabular-nums; }
.wizard-rail__step:not(.is-current) .wizard-rail__num { background: rgba(7,20,43,.08); }

.wizard-body { max-width: 760px; }
.wizard-actions { display: flex; gap: var(--s-2); justify-content: space-between; align-items: center; margin-top: var(--s-5); flex-wrap: wrap; }

/* The preview gate — deliberately visually distinct from a normal form step, because
   it is the last point at which nothing has happened yet. */
.wizard-preview { border: 1px solid var(--line); border-radius: var(--r-m); background: var(--paper); box-shadow: var(--sh-s); padding: var(--s-5); }
.wizard-preview__summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: var(--s-4); margin-bottom: var(--s-4); }
.wizard-note { display: flex; gap: var(--s-2); align-items: flex-start; padding: var(--s-3) var(--s-4); border-radius: var(--r-s); font-size: var(--t-md); margin-bottom: var(--s-2); }
.wizard-note--warn { background: rgba(250,178,25,.1); color: #7a5100; border: 1px solid rgba(250,178,25,.3); }
.wizard-note--block { background: rgba(208,59,59,.08); color: var(--critical-text); border: 1px solid rgba(208,59,59,.25); }

/* Shortcut strip rendered on the screens a wizard belongs beside. */
.wizard-strip { display: flex; gap: var(--s-2); flex-wrap: wrap; margin-bottom: var(--s-4); }
.wizard-strip__link { display: inline-flex; align-items: center; gap: 6px; padding: 7px var(--s-3); border-radius: 999px; border: 1px dashed var(--line); background: var(--paper); font-size: var(--t-sm); font-weight: 600; color: var(--brand-primary, var(--navy)); }
.wizard-strip__link:hover { text-decoration: none; border-style: solid; background: var(--paper-2); }

@media (prefers-reduced-motion: reduce) { .wizard-card { transition: none; } .wizard-card:hover { transform: none; } }
