/* ==================================================================
   Airsoft Cluj — game calendar

   The five official MultiCam colours, and nothing else:

     #b8a78b tan   #48352f brown   #967860 coyote
     #5a613f olive #8c7d50 khaki

   Those five are mid-tone earth colours, and only ONE pairing of them
   clears WCAG AA for text (#48352f on #b8a78b, 4.90:1) — coyote and
   khaki even share the same luminance, so they are the same colour in
   greyscale. The page therefore derives an ink and two pale sands from
   the SAME hues: identical H and S, lightness pushed until type is
   readable. No sixth hue exists on this page.

   The rule everything below follows:
     hue lives in fills, borders and edges;
     text is only ever ink/brown (dark) or paper/sand (light).

   No gradients anywhere. Every surface, rule and event block is a flat
   colour, including the hour ruling (see .hourlines) which used to be
   painted with repeating-linear-gradient.
   ================================================================== */

:root {
  /* --- the five official MultiCam colours, verbatim --- */
  --mc-tan:    #b8a78b;
  --mc-brown:  #48352f;
  --mc-coyote: #967860;
  --mc-olive:  #5a613f;
  --mc-khaki:  #8c7d50;

  /* --- derived: same hue + saturation, lightness moved for legibility --- */
  --mc-ink:      #241a17;  /* brown,  L x0.50 — body text, 14.7:1 on paper */
  --mc-paper:    #f3eee2;  /* tan,    L +80%  — grid, topbar, modals       */
  --mc-sand:     #e6dcc6;  /* tan,    L +62%  — page, weekend, recesses    */
  --mc-deep:     #ccc0ab;  /* tan,    L +28%  — past / elapsed columns     */
  --mc-line:     #c6b9a2;  /* tan,    L +20%  — hairlines, on-hour rules   */
  --mc-line-dim: #d6ccbc;  /* tan,    L +42%  — half-hour rules            */
  --mc-muted:    #755e4b;  /* coyote, L x0.78 — placeholders, 5.2:1        */
  --mc-olive-dk: #484e32;  /* olive,  L x0.80 — primary button hover       */
  --mc-khaki-dk: #6d623e;  /* khaki,  L x0.78 — caution button hover       */
  --mc-blush:    #d1beb8;  /* brown,  L x1.70 — error surfaces             */

  --gutter-w: 56px;
  --hour-h: 48px;
  --day-h: calc(var(--hour-h) * 24);
  --radius: 8px;

  color-scheme: light;
}

* { box-sizing: border-box; }

/* An author `display` rule beats the browser's own [hidden] rule, so any
   element styled `display: flex` (.toast, .daystrip) would stay on screen
   after `el.hidden = true`. This makes the hidden attribute actually win. */
[hidden] { display: none !important; }

html, body { height: 100%; margin: 0; }

body {
  display: flex;
  flex-direction: column;
  background: var(--mc-sand);
  color: var(--mc-ink);
  font: 15px/1.45 ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif,
        /* so emoji in a title or notes render in colour on every platform,
           not as tofu boxes where the sans-serif fallback has no glyph */
        "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji";
  -webkit-text-size-adjust: 100%;
  overflow: hidden;
}

/* ---------------------------------------------------------------- Top bar */

.topbar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 56px;
  padding: 8px max(12px, env(safe-area-inset-left)) 8px max(12px, env(safe-area-inset-right));
  background: var(--mc-paper);
}

/* Flat MultiCam swatch strip — the five colours stated outright, in order. */
.mc-ribbon {
  flex: 0 0 auto;
  display: flex;
  height: 4px;
}
.mc-ribbon i { flex: 1 1 0; }
.mc-ribbon i:nth-child(1) { background: var(--mc-tan); }
.mc-ribbon i:nth-child(2) { background: var(--mc-brown); }
.mc-ribbon i:nth-child(3) { background: var(--mc-coyote); }
.mc-ribbon i:nth-child(4) { background: var(--mc-olive); }
.mc-ribbon i:nth-child(5) { background: var(--mc-khaki); }

.brand {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  font-size: 14px;
  color: var(--mc-ink);
  white-space: nowrap;
}

.brand-mark {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 2px solid var(--mc-olive);
  position: relative;
  flex: 0 0 auto;
}
.brand-mark::after {
  content: "";
  position: absolute;
  inset: 4px;
  border-radius: 50%;
  background: var(--mc-brown);
}

.weeknav { display: flex; align-items: center; gap: 6px; min-width: 0; flex: 1 1 auto; }

.range-label {
  font-size: 14px;
  font-weight: 600;
  margin: 0 0 0 6px;
  color: var(--mc-brown);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

/* ---------------------------------------------------------------- Buttons */

.btn {
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--mc-ink);
  background: var(--mc-sand);
  border: 1px solid var(--mc-khaki);
  border-radius: 6px;
  padding: 7px 12px;
  min-height: 34px;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}
.btn:hover:not(:disabled) { background: var(--mc-tan); border-color: var(--mc-brown); }
.btn:focus-visible { outline: 2px solid var(--mc-ink); outline-offset: 2px; }
.btn:disabled { opacity: 0.4; cursor: not-allowed; }

.btn-icon  { padding: 7px 11px; font-size: 17px; line-height: 1; }
.btn-ghost { background: transparent; }

.btn-primary { background: var(--mc-olive); border-color: var(--mc-olive); color: var(--mc-paper); }
.btn-primary:hover:not(:disabled) { background: var(--mc-olive-dk); border-color: var(--mc-olive-dk); color: var(--mc-paper); }

/* No red and no yellow exist in MultiCam, so caution and danger are carried
   by the darkest colours plus border weight — never by hue alone. */
.btn-warn { background: transparent; border-color: var(--mc-khaki); color: var(--mc-brown); }
.btn-warn:hover:not(:disabled) { background: var(--mc-khaki-dk); border-color: var(--mc-khaki-dk); color: var(--mc-paper); }

.btn-danger { background: transparent; border-color: var(--mc-brown); color: var(--mc-brown); }
.btn-danger:hover:not(:disabled) { background: var(--mc-brown); color: var(--mc-paper); }

/* --------------------------------------------------------- Language toggle */

/* Segmented RO | EN. Flat fills only, and no sixth hue: the active side reuses
   the olive/paper pairing .btn-primary already proves, and the inactive side is
   brown on sand. Contrast computed, not eyeballed:
     paper on olive  5.64:1   AA pass
     brown on sand   8.44:1   AA pass
   --mc-muted on sand would have been the intuitive choice for an inactive
   segment and it FAILS at 4.46:1 for text this size. Don't use it here. */
.langtoggle {
  display: flex;
  flex: 0 0 auto;
  border: 1px solid var(--mc-khaki);
  border-radius: 6px;
  overflow: hidden;
}

.langbtn {
  font: inherit;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  padding: 7px 9px;
  min-height: 34px;
  border: 0;
  cursor: pointer;
  background: var(--mc-sand);
  color: var(--mc-brown);
  transition: background-color 0.12s ease, color 0.12s ease;
}
.langbtn + .langbtn { border-left: 1px solid var(--mc-khaki); }
.langbtn[aria-pressed="true"] { background: var(--mc-olive); color: var(--mc-paper); }
.langbtn:hover:not([aria-pressed="true"]) { background: var(--mc-tan); }
.langbtn:focus-visible { outline: 2px solid var(--mc-ink); outline-offset: -2px; }

/* ------------------------------------------------------- Mobile day strip */

.daystrip {
  flex: 0 0 auto;
  display: flex;
  gap: 4px;
  padding: 8px 10px;
  overflow-x: auto;
  border-bottom: 1px solid var(--mc-line);
  background: var(--mc-sand);
  scrollbar-width: none;
}
.daystrip::-webkit-scrollbar { display: none; }

.daychip {
  flex: 1 0 auto;
  min-width: 44px;
  border: 1px solid var(--mc-khaki);
  background: transparent;
  border-radius: 6px;
  padding: 5px 4px;
  color: var(--mc-brown);
  font: inherit;
  font-size: 11px;
  cursor: pointer;
  text-align: center;
  line-height: 1.25;
}
.daychip b { display: block; font-size: 15px; color: var(--mc-ink); font-weight: 700; }
.daychip[aria-selected="true"] { background: var(--mc-olive); border-color: var(--mc-olive); color: var(--mc-paper); }
.daychip[aria-selected="true"] b { color: var(--mc-paper); }
.daychip.is-today { border-width: 2px; border-color: var(--mc-brown); }
.daychip.is-today b { color: var(--mc-brown); }
.daychip[aria-selected="true"].is-today b { color: var(--mc-paper); }
.daychip .dot {
  display: block;
  width: 5px; height: 5px;
  margin: 2px auto 0;
  border-radius: 50%;
  background: var(--mc-khaki);
}
.daychip[aria-selected="true"] .dot { background: var(--mc-paper); }
.daychip .dot.is-empty { background: transparent; }

/* --------------------------------------------------------------- Calendar */

.calendar { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }

.cal-scroll { flex: 1 1 auto; min-height: 0; overflow: auto; overscroll-behavior: contain; }

.cal-header,
.cal-grid {
  display: grid;
  grid-template-columns: var(--gutter-w) 1fr;
  min-width: 100%;
}

.cal-header {
  position: sticky;
  top: 0;
  z-index: 6;
  background: var(--mc-paper);
  border-bottom: 2px solid var(--mc-brown);
}

.gutter-head { border-right: 1px solid var(--mc-line); }

.dayheads { display: grid; grid-template-columns: repeat(var(--cols, 7), minmax(0, 1fr)); }

.dayhead {
  padding: 6px 4px;
  text-align: center;
  border-left: 1px solid var(--mc-line);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--mc-brown);
  overflow: hidden;
}
.dayhead b {
  display: block;
  font-size: 17px;
  font-weight: 700;
  color: var(--mc-ink);
  letter-spacing: 0;
}
.dayhead.is-weekend { background: var(--mc-sand); }
.dayhead.is-today { background: var(--mc-olive); color: var(--mc-paper); }
.dayhead.is-today b { color: var(--mc-paper); }

/* Hour gutter */

.gutter { position: relative; height: var(--day-h); border-right: 1px solid var(--mc-line); }
.gutter span {
  position: absolute;
  right: 6px;
  transform: translateY(-50%);
  font-size: 10px;
  font-variant-numeric: tabular-nums;
  color: var(--mc-brown);
  user-select: none;
}

/* Day columns */

.daycols {
  position: relative;
  display: grid;
  grid-template-columns: repeat(var(--cols, 7), minmax(0, 1fr));
  height: var(--day-h);
  background: var(--mc-paper);
}

.daycol {
  position: relative;
  border-left: 1px solid var(--mc-line);
  touch-action: pan-y;
}
.daycol.is-weekend { background-color: var(--mc-sand); }
.daycol.is-past    { background-color: var(--mc-deep); }

/*
 * Hour ruling as real elements rather than a repeating gradient. Sits above
 * the day-column backgrounds (z-index 0) and below the events (z-index 1),
 * so the lines show through the weekend tint but never across a game block.
 */
.hourlines {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}
.hourlines i {
  display: block;
  height: calc(100% / 48);
  border-bottom: 1px solid var(--mc-line-dim);
}
.hourlines i.on-hour { border-bottom-color: var(--mc-line); }

/* Event blocks — every game the same flat olive. Per-event colour was
   tried and pulled: a grid of seven different fills reads as noise, and the
   colour carried no meaning to decode anyway. */

.ev {
  /* Overridden by .is-over below; nothing else changes them. */
  --ev-bg: #9ba575;                 /* olive, L +30% — ink clears AA at 6.50:1 */
  --ev-edge: var(--mc-olive);       /* the official olive at full strength     */
  /* Two slots so "you're going" and "being dragged" can both show at once;
     one box-shadow property, filled in independently below. */
  --ev-ring: 0 0 #0000;
  --ev-lift: 0 0 #0000;
  box-shadow: var(--ev-ring), var(--ev-lift);
  position: absolute;
  z-index: 1;
  left: 2px;
  right: 2px;
  min-height: 18px;
  padding: 3px 5px;
  border-radius: var(--radius);
  border: 1px solid rgba(36, 26, 23, 0.25);
  border-left: 4px solid var(--ev-edge);
  background: var(--ev-bg);
  color: var(--mc-ink);
  font-size: 11.5px;
  line-height: 1.3;
  text-align: left;
  overflow: hidden;
  cursor: pointer;
  font-family: inherit;
  /* Without this a mouse drag selects the title instead of moving the game. */
  -webkit-user-select: none;
  user-select: none;
  /* A <button> vertically centres its own content in every browser, which
     floats the title into the middle of a long event. Flex-column with an
     explicit start alignment is what actually pins it to the top. */
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-start;
}
/* Darken on hover: the fills are light, so brightening would wash them into
   the page instead of lifting them off it. */
.ev:hover { z-index: 3; filter: brightness(0.95); }
.ev:focus-visible { outline: 2px solid var(--mc-ink); outline-offset: 1px; }

/* Finished games. Fading with opacity would erase the block against a light
   page, so the colour is drained out instead — the block stays fully legible
   but stops competing with games that are still ahead. */
.ev.is-over { --ev-bg: var(--mc-sand); --ev-edge: var(--mc-line); color: var(--mc-brown); }

/* You're going. Carried by an ink ring plus an inverted count pill rather
   than a fill change, so the state stays readable on a drained past block
   as well as a live one. */
.ev.is-going { --ev-ring: inset 0 0 0 3px var(--mc-ink); }
.ev.is-going .ev-count { background: var(--mc-ink); color: var(--mc-paper); }


.ev-title { font-weight: 700; display: block; }
.ev-meta  { display: block; color: rgba(36, 26, 23, 0.72); font-size: 10.5px; }
.ev-count {
  display: inline-block;
  /* The parent is a stretch flex column, so the pill needs to opt out or it
     spans the full width of the block. */
  align-self: flex-start;
  margin-top: 1px;
  padding: 0 5px;
  border-radius: 999px;
  background: rgba(36, 26, 23, 0.14);
  font-size: 10px;
  font-weight: 700;
  color: var(--mc-ink);
}

/* Your own games: draggable to a new slot, resizable by either edge.

   Deliberately no touch-action override. Touch never drags — a long press
   opens the reschedule form instead — so the grid keeps scrolling natively
   under a finger that happens to land on one of your own games. */
.ev.is-mine {
  cursor: grab;
  -webkit-touch-callout: none;
}

/* Lift, not a fill change: the fill already carries "finished", the inset ring
   already carries "you're going", and the palette has no spare hue. */
.ev.is-mine.is-dragging {
  cursor: grabbing;
  z-index: 5;                       /* over the ghost at 4, under the header at 6 */
  --ev-lift: 0 6px 14px rgba(36, 26, 23, 0.35);
  --ev-edge: var(--mc-brown);
  border-left-width: 7px;
}

/* Grip strips. Absolutely positioned because .ev is a flex column and
   generated content would otherwise become a flex item and shove the title
   down. They are cosmetic — a pointer event on a pseudo-element still reports
   the .ev as its target, so calendar.js hit-tests the edges by geometry. */
.ev.is-mine:not(.clip-start)::before,
.ev.is-mine:not(.clip-end)::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 8px;
  cursor: ns-resize;
}
.ev.is-mine:not(.clip-start)::before { top: 0; }
.ev.is-mine:not(.clip-end)::after { bottom: 0; }

/* Drag-to-create ghost */

.ghost {
  position: absolute;
  z-index: 4;
  left: 2px;
  right: 2px;
  border-radius: var(--radius);
  border: 2px dashed var(--mc-olive);
  background: rgba(90, 97, 63, 0.18);
  color: var(--mc-brown);
  font-size: 11px;
  font-weight: 600;
  padding: 2px 5px;
  pointer-events: none;
}

/* The reschedule preview. Solid brown against the create ghost's dashed olive,
   so the two drags never read as the same gesture. */
.ghost.is-move {
  border-style: solid;
  border-color: var(--mc-brown);
  background: rgba(72, 53, 47, 0.14);
}

/* Current-time line */

.nowline {
  position: absolute;
  z-index: 2;
  left: 0;
  right: 0;
  height: 0;
  border-top: 2px solid var(--mc-ink);
  pointer-events: none;
}
.nowline::before {
  content: "";
  position: absolute;
  left: -4px;
  top: -4px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--mc-ink);
}

/* ------------------------------------------------------------------ Hint */

.hint {
  flex: 0 0 auto;
  margin: 0;
  padding: 7px 12px calc(7px + env(safe-area-inset-bottom));
  text-align: center;
  font-size: 11.5px;
  color: var(--mc-brown);
  border-top: 1px solid var(--mc-line);
  background: var(--mc-sand);
}

/* ---------------------------------------------------------------- Modals */

.modal {
  border: 1px solid var(--mc-line);
  border-top: 4px solid var(--mc-olive);
  border-radius: 12px;
  background: var(--mc-paper);
  color: var(--mc-ink);
  padding: 0;
  width: min(460px, calc(100vw - 24px));
  max-height: calc(100dvh - 32px);
}
.modal-narrow { width: min(380px, calc(100vw - 24px)); }
.modal::backdrop { background: rgba(36, 26, 23, 0.55); }

.modal-body {
  padding: 18px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-height: calc(100dvh - 32px);
  overflow-y: auto;
}

.modal h2 { margin: 0; font-size: 18px; color: var(--mc-ink); overflow-wrap: anywhere; }
.modal h3 { margin: 0; font-size: 13px; }

.muted { margin: 0; font-size: 12.5px; color: var(--mc-brown); }

.field { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.field-label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--mc-brown);
}
/* Sits in the field label. `margin-left: auto` on the count alone pushes only
   the count to the right — space-between on the label would also fling the
   "required" marker away from the word it belongs to. */
.field-label { display: flex; align-items: baseline; gap: 6px; }
.field-count {
  margin-left: auto;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
  text-transform: none;
  color: var(--mc-muted);
}
.field-count.is-near { color: var(--mc-ink); }
.field-count.is-over { color: var(--mc-brown); font-weight: 700; }

.field-label em { font-style: normal; font-weight: 700; color: var(--mc-ink); text-transform: none; letter-spacing: 0; }

.field input,
.field textarea {
  font: inherit;
  font-size: 14px;
  color: var(--mc-ink);
  background: var(--mc-paper);
  border: 1px solid var(--mc-khaki);
  border-radius: 6px;
  padding: 8px 10px;
  min-width: 0;
  width: 100%;
}
.field textarea { resize: vertical; }
/* A second ring rather than a thicker border, so focusing never reflows the
   field by a pixel. */
.field input:focus, .field textarea:focus {
  outline: none;
  border-color: var(--mc-olive);
  box-shadow: 0 0 0 1px var(--mc-olive);
}
.field input::placeholder, .field textarea::placeholder { color: var(--mc-muted); }

.field-row { display: flex; gap: 10px; }
.field-row .field { flex: 1 1 0; }

.form-error {
  margin: 0;
  padding: 6px 9px;
  border-radius: 6px;
  background: var(--mc-blush);
  border: 2px solid var(--mc-brown);
  color: var(--mc-ink);
  font-size: 12.5px;
}

.modal-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin-top: 2px; }
.modal-actions .spacer { flex: 1 1 auto; }

.move-name { font-weight: 700; margin: 0 0 10px; }
.move-row { margin: 0 0 4px; color: var(--mc-ink); }
.move-label {
  display: inline-block;
  /* Wide enough for the longest label in either language: "FROM"/"DE LA". */
  min-width: 54px;
  color: var(--mc-muted);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.move-going { margin: 10px 0 0; color: var(--mc-muted); font-size: 13px; }

/* Event detail */

.event-when { margin: 0; font-size: 14px; font-weight: 600; color: var(--mc-brown); }
.event-where, .event-notes {
  margin: 0;
  font-size: 13px;
  color: var(--mc-ink);
  overflow-wrap: anywhere;
  white-space: pre-wrap;
}
.event-where::before { content: "📍 "; }

.roster {
  border-top: 1px solid var(--mc-line);
  padding-top: 10px;
  display: flex;
  flex-direction: column;
  gap: 7px;
}
.roster-head { color: var(--mc-brown); text-transform: uppercase; letter-spacing: 0.06em; }
.roster-head span { font-size: 16px; color: var(--mc-ink); }

.roster-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  max-height: 140px;
  overflow-y: auto;
}
.roster-list li {
  background: var(--mc-sand);
  border: 1px solid var(--mc-line);
  border-radius: 999px;
  padding: 2px 10px;
  font-size: 12.5px;
  color: var(--mc-ink);
  overflow-wrap: anywhere;
}
.roster-list li.is-you { background: var(--mc-olive); border-color: var(--mc-olive); color: var(--mc-paper); font-weight: 700; }
.roster-empty { margin: 0; font-size: 12.5px; color: var(--mc-brown); font-style: italic; }

.turnstile-host { display: flex; justify-content: center; min-height: 70px; }

/* ----------------------------------------------------------------- Toast */

.toast {
  position: fixed;
  left: 50%;
  bottom: calc(18px + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  z-index: 50;
  max-width: min(440px, calc(100vw - 24px));
  padding: 10px 14px;
  border-radius: 8px;
  background: var(--mc-brown);
  border: 1px solid var(--mc-ink);
  color: var(--mc-paper);
  font-size: 13px;
  display: flex;
  align-items: center;
  gap: 12px;
}
/* Inverted against the normal toast: light panel, heavy brown rule. With no
   red in the palette the reversal is what marks it as a failure. */
.toast.is-error { background: var(--mc-blush); border-width: 2px; border-color: var(--mc-brown); color: var(--mc-ink); }

/* ------------------------------------------------------------ Small screen */

@media (max-width: 700px) {
  :root { --gutter-w: 46px; --hour-h: 52px; }
  .topbar { flex-wrap: wrap; gap: 8px 10px; }
  .weeknav { order: 3; width: 100%; flex-basis: 100%; }
  .range-label { font-size: 13px; }
  .brand-text { display: none; }
  .hint { display: none; }
  .modal-actions .btn { flex: 1 1 auto; min-height: 42px; }
  .modal-actions .btn-danger { flex-basis: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
}
