/* Hallmark - macrostructure: none (application shell) - genre: modern-minimal - tone: technical/utilitarian
 * anchor hue: 200 - system: Bootstrap 6.0.0-alpha.1 (vendored verbatim as bootstrap.min.css) */
/* Hallmark - pre-emit critique: P5 H4 E5 S5 R5 V4 */
/* Hallmark - slop test (58 gates, application-shell subset): 4, 24, 25, 26, 33, 40, 56 failed on the
   first pass and are fixed; 39 is an accepted deviation - Bootstrap's .btn metrics are the deliberate
   instrument density, and the inline error slot gate 39 asks for is Bootstrap's .invalid-feedback. */

/* app.css - everything Bootstrap does not supply.
   Bootstrap owns the design system: tokens, grid, components, utilities. This file only
   (1) retunes its tokens to the planner's own palette and density - every colour is one
   light-dark() pair, so a single declaration serves both themes - and
   (2) states the conventions it has no component for: the focus ring, the queued-edit
   mark, the sticky stint column, the row accents, the section rail's flat shape, the stint
   timeline, the driver colour dot and the pending-edit marker. Every colour in this file
   lives in the :root block below. */

:root {
  /* -- Surfaces: Bootstrap's bg ladder maps onto the planner's paper ladder -- */
  --bs-bg-body: light-dark(oklch(97% 0.003 245), oklch(21% 0.008 245));
  --bs-bg-1: light-dark(oklch(93% 0.005 245), oklch(25% 0.009 245));
  --bs-bg-2: light-dark(oklch(89% 0.006 245), oklch(29% 0.010 245));
  --bs-bg-3: light-dark(oklch(84% 0.008 245), oklch(34% 0.011 245));

  /* -- Text: fg-body is plan text, fg-1 headings, fg-2 the "secondary" a hint uses -- */
  --bs-fg-body: light-dark(oklch(24% 0.012 245), oklch(96% 0.004 245));
  --bs-fg-1: light-dark(oklch(40% 0.012 245), oklch(80% 0.007 245));
  /* 66 % keeps muted text at 4.54:1 on --bs-bg-2 (WCAG 4.5 for body text). */
  --bs-fg-2: light-dark(oklch(48% 0.012 245), oklch(66% 0.009 245));

  /* -- Lines -- */
  --bs-border-color: light-dark(oklch(84% 0.008 245), oklch(34% 0.011 245));
  --bs-border-body: light-dark(oklch(78% 0.010 245), oklch(38% 0.011 245));
  --bs-border-emphasized: light-dark(oklch(62% 0.013 245), oklch(50% 0.013 245));

  /* -- Accent: the one colour the planner owns, a cyan at hue 200 -- */
  --bs-primary-base: light-dark(oklch(48% 0.12 200), oklch(74% 0.13 200));
  --bs-primary-bg: var(--bs-primary-base);
  --bs-primary-fg: var(--bs-primary-base);
  --bs-primary-fg-emphasis: light-dark(oklch(38% 0.11 200), oklch(86% 0.10 200));
  --bs-primary-bg-subtle: light-dark(oklch(90% 0.04 200), oklch(32% 0.045 200));
  --bs-primary-bg-muted: light-dark(oklch(84% 0.06 200), oklch(38% 0.06 200));
  --bs-primary-border: light-dark(oklch(70% 0.09 200), oklch(50% 0.09 200));
  --bs-primary-contrast: light-dark(oklch(98% 0.01 200), oklch(20% 0.03 200));
  --bs-primary-focus-ring: light-dark(oklch(46% 0.13 200), oklch(80% 0.13 200));
  --bs-focus-ring-color: var(--bs-primary-focus-ring);

  /* -- Density and numerals: a pit-wall instrument, not a marketing page -- */
  --bs-body-font-size: 0.875rem;
  --bs-font-mono: ui-monospace, "Cascadia Mono", Consolas, "SFMono-Regular", Menlo, monospace;

  /* -- Driver identities: six theme-aware presets, which a driver may replace with any colour -- */
  --color-driver-1: light-dark(oklch(50% 0.14 200), oklch(72% 0.15 200));
  --color-driver-2: light-dark(oklch(54% 0.13 80), oklch(75% 0.15 80));
  --color-driver-3: light-dark(oklch(50% 0.16 320), oklch(72% 0.16 320));
  --color-driver-4: light-dark(oklch(48% 0.13 150), oklch(74% 0.15 150));
  --color-driver-5: light-dark(oklch(52% 0.17 25), oklch(70% 0.17 25));
  --color-driver-6: light-dark(oklch(48% 0.14 285), oklch(70% 0.13 285));
  /* Text that sits ON a driver colour (a timeline block), whatever that colour is. */
  --driver-ink: oklch(16% 0.01 245);
}

/* -- Numbers are read in columns: every figure sits in the mono face -- */
.figures, td.num, input.num, .totals dd, .room-code, .who {
  font-family: var(--bs-font-mono);
  font-variant-numeric: tabular-nums;
}

/* -- The room code reads as a code, not as a label -- */
.room-code { letter-spacing: 0.12em; }

/* -- A driver's own colour: one variable, set inline from the plan -- */
.driver-dot {
  display: inline-block;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: var(--bs-radius-pill);
  background: var(--driver-colour, var(--bs-fg-2));
  vertical-align: middle;
}

/* -- Four wheels where they are on the car: the front pair over the rear pair, each
      box labelled with its own corner. Used twice - the stop's tick list in the plan
      table and the driver's live reading on the Live tab. -- */
.wheels {
  display: grid;
  grid-template-columns: auto auto;
  gap: 0.125rem 0.5rem;
  justify-content: start;
}
.wheel {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  font-family: var(--bs-font-mono);
  font-size: 0.6875rem;
  color: var(--bs-fg-2);
  cursor: pointer;
}
.wheel input[type="text"] { width: 2.75rem; }

/* -- A queued edit that has not been acknowledged by the server yet. The mark sits on
      the field's cell or wrapper: an <input> is a replaced element and paints no
      ::after, so the same rule hung off the control showed nothing at all. -- */
.pending { position: relative; }
.pending::after {
  content: "";
  position: absolute;
  top: 0;
  inset-inline-end: 0.35rem;
  width: 0.4rem;
  height: 0.4rem;
  border-radius: 50%;
  background: var(--bs-warning-base);
  pointer-events: none;
}
td.pending { padding-inline-end: 0.9rem; }

/* -- Feedback has to be where the eye already is: the banner reports a copy, a server
      error or a queued destructive action, and it used to scroll away with the page. -- */
#banner {
  position: sticky;
  top: 0;
  z-index: 2050;
}
/* The header sticks at the top as well, and the banner sits above it in the flow: with
   both at top: 0 the message covered the Room and Theme buttons. --banner-h is the
   banner's own height (it wraps on a phone), written by banner(). */
header.navbar { top: var(--banner-h, 0px); }

/* -- Keyboard focus. Bootstrap rings its own .form-control and nothing else, so the
      tab strip, the buttons and the plan table's cells had no visible focus at all. -- */
:is(.btn, .nav-link, .form-control, .form-range-input, .check, button.badge, [role="tabpanel"]):focus-visible {
  outline: 2px solid var(--bs-focus-ring-color);
  outline-offset: 2px;
}
td :is(.form-control, .check):focus-visible { outline-offset: -2px; }

/* -- A "Needs input" chip is a button: it opens the tab that owns the field. -- */
button.badge { cursor: pointer; border: 0; }

/* -- The plan is 22 columns wide and scrolls sideways. The stint number and its
      badges are what every other number is read against, so they stay put. -- */
.table-plan th:first-child,
.table-plan td:first-child {
  position: sticky;
  inset-inline-start: 0;
  z-index: 3;
  background: var(--bs-bg-body);
}
.table-plan thead th:first-child { z-index: 4; }
/* The input is borderless so the table reads as a table; that also made a cell you can
   type in look exactly like one you cannot. A hairline under it says which is which. */
.table-plan td input.form-control-plaintext { border-bottom: 1px dashed var(--bs-border-emphasized); border-radius: 0; }
.table-plan td input.form-control-plaintext:hover { border-bottom-color: var(--bs-primary-base); }
.table-plan td input.num { min-width: 3.25rem; }

/* Bootstrap's .row is a flex container, so a column's min-width:auto lets a wide child
   (the 22-column plan table, the tab strip) push the whole document sideways. */
main .row > .col-12 { min-width: 0; }

/* -- The rail reads as a sidebar, not a floating capsule. Bootstrap's .nav-pills is a
      segmented control - a stadium container with a filled pill for the active tab -
      which is right for two or three options and wrong for six sections down a column.
      Its tokens are declared *on* .nav-pills, so they cannot be retuned from :root;
      they are set here, on the rail, and they win on specificity.
      Two layout facts come with it: .nav is inline-flex, so the strip shrink-to-fits its
      widest label (a 236px column held a 101px blob) and can drag the document
      sideways, and .nav-link centres its label - right in a pill strip, wrong in a list. -- */
#rail {
  display: flex;
  /* The banner sticks to the very top too, and the header starts under it, so the rail
     has to start under both. --banner-h is written by banner() and is 0px when there is
     no message. (This replaces the inline top on the nav.) */
  top: calc(var(--banner-h, 0px) + 4.5rem);
  --bs-nav-pills-bg: transparent;
  --bs-nav-pills-padding: 0;
  --bs-nav-pills-border-radius: 0;
  --bs-nav-pills-link-border-radius: var(--bs-radius-4);
  /* One step stronger than the "wash" the recommended strategy row uses: a selected
     section has to be visible at a glance, and -subtle sat at 1.2:1 against the page. */
  --bs-nav-pills-link-active-bg: var(--bs-primary-bg-muted);
  --bs-nav-pills-link-active-color: var(--bs-primary-fg-emphasis);
}
#rail .nav-link { justify-content: flex-start; text-align: start; }
/* The active section is a tint, not a fill: --bs-gradient is a white sheen meant for
   a filled pill, and over a tint it just muddies it. */
#rail .nav-link.active { background-image: none; }

/* -- Below a phone breakpoint the sticky header is the whole fixed-chrome budget: the
      read-outs Live already shows leave it, and the tab strip runs on one line and
      scrolls sideways instead of wrapping onto a second row. -- */
@media (max-width: 575.98px) {
  #memberCount, #driverInCar { display: none; }
  /* The strip is one line that scrolls inside itself (see the display rule above). */
  #rail { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
  #rail::-webkit-scrollbar { display: none; }
  #rail .nav-link { flex: 0 0 auto; white-space: nowrap; }
}

/* -- Row accents on the plan table (Bootstrap has no "this row breaks a rule" state) -- */
tr.is-violation td:first-child { box-shadow: inset 3px 0 0 var(--bs-danger-base); }

/* Bootstrap's .dialog sets display:flex, which defeats the browser's own
   dialog:not([open]) { display: none }. Left alone, a closed dialog stays in the
   layout with opacity 0 - invisible, but still able to swallow a click. */
dialog:not([open]) { display: none; }

/* -- The stint Timeline: the driver's name, then their lane with one block per
      stint, positioned by race time -- */
.gantt { display: grid; gap: 0.25rem; }
.lane { display: grid; grid-template-columns: 6rem minmax(0, 1fr); align-items: center; gap: 0.375rem; }
.lane__name {
  font-family: var(--bs-font-mono);
  font-size: 0.6875rem;
  color: var(--driver-colour, var(--bs-fg-2));
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lane__track {
  position: relative;
  height: 26px;
  background: repeating-linear-gradient(90deg, var(--bs-bg-2) 0 1px, transparent 1px 6px);
  border: 1px solid var(--bs-border-color);
  border-radius: var(--bs-radius-3);
}
.lane.is-bad .lane__track { outline: 2px solid var(--bs-danger-base); }
.blk {
  position: absolute;
  top: 3px;
  height: 20px;
  background: var(--driver-colour);
  border-radius: var(--bs-radius-3);
  overflow: hidden;
  font-family: var(--bs-font-mono);
  font-size: 0.6875rem;
  color: var(--driver-ink);
  font-weight: var(--bs-font-weight-semibold);
  text-align: center;
  line-height: 20px;
}
.blk.is-bad { outline: 2px solid var(--bs-danger-base); }
.axis {
  display: flex;
  justify-content: space-between;
  font-family: var(--bs-font-mono);
  font-size: 0.6875rem;
  color: var(--bs-fg-2);
  margin-inline-start: 6.375rem;
}
