/*
 * Element defaults, typography roles and the application shell.
 *
 * Everything here is expressed in tokens (styles/tokens.css). No colour, size or duration is
 * spelled out literally, so light mode, reduced motion and a retune of the scale all happen in
 * one file rather than in every rule that happened to need a grey.
 */

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

/*
 * `hidden` means hidden.
 *
 * The HTML attribute only sets `display: none` at the user-agent level, so any component rule
 * with a display of its own silently beats it — and most of this library has one. A `.btn` is
 * `inline-flex`, so `addBtn.hidden = true` left the button on screen, which is how a New Play
 * button ended up on the Team tab. The editor had already worked around it twice with
 * `.editor__quick[hidden]` and `.editor__selbar[hidden]` rules; this is that fix, once, and
 * both of those workarounds have since been deleted.
 */
[hidden] {
  display: none !important;
}

html,
body {
  height: 100%;
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: var(--fs-label);
  line-height: var(--lh-label);
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
  overscroll-behavior: none;
  /*
   * THE APP UI DOES NOT PINCH. THE FOOTBALL FIELD DOES.
   *
   * `pan-x pan-y` allows every pan the app performs and refuses the two the browser would
   * perform on its own — pinch-zoom and double-tap-zoom. It costs nothing here because the page
   * itself never scrolls (`body { overflow: hidden }` below): every scroll in the app happens
   * inside `.view-scroll`, `.sheet__body`, `.editor__panel`, `.menu` or one of the three
   * horizontal strips, and all of those are pans, which this allows.
   *
   * It has to be `pan-x pan-y` rather than `pan-y`. The theme row, the playbook tabs and the
   * call-sheet situation tabs scroll sideways, and touch-action is INTERSECTED down the tree,
   * never re-widened — starve horizontal panning here and no rule on those strips can give it
   * back.
   *
   * On <body> rather than `#app` because bottom sheets and menus are appended to the body, not
   * into `#app` (see components/sheet.js and components/menu.js): a rule scoped to `#app` would
   * miss every sheet in the application.
   *
   * The football canvas declares `touch-action: none` (editor.css) and an intersection with
   * `none` is `none`, so the field still receives every finger and runs its own pinch-to-zoom.
   * That is the whole scoping story: one permissive rule at the top, one strict rule on the one
   * surface that owns its gestures.
   *
   * iOS Safari ignores all of this for page zoom, which is what appChrome.js is for.
   */
  touch-action: pan-x pan-y;
}

body {
  overflow: hidden; /* views manage their own scrolling; prevents page rubber-banding */
}

#app {
  height: 100%;
  height: 100dvh;
  display: flex;
  flex-direction: column;
}

img,
canvas,
svg {
  max-width: 100%;
}

/* ---- Typography roles ------------------------------------------------------------
   Six roles, each with one job. A screen title is the one big thing on a screen; a
   section title names a group; a label names a control; body is prose; secondary is the
   value beside a label; caption is the sentence under it. Anything that does not fit one
   of these is probably two things. */

.t-screen {
  font-size: var(--fs-screen);
  line-height: var(--lh-screen);
  font-weight: var(--fw-bold);
  letter-spacing: -0.02em;
  margin: 0;
}

.t-title {
  font-size: var(--fs-title);
  line-height: var(--lh-title);
  font-weight: var(--fw-bold);
  letter-spacing: -0.01em;
  margin: 0;
}

.t-label {
  font-size: var(--fs-label);
  line-height: var(--lh-label);
  font-weight: var(--fw-semibold);
}

.t-body {
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  font-weight: var(--fw-regular);
}

.t-secondary {
  font-size: var(--fs-secondary);
  line-height: var(--lh-secondary);
  color: var(--text-2);
}

.t-caption {
  font-size: var(--fs-caption);
  line-height: var(--lh-caption);
  color: var(--text-2);
}

/* ---- The display role ------------------------------------------------------------
 *
 * THE SEVENTH ROLE, AND THE ONLY ONE SET IN THE DISPLAY FACE.
 *
 * A short capitalised label naming a thing rather than saying something: a section, a football
 * category, a phase of a play. It was spelled out in six different rules before it had a name,
 * and the comment on the fifth of them asked for exactly this — one rule the next one composes
 * with instead of copying a seventh time. This is that rule.
 *
 * THE LIST IS THE DECISION. Nothing looks at a string and decides it is uppercase enough for
 * the display face; a selector is on this list because of what it NAMES. Adding one is a line
 * here, and the line is the review.
 *
 * Deliberately NOT on it, and each for its own reason:
 *   `.timing-player__name`  — a player's label, which is a coach's own words (editor.css)
 *   `.timing-row__field`    — a form label wrapping the number field it names (editor.css)
 *   `.code-input`, `.share-code` — a share code, read down a phone and typed back in. It is
 *                             monospaced on purpose so 0 and O cannot be confused, which is
 *                             the one thing a condensed display face would undo.
 *   every sentence-case label in the app — a button that says "Save as Formation" is not
 *                             shouted at a coach just because a new face arrived.
 *
 * `.technique__label` is on the list and has no call site today: the Technique panel is built
 * from `section()`. It keeps the role it is named for, so the day it renders it matches.
 *
 * `font-synthesis: none` is load-bearing. One weight of this face ships, and a browser asked
 * for a bold it does not have will smear the glyphs sideways — on a face this condensed that
 * closes the counters and the label turns to mud. The weight is 400 and it stays 400.
 */
/* THE FACE. One list, every selector that is set in it, at any size. */
.t-display,
.t-section,
.section-label,
.section-head__title,
.section__name,
.group-row--stated .group-row__title,
.roster-side,
.sequence-phase__name,
.technique__label,
.t-display-md,
.t-display-lg,
.t-screen,
.appbar__title.appbar__title--display,
.empty h2 {
  font-family: var(--font-display);
  font-weight: var(--fw-regular);
  font-synthesis: none;
  text-transform: uppercase;
}

/*
 * THE LABEL STEP — a short capitalised label naming a thing: a section, a football category, a
 * phase of a play.
 */
.t-display,
.t-section,
.section-label,
.section-head__title,
.section__name,
.group-row--stated .group-row__title,
.roster-side,
.sequence-phase__name,
.technique__label {
  font-size: var(--fs-display);
  line-height: var(--lh-display);
  letter-spacing: var(--tracking-display);
}

/*
 * THE HEADING STEPS — text that is the biggest thing on its screen.
 *
 * `.appbar__title--display` is stated with its base class so it carries two classes' worth of
 * specificity: `.appbar__title` sets its own size and weight further down this file, and a
 * single-class modifier would lose to it on order. `.empty h2` is one class and one element for
 * the same reason, against the bare `h2` rule below.
 *
 * WHICH APP BARS. Only the ones whose title is the APP'S OWN WORDS — Roots Playbook, Playbooks,
 * Settings, Share / Print, Team Playbook Access. A playbook's name and a play's name are a
 * coach's words and stay in the interface face, which is why `appbar()` takes an opt-in rather
 * than styling every title it renders.
 */
.t-display-md,
.appbar__title.appbar__title--display,
.empty h2 {
  font-size: var(--fs-display-md);
  line-height: var(--lh-display-md);
  letter-spacing: var(--tracking-display-md);
}

/* The screen-title role, for the one big thing on a screen. */
.t-display-lg,
.t-screen {
  font-size: var(--fs-display-lg);
  line-height: var(--lh-display-lg);
  letter-spacing: var(--tracking-display-lg);
  margin: 0;
}

/* The role's default colour. Its own rule, because three of the selectors above override it
   and one of them (`.roster-side`) does so per side. */
.t-display,
.t-section {
  color: var(--text-3);
}

/* Timings, yardages, jersey numbers, clocks. Tabular so a counting digit does not shove
   the label beside it left and right as it changes. */
.t-num {
  font-family: var(--font-num);
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-secondary);
  line-height: var(--lh-secondary);
  font-weight: var(--fw-semibold);
}

h1,
h2,
h3 {
  margin: 0;
  font-weight: var(--fw-bold);
  letter-spacing: -0.01em;
}

h1 {
  font-size: var(--fs-screen);
  line-height: var(--lh-screen);
}

h2 {
  font-size: var(--fs-title);
  line-height: var(--lh-title);
}

h3 {
  font-size: var(--fs-label);
  line-height: var(--lh-label);
}

p {
  margin: 0 0 var(--space-3);
}

p:last-child {
  margin-bottom: 0;
}

/* ---- Form elements --------------------------------------------------------------- */

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

/*
 * ...EXCEPT the face, for anything a coach types into.
 *
 * `font: inherit` is a shorthand, so a `font-family` set on a container reaches every control
 * inside it — which is how a two-font system quietly ends up setting a number field, a select's
 * options or a note in a condensed display face. The display face is for labels the app writes;
 * what a coach writes stays in the interface face wherever it sits.
 *
 * `letter-spacing` comes back to normal for the same reason. It is stated as its own rule
 * rather than folded into the one above, because that one says "match the page" and this one
 * says "never match the display face", and only the second is load-bearing.
 */
input,
select,
textarea,
[contenteditable] {
  font-family: var(--font-ui);
  letter-spacing: normal;
}

button {
  cursor: pointer;
  border: 0;
  background: none;
  padding: 0;
  margin: 0;
  touch-action: manipulation;
}

input,
select,
textarea {
  width: 100%;
  min-height: var(--control-h);
  padding: 0 var(--space-3);
  border-radius: var(--radius-sm);
  border: var(--border-width) solid var(--hairline);
  background: var(--surface-3);
  color: var(--text);
  font-size: 16px; /* ≥16px prevents iOS Safari zoom-on-focus */
  outline: none;
  transition: border-color var(--dur-fast) var(--ease-standard), box-shadow var(--dur-fast) var(--ease-standard);
}

input::placeholder,
textarea::placeholder {
  color: var(--text-3);
}

textarea {
  padding: var(--space-3);
  min-height: 88px;
  line-height: var(--lh-body);
  resize: vertical;
}

input:focus,
select:focus,
textarea:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

input[type="color"] {
  padding: var(--space-1);
  width: 56px;
  min-width: 56px;
  height: var(--control-h);
  background: var(--surface-3);
}

input[type="range"] {
  padding: 0;
  height: var(--control-h);
  background: transparent;
  border: 0;
  box-shadow: none;
  accent-color: var(--accent);
}

input[type="range"]:focus {
  box-shadow: none;
}

/* ---- Focus -----------------------------------------------------------------------
   Keyboard focus is always visible and always the same shape. `:focus-visible` rather
   than `:focus` so a tapped button does not keep a ring a touch user never asked for. */

:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
  border-radius: var(--radius-xs);
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* Skip link: first thing in the tab order, invisible until it has focus. */
.skip-link {
  position: absolute;
  top: var(--space-2);
  left: var(--space-2);
  z-index: 100;
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-sm);
  background: var(--accent);
  color: var(--text-on-accent);
  font-weight: var(--fw-semibold);
  transform: translateY(-200%);
  transition: transform var(--dur-fast) var(--ease-standard);
}

.skip-link:focus-visible {
  transform: translateY(0);
}

/* ---- View shell ------------------------------------------------------------------ */

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

.view-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: var(--space-4) var(--gutter);
  padding-bottom: calc(var(--space-6) + var(--safe-bottom));
}

/* A reading measure. Settings and other form-heavy screens stop growing with the window:
   a 1600px display is not an argument for a 1600px-wide text field. */
.view-scroll--measure > * {
  max-width: 720px;
  margin-inline: auto;
  width: 100%;
}

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

.appbar {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: calc(52px + var(--safe-top));
  padding: var(--safe-top) var(--space-2) 0 var(--space-2);
  background: var(--surface);
  border-bottom: var(--border-width) solid var(--hairline);
  flex-shrink: 0;
}

/* Translucency, used where it earns its place: a bar the content scrolls under reads as a
   layer rather than a lid. Never over the canvas — see DESIGN_SYSTEM.md. */
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .appbar--glass {
    background: var(--glass);
    backdrop-filter: blur(var(--glass-blur)) saturate(180%);
    -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(180%);
  }
}

.appbar__title {
  flex: 1;
  min-width: 0;
  font-size: var(--fs-title);
  line-height: var(--lh-title);
  font-weight: var(--fw-bold);
  letter-spacing: -0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: center;
}

/* The editor's title is a rename button. It inherits the bar's type rather than restating it
   inline, which is how it ended up at a weight the scale does not have. */
.appbar__title--button {
  background: none;
  color: inherit;
  min-height: var(--tap-min);
}

/* Large-title variant: the title sits under the bar, the way a library screen reads on
   both platforms, and the bar keeps only the actions. */
.appbar__title--start {
  text-align: left;
  padding-left: var(--space-2);
}

.appbar__spacer {
  width: var(--control-h);
  flex-shrink: 0;
}

.screen-head {
  padding: var(--space-2) var(--gutter) var(--space-4);
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-3);
  flex-shrink: 0;
}

.screen-head__sub {
  font-size: var(--fs-secondary);
  line-height: var(--lh-secondary);
  color: var(--text-2);
  margin-top: var(--space-1);
}
