@layer design {
  /* Base Styles */
  body {
    margin: 0;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    touch-action: manipulation;
  }

  .skip-link {
    position: absolute;
    top: -100px;
    left: 0;
    background: var(--primary);
    color: var(--on-primary);
    padding: var(--space-2) var(--space-4);
    z-index: 100;
    transition: top 0.2s;
  }

  .skip-link:focus {
    top: 0;
  }

  .container {
    width: 100%;
    max-width: var(--container-max-width);
    margin-inline: auto;
  }

  main {
    flex: 1;
  }

  /* Headings: Beer.css defaults (h1 = 3.5625rem) are oversized for this app.
     Pin h1 to a fixed size and derive the rest from a modular scale via calc(),
     exposing each computed size as its own var for easy per-heading overrides. */
  h1 {
    font-size: var(--h1-size);
    text-wrap: balance;
  }

  h2 {
    font-size: var(--h2-size);
    text-wrap: balance;
  }

  h3 {
    font-size: var(--h3-size);
    text-wrap: balance;
  }

  h4 {
    font-size: var(--h4-size);
    text-wrap: balance;
  }

  h5 {
    font-size: var(--h5-size);
  }

  h6 {
    font-size: var(--h6-size);
  }

  /* Multi-row headings: each row is its own block so text reflows at zoom
     instead of being pinned by <br>. */
  .heading-row {
    display: block;
  }

  /* Language selector: a comfortable tap target with explicit colors, so the
     native select stays legible on Windows dark-mode browsers. */
  #language-select {
    min-height: 24px;
    background-color: var(--surface);
    color: var(--on-surface);
  }

  /* Specific UI Elements */
  .password-display {
    font-family: var(--monospace-font), monospace;
    background: var(--surface-variant);
    color: var(--on-surface-variant);
    padding: var(--space-1) var(--space-2);
    border-radius: var(--border-radius);
    font-weight: bold;
  }

  /* Utility Classes */
  .visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }

  /* Numeric table cells (vote counts, voted column): tabular numerals so
     columns line up for at-a-glance comparison, right-aligned. In the
     stacked mobile layout the cell stays display:block, so the label and
     value both align to the end — still readable as a labelled card. */
  .num {
    font-variant-numeric: tabular-nums;
    text-align: end;
  }

  a:not(.button) {
    text-decoration: underline;
  }

  .clipboard-btn {
    cursor: pointer;
    font-size: 1.1em;
    opacity: 0.5;
    transition: opacity 0.15s;
    border: none;
    background: none;
    padding: 0;
    color: inherit;
    font-family: inherit;
    display: inline;
    line-height: inherit;
  }

  .clipboard-btn:hover {
    opacity: 1;
  }

  .mt-2 {
    margin-top: var(--space-3);
  }

  .mt-4 {
    margin-top: var(--space-5);
  }

  /* List rows inherit BeerCSS `white-space: nowrap`, which stops long
     proposed-date strings and player names from wrapping. Let the flex
     `.max` box shrink and wrap so it stays inside its row instead of
     pushing the row's switch out of view. `overflow-wrap: anywhere` breaks
     long unbreakable names (e.g. a 60-character name) mid-word. */
  .list .max {
    min-width: 0;
    white-space: normal;
    overflow-wrap: anywhere;
  }

  /* BeerCSS `.list > li` is `flex-wrap: nowrap`; when a long proposed date
     and the "votable" switch cannot share one line, let the row
     wrap so the switch drops below the date instead of overlapping it. */
  .list li {
    flex-wrap: wrap;
  }

  /* Proposed-date card list: each date is a card with a header row (date/venue | actions)
     and a details row (clashes/occupancy). CSS grid replaces the old table layout. */
  .proposed-date-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
  }

  .proposed-date-card {
    display: grid;
    grid-template-columns: 1fr auto;
    grid-template-rows: auto 1fr;
    gap: var(--space-2);
    padding: var(--space-3);
    border-radius: var(--border-radius);
    background: var(--surface-container-lowest);
    border: 1px solid var(--outline-variant);
    height: 7rem;
  }

  .proposed-date-header {
    grid-column: 1 / -1;
    grid-row: 1;
    display: flex;
    align-items: center;
    gap: var(--space-2);
  }

  .proposed-date-details {
    grid-column: 1 / -1;
    grid-row: 2;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    align-content: flex-end;
    overflow: hidden;
  }

  .proposed-date-info {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-width: 0;
  }

  .proposed-date-info > .max {
    max-width: 12.5rem;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .proposed-date-actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-shrink: 0;
  }

  .proposed-date-details > * {
    margin: 0;
  }

  /* Proposed-date cards with clashes: left error border + subtle tint.
     Reduce left padding by the border width so content aligns with clean rows. */
  .proposed-date-card.clash-row {
    border-inline-start: 4px solid var(--error);
    background: var(--error-container);
    padding-inline-start: calc(var(--space-3) - 4px);
  }

  /* Switch inside proposed-date card header. BeerCSS switch needs a positioned ancestor. */
  .proposed-date-actions .switch {
    position: relative;
  }

  /* Below 600px the header row may wrap so the page title drops onto its
     own line instead of being clipped between the logo and the language
     buttons. At 600px and wider it stays a single row. */
  @media (max-width: 599px) {
    header > .row.no-wrap {
      flex-wrap: wrap;
    }

    header > .row.no-wrap > h1 {
      flex-basis: 100%;
    }
  }

  /* Below 993px tables stack into labeled cards instead of overflowing.
     The header row is visually hidden (clip pattern) but keeps real
     table semantics for screen readers; each cell prints its column label
     above its value via data-label. */
  @media (max-width: 992px) {
    table:has(td[data-label]) > thead {
      position: absolute;
      width: 1px;
      height: 1px;
      padding: 0;
      margin: -1px;
      overflow: hidden;
      clip: rect(0, 0, 0, 0);
      white-space: nowrap;
      border: 0;
    }

    table:has(td[data-label]) tbody,
    table:has(td[data-label]) tr {
      display: block;
    }

    table:has(td[data-label]) td {
      display: block;
    }

    table:has(td[data-label]) td[data-label]::before {
      content: attr(data-label);
      display: block;
      color: var(--on-surface-variant);
      font-size: 0.75rem;
    }

    /* Row headers (player names) in the per-player results table stack the
       same way, so the name sits above its votes instead of staying an
       orphaned table-cell. */
    table:has(td[data-label]) th[scope="row"] {
      display: block;
    }
  }

  /* Global loading spinner */
  .global-spinner {
    position: fixed;
    inset: 0;
    display: none;
    align-items: center;
    justify-content: center;
    gap: var(--space-3);
    background: var(--spinner-overlay);
    z-index: 1000;
    pointer-events: none;
  }

  .global-spinner.is-active {
    display: flex;
  }

  body.is-loading {
    cursor: progress;
  }

  .global-spinner__circle {
    width: var(--spinner-size);
    height: var(--spinner-size);
    border-radius: 50%;
    border: var(--spinner-border-width) solid rgba(255, 255, 255, 0.4);
    border-top-color: var(--primary);
    animation: global-spinner-rotate var(--spinner-speed) linear infinite;
  }

  .global-spinner__label {
    background: var(--spinner-label-bg);
    padding: 0.2em 0.6em;
    border-radius: var(--border-radius);
    color: #fff;
    font-weight: 600;
  }

  @keyframes global-spinner-rotate {
    to {
      transform: rotate(360deg);
    }
  }

  @media (prefers-reduced-motion: reduce) {
    .global-spinner__circle {
      animation: none;
    }

    .skip-link {
      transition: none;
    }

    .clipboard-btn {
      transition: none;
    }
  }

  /* Delete-confirmation dialogs. BeerCSS's `dialog` runs an entrance
     `transition: all` with `visibility:hidden`, which at showModal() time
     leaves the subtree non-focusable and strands focus on <body>; killing the
     transition lets the browser's native focus steps land inside the dialog
     and engage the focus trap. */
  dialog {
    border: 1px solid var(--outline-variant);
    transition: none;
    overscroll-behavior: contain;
  }

  dialog::backdrop {
    background: var(--spinner-overlay);
  }

  /* Radio groups: BeerCSS .radio is inline-flex, so radios in a fieldset
     render side-by-side. Stack them vertically for readability and a11y
     target size. Override .field's fixed height which is meant for inputs. */
  .radio-group {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-2) 0;
    height: auto;
  }

  /* Vote radio group: horizontal Yes/Maybe/No row. */
  .vote-radio-group {
    flex-direction: row;
    gap: var(--space-4);
  }

  /* air-datepicker themed to the BeerCSS/Material palette (design layer beats vendor). */
  .air-datepicker {
    --adp-background-color: var(--surface);
    --adp-background-color-hover: var(--surface-container-high);
    --adp-background-color-active: var(--surface-container-high);
    --adp-color: var(--on-surface);
    --adp-color-secondary: var(--on-surface-variant);
    --adp-accent-color: var(--primary);
    --adp-color-current-date: var(--primary);
    --adp-color-other-month: var(--on-surface-variant);
    --adp-color-disabled: var(--on-surface-variant);
    --adp-border-color: var(--outline-variant);
    --adp-border-color-inner: var(--outline-variant);
    --adp-border-radius: var(--border-radius);
    --adp-nav-arrow-color: var(--on-surface-variant);
    --adp-nav-color-secondary: var(--on-surface-variant);
    --adp-day-name-color: var(--primary);
    --adp-day-name-color-hover: var(--primary);
    --adp-cell-border-radius: var(--border-radius);
    --adp-cell-background-color-hover: var(--surface-container-high);
    --adp-cell-background-color-selected: var(--primary);
    --adp-cell-background-color-selected-hover: var(--primary);
    --adp-cell-border-color-in-range: var(--primary);
    --adp-btn-color: var(--primary);
    --adp-time-track-color: var(--outline);
    --adp-time-track-color-hover: var(--primary);
    --adp-time-day-period-color: var(--on-surface-variant);
  }

  .air-datepicker--pointer:after {
    background: var(--surface);
  }

  /* WCAG 2.2 AA target size: air-datepicker's 17px-tall time sliders fail
     target-size/target-offset; grow the rows and the gap between them. */
  .air-datepicker-time--row {
    height: 24px;
  }

  .air-datepicker-time--row:first-child {
    margin-bottom: 24px;
  }

  /* Picker buttons inline inside field wrappers */
  .field:has(.picker-btn) {
    position: relative;
  }

  .field:has(.picker-btn) > input,
  .field:has(.picker-btn) > select {
    padding-right: 3rem;
    position: relative;
    z-index: 0;
  }

  .picker-btn {
    position: absolute !important;
    right: 0.25rem;
    top: 50%;
    transform: translateY(-50%);
    margin: 0;
    padding: 0;
    min-width: auto;
    width: 2.5rem;
    height: 2.5rem;
    background: transparent !important;
    border: none !important;
    z-index: 1;
  }

  .picker-btn > i {
    font-size: 1.5rem;
  }

  /* Confirm-clash warning: a persistent, high-visual-weight banner (vs the
     throwaway red `.error` text it used to be). Solid error surface with the
     on-error text makes it the strongest thing on the edit card; it stays in
     place until the next partial swap instead of flashing once. */
  .confirm-clash-warning {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    background: var(--error);
    color: var(--on-error);
    font-weight: 600;
    padding: var(--space-3) var(--space-4);
    border-radius: var(--border-radius);
  }

  /* BeerCSS floating-label fields: hide placeholder when empty & unfocused
     so it doesn't overlap the label. Shows when typing or focused. */
  .field.label input:not(:focus):placeholder-shown {
    color: transparent;
  }

  .field.label input:not(:focus):placeholder-shown::placeholder {
    color: transparent;
  }

  /* Venue-occupancy tooltip: the count chip's popup listing the conflicting
     matches. Hidden by default; JS toggles `.is-open` on the host on hover,
     keyboard focus, or tap, and dismisses on pointer leave, focus loss, or
     Escape. Positioned above the chip (bottom: 100%) so it never reflows the
     row. */
  .venue-occupancy {
    position: relative;
    display: inline-block;
  }

  /* Occupancy warning chip: a busy venue (Venue Occupancy > 0) paints the
     count trigger amber — informational, never blocks — kept distinct from
     the --error clash tint. */
  .venue-occupancy__trigger {
    background: var(--warning-container);
    color: var(--on-warning-container);
    border-color: transparent;
  }

  .occupancy-tooltip {
    display: none;
    position: absolute;
    bottom: calc(100% + var(--space-2));
    left: 0;
    z-index: 10;
    min-width: 13rem;
    padding: var(--space-3) var(--space-4);
    border-radius: var(--border-radius);
    background: var(--inverse-surface);
    color: var(--inverse-on-surface);
    box-shadow: 0 4px 12px rgb(0 0 0 / 0.25);
  }

  .venue-occupancy.is-open .occupancy-tooltip {
    display: block;
  }

  .occupancy-tooltip__title {
    display: block;
    font-weight: 600;
    margin-bottom: var(--space-1);
  }

  .occupancy-tooltip__list {
    margin: 0;
    padding-inline-start: var(--space-4);
  }

  /* Generate proposed dates form: grid layout for From/To/Venue row. */
  .generate-controls {
    display: grid;
    grid-template-columns: auto auto 1fr;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: 3rem;
  }

  .generate-controls .date-field {
    width: 9rem;
  }

  .generate-controls .venue-field {
    width: 12.5rem;
  }

  /* Time inputs in generate form: constrain to ~80px. */
  .generate-time-row .time-field {
    width: 9rem;
  }
}
