/* The auth screens and the shared app chrome.
 *
 * Ported from the <style> block in `design/app-screens.html:8-220`. That block is component CSS,
 * not tokens, so it is ours to carry — but every colour, spacing, radius, font-size and shadow
 * below is a `var(--token)` from `brand-tokens.css`. The only literals are the structural ones
 * that appear as literals in the design source: `380px`, `52ch`, `40ch`, `1px solid`, the 900px
 * and 640px breakpoints, and the dot sizes on the aside bullets.
 *
 * `brand-tokens.css` is generated — see `bin/sync-design-tokens`. Anything hand-written, the
 * flash aliases below included, belongs here instead; the sync script would wipe it there.
 */

/* --- Flash colours: aliases the token file does not provide ---------------
 * `brand-tokens.css` ships `--error-on-light` / `--error-on-dark` (and the success pair) but
 * never maps them onto a theme — there is no `--color-error-text`. These three blocks close
 * that gap, mirroring the token file's own structure (`:root`, `[data-theme='dark']`, and the
 * `prefers-color-scheme` block that leaves an explicit light theme alone). They are
 * `var()`-to-`var()` aliases, not hand-written colours.
 */
:root {
  --flash-error: var(--error-on-light);
  --flash-notice: var(--success-on-light);
}

[data-theme='dark'] {
  --flash-error: var(--error-on-dark);
  --flash-notice: var(--success-on-dark);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    --flash-error: var(--error-on-dark);
    --flash-notice: var(--success-on-dark);
  }
}

/* --- Reset and document ------------------------------------------------- */
* { box-sizing: border-box }

body {
  margin: 0;
  background: var(--color-background);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: 1.5;
  /* Not in the design, which has no flash. The auth screens want the full viewport height, but
   * a flash renders above them in the layout — a fixed `100vh` on `.auth` would then overflow
   * by exactly the height of the message. Column flex lets `.auth` take what is left instead. */
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

h1, h2, h3 { font-family: var(--font-heading); line-height: 1.2; margin: 0 }

a { color: var(--color-accent-text) }

/* Focus is non-negotiable for a keyboard-heavy library tool. Ported verbatim from
 * `design/app-screens.html:15-16`; this rule is the whole of the visible-focus requirement. */
:where(a, button, input, select, [tabindex]):focus-visible {
  outline: 2px solid var(--color-accent-text);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* --- Flash --------------------------------------------------------------
 * Modelled on the design's `.banner` (`app-screens.html:90-94`): a coloured left edge on a
 * surface, not a filled block. Rendered from the layout by `shared/_flash.html.erb`.
 */
.flashes {
  /* `width: 100%` is not redundant. `body` is a column flex container, and a flex item with auto
   * cross-axis margins is never stretched — without a definite width this would shrink-wrap to
   * the length of the message. Same reason on `.wrap` below. */
  width: 100%;
  max-width: 1240px;
  margin: 0 auto;
  padding: var(--space-4) var(--space-4) 0;
}

.flash {
  border-left: 3px solid;
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  background: var(--color-surface);
  padding: var(--space-3) var(--space-4);
  margin-bottom: var(--space-3);
  font-size: var(--text-sm);
}

.flash--alert { color: var(--flash-error); border-left-color: var(--flash-error) }
.flash--notice { color: var(--flash-notice); border-left-color: var(--flash-notice) }

/* --- Auth ---------------------------------------------------------------
 * The design's `min-height` is `calc(100vh - 57px)`, discounting the height of the sticky
 * screen-switcher in `app-screens.html`. That switcher is a demo affordance and does not exist
 * in the app; `flex: 1` against the column-flex body is the same intent without the magic number.
 */
.auth {
  display: grid;
  grid-template-columns: 1fr 1fr;
  flex: 1;
}

/* Not in the design, which only draws the two screens that have an aside. The password-reset
 * screens have nothing to put beside the form, and a half-width empty column would leave the
 * form parked off-centre. */
.auth.single { grid-template-columns: 1fr }

.auth-form {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-8) var(--space-4);
}

.auth-inner { width: 100%; max-width: 380px }

.brandline {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-8);
}

.brandline span {
  font-family: var(--font-heading);
  font-size: var(--text-xl);
  font-weight: var(--weight-semibold);
}

.auth h1 { font-size: var(--text-3xl); margin-bottom: var(--space-2) }
.auth .sub { color: var(--color-text-secondary); margin-bottom: var(--space-8) }

.alt { margin-top: var(--space-6); font-size: var(--text-sm); color: var(--color-text-secondary) }

.aside {
  background: var(--color-surface-sunken);
  border-left: 1px solid var(--color-border);
  padding: var(--space-16) var(--space-8);
  display: flex;
  align-items: center;
}

.aside ul { list-style: none; padding: 0; margin: 0; max-width: 40ch }
.aside li { margin-bottom: var(--space-6); padding-left: var(--space-6); position: relative }

.aside li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 9px;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--color-accent-fill);
}

.aside b { display: block; font-family: var(--font-heading); font-size: var(--text-lg) }
.aside p { margin: var(--space-1) 0 0; color: var(--color-text-secondary); font-size: var(--text-sm) }

/* --- Form controls ------------------------------------------------------ */
label {
  display: block;
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  margin-bottom: var(--space-1);
}

.field { margin-bottom: var(--space-4) }
.hint { font-size: var(--text-xs); color: var(--color-text-secondary); margin-top: var(--space-1) }

/* The design carries this as an inline `style="display:inline"` on the *Optional* tag beside the
 * "What do you play?" label (`app-screens.html:258`). Inline styles do not belong in ERB. */
.hint--inline { display: inline }

/* --- Validation errors --------------------------------------------------
 * The design draws no error state for a form — only the `.banner` at `app-screens.html:90-94`,
 * which these mirror. Both rules re-use `--flash-error`, the `var()`-to-`var()` alias defined at
 * the top of this file, so no colour is hand-written here either.
 *
 * `.form-errors` is the summary above the form; `.hint--error` is the same message repeated
 * beside the field that produced it.
 */
.form-errors {
  border-left: 3px solid var(--flash-error);
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  background: var(--color-surface);
  padding: var(--space-3) var(--space-4);
  margin-bottom: var(--space-4);
  color: var(--flash-error);
  font-size: var(--text-sm);
}

.form-errors ul { margin: 0; padding-left: var(--space-4) }

.hint--error { color: var(--flash-error) }

input, select {
  width: 100%;
  height: var(--input-height);
  padding: 0 var(--input-padding-x);
  border-radius: var(--input-radius);
  border: var(--input-border);
  background: var(--color-surface);
  color: var(--color-text);
  font: inherit;
  font-size: var(--text-sm);
}

.btn {
  height: var(--button-height-md);
  padding: 0 var(--button-padding-x);
  border: 0;
  border-radius: var(--button-radius);
  background: var(--button-fill);
  color: var(--button-label);
  font: inherit;
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  cursor: pointer;
  transition: filter 160ms ease-out;
}

.btn:hover { filter: brightness(1.06) }
.btn:active { filter: brightness(0.94); transform: translateY(1px) }
.btn:disabled { opacity: .5; cursor: not-allowed; filter: none; transform: none }
.btn.block { width: 100% }
.btn.ghost { background: transparent; color: var(--color-text); border: 1px solid var(--color-border-strong) }
.btn.sm { height: var(--button-height-sm); font-size: var(--text-xs); padding: 0 var(--space-3) }

/* --- Shared app chrome -------------------------------------------------- */
.wrap { width: 100%; max-width: 1240px; margin: 0 auto; padding: var(--space-8) var(--space-4) }

.head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
  margin-bottom: var(--space-6);
}

.head h2 { font-size: var(--text-2xl) }
.head .count { color: var(--color-text-secondary); font-size: var(--text-sm); margin-top: var(--space-1) }

.empty {
  text-align: center;
  padding: var(--space-16) var(--space-8);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
}

/* The design carries this as an inline `style="margin-top:var(--space-3)"` on the heading
 * (`app-screens.html:583`). Inline styles do not belong in ERB, so it lives here. */
.empty h3 { margin-top: var(--space-3) }

.empty p { color: var(--color-text-secondary); max-width: 52ch; margin: var(--space-2) auto var(--space-6) }

/* --- Breakpoints --------------------------------------------------------
 * `design/app-screens.html:189-218` (the 900px and 640px blocks), plus the reduced-motion rule
 * at `:219`. Only the rules for selectors these screens actually use are ported; the library
 * table's block-row treatment arrives with the table it reformats.
 */
@media (max-width: 900px) {
  .auth { grid-template-columns: 1fr }
  .aside { display: none }
}

@media (max-width: 640px) {
  .hide-sm { display: none }
  .wrap { padding: var(--space-6) var(--space-3) }
  .flashes { padding: var(--space-3) var(--space-3) 0 }
}

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