/*
  Two Cart Race — Breezeway Labs Physics Lab
  https://breezewaylabs.com/physics/Cart-Race/sim.html

  Copyright (c) 2015–2026 Keith Warren
  MIT License — https://opensource.org/licenses/MIT

  Free to use, copy, modify, and distribute for any purpose.
  Attribution appreciated but not required.
*/

/* ══════════════════════════════════════════
   EXTERNAL FONT
   Space Grotesk is a geometric sans-serif that
   reads well at small sizes on both retina and
   standard displays.  Weights 400 (regular) and
   600/700 (semi-bold/bold) are used throughout.
══════════════════════════════════════════ */
@import url("https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;600;700&display=swap");

/* ══════════════════════════════════════════
   CSS CUSTOM PROPERTIES (DESIGN TOKENS)
   Centralised colour palette for the simulation.
   Changing a value here updates every element
   that references it.

   --bg1      : top gradient colour (light sky blue)
   --bg2      : bottom gradient colour (deeper blue)
   --ink      : primary text / line colour
   --card     : semi-transparent white for config cards
   --line     : dark border colour used on .track
   --lane     : light stripe in the track lane pattern
   --lane-edge: lane divider line colour
   --red      : Cart A accent colour
   --green    : Cart B accent colour
══════════════════════════════════════════ */
:root {
  --bg1:       #f2f8ff; /* lightest sky — gradient top    */
  --bg2:       #d6e8ff; /* deeper sky  — gradient bottom  */
  --ink:       #1a2634; /* near-black  — text and borders */
  --card:      rgba(255, 255, 255, 0.8); /* frosted white for config panels */
  --line:      #22354e; /* dark navy   — track border     */
  --lane:      #e8ecf1; /* pale grey   — lane stripe A    */
  --lane-edge: #8e9aaa; /* medium grey — lane divider     */
  --red:       #d63232; /* bright red  — Cart A           */
  --green:     #2c9a48; /* vivid green — Cart B           */
}

/* ══════════════════════════════════════════
   GLOBAL RESET
   Apply border-box sizing to every element so
   padding and border are included in width/height
   calculations.  Prevents layout surprises.
══════════════════════════════════════════ */
* {
  box-sizing: border-box;
}

/* ══════════════════════════════════════════
   BODY
   Full-viewport light-blue gradient background.
   Margin reset ensures the gradient reaches all
   edges.  Font stack: Google Font with system
   fallbacks for offline use.
══════════════════════════════════════════ */
body {
  margin: 0;
  font-family: "Space Grotesk", "Trebuchet MS", sans-serif;
  color: var(--ink);
  /* Vertical gradient from light sky (top) to slightly deeper blue (bottom) */
  background: linear-gradient(180deg, var(--bg1), var(--bg2));
}

/* ══════════════════════════════════════════
   APP WRAPPER
   Centers the simulation horizontally and adds
   breathing room around the edges.
   max-width: 1060 px keeps the layout readable
   on large monitors without stretching the track.
══════════════════════════════════════════ */
.app {
  max-width: 1060px;
  margin: 0 auto;         /* horizontal centering */
  padding: 20px 16px 28px; /* top / sides / bottom */
}

/* ══════════════════════════════════════════
   TOP BAR — TITLE & DESCRIPTION
   The simulation heading and one-line physics
   description at the top of the page.
══════════════════════════════════════════ */

/* Responsive heading: scales between 1.5 rem (mobile) and 2 rem (desktop) */
.topbar h1 {
  margin: 0;
  font-size: clamp(1.5rem, 3vw, 2rem);
}

.topbar p {
  margin: 8px 0 0; /* small gap below the heading */
}

/* ══════════════════════════════════════════
   CONTROLS SECTION
   Two-column grid holding the Cart A and Cart B
   configuration cards side by side.  Each column
   is at least 240 px wide and grows equally.
══════════════════════════════════════════ */
.controls {
  margin-top: 16px;
  display: grid;
  grid-template-columns: repeat(2, minmax(240px, 1fr)); /* 2 equal columns */
  gap: 12px;
}

/* ══════════════════════════════════════════
   CONFIG CARD
   Individual cart configuration panel.
   Semi-transparent white (--card) over the blue
   gradient gives a subtle frosted-glass appearance.
══════════════════════════════════════════ */
.config {
  padding: 12px;
  border-radius: 12px;
  background: var(--card);       /* frosted white */
  border: 2px solid #c8d7ea;     /* light blue-grey border */
}

.config h2 {
  margin: 0 0 8px;
  font-size: 1.1rem;
}

/* ── Colour-coded left border identifies each cart ── */

/* Cart A (Red): thick red stripe on the left edge */
.config.red {
  border-left: 8px solid var(--red);
}

/* Cart B (Green): thick green stripe on the left edge */
.config.green {
  border-left: 8px solid var(--green);
}

/* Label above each select: displayed as block so it sits on its own line */
.config label {
  display: block;
  margin-top: 8px;
  font-weight: 600;
}

/* Force/mass dropdown: full-width, consistent padding and border-radius */
.config select {
  margin-top: 4px;
  width: 100%;
  padding: 8px;
  font-size: 1rem;
  border-radius: 8px;
  border: 1px solid #94a8bf;
  background: #fff;
}

/* ══════════════════════════════════════════
   ACCELERATION READOUT  (unused in current DOM
   but reserved for future inline a = F/m display)
══════════════════════════════════════════ */
.accel {
  margin: 10px 0 0;
  font-weight: 700;
}

/* ══════════════════════════════════════════
   RACE ACTIONS BAR
   Horizontal flex row containing: Start Race,
   Reset, Nudge A/B buttons, Start Position
   dropdown, and the result text paragraph.
   flex-wrap lets it reflow to multiple lines
   on narrow screens.
══════════════════════════════════════════ */
.race-actions {
  margin-top: 14px;
  display: flex;
  flex-wrap: wrap;    /* wrap to next line on narrow screens */
  align-items: center;
  gap: 10px;
}

.race-actions label {
  font-weight: 600;
}

/* Start-position dropdown in the actions bar */
.race-actions select {
  padding: 9px 10px;
  font-size: 0.95rem;
  border-radius: 8px;
  border: 1px solid #94a8bf;
  background: #fff;
  font-family: inherit; /* match the body font, not the browser default */
}

/* ══════════════════════════════════════════
   BUTTONS
   Primary button style: dark navy fill, white
   text.  All buttons share this base; the
   .secondary modifier applies a grey variant.
══════════════════════════════════════════ */
button {
  border: 0;
  border-radius: 10px;
  padding: 10px 14px;
  font-family: inherit; /* match body font */
  font-weight: 700;
  cursor: pointer;
  background: #1f4d88; /* dark navy — primary action colour */
  color: #fff;
}

/* Secondary buttons (Reset, Nudge): muted grey variant */
button.secondary {
  background: #5b6f88;
}

/* Disabled state: dim and show a not-allowed cursor */
button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* ══════════════════════════════════════════
   RESULT DISPLAY
   The paragraph that shows "Result: Racing…",
   winner announcement, or "Tie".
   Bold weight ensures it stands out in the
   crowded actions bar.
══════════════════════════════════════════ */
#result {
  margin: 0;
  font-weight: 700;
}

/* ══════════════════════════════════════════
   RACE STAGE
   Wrapper around the track.  Top margin
   separates it from the actions bar.
══════════════════════════════════════════ */
.race-stage {
  margin-top: 14px;
}

/* ══════════════════════════════════════════
   TRACK
   Outer container for the two lanes and the
   finish line.  position:relative is required
   so absolutely-positioned children (finish
   line, vectors, carts) are placed relative
   to this element.  overflow:hidden clips
   any element that moves outside the track.
══════════════════════════════════════════ */
.track {
  position: relative;
  border: 3px solid var(--line);   /* bold dark border frames the track */
  border-radius: 14px;
  overflow: hidden;                /* clip carts/vectors outside the track */
  background: #cfd8e3;             /* medium grey between the two lanes */
}

/* ══════════════════════════════════════════
   LANE
   Each lane is a fixed-height strip that
   contains a cart and its vector overlays.
   The repeating-gradient gives a track-tile
   appearance using alternating light-grey bands.
   position:relative is required for the
   absolutely-positioned cart and vectors.
══════════════════════════════════════════ */
.lane {
  position: relative;
  height: 96px;
  border-top: 2px solid var(--lane-edge);    /* divider between lanes */
  border-bottom: 2px solid var(--lane-edge);
  /* Alternating 30 px tile pattern: --lane grey / lighter grey */
  background:
    repeating-linear-gradient(
      90deg,
      var(--lane) 0 30px,   /* lane colour stripe: 30 px wide  */
      #f2f4f7 30px 60px     /* lighter stripe:     30 px wide  */
    );
}

/* Remove the redundant top border from the first lane (track border covers it) */
.lane:first-child {
  border-top: 0;
}

/* Remove the redundant bottom border from the last lane */
.lane:last-child {
  border-bottom: 0;
}

/* ══════════════════════════════════════════
   FINISH LINE
   Checkered vertical strip positioned near the
   right end of the track (64 px from the right
   edge).  The repeating-gradient creates the
   classic black-and-white checkered pattern.
   z-index:2 keeps it above the track background
   but below the carts (z-index:3).
══════════════════════════════════════════ */
.finish-line {
  position: absolute;
  top: 0;
  bottom: 0;
  right: 64px;   /* 64 px gap from the right edge — matches JS finish detection */
  width: 10px;
  /* Alternating 12 px black and white squares stacked vertically */
  background:
    repeating-linear-gradient(
      180deg,
      #ffffff 0 12px,  /* white square: 12 px tall */
      #000000 12px 24px /* black square: 12 px tall */
    );
  z-index: 2;
}

/* ══════════════════════════════════════════
   CART
   The coloured block that races along the lane.
   position:absolute + left:18px places it at the
   starting position (START_LEFT = 18 px in JS).
   top:28px centres it vertically within the
   96 px lane (96/2 − 40/2 = 28 px).
   z-index:3 places carts above the finish line
   and lane background.
══════════════════════════════════════════ */
.cart {
  position: absolute;
  left: 18px;         /* initial x position — matches JS START_LEFT constant */
  top: 28px;          /* vertical centre within 96 px lane: (96 - 40) / 2 = 28 */
  width: 92px;
  height: 40px;
  border-radius: 10px;
  color: #fff;
  font-weight: 700;
  display: grid;
  place-items: center; /* centre the cart label text horizontally and vertically */
  z-index: 3;          /* above finish line (z:2) and lane background (z:auto) */
  box-shadow: 0 7px 12px rgba(0, 0, 0, 0.24); /* subtle drop shadow for depth */
}

/* ══════════════════════════════════════════
   VECTOR OVERLAYS (BASE)
   Common base for all arrow elements (speed
   vectors and force vectors).
   position:absolute + pointer-events:none lets
   them float over the lane without capturing
   mouse events.  z-index:4 keeps them above carts.
══════════════════════════════════════════ */
.vector {
  position: absolute;
  pointer-events: none; /* arrows are display-only; don't intercept clicks */
  z-index: 4;           /* above carts (z:3) */
}

/* ══════════════════════════════════════════
   SPEED (VELOCITY) VECTOR
   A thin dark horizontal bar with a right-pointing
   arrowhead, showing the cart's current speed.
   The bar length is set by JavaScript (min 8 px,
   max 170 px).  The ::after pseudo-element draws
   the arrowhead using CSS borders (triangle trick).
   .reverse is added by JS when velocity is negative.
══════════════════════════════════════════ */
.speed-vector {
  height: 4px;               /* thin bar */
  background: #1a2634;       /* same dark colour as --ink */
  border-radius: 2px;
  transform: translateY(-50%); /* vertically centre on the set top value */
}

/* Right-pointing arrowhead for positive (rightward) velocity */
.speed-vector::after {
  content: "";
  position: absolute;
  top: 50%;
  right: -2px;                               /* attached to the right end of the bar */
  transform: translateY(-50%);
  border-top: 8px solid transparent;
  border-bottom: 8px solid transparent;
  border-left: 12px solid #1a2634;           /* rightward triangle */
}

/* .reverse modifier: flip to a left-pointing arrowhead for negative velocity */
.speed-vector.reverse::after {
  right: auto;
  left: -2px;                                /* attached to the left end instead */
  border-left: 0;                            /* remove the right-pointing triangle */
  border-right: 12px solid #1a2634;          /* leftward triangle */
}

/* ══════════════════════════════════════════
   FORCE VECTOR
   A slightly thicker bar (7 px) with a larger
   arrowhead indicating an applied force.
   .left arrows represent rightward forces
   (placed to the left of the cart, pointing in).
   .right arrows represent leftward forces
   (placed to the right of the cart, pointing in).
   The ::after pseudo-element draws the arrowhead;
   left vs. right variant is set by .left/.right.
══════════════════════════════════════════ */
.force-vector {
  height: 7px;              /* thicker than speed vector to visually distinguish */
  background: #0f1a29;      /* slightly darker than speed vector */
  border-radius: 3px;
  transform: translateY(-50%);
}

/* Arrowhead positioning shared between .left and .right */
.force-vector::after {
  content: "";
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
}

/* .left force arrows point rightward (rightward push on the cart from the left side) */
.force-vector.left::after {
  right: -2px;                            /* arrowhead at the right end of the bar */
  border-top: 11px solid transparent;
  border-bottom: 11px solid transparent;
  border-left: 14px solid #0f1a29;        /* rightward triangle */
}

/* .right force arrows point leftward (leftward push on the cart from the right side) */
.force-vector.right::after {
  left: -2px;                             /* arrowhead at the left end of the bar */
  border-top: 11px solid transparent;
  border-bottom: 11px solid transparent;
  border-right: 14px solid #0f1a29;       /* leftward triangle */
}

/* ══════════════════════════════════════════
   CART COLOUR VARIANTS
   Gradient backgrounds give the carts a slightly
   three-dimensional look.  The gradient goes
   135 deg (top-left to bottom-right), lighter
   at the top, darker at the bottom.
══════════════════════════════════════════ */

/* Cart A — red gradient (bright red → dark red) */
.red-cart {
  background: linear-gradient(135deg, #f05252, #b61f1f);
}

/* Cart B — green gradient (bright green → dark green) */
.green-cart {
  background: linear-gradient(135deg, #46cb73, #21753a);
}

/* ══════════════════════════════════════════
   RESPONSIVE — NARROW SCREENS (≤ 760 px)
   On mobile / tablet:
     • Controls stack vertically (1 column).
     • Carts shrink slightly to fit the narrower track.
══════════════════════════════════════════ */
@media (max-width: 760px) {
  /* Stack the two config cards vertically */
  .controls {
    grid-template-columns: 1fr;
  }

  /* Reduce cart width so they fit in the narrower track */
  .cart {
    width: 78px;
    font-size: 0.9rem;
  }
}
