/* ============================================================================
   base.css — reset, typography, the binder shell, forms and tables.

   OWNERSHIP: Agent A. This is the Phase 0 skeleton: it is correct and legible
   but deliberately plain. A replaces the look — the CLASS NAMES below are the
   contract and must keep working.

   No colour literal appears in this file. Everything reads from tokens.css.
   (Contract rule 4, asserted by pw-audit/tb-static.js.)
   ============================================================================ */

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  min-height: 100dvh;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--step-0);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 { font-family: var(--font-display); line-height: 1.2; margin: 0 0 var(--sp-2); }
h1 { font-size: var(--step-4); }
h2 { font-size: var(--step-3); }
h3 { font-size: var(--step-2); }
p  { margin: 0 0 var(--sp-3); }
p:last-child { margin-bottom: 0; }

a { color: var(--brand); }
img, svg { max-width: 100%; height: auto; }

/* One focus ring everywhere. Never remove it — a teacher tabbing through a
   roster with one hand needs to see where she is. */
:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

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

.skip-link {
  position: absolute; left: var(--sp-3); top: -3rem; z-index: 90;
  background: var(--brand); color: var(--on-brand);
  padding: var(--sp-2) var(--sp-4); border-radius: var(--r-pill);
  font-weight: 700; text-decoration: none;
  transition: top var(--dur-2) var(--ease);
}
.skip-link:focus { top: var(--sp-3); }

/* ---------------------------------------------------------------------------
   Boot cloak. Everything is hidden behind the splash until app.js has rendered
   the first view, so nobody sees an empty tab strip for a frame.
   --------------------------------------------------------------------------- */

.splash {
  position: fixed; inset: 0; z-index: 80;
  display: none; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-3); background: var(--bg); color: var(--brand);
}
.splash-mark { font-size: 3.5rem; }
.splash-word { font-family: var(--font-display); font-weight: 700; font-size: var(--step-2); margin: 0; }

.booting .splash { display: flex; }
.booting .binder,
.booting .decor { visibility: hidden; }

.noscript-card {
  margin: var(--sp-6) auto; max-width: 34rem;
  background: var(--surface); border: 2px solid var(--line-strong);
  border-radius: var(--r-lg); padding: var(--sp-5); box-shadow: var(--shadow-md);
}

/* ---------------------------------------------------------------------------
   The binder shell
   --------------------------------------------------------------------------- */

.binder {
  position: relative;
  max-width: var(--shell);
  margin: var(--sp-4) auto;
  background: var(--surface);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  min-height: calc(100dvh - var(--sp-6));
}

@media (min-width: 900px) {
  .binder { margin: var(--sp-5) auto; padding-left: var(--sp-6); }
}

/* Metal rings down the spine. Decorative only, so they vanish where there is
   no room for them and never appear on paper. */
.binder-rings {
  display: none;
  position: absolute; left: 10px; top: 15%; bottom: 15%; z-index: 3;
  flex-direction: column; justify-content: space-between;
  pointer-events: none;
}
@media (min-width: 900px) { .binder-rings { display: flex; } }

.binder-ring {
  width: 22px; height: 40px; border-radius: var(--r-pill);
  background: linear-gradient(135deg,
    var(--ring-metal-hi) 0%, var(--ring-metal) 45%,
    var(--ring-metal-hi) 62%, var(--ring-metal) 100%);
  box-shadow: var(--shadow-sm), inset -1px -2px 3px var(--ring-gloss);
}

.topbar {
  position: sticky; top: 0; z-index: 20;
  background: var(--surface);
  border-bottom: 2px solid var(--line);
}

.topbar-inner {
  display: flex; align-items: center; gap: var(--sp-3);
  flex-wrap: wrap;
  padding: var(--sp-3) var(--sp-4);
}

.brand {
  display: flex; align-items: center; gap: var(--sp-3);
  background: none; border: 0; padding: var(--sp-1); cursor: pointer;
  color: inherit; text-align: left; border-radius: var(--r-md);
}
.brand-mark {
  width: 46px; height: 46px; flex: none;
  display: grid; place-items: center;
  background: var(--brand-soft); border-radius: var(--r-md);
  font-size: 1.6rem;
}
.brand-text strong {
  display: block; font-family: var(--font-display);
  font-size: var(--step-1); color: var(--brand-strong); line-height: 1.15;
}
.brand-text small { display: block; color: var(--ink-faint); font-size: var(--step--1); }

.topbar-search { flex: 1 1 12rem; min-width: 0; }
.topbar-actions { display: flex; gap: var(--sp-2); flex-wrap: wrap; }

.btn-icon {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-height: var(--tap); padding: 0 var(--sp-3);
  background: var(--surface-2); color: var(--ink-soft);
  border: 1.5px solid var(--line); border-radius: var(--r-pill);
  font: inherit; font-weight: 700; font-size: var(--step--1); cursor: pointer;
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.btn-icon:hover { background: var(--brand-soft); color: var(--brand-strong); }
@media (max-width: 640px) {
  .btn-icon-text { display: none; }
  .btn-icon { padding: 0 var(--sp-3); }

  /* Guide and Celebrate move to Settings on a phone. Four icon buttons plus a
     search field crowd a 360px topbar into either wrapping or squeezing the
     search box down to nothing; Print and Settings (the two used daily) stay,
     and both moved buttons remain reachable — Guide from Settings → Backup &
     Data, Celebrate from Settings → Look & Feel. */
  .topbar-extra { display: none; }
}

/* -- Tab strip ------------------------------------------------------------- */

.tabs {
  position: relative;
  border-top: 1px solid var(--line);
  background: var(--surface-2);
}

.tabs-scroll {
  display: flex; gap: var(--sp-1);
  padding: var(--sp-2) var(--sp-3);
  overflow-x: auto;
  scrollbar-width: none;
  scroll-behavior: smooth;
}
.tabs-scroll::-webkit-scrollbar { display: none; }

/* The scroll affordance a mouse needs and a finger doesn't.

   Twelve tabs are wider than the binder's own capped width at every desktop
   size, so the strip always has somewhere left to scroll to on a laptop or
   desktop — but scrollbar-width:none above hides the one hint a mouse user
   would otherwise get. app.js shows exactly one of these at a time, and only
   the side that actually has more tabs past the edge. */
.tabs-nav {
  position: absolute; top: 0; bottom: 0; z-index: 2;
  width: 2.25rem;
  display: flex; align-items: center; justify-content: center;
  border: 0; padding: 0; cursor: pointer;
  color: var(--ink-soft);
  font-size: 1.3rem; line-height: 1;
}
.tabs-nav--prev {
  left: 0;
  background: linear-gradient(to right, var(--surface-2) 55%, transparent);
}
.tabs-nav--next {
  right: 0;
  background: linear-gradient(to left, var(--surface-2) 55%, transparent);
}
.tabs-nav:hover { color: var(--brand); }

/* A mouse-only convenience: on a touch device swiping is the natural motion
   and a pair of arrows sitting over the first/last tab is one more thing to
   accidentally tap. */
@media (hover: none) and (pointer: coarse) {
  .tabs-nav { display: none; }
}

.tab {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  flex: none; min-height: var(--tap); padding: 0 var(--sp-4);
  background: var(--surface); color: var(--ink-soft);
  border: 1.5px solid var(--line);
  border-radius: var(--r-md) var(--r-md) var(--r-sm) var(--r-sm);
  font: inherit; font-weight: 700; font-size: var(--step--1);
  cursor: pointer; white-space: nowrap;
  transition: transform var(--dur-1) var(--ease), background var(--dur-1) var(--ease);
}
.tab:hover { transform: translateY(-2px); }
.tab.is-on {
  background: var(--sec, var(--brand)); color: var(--sec-on, var(--on-brand));
  border-color: transparent; box-shadow: var(--shadow-sm);
}
/* The emoji is the tab's identity once the label is hidden on a phone, so it
   grows there rather than shrinking with the rest of the button. */
.tab-emoji { font-size: 1.1em; line-height: 1; }

@media (max-width: 640px) {
  .tab-label { display: none; }
  .tab { padding: 0 var(--sp-3); }
  .tab-emoji { font-size: 1.35em; }
}

.subtabs {
  display: flex; gap: var(--sp-2); flex-wrap: wrap;
  padding: var(--sp-2) var(--sp-4);
  border-top: 1px solid var(--line);
  background: var(--surface);
}

.subtab {
  min-height: var(--tap); padding: 0 var(--sp-3);
  background: var(--surface-2); color: var(--ink-soft);
  border: 1.5px solid var(--line); border-radius: var(--r-pill);
  font: inherit; font-weight: 600; font-size: var(--step--1); cursor: pointer;
}
.subtab.is-on { background: var(--sec-soft); color: var(--sec-strong); border-color: var(--sec); }

/* -- Content --------------------------------------------------------------- */

.view {
  flex: 1;
  padding: var(--sp-5) var(--sp-4);
  display: flex; flex-direction: column; gap: var(--sp-5);
}
@media (min-width: 700px) { .view { padding: var(--sp-6) var(--sp-5); } }

.binder-foot {
  display: flex; justify-content: space-between; align-items: center; gap: var(--sp-3);
  flex-wrap: wrap;
  padding: var(--sp-4);
  border-top: 2px solid var(--line);
  background: var(--surface-2);
  color: var(--ink-faint); font-size: var(--step--1); font-weight: 600;
}

/* ---------------------------------------------------------------------------
   Forms
   --------------------------------------------------------------------------- */

.field { display: flex; flex-direction: column; gap: var(--sp-1); }
.field-label { font-weight: 700; font-size: var(--step--1); color: var(--ink-soft); }
.field-hint { display: block; font-weight: 500; color: var(--ink-faint); }

.input {
  width: 100%; min-height: var(--tap);
  padding: var(--sp-2) var(--sp-3);
  background: var(--surface);
  color: var(--ink);
  border: 1.5px solid var(--line-strong);
  border-radius: var(--r-md);
  font: inherit; font-size: var(--step-0);
}
.input::placeholder { color: var(--ink-faint); }
.input:focus-visible { border-color: var(--brand); box-shadow: var(--ring); outline: none; }
.input--area { min-height: 6rem; resize: vertical; line-height: 1.5; }
.input--search { border-radius: var(--r-pill); padding-left: var(--sp-4); }
.input--select { appearance: none; padding-right: var(--sp-5); cursor: pointer; }

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

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  min-height: var(--tap); padding: 0 var(--sp-4);
  background: var(--surface-2); color: var(--ink);
  border: 1.5px solid var(--line-strong); border-radius: var(--r-pill);
  font: inherit; font-weight: 700; font-size: var(--step--1);
  cursor: pointer; text-align: center;
  transition: transform var(--dur-1) var(--ease), background var(--dur-1) var(--ease);
}
.btn:hover:not(:disabled) { transform: translateY(-1px); background: var(--surface-3); }
.btn:disabled { opacity: .5; cursor: not-allowed; }

.btn--brand  { background: var(--brand);  color: var(--on-brand);  border-color: transparent; }
.btn--brand:hover:not(:disabled)  { background: var(--brand-strong); }
.btn--sec    { background: var(--sec);    color: var(--sec-on);    border-color: transparent; }
.btn--danger { background: var(--danger); color: var(--surface);   border-color: transparent; }
.btn--ghost  { background: transparent;   border-color: var(--line); }
/* --sm is a DENSITY modifier, not a permission to go under the tap minimum.
   It buys back horizontal room and drops the type a step; the height stays at
   var(--tap) because the thing it is most used for is a calendar day cell, and
   a teacher adding a field trip on a phone should not have to aim. */
.btn--sm     { min-height: var(--tap); padding: 0 var(--sp-2); font-size: var(--step--1); }
.btn--icon   { min-width: var(--tap); padding: 0 var(--sp-2); }
.btn--block  { display: flex; width: 100%; }

/* ---------------------------------------------------------------------------
   Tables

   A binder is mostly tables, so this carries a lot of weight. The wrapper
   scrolls rather than the page: a 180-day attendance matrix must never make
   the whole document scroll sideways. (Asserted at all six viewports.)
   --------------------------------------------------------------------------- */

.table-wrap {
  overflow-x: auto;
  border: 1.5px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface);
  -webkit-overflow-scrolling: touch;
}

.table { width: 100%; border-collapse: collapse; font-size: var(--step--1); }

.table th {
  position: sticky; top: 0; z-index: 1;
  background: var(--sec-soft, var(--surface-3));
  color: var(--sec-strong, var(--ink));
  text-align: left; font-weight: 800;
  padding: var(--sp-3);
  white-space: nowrap;
  border-bottom: 2px solid var(--line);
}

/* Each column header takes its own pastel, cycling through six hues.

   This is the most recognisable thing about the printable this competes with —
   a roster whose Name / Birthday / Parent / Notes headers are pink, yellow,
   mint and blue — and it costs six rules because the hues are already tokens.

   Deliberately NOT applied to .table--compact: that class marks the wide
   matrices (attendance across a quarter, the whole gradebook), where forty
   alternating colours would be noise rather than navigation. */
.table:not(.table--compact) th:nth-child(6n+1) { background: var(--th-1);  color: var(--th-1-ink); }
.table:not(.table--compact) th:nth-child(6n+2) { background: var(--th-2);  color: var(--th-2-ink); }
.table:not(.table--compact) th:nth-child(6n+3) { background: var(--th-3);  color: var(--th-3-ink); }
.table:not(.table--compact) th:nth-child(6n+4) { background: var(--th-4);  color: var(--th-4-ink); }
.table:not(.table--compact) th:nth-child(6n+5) { background: var(--th-5);  color: var(--th-5-ink); }
.table:not(.table--compact) th:nth-child(6n+6) { background: var(--th-6); color: var(--th-6-ink); }

.table td {
  padding: var(--sp-3);
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
}

/* A person's name never wraps.

   Auto table layout gives every column an equal share of the pressure, so on a
   roster with eight columns "Emma Watson" breaks after "Emma" even though
   Pronouns beside it is empty. A cell carrying an avatar is a person, and a
   name split across two lines reads as a rendering fault in a screenshot. */
.table td:has(.avatar) { white-space: nowrap; }
.table tr:last-child td { border-bottom: 0; }
.table tbody tr:hover td { background: var(--surface-2); }

.table-empty td {
  padding: var(--sp-5); text-align: center;
  color: var(--ink-faint); font-style: italic;
}

/* Blank ruled rows, used by printRender to turn a short table into a paper
   form somebody can fill in by hand. */
.row-blank td { height: 2.2rem; }
.cell-blank { border-bottom: 1px solid var(--line); }

/* Denser padding for a wide matrix — the attendance grid and the gradebook
   run to forty columns and the default padding makes them unreadable. */
.table--compact th,
.table--compact td { padding: var(--sp-1) var(--sp-2); }

/* A wide table declares itself so print.css can give it a landscape page
   instead of clipping the right-hand columns. */
.table-wrap--wide { --wide: 1; }

/* Numbers line up on the decimal point. Scores, money and counts are read as a
   column and compared against each other, so proportional digits are wrong. */
.cell-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
}
