/* ============================================================
   Laeeb — design-system entry point.
   Consumers link THIS one file. The two imports below ship the
   brand webfonts and the complete token set (colors, type scale,
   spacing, radii, font-family vars, Arabic, semantic type/surface
   classes). The app-specific :root + utilities/animations follow
   inline and win any cascade conflict, so the live app is unchanged.
   (@import rules must stay first.)
   ============================================================ */
@import url('tokens/fonts.css');
@import url('colors_and_type.css');

/* Laeeb — global tokens (mirrors C in shared.jsx) */
:root {
  /* Backgrounds */
  --cream: #efe8dc;
  --cream-2: #e8e0d0;
  --paper: #f6f1e6;
  /* Ice family */
  --ice: #c8dde9;
  --ice-2: #b4cfde;
  --ice-3: #d8e7ef;
  --ice-4: #e6eff5;
  /* Navy family */
  --navy: #142340;
  --navy-2: #1a2c4d;
  --navy-3: #0e1a32;
  /* CTA */
  --cta: #1f3a8e;
  --cta-2: #1b3380;
  --cta-disabled: #a9b3c9;
  --cta-disabled-txt: rgba(239,234,240,0.85);
  /* Text */
  --ink: #14223c;
  --muted: #5a6378;
  --muted-dark: #4c5468;
  --faint: #6f7790;
  /* Borders */
  --line: rgba(20, 34, 60, 0.12);
  /* Sport-item accent tones */
  --tan: #cdbfa5;
  --tan-2: #b9a880;
  --ball-blue: #2a4a7b;
  /* Semantic — canonical tokens (design audit S2) */
  --ok: #1e7a6e;
  --ok-on-dark: #5cc4a3;
  --warn: #c47a1d;
  --bad: #b03a3a;
  --info: #2a6fdb;
  --waitlist: #5b54c9;
  --navy-alt: #1c3055;
  /* Champagne-gold ramp (Elite / premium surfaces) */
  --gold-hi: #d8c08a;
  --gold: #b99a5c;
  --gold-lo: #9a7b2e;
  --gold-deep: #7a5c08;
  /* v2 — off-white text on dark surfaces */
  --off-white: #f4eee2;
  --off-white-muted: #b9c2d4;
  --off-white-faint: #7e8aa3;
  /* v2 — warm card surface */
  --card-warm: #fffefe;
  /* v2 — live indicator */
  --live: #e0483d;
  /* v2 — focus halo */
  --focus-ring: rgba(31,58,142,0.55);

  /* Sport identity (accents only, not CTAs) */
  --sport-badminton:  #2a4a7b;
  --sport-padel:      #0f7e8c;
  --sport-tennis:     #74810a;
  --sport-basketball: #c2641e;
  --sport-dodgeball:  #b03a3a;
  --sport-squash:     #5a3e8c;
  --sport-pickleball: #c89b2a;
  --sport-cycling:    #b5388a;
  --sport-biking:     #2e8b57;

  /* Skill-level accents */
  --skill-beginner:     #3e7c8c;
  --skill-intermediate: #2f6f4f;
  --skill-advanced:     #b5852a;
  --skill-competitive:  #8e3b6b;
  --skill-open:         #5a6378; /* Open = no level needed, all welcome (not a rank) */
}
* { box-sizing: border-box; -webkit-font-smoothing: antialiased; }
html, body { margin: 0; padding: 0; font-family: 'Inter', -apple-system, system-ui, sans-serif; color: var(--ink); }
body { background: #1a1814; }

.font-display { font-family: 'Anton', 'Inter Tight', system-ui, sans-serif; font-weight: 400; letter-spacing: 0.005em; }
.font-mono { font-family: 'JetBrains Mono', 'SF Mono', monospace; }

/* tag — small tracked uppercase */
.tag {
  font-family: 'Inter', sans-serif;
  font-weight: 600; font-size: 11px; letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* navy section card */
.navy-card { background: var(--navy); color: var(--off-white); }

/* scrollbar hide */
.no-scroll::-webkit-scrollbar { display: none; }
.no-scroll { scrollbar-width: none; }

/* signature scribble */
.signature {
  font-family: 'Caveat', 'Reenie Beanie', cursive;
  font-style: italic; transform: rotate(-6deg);
  color: var(--navy);
}

/* shuttlecock icon */
.dot-3 { display: inline-flex; gap: 3px; }
.dot-3 > span { width: 4px; height: 4px; border-radius: 99px; background: currentColor; }

/* B&W image filter */
.bw { filter: grayscale(1) contrast(1.06) brightness(0.92); }

/* Paper grain — RETIRED (2026-06-09). The flat cream used on Explore's sheet
   is now the app-wide background: .paper-tex no longer paints a dot field.
   The class (and the --paper-shift parallax wiring in the Phone wrapper) is
   kept as a harmless no-op so the hundreds of existing call sites don't need
   touching; the inline `background` on each screen supplies the cream fill. */
.paper-tex {
  background-image: none !important;
}

/* nav arrow circle button */
.arrow-btn {
  width: 44px; height: 44px; border-radius: 99px;
  border: 1.5px solid var(--navy);
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; cursor: pointer;
  color: var(--navy);
}

/* avatar ring */
.avatar-ring { box-shadow: 0 0 0 2px var(--ice-3); border-radius: 99px; }

/* drop shadow for cards */
.card-shadow { box-shadow: 0 1px 0 rgba(20,34,60,0.04), 0 8px 24px rgba(20,34,60,0.06); }

/* underline link */
.ulink { border-bottom: 1px solid currentColor; padding-bottom: 1px; }

/* Skeleton — shimmer sweep on ice4 fill, gated by reduced-motion */
@keyframes shimmerSweep {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
.skel {
  background-color: var(--ice-4);
  background-image: linear-gradient(
    90deg,
    rgba(230, 239, 245, 0) 0%,
    rgba(255, 255, 255, 0.55) 50%,
    rgba(230, 239, 245, 0) 100%
  );
  background-size: 200% 100%;
  background-repeat: no-repeat;
  animation: shimmerSweep 1.4s linear infinite;
  border-radius: 8px;
}
@media (prefers-reduced-motion: reduce) {
  .skel { animation: none; background-image: none; background-color: var(--ice-4); }
}

/* CTA button — pressed + loading states (§7 [v2]) */
@keyframes ctaSpin { to { transform: rotate(360deg); } }
.cta-btn { transition: transform 120ms cubic-bezier(0.2, 0.9, 0.3, 1.2), background-color 120ms ease; }
.cta-btn:not(:disabled):active { transform: scale(0.97); }
.cta-btn[data-variant="primary"]:not(:disabled):not([data-loading]):active { background-color: var(--cta-2); }
.cta-btn[data-variant="destructive"]:not(:disabled):active { background-color: rgba(176,58,58,0.08); }

/* Field focus halo (§7 [v2]) */
.field-focus { box-shadow: 0 0 0 3px var(--focus-ring); border-color: var(--cta) !important; }
.field-error { border-color: var(--bad) !important; }

/* Tab swipe — content slides + fades in from the side of travel
   when the user taps a different dock tab. */
@keyframes tabSwipeFwd {
  from { transform: translate3d(28px, 0, 0); opacity: 0; }
  to   { transform: translate3d(0, 0, 0);    opacity: 1; }
}
@keyframes tabSwipeBack {
  from { transform: translate3d(-28px, 0, 0); opacity: 0; }
  to   { transform: translate3d(0, 0, 0);     opacity: 1; }
}
.tab-swipe { min-height: 100%; will-change: transform, opacity; }
.tab-swipe--fwd  { animation: tabSwipeFwd  280ms cubic-bezier(0.2, 0.7, 0.2, 1) both; }
.tab-swipe--back { animation: tabSwipeBack 280ms cubic-bezier(0.2, 0.7, 0.2, 1) both; }
.tab-swipe--none { animation: none; }

/* Wireframe animations — every keyframe has a reduce-motion fallback.
   Centralised here so a single @media block can flip the whole system. */
@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 rgba(224,72,61,0.6); }
  100% { box-shadow: 0 0 0 8px rgba(224,72,61,0); }
}
@keyframes sportPulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.35); }
}
@keyframes pulseDot {
  0%   { transform: scale(1);   opacity: 0.4; }
  60%  { transform: scale(2.2); opacity: 0; }
  100% { transform: scale(2.2); opacity: 0; }
}
@keyframes sportCycle {
  0%, 88%, 100% { transform: scale(0.75); opacity: 0.32; }
  6%, 9%        { transform: scale(1.35); opacity: 1; }
  16%           { transform: scale(0.75); opacity: 0.32; }
}
@keyframes levelPulse {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.025); }
  100% { transform: scale(1); }
}
@keyframes pop {
  from { transform: scale(0.4); opacity: 0; }
  to   { transform: scale(1);   opacity: 1; }
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Reduce-motion fallbacks — each keyframe collapses to its end-state,
   spinners freeze, pop loses its scale bounce. (§a11y) */
@media (prefers-reduced-motion: reduce) {
  @keyframes pulse      { from, to { box-shadow: none; } }
  @keyframes sportPulse { from, to { transform: scale(1); } }
  @keyframes pulseDot   { from, to { transform: scale(1); opacity: 0; } }
  @keyframes sportCycle { from, to { transform: scale(1); opacity: 1; } }
  @keyframes levelPulse { from, to { transform: none; } }
  @keyframes pop        { from { opacity: 0; transform: none; } to { opacity: 1; transform: none; } }
  @keyframes spin       { from, to { transform: none; } }
  @keyframes ctaSpin    { from, to { transform: none; } }
  @keyframes tabSwipeFwd  { from, to { transform: none; opacity: 1; } }
  @keyframes tabSwipeBack { from, to { transform: none; opacity: 1; } }
}

/* ── Content entrance — restraint-first rise+fade, with optional stagger.
   Add .rise to an element, or .rise-stagger to a parent to cascade its
   direct children. Purely decorative; collapses under reduced-motion. */
@keyframes riseIn {
  from { opacity: 0; transform: translate3d(0, 14px, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}
.rise { animation: riseIn 480ms cubic-bezier(0.2, 0.7, 0.2, 1) both; }
.rise-stagger > * { animation: riseIn 480ms cubic-bezier(0.2, 0.7, 0.2, 1) both; }
.rise-stagger > *:nth-child(1) { animation-delay: 40ms; }
.rise-stagger > *:nth-child(2) { animation-delay: 100ms; }
.rise-stagger > *:nth-child(3) { animation-delay: 160ms; }
.rise-stagger > *:nth-child(4) { animation-delay: 220ms; }
.rise-stagger > *:nth-child(5) { animation-delay: 280ms; }
.rise-stagger > *:nth-child(6) { animation-delay: 340ms; }
.rise-stagger > *:nth-child(7) { animation-delay: 400ms; }
.rise-stagger > *:nth-child(n+8) { animation-delay: 440ms; }
@media (prefers-reduced-motion: reduce) {
  @keyframes riseIn { from, to { opacity: 1; transform: none; } }
  .rise, .rise-stagger > * { animation-delay: 0ms !important; }
}

/* Chart line draw-on — primary trend line sweeps in left→right. Uses
   pathLength="1" so it's length-independent. Reduced-motion shows full line. */
@keyframes chartDraw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
.chart-draw { stroke-dasharray: 1; stroke-dashoffset: 1; animation: chartDraw 1100ms cubic-bezier(0.4, 0, 0.2, 1) 120ms forwards; }
@media (prefers-reduced-motion: reduce) {
  .chart-draw { animation: none; stroke-dashoffset: 0; }
}

/* Bottom-sheet rise — used by SheetScrim (academy packages/directions/schedule
   sheets). Defined globally (not inline) so the keyframes always resolve, and
   uses forwards fill so the sheet rests at translateY(0). */
@keyframes omSheetRise { from { transform: translateY(100%); } to { transform: translateY(0); } }
.om-sheet-rise { animation: omSheetRise 0.34s cubic-bezier(0.16, 1, 0.3, 1) both; }
/* "+" fork menu (admin Sessions/Templates) — same motion as the court-booking
   sheet (omSheetRise timing/easing), adapted to an anchored popover: it drops
   from the nav "+" instead of rising from the bottom edge. */
@keyframes omMenuPop { from { opacity: 0; transform: translateY(-10px) scale(0.96); } to { opacity: 1; transform: translateY(0) scale(1); } }
.om-menu-pop { animation: omMenuPop 0.34s cubic-bezier(0.16, 1, 0.3, 1) both; transform-origin: top right; }
@media print {
  .om-sheet-rise { animation: none; }
  .om-menu-pop { animation: none; }
}
@media (prefers-reduced-motion: reduce) {
  .om-sheet-rise { animation: none; }
  .om-menu-pop { animation: none; }
}

/* Founding map — node twinkle (pulses/flashes use inline SMIL) */
@keyframes fp-twinkle { 0%,100% { opacity:.55 } 50% { opacity:1 } }
.fp-twinkle { animation: fp-twinkle 2.6s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce){ .fp-twinkle{ animation:none } }

/* Onboarding · Navy Marquee connected flow (OnboardingFlowB) —
   vertical page-slide routing: forward slides up, back slides down,
   while the navy band + chrome stay fixed. */
.obfx-out-up   { animation: obfxOutUp 500ms cubic-bezier(0.55, 0, 0.15, 1) forwards; }
.obfx-in-up    { animation: obfxInUp 500ms cubic-bezier(0.55, 0, 0.15, 1) forwards; }
.obfx-out-down { animation: obfxOutDown 500ms cubic-bezier(0.55, 0, 0.15, 1) forwards; }
.obfx-in-down  { animation: obfxInDown 500ms cubic-bezier(0.55, 0, 0.15, 1) forwards; }
@keyframes obfxOutUp   { to   { transform: translateY(-100%); } }
@keyframes obfxInUp    { from { transform: translateY(100%); } }
@keyframes obfxOutDown { to   { transform: translateY(100%); } }
@keyframes obfxInDown  { from { transform: translateY(-100%); } }
/* Band headline swap — short drift = parallax against the full-height slide */
.obBandHead { animation: obBandHead 500ms cubic-bezier(0.55, 0, 0.15, 1) both; }
@keyframes obBandHead { from { transform: translateY(26px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .obfx-out-up, .obfx-in-up, .obfx-out-down, .obfx-in-down, .obBandHead { animation-duration: 1ms; }
}
