/* Layout and structure shared by both themes.
 *
 * Both theme sheets are always linked (index.html never swaps the <link>
 * tags, only the data-theme attribute), so this file owns geometry only —
 * grids, spacing, sizing — and reaches for a custom property everywhere a
 * colour would normally go. Kit's token sheets (css/kit/retro-tokens.css and
 * css/kit/clean-tokens.css) define every property this file reads, and
 * retro.css / clean.css add Scheduler's own (--bucket-*).
 *
 * Motion is structure too, so it lives here, and only through Kit's tokens
 * (css/kit/motion.css): the durations and easings, the wp-enter and
 * wp-toast-in keyframes. Only transform, opacity and colours ever animate,
 * and motion.css's reduced-motion rule stops all of it.
 */

*, *::before, *::after { box-sizing: border-box; }

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

body {
  font-family: var(--font-body);
  color: var(--text);
  background: var(--bg);
  line-height: 1.4;
}

button, input, select, textarea {
  font-family: inherit;
  font-size: inherit;
  color: inherit;
}

h1, h2, h3, h4, p, ul, ol, fieldset {
  margin: 0;
}

ul { list-style: none; padding: 0; }

/* Keyboard focus has to survive both themes without this file knowing what
 * either one looks like, so the ring shape lives here and each theme only
 * supplies --focus. Every interactive control in the markup is one of these
 * tags, so a single rule covers "every button and input" without hunting
 * down each id.
 */
:is(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

/* The app toggles whole panels with the `hidden` attribute rather than a
 * class, so this has to out-rank every display value either theme sets on
 * #person-form-panel, .view, #saved-calendars-panel and #toast — otherwise
 * flipping one view back on leaves the others visible underneath it.
 */
[hidden] { display: none !important; }

/* ============================== App shell ============================== */

#app {
  min-height: 100%;
  display: grid;
  grid-template-columns: 220px 1fr;
  grid-template-rows: auto 1fr;
  grid-template-areas:
    "topbar topbar"
    "sidebar main";
}

#topbar {
  grid-area: topbar;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 20px;
}

#brand {
  font-size: 22px;
  font-weight: bold;
}

/* The appearance control (Kit's appearance.js and appearance.css) sits where
   the two theme buttons used to. Kit stacks its parts; the topbar lays them
   out in one row on a wide screen: title, theme, scheme, and the retro note
   beside them. On a phone it sits behind #appearance-menu, a <details> whose
   summary is a 44px button on the brand row and whose panel drops below the
   topbar (app.js keeps it open on wider screens, where the summary is
   hidden). This only places Kit's pieces; the themes colour them. */
#appearance .wp-appearance {
  max-width: none;
  grid-template-columns: auto minmax(130px, auto) minmax(200px, auto) auto;
  align-items: center;
  column-gap: 12px;
  row-gap: 4px;
}

#appearance-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  padding: 0 14px;
  cursor: pointer;
  list-style: none;
  user-select: none;
}

#appearance-toggle::-webkit-details-marker { display: none; }

#appearance-toggle::after {
  content: "\25BE";
  transition: transform var(--duration-fast) var(--ease-standard);
}

#appearance-menu[open] #appearance-toggle::after { transform: rotate(180deg); }

/* Chromium lays out a closed <details>'s content under content-visibility:
   hidden, and that containment makes the hidden panel measure (and
   position) against the summary. Take it out of layout altogether. */
#appearance-menu:not([open]) #appearance { display: none; }

@media (min-width: 701px) {
  #appearance-toggle { display: none; }
}

#sidebar {
  grid-area: sidebar;
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 16px 12px;
}

.nav-item {
  display: block;
  width: 100%;
  text-align: left;
  padding: 10px 12px;
  cursor: pointer;
}

.sidebar-note {
  margin-top: auto;
  font-size: 12px;
  padding: 8px 12px 0;
}

#main {
  grid-area: main;
  padding: 20px 24px 80px;
  overflow-y: auto;
  min-width: 0;
}

@media (max-width: 700px) {
  #topbar { position: relative; }
  #appearance {
    position: absolute;
    z-index: 20;
    top: 100%;
    left: 8px;
    right: 8px;
    padding: 12px;
    border-radius: var(--radius);
    box-shadow: var(--shadow-3);
    transform-origin: top;
    animation: wp-pop var(--duration-fast) var(--ease-out);
  }
  #appearance .wp-appearance { grid-template-columns: 2fr 3fr; }
  #appearance .wp-appearance-title,
  #appearance .wp-appearance-note { grid-column: 1 / -1; }
  #app {
    grid-template-columns: 1fr;
    grid-template-areas:
      "topbar"
      "sidebar"
      "main";
  }
  #sidebar {
    flex-direction: row;
    flex-wrap: wrap;
  }
  .sidebar-note { margin-top: 0; width: 100%; }
}

/* ================================ Views ================================= */

.view {
  display: flex;
  flex-direction: column;
  gap: 16px;
  max-width: 1100px;
}

.view-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}

.view-head-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.empty-note {
  padding: 16px;
  text-align: center;
}

.hint {
  font-size: 13px;
}

/* ================================ Cards ================================= */

.card-list, .check-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.person-card, .saved-calendar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 14px;
  border-radius: var(--radius);
}

.day-detail-row, .commitment-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 12px;
  border-radius: var(--radius-sm);
}

.check-list li {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
}

/* All / None, the name search and the saved-group chips above the people
   checklist (FEAT-scheduler-10). Layout only; the themes style buttons. */
.checklist-tools,
.checklist-groups {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
}

.checklist-search {
  flex: 1 1 100%;
  min-width: 0;
  padding: 4px 8px;
}

.group-chip {
  border-radius: 999px;
}

/* ================================ Panels ================================= */

.panel {
  padding: 18px 20px;
  border-radius: var(--radius);
}

.field-row {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-bottom: 12px;
}

.field-row.checkbox-row {
  flex-direction: row;
  align-items: center;
  gap: 8px;
}

/* A checkbox is not a text field. Without this it picks up the 420px width
   every other control in a .field-row gets, renders its 13px glyph at the far
   left of that box, and shoves its own label most of a panel-width away. */
.field-row.checkbox-row input[type="checkbox"] {
  width: auto;
  max-width: none;
  flex: none;
  margin: 0;
}

.field-row.checkbox-row label {
  margin: 0;
  flex: 1 1 auto;
}

.field-row label {
  font-size: 13px;
  font-weight: bold;
}

.field-row .inline-label {
  display: inline;
  margin-left: 8px;
}

#commitment-time-row {
  flex-direction: row;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
#commitment-time-row label { margin: 0; }

.field-row input,
.field-row select,
.field-row textarea {
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  width: 100%;
  max-width: 420px;
}

.form-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 8px;
}

button.primary, button.danger, #person-save, .form-actions button {
  padding: 9px 16px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-weight: bold;
}

.errors {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 10px 14px;
  border-radius: var(--radius-sm);
}

/* ====================== Availability / schedule grid ===================== */

.schedule-grid {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* minmax(0, 1fr), not 1fr. `1fr` is shorthand for minmax(auto, 1fr), and that
   `auto` is a min-content floor: each column refuses to shrink below the
   widest thing inside it, so seven day cards holding two time inputs each blew
   the row out to roughly twice the panel and ran off the right of the page.
   The zero lets the tracks actually divide the space they have. */
.sched-week {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 8px;
}

.sched-day {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 8px;
  border-radius: var(--radius-sm);
  min-height: 90px;
  min-width: 0;
}

/* Label beside its input, one pair per row, with Remove across the bottom.
   A card seven-across is about 140px and Safari's time input is wider than
   Chrome's, so anything that puts both times on one line only looks right on
   the machine it was written on. */
.sched-interval {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: 4px 6px;
  padding: 4px 6px;
  border-radius: var(--radius-sm);
  font-size: 12px;
}

.sched-time-label {
  font-size: 11px;
  opacity: 0.8;
}

.sched-interval input[type="time"] {
  width: 100%;
  min-width: 0;
  max-width: none;
  padding: 2px 4px;
  font-size: 12px;
}

/* The native clock button eats about 20px, which in a 140px card is the
   difference between "09:00 AM" and "09:00 A". The field still takes typed
   input and still opens its picker from the keyboard, so the affordance is
   dropped, not the capability. */
.sched-interval input[type="time"]::-webkit-calendar-picker-indicator {
  display: none;
}

.sched-interval .sched-remove-window {
  grid-column: 1 / -1;
  font-size: 11px;
  padding: 3px 6px;
}

.sched-day .sched-add-window,
.sched-day .sched-copy {
  font-size: 11px;
  padding: 4px 6px;
  width: 100%;
  min-width: 0;
}

/* The whole-week presets, one row above the weeks (FEAT-scheduler-1). */
.sched-presets {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-bottom: 4px;
}

.sched-presets-label {
  font-size: 13px;
  font-weight: 600;
}

.sched-preset {
  font-size: 13px;
}

/* A day whose window failed validation (UX-scheduler-9). */
.sched-day.invalid {
  outline: 2px solid var(--danger);
  outline-offset: 1px;
}

/* A 4-week rotation is 28 cards; seven across stays readable down to about
 * 900px, below which point they get narrower than their own time labels, so
 * the grid gives up on one row per week and wraps by card width instead.
 */
@media (max-width: 900px) {
  .sched-week {
    grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  }
}

/* ================================ Scheduler ============================== */

#scheduler-body {
  display: grid;
  grid-template-columns: 240px 1fr 280px;
  gap: 20px;
  align-items: start;
}

@media (max-width: 900px) {
  #scheduler-body {
    grid-template-columns: 1fr;
  }
}

#scheduler-controls {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 16px;
  border-radius: var(--radius);
}

#calendar-pane {
  padding: 16px;
  border-radius: var(--radius);
  min-width: 0;
}

#calendar-header {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 12px;
}

#cal-title { flex: 1; text-align: center; font-size: 16px; }

.cal-weekdays {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  margin-bottom: 6px;
}

.cal-weekday {
  text-align: center;
  font-size: 11px;
  font-weight: bold;
  padding: 4px 0;
}

.cal-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
}

.cal-day {
  aspect-ratio: 1;
  display: flex;
  /* Column, not row. The cell holds two separate spans — the day of the month
     and the availability count — and side by side with no separator they read
     as one number: the 1st of a month showing 2 of 2 free rendered as
     "12/2". Stacking them is what makes the grid legible. */
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 13px;
  padding: 0;
  line-height: 1.1;
}

.cal-day-number {
  display: block;
  font-size: 14px;
  font-weight: bold;
}

/* Deliberately quieter than the date: it is an annotation on the day, not the
   day itself. Hidden when nobody is selected, because "0/0" is noise. */
.cal-day-count {
  display: block;
  font-size: 10px;
  opacity: 0.85;
  font-variant-numeric: tabular-nums;
}

.cal-day[data-bucket="none"] .cal-day-count {
  visibility: hidden;
}

.legend {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 14px;
  font-size: 12px;
}

.legend-item {
  display: flex;
  align-items: center;
  gap: 6px;
}

/* The swatch borrows `color` rather than a background var of its own: each
 * theme sets `color` on .legend-item[data-bucket="…"] to the same value it
 * uses for that bucket's calendar fill, so the key always matches the grid
 * without a second colour to keep in sync. The JS never sets a colour here —
 * bucket colours come from CSS attribute selectors only.
 */
/* The swatch carries the bucket colour; the label stays body text. Painting
   both the same colour (background: currentColor) is what dragged five of the
   eight legend labels under 4.5:1 — worst was 2.27:1 — because a fill that
   reads well as a 12px block does not read well as 12px type. */
.legend-item::before {
  content: "";
  display: inline-block;
  width: 12px;
  height: 12px;
  border-radius: 3px;
  flex: none;
  background: var(--swatch, currentColor);
  /* The clean theme's fills are pale tints chosen to sit behind a whole day
     cell; at 12px on a white panel the green one is all but invisible without
     an edge to hold it. */
  border: 1px solid var(--border);
}

#day-detail {
  padding: 16px;
  border-radius: var(--radius);
  min-width: 0;
}

#additional-commitments {
  margin-top: 4px;
  padding: 14px 16px;
  border-radius: var(--radius);
}

#additional-commitments summary {
  cursor: pointer;
  font-weight: bold;
}

#additional-commitments form {
  margin-top: 14px;
}

/* "Use this time" under the day detail, and the invite it opens. The panel
   spans the whole Scheduler row rather than landing in its first column. */
.slot-list {
  list-style: none;
  margin: 12px 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.use-slot {
  max-width: 100%;
}

#invite-panel {
  grid-column: 1 / -1;
  min-width: 0;
}

/* A link that does a button's job (the mailto: invite). */
a.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 9px 16px;
  border-radius: var(--radius-sm);
  font-weight: bold;
  text-decoration: none;
  cursor: pointer;
}

/* ================================= Toast ================================= */

/* Centred with auto margins, not translateX(-50%): the arrival animation
   (wp-toast-in) moves transform, and would drop a centring transform for
   its duration and then jump. */
#toast {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 20px;
  width: fit-content;
  margin: 0 auto;
  max-width: min(90vw, 480px);
  padding: 12px 18px;
  border-radius: var(--radius);
  text-align: center;
  z-index: 1000;
}

/* ============================== Data view ================================ */

#export-output, #import-input {
  width: 100%;
  padding: 10px;
  border-radius: var(--radius-sm);
  font-family: monospace;
  resize: vertical;
}

.count-badge {
  font-size: 12px;
  font-weight: normal;
  margin-left: 8px;
}


/* ===================== Hooks the views apply by name =====================
 * Everything below is a class the JavaScript puts on an element. They were
 * added to the markup as it was built and never picked up styles, which is
 * how .sr-only got away with rendering visibly. Nothing here is decorative
 * beyond what each element needs to be readable; the themes supply colour.
 */

/* A person's schedule in one line, under their name in the roster. It is an
   annotation, so it must not compete with the name itself. */
.person-card-summary {
  font-size: 12px;
  opacity: 0.75;
}

.sched-day-label {
  font-size: 12px;
  font-weight: bold;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.sched-day-toggle {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
}

/* The checkbox here is the one exception to the form-field width rule for the
   same reason as .checkbox-row: it is a glyph, not a field. */
.sched-day-toggle input[type="checkbox"] {
  width: auto;
  max-width: none;
  flex: none;
  margin: 0;
}

.sched-intervals {
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.next-times-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 0 0 12px;
  padding: 0;
  list-style: none;
}

.next-time {
  display: block;
  width: 100%;
  min-height: 44px;
  padding: 8px 12px;
  text-align: left;
  cursor: pointer;
}

.check-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border-radius: var(--radius-sm);
}

.check-row label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: pointer;
}

.person-check {
  width: auto;
  max-width: none;
  flex: none;
  margin: 0;
  cursor: pointer;
}

.day-detail-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}

.day-detail-name {
  font-weight: bold;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.day-detail-hours,
.day-detail-times {
  font-size: 12px;
  opacity: 0.8;
  white-space: nowrap;
}

/* The day timeline (FEAT-scheduler-7): layout only; the theme sheets map each
   cell's data-color to a --swatch. */
.timeline {
  margin-block: 8px;
}

.timeline-hours,
.timeline-row,
.timeline-everyone {
  display: flex;
  align-items: center;
  gap: 4px;
}

.timeline-name {
  flex: 0 0 5.5rem;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.timeline-track,
.timeline-hour,
.timeline-cell {
  flex: 1 1 0;
  min-width: 0;
}

.timeline-track {
  display: flex;
}

.timeline-cell {
  height: 18px;
  border: 1px solid var(--border);
}

.timeline-cell[data-state="free"] {
  background: var(--swatch, currentColor);
}

.timeline-hour {
  font-size: 11px;
  white-space: nowrap;
  overflow: visible;
}

.day-detail-local {
  font-size: 12px;
  white-space: nowrap;
}

.commitment-row,
.saved-calendar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.commitment-text,
.saved-calendar-name {
  min-width: 0;
  flex: 1 1 auto;
}

.saved-calendar-name {
  font-weight: bold;
  text-align: left;
}

.commitment-remove,
.saved-calendar-load,
.saved-calendar-delete {
  flex: none;
  font-size: 12px;
  padding: 4px 10px;
}

/* The sidebar marks the open section twice — aria-current for assistive tech,
   .active for the eye. The themes colour it; this only reserves the hook. */
.nav-item.active {
  font-weight: bold;
}

/* Shown when the browser refuses to persist anything, so it has to read as a
   warning rather than as the ordinary "saved here only" note. */
.warn {
  font-weight: bold;
  opacity: 1;
}

/* ================================= Motion ================================
 * Kit's catalogue (clean-theme plan 5.2), on its tokens. Controls fade their
 * colours and shadow on hover and focus, and press in slightly; a view that
 * just lost `hidden` enters with wp-enter; the toast arrives with
 * wp-toast-in. Hover lifts that move or shadow sit under (hover: hover), in
 * the theme sheets.
 */
button, input, select, textarea, summary {
  transition:
    background-color var(--duration-fast) var(--ease-standard),
    color var(--duration-fast) var(--ease-standard),
    border-color var(--duration-fast) var(--ease-standard),
    box-shadow var(--duration-fast) var(--ease-standard),
    outline-color var(--duration-fast) var(--ease-standard),
    transform var(--duration-fast) var(--ease-standard);
}

button:active:not(:disabled) {
  transform: scale(0.98);
}

.view:not([hidden]) {
  animation: wp-enter var(--duration) var(--ease-out);
}

#toast:not([hidden]) {
  animation: wp-toast-in var(--duration) var(--ease-out);
}
