/* THE PATANS DESIGN SYSTEM
 * ============================================================================
 *
 * One set of tokens, one component vocabulary, one shell. Everything else in
 * the product is expected to reach for these rather than invent its own.
 *
 * WHY THIS IS CSS AND DJANGO PARTIALS RATHER THAN SHADCN + RADIX
 *
 * The brief names shadcn/ui, Radix, TanStack Table and Motion. Patans has no
 * package.json, no build step and no React: it is 189 server-rendered Django
 * templates. Adopting those would not be a redesign, it would be rebuilding
 * the entire frontend as a single-page app — which contradicts the same
 * brief's rules about preserving routes, flows and business logic, and would
 * replace working server-rendered pages with a rewrite.
 *
 * So the *system* is what has been adopted, not the libraries: the same
 * tokens, the same component vocabulary, the same shell, the same interaction
 * grammar, expressed as custom properties and reusable partials. A reader
 * cannot tell the difference; a maintainer gets to keep their stack.
 *
 * HOW ONE FILE RESTYLES A HUNDRED AND EIGHTY-NINE TEMPLATES
 *
 * `tuition.css` was already written entirely against custom properties —
 * `var(--green-700)`, `var(--line)`, `var(--bg-soft)` — so the palette has a
 * single point of control. Re-pointing those names at the new values moves
 * every page in the product at once and in step. That is why the token block
 * below defines both the new names and the old ones: the new names are what
 * anything written from here on should use, and the old ones are the bridge
 * that stops the product looking like two products during the changeover.
 *
 * THE ONE HOUSE RULE THIS OVERTURNS
 *
 * `--radius: 0` — "nothing on this site is rounded" — was a real decision and
 * it is deliberately reversed here, because the brief asks for it directly.
 * Everything else the old system believed is kept: yellow means the primary
 * action and nothing else, colour is never the only carrier of meaning, and
 * nothing is decorative.
 */

:root {
  /* ---------------------------------------------------------------- brand */
  --pat-green: #176B45;
  --pat-green-dark: #105338;
  --pat-green-light: #EAF5EF;
  --pat-yellow: #F4C400;
  --pat-yellow-light: #FFF8D8;

  /* -------------------------------------------------------------- surface */
  --pat-app: #F8FAF8;          /* the page behind everything          */
  --pat-surface: #FFFFFF;      /* a card                              */
  --pat-surface-muted: #F3F6F3;/* a panel inside a card               */

  /* ------------------------------------------------------------------ ink */
  --pat-ink: #17221D;
  --pat-ink-2: #607067;
  --pat-ink-3: #87938C;

  /* --------------------------------------------------------------- lines */
  --pat-line: #E3E9E5;
  --pat-line-strong: #D3DDD7;

  /* --------------------------------------------------------------- shape */
  /* Two radii and no more. A card and a control that disagree by two pixels
     is the kind of difference nobody can name and everybody can feel. */
  --pat-radius: 12px;
  --pat-radius-sm: 8px;
  --pat-radius-pill: 999px;

  /* Shadows, kept to the point of being almost invisible. Depth here is a
     hairline and a change of ground, not a drop shadow. */
  --pat-shadow-sm: 0 1px 2px rgba(23, 34, 29, .04);
  --pat-shadow: 0 1px 3px rgba(23, 34, 29, .06), 0 1px 2px rgba(23, 34, 29, .04);
  --pat-shadow-pop: 0 8px 24px rgba(23, 34, 29, .10);

  /* --------------------------------------------------------------- space */
  /* An 8px system. Named so a template can say what it means rather than
     picking a number, which is how arbitrary values get in. */
  --pat-1: 4px;   --pat-2: 8px;   --pat-3: 12px;  --pat-4: 16px;
  --pat-6: 24px;  --pat-8: 32px;  --pat-10: 40px; --pat-12: 48px;
  --pat-16: 64px; --pat-20: 80px;

  /* ---------------------------------------------------------------- type */
  /* Inter, with a real fallback stack. Not loaded from a font service: the
     product is used on Ugandan mobile connections, and a webfont on the
     critical path costs more than the shapes are worth. Inter is requested
     where it is installed and the system UI face carries everything else —
     both are neutral grotesques at the same optical size. */
  --pat-font: Inter, "Segoe UI Variable Text", "Segoe UI", system-ui,
              -apple-system, "Helvetica Neue", Arial, sans-serif;

  --pat-t-page: 30px;    /* page title      700 */
  --pat-t-section: 19px; /* section title   600 */
  --pat-t-card: 16px;    /* card title      600 */
  --pat-t-body: 15px;    /* body            400 */
  --pat-t-2: 14px;       /* secondary       400 */
  --pat-t-label: 13px;   /* label           500 */

  /* Display sizes. Three, named, because a hero heading and a figure in a ring
     are not body text at a bigger number — they are their own job, and a
     nameless 26px in one file becomes a 27px in the next. */
  --pat-t-display: 26px; /* a page's own hero heading      */
  --pat-t-figure: 24px;  /* a number that is the point     */
  --pat-t-name: 18px;    /* somebody's name on their card  */
  --pat-t-initial: 32px; /* the letter standing in for a face */

  /* Ink that reads on the two yellows. Neither is a palette colour so much as
     the only thing dark enough to sit on one at AA. */
  --pat-on-yellow: #3D3100;
  --pat-on-yellow-soft: #6B5600;
  /* The edge of a light-green surface. The neutral line disappears on it. */
  --pat-green-line: #D6E9DE;

  /* -------------------------------------------------------------- motion */
  --pat-quick: 150ms;
  --pat-move: 200ms;
  --pat-ease: cubic-bezier(.2, 0, .2, 1);

  --pat-sidebar: 232px;
  --pat-topbar: 60px;

  /* ======================================================================
   * THE BRIDGE
   *
   * The old names, re-pointed. Every one of the 189 templates already reads
   * these, so this block is what makes the whole product change together
   * instead of page by page. Nothing new should use them.
   * ==================================================================== */
  --green-700: var(--pat-green);
  --green-900: var(--pat-green-dark);
  --green-800: #125C3C;
  --green-600: #1E7E52;
  --green-300: #9CC4AF;
  --green-100: var(--pat-green-light);

  --yellow: var(--pat-yellow);
  --yellow-dark: #DDB100;

  --blue: #0B6E99;
  --pink: #C2557A;
  --pink-deep: #9E3B5E;

  --ink: var(--pat-ink);
  --ink-strong: var(--pat-ink);
  --muted: var(--pat-ink-2);
  --muted-2: var(--pat-ink-3);

  --link-wash: var(--pat-green-light);
  --rail-hover: var(--pat-green-light);
  --rail-on: #DCEEE4;
  --line: var(--pat-line);
  --line-soft: var(--pat-line);
  --bg: var(--pat-surface);
  --bg-soft: var(--pat-surface-muted);
  --warn: #0B6E99;

  --radius: var(--pat-radius);
}

/* The app sits on the tinted ground; cards are what is white. That inversion
   is most of the difference between "a document" and "an application". */
body { background: var(--pat-app); color: var(--pat-ink);
       font-family: var(--pat-font); font-size: var(--pat-t-body); }

/* ------------------------------------------------------------- typography */
/* A hierarchy with real steps in it. The old sheet ran headings and body
   within a couple of pixels of each other, which is why every page read as one
   undifferentiated column of text. */
h1, .t-page { font-size: var(--pat-t-page); font-weight: 700;
              line-height: 1.2; letter-spacing: -.02em; color: var(--pat-ink); }
h2, .t-section { font-size: var(--pat-t-section); font-weight: 600;
                 line-height: 1.3; letter-spacing: -.01em; color: var(--pat-ink); }
h3, .t-card { font-size: var(--pat-t-card); font-weight: 600;
              line-height: 1.4; color: var(--pat-ink); }
.t-body { font-size: var(--pat-t-body); color: var(--pat-ink); }
.t-2 { font-size: var(--pat-t-2); color: var(--pat-ink-2); line-height: 1.55; }
.t-label { font-size: var(--pat-t-label); font-weight: 500; color: var(--pat-ink-2); }
/* An eyebrow. Uppercase and tracked, but never below 12px — small text is not
   a way to fit more in, it is a way to make less of it readable. */
.t-eyebrow { font-size: 12px; font-weight: 600; letter-spacing: .08em;
             text-transform: uppercase; color: var(--pat-ink-3); }

/* ---------------------------------------------------------- page container */
.pat-page { max-width: 1120px; margin: 0 auto;
            padding: var(--pat-8) var(--pat-6) var(--pat-16); }
/* Narrower for anything that is mostly a form or mostly prose: a text field
   1000px wide is harder to read, not more generous. */
.pat-page--narrow { max-width: 760px; }
.pat-page--wide { max-width: 1320px; }

.pat-head { display: flex; align-items: flex-start; justify-content: space-between;
            gap: var(--pat-6); margin-bottom: var(--pat-8); flex-wrap: wrap; }
.pat-head__text { min-width: 0; }
.pat-head h1 { margin: 0; }
.pat-head p { margin: var(--pat-2) 0 0; font-size: var(--pat-t-2);
              color: var(--pat-ink-2); line-height: 1.55; max-width: 68ch; }
.pat-head__actions { display: flex; gap: var(--pat-2); flex: none; }

/* ------------------------------------------------------------------- card */
/* A card is a group of related things. It is not a wrapper for every
   individual fact — a page of one-fact cards has the same hierarchy as a page
   with none, and costs more space to say it. */
.pat-card { background: var(--pat-surface); border: 1px solid var(--pat-line);
            border-radius: var(--pat-radius); box-shadow: var(--pat-shadow-sm); }
.pat-card__pad { padding: var(--pat-6); }
.pat-card__head { display: flex; align-items: flex-start; gap: var(--pat-3);
                  justify-content: space-between; padding: var(--pat-6) var(--pat-6) 0; }
.pat-card__head h2, .pat-card__head h3 { margin: 0; }
.pat-card__sub { margin: var(--pat-1) 0 0; font-size: var(--pat-t-2);
                 color: var(--pat-ink-2); }
.pat-card__body { padding: var(--pat-6); }
.pat-card__foot { padding: var(--pat-4) var(--pat-6);
                  border-top: 1px solid var(--pat-line);
                  background: var(--pat-surface-muted);
                  border-radius: 0 0 var(--pat-radius) var(--pat-radius); }
/* Rows inside a card are separated by a hairline, not boxed individually. */
.pat-rows > * + * { border-top: 1px solid var(--pat-line); }
.pat-row { display: flex; align-items: center; gap: var(--pat-4);
           padding: var(--pat-4) var(--pat-6); }

/* ----------------------------------------------------------------- button */
/* Three weights and a size. Yellow is the primary action and appears once per
   screen; green is used for a secondary action that is still an action; the
   quiet one is everything else. */
.pat-btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--pat-2); padding: 0 var(--pat-4); height: 38px;
  font: inherit; font-size: var(--pat-t-2); font-weight: 600;
  border-radius: var(--pat-radius-sm); border: 1px solid transparent;
  cursor: pointer; text-decoration: none; background-image: none;
  white-space: nowrap;
  transition: background var(--pat-quick) var(--pat-ease),
              border-color var(--pat-quick) var(--pat-ease),
              color var(--pat-quick) var(--pat-ease);
}
.pat-btn svg { width: 16px; height: 16px; flex: none; }
.pat-btn--primary { background: var(--pat-yellow); color: var(--pat-on-yellow); }
.pat-btn--primary:hover { background: var(--yellow-dark); color: var(--pat-on-yellow); }
.pat-btn--green { background: var(--pat-green); color: #fff; }
.pat-btn--green:hover { background: var(--pat-green-dark); color: #fff; }
.pat-btn--quiet { background: var(--pat-surface); color: var(--pat-ink);
                  border-color: var(--pat-line-strong); }
.pat-btn--quiet:hover { background: var(--pat-surface-muted); }
.pat-btn--ghost { background: transparent; color: var(--pat-ink-2); }
.pat-btn--ghost:hover { background: var(--pat-surface-muted); color: var(--pat-ink); }
.pat-btn--sm { height: 32px; font-size: var(--pat-t-label); padding: 0 var(--pat-3); }
.pat-btn:focus-visible, .pat-icon-btn:focus-visible {
  outline: 2px solid var(--pat-green); outline-offset: 2px;
}
.pat-btn[disabled], .pat-btn[aria-disabled="true"] {
  opacity: .5; cursor: not-allowed;
}

.pat-icon-btn { display: inline-flex; align-items: center; justify-content: center;
                width: 36px; height: 36px; border-radius: var(--pat-radius-sm);
                border: 1px solid transparent; background: transparent;
                color: var(--pat-ink-2); cursor: pointer; }
.pat-icon-btn:hover { background: var(--pat-surface-muted); color: var(--pat-ink); }
.pat-icon-btn svg { width: 18px; height: 18px; }

/* ------------------------------------------------------------------ field */
.pat-field { margin-bottom: var(--pat-6); }
.pat-field > label, .pat-field__label {
  display: block; margin-bottom: var(--pat-2);
  font-size: var(--pat-t-label); font-weight: 500; color: var(--pat-ink);
}
.pat-field__help { margin: var(--pat-2) 0 0; font-size: var(--pat-t-label);
                   color: var(--pat-ink-3); line-height: 1.5; }
.pat-field__error { margin: var(--pat-2) 0 0; font-size: var(--pat-t-label);
                    color: #9E3B2E; line-height: 1.5; }

.pat-input, .pat-field input[type=text], .pat-field input[type=email],
.pat-field input[type=url], .pat-field input[type=number],
.pat-field input[type=time], .pat-field textarea, .pat-field select {
  width: 100%; font: inherit; font-size: var(--pat-t-body);
  padding: 9px var(--pat-3); color: var(--pat-ink);
  background: var(--pat-surface);
  border: 1px solid var(--pat-line-strong); border-radius: var(--pat-radius-sm);
  transition: border-color var(--pat-quick) var(--pat-ease),
              box-shadow var(--pat-quick) var(--pat-ease);
}
.pat-input:focus, .pat-field input:focus, .pat-field textarea:focus,
.pat-field select:focus {
  outline: none; border-color: var(--pat-green);
  box-shadow: 0 0 0 3px var(--pat-green-light);
}
.pat-field textarea { min-height: 120px; line-height: 1.6; resize: vertical; }
.pat-field--invalid input, .pat-field--invalid textarea { border-color: #C0664F; }

/* Two columns where two fields genuinely belong side by side, one column on
   anything narrow. Never a form field stretched across a whole screen. */
.pat-grid-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
              gap: var(--pat-4) var(--pat-6); }
@media (max-width: 640px) { .pat-grid-2 { grid-template-columns: 1fr; } }

/* ------------------------------------------------------------------ badge */
.pat-badge { display: inline-flex; align-items: center; gap: var(--pat-1);
             padding: 3px var(--pat-2); border-radius: var(--pat-radius-pill);
             font-size: 12px; font-weight: 600; line-height: 1.4;
             background: var(--pat-surface-muted); color: var(--pat-ink-2); }
.pat-badge--good { background: var(--pat-green-light); color: var(--pat-green-dark); }
.pat-badge--todo { background: var(--pat-yellow-light); color: var(--pat-on-yellow-soft); }
.pat-badge--quiet { background: var(--pat-surface-muted); color: var(--pat-ink-3); }

/* A status is a dot and a word. The dot alone would put the whole meaning in
   a colour, which is exactly what somebody who cannot separate the colours
   would miss. */
.pat-status { display: inline-flex; align-items: center; gap: var(--pat-2);
              font-size: var(--pat-t-2); color: var(--pat-ink-2); }
.pat-status::before { content: ""; width: 8px; height: 8px; flex: none;
                      border-radius: 50%; background: var(--pat-ink-3); }
.pat-status--on::before { background: var(--pat-green); }
.pat-status--off::before { background: var(--pat-line-strong); }
.pat-status--warn::before { background: var(--pat-yellow); }

/* ----------------------------------------------------------------- avatar */
.pat-avatar { display: inline-flex; align-items: center; justify-content: center;
              width: 36px; height: 36px; border-radius: 50%; overflow: hidden;
              background: var(--pat-green-light); color: var(--pat-green-dark);
              font-weight: 600; font-size: var(--pat-t-2); flex: none; }
.pat-avatar img { width: 100%; height: 100%; object-fit: cover; }
.pat-avatar--lg { width: 64px; height: 64px; font-size: 20px; }
.pat-avatar--xl { width: 96px; height: 96px; font-size: 28px; }
/* Name beside face, which is how a person is identified in a list. */
.pat-who { display: flex; align-items: center; gap: var(--pat-3); min-width: 0; }
.pat-who__name { font-weight: 600; font-size: var(--pat-t-2); color: var(--pat-ink);
                 overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pat-who__sub { font-size: var(--pat-t-label); color: var(--pat-ink-3); }

/* ------------------------------------------------------------------- tabs */
.pat-tabs { display: flex; gap: var(--pat-1); padding: var(--pat-1);
            background: var(--pat-surface-muted); border-radius: var(--pat-radius-sm);
            overflow-x: auto; }
.pat-tabs a { flex: none; padding: 7px var(--pat-4); border-radius: 6px;
              font-size: var(--pat-t-2); font-weight: 500; color: var(--pat-ink-2);
              text-decoration: none; background-image: none; white-space: nowrap;
              transition: background var(--pat-quick) var(--pat-ease); }
.pat-tabs a:hover { color: var(--pat-ink); }
.pat-tabs a[aria-current] { background: var(--pat-surface); color: var(--pat-green-dark);
                            font-weight: 600; box-shadow: var(--pat-shadow-sm); }

/* -------------------------------------------------------------- stat card */
.pat-stats { display: grid; gap: var(--pat-4);
             grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }
.pat-stat { background: var(--pat-surface); border: 1px solid var(--pat-line);
            border-radius: var(--pat-radius); padding: var(--pat-4) var(--pat-6); }
.pat-stat__label { display: block; font-size: var(--pat-t-label);
                   color: var(--pat-ink-2); margin-bottom: var(--pat-1); }
.pat-stat__value { display: block; font-size: 26px; font-weight: 700;
                   line-height: 1.15; color: var(--pat-ink);
                   font-variant-numeric: tabular-nums; }
.pat-stat__note { display: block; margin-top: var(--pat-1);
                  font-size: var(--pat-t-label); color: var(--pat-ink-3); }

/* --------------------------------------------------------------- progress */
.pat-progress { height: 8px; border-radius: var(--pat-radius-pill);
                background: var(--pat-surface-muted); overflow: hidden; }
.pat-progress__fill { height: 100%; background: var(--pat-green);
                      border-radius: inherit;
                      transition: width var(--pat-move) var(--pat-ease); }

/* ------------------------------------------------------------------ table */
/* Readable rows, hairline separators, no vertical rules. A grid of boxes is
   how a table stops being scannable. */
.pat-table-wrap { overflow-x: auto; border: 1px solid var(--pat-line);
                  border-radius: var(--pat-radius); background: var(--pat-surface); }
.pat-table { width: 100%; border-collapse: collapse; }
.pat-table th, .pat-table td { padding: var(--pat-3) var(--pat-4);
                               text-align: left; font-size: var(--pat-t-2); }
.pat-table thead th { font-size: var(--pat-t-label); font-weight: 600;
                      color: var(--pat-ink-2); background: var(--pat-surface-muted);
                      white-space: nowrap; }
.pat-table tbody tr + tr td { border-top: 1px solid var(--pat-line); }
.pat-table tbody tr:hover td { background: var(--pat-app); }
.pat-table .n { text-align: right; font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------------ empty state */
/* Says what would be here, and offers the thing that puts it there. An empty
   panel with "no data" in it tells somebody they are stuck. */
.pat-empty { text-align: center; padding: var(--pat-12) var(--pat-6); }
.pat-empty svg { width: 24px; height: 24px; color: var(--pat-ink-3);
                 margin-bottom: var(--pat-3); }
.pat-empty h3 { margin: 0 0 var(--pat-2); }
.pat-empty p { margin: 0 auto var(--pat-4); max-width: 42ch;
               font-size: var(--pat-t-2); color: var(--pat-ink-2); }

/* -------------------------------------------------------------- skeleton */
.pat-skeleton { background: var(--pat-surface-muted); border-radius: var(--pat-radius-sm);
                position: relative; overflow: hidden; }
.pat-skeleton::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.6), transparent);
  animation: pat-sheen 1.4s infinite;
}
@keyframes pat-sheen { to { transform: translateX(100%); } }

/* ============================================================ ACCESSIBILITY
 *
 * Motion is an affordance here, never an entrance. Anybody who has asked their
 * system for less of it gets none: the states still change, they just arrive
 * rather than travel.
 */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important; animation-iteration-count: 1 !important;
    transition-duration: .01ms !important; scroll-behavior: auto !important;
  }
}

/* ============================================================== THE SHELL
 *
 * Restyled where it stands rather than rebuilt. `base.html`'s grid — masthead,
 * rail column, content, footer — is correct and is what 189 templates render
 * inside; replacing it would break every one of them to change how three
 * regions look. So the regions keep their structure and get the new surface.
 *
 * The old shell was a white page with a green masthead strip and a rail that
 * was part of the document. The new one is an application: a tinted ground, a
 * white sidebar and top bar that stay put, and content that scrolls between
 * them.
 */

/* -------------------------------------------------------------- the top bar */
.masthead {
  background: var(--pat-surface);
  border-bottom: 1px solid var(--pat-line);
  min-height: var(--pat-topbar);
}
.masthead__account a, .masthead__account .whoami { font-size: var(--pat-t-2); }
.whoami { border-radius: var(--pat-radius-sm); padding: 6px var(--pat-2); }
.whoami:hover { background: var(--pat-surface-muted); }
.whoami__role { color: var(--pat-ink-3); font-size: 12px; }

/* THE SECTIONS STRIP, AND THE ONE THING THIS FILE FORGOT
 *
 * It was a green band with white links, and this file made the band white and
 * left the links alone. White on white: the strip rendered as an empty bar and
 * its items only appeared under the pointer, where the house's hover rule
 * painted a dark ground behind them. Exactly the failure the tutoring rail had
 * — half a rule moved, and the half left behind was the one carrying the ink.
 *
 * It reads as a hover effect rather than as a bug, which is what makes this
 * kind expensive: nothing errors, nothing logs, and the person using it
 * assumes the menu is meant to work that way.
 *
 * Every item is legible at rest now, and the one you are on is the only thing
 * with a ground under it.
 */
.sections { background: var(--pat-surface);
            border-bottom: 1px solid var(--pat-line); }
.sections__inner { gap: var(--pat-1); }
.sections a {
  font-size: var(--pat-t-2); font-weight: 500; letter-spacing: 0;
  color: var(--pat-ink-2); padding: 7px var(--pat-3);
  border-radius: var(--pat-radius-sm);
  transition: background var(--pat-quick) var(--pat-ease),
              color var(--pat-quick) var(--pat-ease);
}
.sections a:hover { background: var(--pat-surface-muted); color: var(--pat-ink); }
.sections a[aria-current="page"] {
  background: var(--pat-green-light); color: var(--pat-green-dark);
  font-weight: 600; box-shadow: none;
}
.sections a:focus-visible { outline: 2px solid var(--pat-green);
                            outline-offset: -2px; }

/* -------------------------------------------------------------- the sidebar */
/* White, not a solid green slab. The active row is a light-green ground with
   green ink — present enough to find at a glance, quiet enough that eleven
   inactive rows beside it are still readable. */
body:not(.shell--full) .rail-col {
  background: var(--pat-surface);
  border-right: 1px solid var(--pat-line);
}
.rail { padding-block: var(--pat-4); }
.rail__title {
  font-size: 12px; font-weight: 600; letter-spacing: .08em;
  text-transform: uppercase; color: var(--pat-ink-3);
  margin: var(--pat-6) 0 var(--pat-2); padding-left: var(--pat-3);
}
.rail__list > li { margin-bottom: 2px; }
.rail a {
  gap: var(--pat-3); padding: 8px var(--pat-3);
  border-radius: var(--pat-radius-sm); border-left: 0;
  font-size: var(--pat-t-2); font-weight: 500; color: var(--pat-ink-2);
  transition: background var(--pat-quick) var(--pat-ease),
              color var(--pat-quick) var(--pat-ease);
}
.rail a svg { width: 18px; height: 18px; color: var(--pat-ink-3); }
.rail a:hover { background: var(--pat-surface-muted); color: var(--pat-ink); }
.rail a:hover svg { color: var(--pat-ink-2); }
.rail a[aria-current] {
  background: var(--pat-green-light); color: var(--pat-green-dark);
  font-weight: 600; border-left: 0;
}
.rail a[aria-current] svg { color: var(--pat-green); }
.rail a:focus-visible { outline: 2px solid var(--pat-green); outline-offset: -2px; }

/* The tutoring section's own rail was a solid green panel — the one thing the
   brief rules out by name. It becomes the same white sidebar as everything
   else, which is also what makes the product feel like one product. */
.rail.tut-rail, body:not(.shell--full) .rail.tut-rail {
  background: transparent; color: var(--pat-ink); border-top: 0;
}
.tut-rail__title { color: var(--pat-ink-3); font-size: 12px; font-weight: 600;
                   letter-spacing: .08em; padding: var(--pat-6) var(--pat-3) var(--pat-2); }
.rail.tut-rail .tut-rail__list a { color: var(--pat-ink-2); padding: 8px var(--pat-3);
                                   margin: 0 var(--pat-2); border-radius: var(--pat-radius-sm);
                                   border-left: 0; }
.rail.tut-rail .tut-rail__list a:hover { background: var(--pat-surface-muted);
                                         color: var(--pat-ink); }
.rail.tut-rail .tut-rail__list a[aria-current="page"] {
  background: var(--pat-green-light); color: var(--pat-green-dark);
  border-left: 0; font-weight: 600;
}
.rail.tut-rail .tut-rail__list a svg,
.rail.tut-rail .tut-rail__list a:hover svg { color: var(--pat-ink-3); opacity: 1; }
.rail.tut-rail .tut-rail__list a[aria-current="page"] svg { color: var(--pat-green); }
.tut-rail__note { color: var(--pat-ink-3); padding: var(--pat-2) var(--pat-3) var(--pat-4); }
.tut-rail__note a { color: var(--pat-green-dark); }
.tut-rail__sep { margin: var(--pat-2) var(--pat-3);
                 border-top: 1px solid var(--pat-line); }
.tut-rail .rail-toggle-label { background: var(--pat-surface); color: var(--pat-ink); }
.tut-rail .rail-toggle-label__hint { color: var(--pat-green); }

/* The green band at the top of a tutoring page went with the green rail: the
   page title is the heading now, which is what the type is for. */
.tut__band { background: var(--pat-surface); color: var(--pat-ink);
             border: 1px solid var(--pat-line); border-bottom-width: 1px;
             border-radius: var(--pat-radius); padding: var(--pat-6); }
.tut__band h1 { color: var(--pat-ink); font-size: 24px; }
.tut__band p { color: var(--pat-ink-2); }
.tut__band a { color: var(--pat-green-dark); }
.tut__band-facts b { color: var(--pat-ink); }
.tut__band-facts li { color: var(--pat-ink-2); }

/* ----------------------------------------------------------- mobile drawer */
/* The sidebar is not shrunk on a phone, it is put away: the same rows behind
   one line, opened by a control that works with the script blocked. */
@media (max-width: 60rem) {
  .rail-toggle-label { background: var(--pat-surface);
                       border-bottom: 1px solid var(--pat-line);
                       color: var(--pat-ink); font-size: var(--pat-t-2); }
  body:not(.shell--full) .rail-col { border-right: 0; }
}

/* ==================================================== THE GLOBAL PRIMITIVES
 *
 * `.btn`, `.card`, `.grid`, `.pill`, `.lede`, `.meta`, `.rows`, `.band` — the
 * vocabulary the whole product was already built on. `.btn` alone appears in
 * 63 templates, `.meta` in 52, `.lede` in 41.
 *
 * That is the seam. Converting these converts the catalogue, the courses, the
 * games, the materials and every page in every other app that reaches for
 * them, in one step and in step with each other. Rule 21 asks that a button
 * feel like the same button from the dashboard to the planner to a profile;
 * this is the only way that is true by construction rather than by vigilance.
 */

/* ------------------------------------------------------------------ button */
/* Sentence case, not uppercase-and-tracked. Shouting is what a button does
   when it is not confident of its position, and a 0.9rem uppercase label with
   .04em tracking is harder to read than the sentence it replaced. */
.btn {
  min-height: 0; height: 38px; padding: 0 var(--pat-4); gap: var(--pat-2);
  font-family: var(--pat-font); font-size: var(--pat-t-2); font-weight: 600;
  letter-spacing: 0; text-transform: none; line-height: 1;
  background: var(--pat-yellow); color: var(--pat-on-yellow);
  border-radius: var(--pat-radius-sm);
  transition: background var(--pat-quick) var(--pat-ease),
              border-color var(--pat-quick) var(--pat-ease),
              color var(--pat-quick) var(--pat-ease);
}
.btn:hover { background: var(--yellow-dark); color: var(--pat-on-yellow); }
.btn svg { width: 16px; height: 16px; }
.btn:focus-visible { outline: 2px solid var(--pat-green); outline-offset: 2px; }

/* The secondary. An outline rather than an inset shadow pretending to be one:
   a real border participates in layout, which is why the shadow version
   always sat a hair off from the buttons beside it. */
.btn--quiet {
  background: var(--pat-surface); color: var(--pat-ink);
  border: 1px solid var(--pat-line-strong); box-shadow: none;
}
.btn--quiet:hover { background: var(--pat-surface-muted); color: var(--pat-ink); }
.btn--ghost { background: transparent; color: var(--pat-ink-2);
              border: 1px solid transparent; box-shadow: none; }
.btn--ghost:hover { background: var(--pat-surface-muted); color: var(--pat-ink); }
.btn--green { background: var(--pat-green); color: #fff; }
.btn--green:hover { background: var(--pat-green-dark); color: #fff; }
.btn--small { height: 32px; padding: 0 var(--pat-3); font-size: var(--pat-t-label); }
.btn--block { width: 100%; }

/* On a dark band the quiet button has to read against the green rather than
   against white. */
.band--dark .btn--quiet, .site-header .btn--quiet {
  background: transparent; color: #fff;
  border-color: rgba(255, 255, 255, .45); box-shadow: none;
}
.band--dark .btn--quiet:hover, .site-header .btn--quiet:hover {
  background: rgba(255, 255, 255, .12); color: #fff;
}

/* A submit button with no class on it. Full width was right when a form was
   the whole page and wrong everywhere else — it is sized to its label now,
   and a form that wants the full width says so with `.btn--block`. */
form button[type=submit] {
  width: auto; min-height: 0; height: 38px; padding: 0 var(--pat-4);
  font-family: var(--pat-font); font-size: var(--pat-t-2); font-weight: 600;
  background: var(--pat-yellow); color: var(--pat-on-yellow);
  border-radius: var(--pat-radius-sm);
}
form button[type=submit]:hover { background: var(--yellow-dark); }
form button[type=submit]:focus-visible { outline: 2px solid var(--pat-green);
                                         outline-offset: 2px; }

/* -------------------------------------------------------------------- card */
/* A green rule across the top of every card was the old signature. Eight of
   them down a catalogue page is eight green lines and no hierarchy — the
   colour was carrying "this is a card", which is the one thing the shape
   already says. White, one hairline, and the green kept for the things that
   mean something. */
.card {
  background: var(--pat-surface); border: 1px solid var(--pat-line);
  border-top: 1px solid var(--pat-line); border-radius: var(--pat-radius);
  padding: var(--pat-6); box-shadow: var(--pat-shadow-sm);
  transition: border-color var(--pat-quick) var(--pat-ease),
              box-shadow var(--pat-quick) var(--pat-ease);
}
.card:hover { border-color: var(--pat-line-strong); box-shadow: var(--pat-shadow); }
.card h3, .card__title { margin-top: 0; font-size: var(--pat-t-card);
                         font-weight: 600; color: var(--pat-ink); }
.card a { color: var(--pat-ink); text-decoration: none; background-image: none; }
.card a:hover { color: var(--pat-green-dark); }
.card--boxed, .card--soft { border: 1px solid var(--pat-line);
                            border-top: 1px solid var(--pat-line); }
.card--soft { background: var(--pat-surface-muted); box-shadow: none; }

.grid { gap: var(--pat-4);
        grid-template-columns: repeat(auto-fit, minmax(min(17rem, 100%), 1fr)); }

/* -------------------------------------------------------------------- pill */
.pill { padding: 3px var(--pat-2); margin-right: var(--pat-1);
        border-radius: var(--pat-radius-pill);
        background: var(--pat-green-light); color: var(--pat-green-dark);
        font-size: 12px; font-weight: 600; }
.pill--yellow { background: var(--pat-yellow-light); color: var(--pat-on-yellow-soft); }

/* ------------------------------------------------------------------- text */
/* 13px was the old `.meta`, which is below the floor this system sets: small
   text is not a way to fit more in, it is a way to make less of it readable. */
.lede { font-size: 17px; line-height: 1.6; color: var(--pat-ink-2); }
.meta { font-size: var(--pat-t-2); color: var(--pat-ink-2); }

/* ------------------------------------------------------------------- rows */
.rows { list-style: none; margin: var(--pat-6) 0 0; padding: 0;
        background: var(--pat-surface); border: 1px solid var(--pat-line);
        border-radius: var(--pat-radius); }
.rows li { padding: var(--pat-4) var(--pat-6); border-bottom: 1px solid var(--pat-line); }
.rows li:first-child { border-top: 0; }
.rows li:last-child { border-bottom: 0; }

/* ------------------------------------------------------------------- band */
.band { background: var(--pat-green-light); padding-block: var(--pat-16);
        margin: var(--pat-16) 0 0; }
.band--dark { background: var(--pat-green); color: #fff; }
.band--dark .lede { color: #C9E3D6; }

/* ------------------------------------------------------ the content indexes */
/* Two catalogue surfaces with vocabularies of their own — the games arcade and
   the worksheet index. Both are browse pages: somebody scanning for the one
   thing they want, which is what the card grid is for. */

.arcade { gap: var(--pat-4); margin: var(--pat-6) 0 0;
          grid-template-columns: repeat(auto-fill, minmax(min(17rem, 100%), 1fr)); }
.arcade__card { border: 1px solid var(--pat-line); border-radius: var(--pat-radius);
                background: var(--pat-surface); overflow: hidden;
                box-shadow: var(--pat-shadow-sm);
                transition: border-color var(--pat-quick) var(--pat-ease),
                            box-shadow var(--pat-quick) var(--pat-ease); }
/* No lift on hover. A card that rises under the pointer is decoration, and it
   makes a grid of them feel unstable when the pointer crosses it — the border
   and the shadow say "pressable" without moving the page. */
.arcade__card:hover, .arcade__card:focus-visible {
  border-color: var(--pat-line-strong); box-shadow: var(--pat-shadow);
  transform: none; color: var(--pat-ink);
}
.arcade__card:focus-visible { outline: 2px solid var(--pat-green); outline-offset: 2px; }
.arcade__shot { background: var(--pat-surface-muted); }
.arcade__body { padding: var(--pat-4); }
.arcade__title { font-size: var(--pat-t-card); font-weight: 600; color: var(--pat-ink); }
.arcade__hook { font-size: var(--pat-t-2); color: var(--pat-ink-2); line-height: 1.55; }

.cat__unit { margin: 0 0 var(--pat-8); }
.cat__unitname { margin: 0; font-size: var(--pat-t-section); font-weight: 600; }
.cat__from { margin: var(--pat-1) 0 var(--pat-3); font-size: var(--pat-t-2);
             color: var(--pat-ink-2); }
.cat__none { color: var(--pat-ink-3); font-size: var(--pat-t-2); }
.cat__count { font-size: var(--pat-t-2); color: var(--pat-ink-2); }

/* The worksheet list on that page. Rows in a card rather than a bare list
   against the page — the ground is tinted now, so a list with no surface under
   it reads as unfinished. */
.sheets { border: 1px solid var(--pat-line); border-radius: var(--pat-radius);
          background: var(--pat-surface); border-top: 1px solid var(--pat-line);
          margin: 0 0 var(--pat-6); overflow: hidden; }

/* ================================================== WHAT IS NOT CONVERTED
 *
 * Reading surfaces. A lesson, a blog post and the sixteen block templates a
 * lesson is built from have a house style of their own — media first, bold
 * leads, prose set in a serif at reading size, one saturated accessory colour
 * on a neutral figure — and it was arrived at deliberately for people reading
 * rather than operating.
 *
 * Turning those into cards on a tinted ground would be applying an
 * application's furniture to a book. They keep their layout and their type,
 * and they take the new palette through the tokens they already read, which
 * is the whole of what they should take.
 *
 * The bridge course player is excluded for the same reason and by request:
 * nothing in this file names `.focus*`.
 */

/* --------------------------------------------------------------- filtering */
/* The chip row on the worksheet index, and anywhere else a page filters
   itself. Plain links carrying the choice in the query string — so the page
   works with no JavaScript, a filtered view can be sent to somebody, and the
   back button behaves. That was already true; what changes is that they now
   look like the rest of the product's controls.
   
   The label was 11px uppercase, under this system's floor. Small text is not a
   way to fit more in. */
.chips { gap: var(--pat-2); margin: 0 0 var(--pat-8);
         padding-bottom: var(--pat-4); border-bottom: 1px solid var(--pat-line); }
.chips__row { gap: var(--pat-2); align-items: center; }
.chips__what { flex: 0 0 5rem; font-family: var(--pat-font); font-size: 12px;
               font-weight: 600; letter-spacing: .08em; text-transform: uppercase;
               color: var(--pat-ink-3); }
.chips a.chip {
  padding: 5px var(--pat-3); font-size: var(--pat-t-2); line-height: 1.4;
  color: var(--pat-ink-2); background: var(--pat-surface);
  border: 1px solid var(--pat-line); border-radius: var(--pat-radius-pill);
  transition: background var(--pat-quick) var(--pat-ease),
              border-color var(--pat-quick) var(--pat-ease),
              color var(--pat-quick) var(--pat-ease);
}
.chips a.chip:hover { border-color: var(--pat-line-strong);
                      background: var(--pat-surface-muted); color: var(--pat-ink); }
/* The chosen one is filled green. It is the only filled thing in the row, so
   the state reads at a glance without anybody having to compare borders. */
.chips a.chip--on { background: var(--pat-green); color: #fff;
                    border-color: var(--pat-green); }
.chips a.chip:focus-visible { outline: 2px solid var(--pat-green); outline-offset: 2px; }

.cat__head { margin-bottom: var(--pat-6); }
.cat__head h1 { margin-bottom: var(--pat-2); }

/* ====================================================== ASSESSMENT SURFACES
 *
 * WHAT IS NOT HERE, AND WHY
 *
 * **The analytics pages.** All eight of them extend `wagtailadmin/base.html`
 * and are built on Wagtail's own colour tokens on purpose, so they follow the
 * admin into dark mode instead of fighting it. Painting the Patans palette
 * over them would put a light-green card inside a dark admin chrome. They are
 * a different product's pages and they stay that way.
 *
 * **The sitting.** `sit.html` and the five question templates are one task
 * with nowhere else to go — no nav, no footer, no rail, because every link is
 * a way to abandon a twenty-five-minute test and there is one shot at a
 * completion. That is the same argument as the bridge course player, and it
 * gets the same answer: the layout is left exactly as it is.
 *
 * **The printed report.** `report_pdf.html` is ink on paper.
 *
 * What is converted is everything a person operates rather than sits: the
 * start page, the reports, the readiness page, and the paper builder.
 */

/* ------------------------------------------------------------ the actions */
.actions { gap: var(--pat-2); margin-top: var(--pat-6); }

/* ------------------------------------------------------------ form errors */
/* An error was 14px in the attention blue with no ground under it, which read
   as a note rather than as something to fix. */
.errors { margin: var(--pat-2) 0 0; padding: var(--pat-2) var(--pat-3);
          font-size: var(--pat-t-2); line-height: 1.5; color: #8A3324;
          background: #FDF3F0; border-radius: var(--pat-radius-sm); }
.checkline { gap: var(--pat-3); margin: var(--pat-4) 0 0; }
.checkline input { accent-color: var(--pat-green); }
.checkline label { font-size: var(--pat-t-body); }

/* -------------------------------------------------------------- the gate */
/* What a parent sees before a report is unlocked. Light green rather than the
   old flat block: it is an invitation, not a warning. */
.gate { background: var(--pat-green-light); border: 1px solid #CFE6DA;
        border-radius: var(--pat-radius); padding: var(--pat-6);
        margin: var(--pat-8) 0; }
.gate h2 { margin-top: 0; }

/* ------------------------------------------------------------ the meters */
/* A score bar. The system's Progress, so the one on a report and the one on a
   tutoring profile are the same object. */
.bar__track { height: 8px; background: var(--pat-surface-muted);
              border-radius: var(--pat-radius-pill); }
.bar__fill { background: var(--pat-green);
             transition: width var(--pat-move) var(--pat-ease); }
/* A low score is yellow rather than red, and that was already the decision:
   there is no red in this palette, and a twelve-year-old's diagnostic is not
   the place to introduce one. */
.bar--low .bar__fill { background: var(--pat-yellow); }
.bar__label { font-size: var(--pat-t-label); color: var(--pat-ink-2); }

/* --------------------------------------------------------------- the plan */
/* What to do next, on a report. The rule down the left is kept — it is a
   sequence, and a sequence wants a spine — and the yellow panel at the top of
   it stays, because that is the one thing on the page being asked for. */
.plan { border-left: 2px solid var(--pat-green); padding-left: var(--pat-4);
        margin: var(--pat-6) 0 var(--pat-8); }
.plan__fix { background: var(--pat-yellow-light); color: #4A3B00;
             border-radius: var(--pat-radius); padding: var(--pat-4);
             margin: 0 0 var(--pat-4); font-size: var(--pat-t-body); }
.plan__mark { width: 24px; height: 24px; font-size: var(--pat-t-label);
              font-weight: 700; }
.plan__step.is-ready .plan__mark { background: var(--pat-green); color: #fff; }

/* ------------------------------------------------------- the paper studio */
/* The authoring tool keeps its own layout — it is a workbench with panels that
   have to hold their positions while somebody drags items between them, and
   that is not a card grid. What it takes is the palette, the type and the
   controls, so it stops being a different-looking application. */
.studio input[type=text], .studio input[type=number], .studio textarea,
.studio select {
  font-family: var(--pat-font); font-size: var(--pat-t-2);
  border-radius: var(--pat-radius-sm); border-color: var(--pat-line-strong);
}

/* ================================================== ACCOUNTS, FAMILY, PLAY
 *
 * Four small apps that were already almost entirely on the global primitives,
 * so most of them moved when those did. What is left is the handful of names
 * each one had of its own — and one class that turned out never to have been
 * defined at all.
 */

/* `.quiet` appears thirty-two times across the sign-in and application pages
   and has no rule anywhere in the product. It has been rendering as ordinary
   body text the whole time, which is why those pages read as a wall: the note
   under a field looked exactly like the question above it. */
.quiet { font-size: var(--pat-t-2); color: var(--pat-ink-2); line-height: 1.55; }

/* The column an auth form sits in. `--narrow` was 34rem, which is wide for
   four fields — a login form the width of an essay does not read as easier,
   it reads as unfinished. */
.narrow { max-width: 26rem; }

/* -------------------------------------------------------------- accounts */
/* Signing in and applying. These are the first screens anybody meets, and
   rule 10 is the whole brief for them: a label, a field, help where it earns
   its place, and one obvious action. */
.narrow input[type=text], .narrow input[type=email], .narrow input[type=password],
.narrow input[type=tel], .narrow select, .narrow textarea {
  width: 100%; font: inherit; font-size: var(--pat-t-body);
  padding: 10px var(--pat-3); color: var(--pat-ink);
  background: var(--pat-surface); border: 1px solid var(--pat-line-strong);
  border-radius: var(--pat-radius-sm);
}
.narrow input:focus, .narrow select:focus, .narrow textarea:focus {
  outline: none; border-color: var(--pat-green);
  box-shadow: 0 0 0 3px var(--pat-green-light);
}
.narrow label { display: block; margin-bottom: var(--pat-2);
                font-size: var(--pat-t-label); font-weight: 500;
                color: var(--pat-ink); }
.narrow p { margin-bottom: var(--pat-4); }

/* Choosing what kind of account this is. A real card each, because each one
   is a genuine group — an icon, a name and a sentence saying who it is for. */
.rolecard { gap: var(--pat-1) var(--pat-3); padding: var(--pat-4);
            border: 1px solid var(--pat-line); border-radius: var(--pat-radius);
            background: var(--pat-surface); box-shadow: var(--pat-shadow-sm);
            transition: border-color var(--pat-quick) var(--pat-ease),
                        box-shadow var(--pat-quick) var(--pat-ease); }
.rolecard:hover { border-color: var(--pat-green); background: var(--pat-surface);
                  box-shadow: var(--pat-shadow); }
.rolecard:focus-visible { outline: 2px solid var(--pat-green); outline-offset: 2px; }
.rolecard__icon { color: var(--pat-green); }
.rolecard__name { font-family: var(--pat-font); font-size: var(--pat-t-card);
                  font-weight: 600; color: var(--pat-ink); }
.rolecard__what { font-size: var(--pat-t-2); color: var(--pat-ink-2); }

.signup-or { margin: var(--pat-4) 0 0; font-size: var(--pat-t-2);
             color: var(--pat-ink-3); }
.signup-google { margin: var(--pat-4) 0 0; }
.signup-google button.signup-google__btn {
  width: 100%; height: 42px; padding: 0 var(--pat-4); margin: 0;
  font-family: var(--pat-font); font-size: var(--pat-t-body); font-weight: 600;
  border-radius: var(--pat-radius-sm);
}

/* ---------------------------------------------------------------- family */
/* The parent's side. It borrows the teaching scope, so most of it converted
   with that; these are the names it has of its own. */
.fam__h { font-size: var(--pat-t-section); font-weight: 600; color: var(--pat-ink);
          margin: var(--pat-8) 0 var(--pat-3); }
.fam__box { background: var(--pat-surface); border: 1px solid var(--pat-line);
            border-radius: var(--pat-radius); padding: var(--pat-6);
            box-shadow: var(--pat-shadow-sm); margin-bottom: var(--pat-4); }
.fam__when { font-size: var(--pat-t-label); color: var(--pat-ink-3);
             font-variant-numeric: tabular-nums; }
.fam__none { font-size: var(--pat-t-2); color: var(--pat-ink-3); }

/* -------------------------------------------------------- the small button */
/* `.tcb` is the button the planner and the family pages use, and it was a
   different object from `.btn` — a different size, a different weight, square
   where the other is rounded. Rule 21 asks that a button feel like the same
   button wherever it is met, so it is the same button.

   `form button[type=submit]` is (0,1,2), so the element is carried here too
   rather than the rule being lost to the one it is written to beat. */
.tcb, form button.tcb {
  display: inline-flex; align-items: center; gap: var(--pat-2);
  width: auto; min-height: 0; height: 34px; padding: 0 var(--pat-3); margin: 0;
  font-family: var(--pat-font); font-size: var(--pat-t-2); font-weight: 500;
  letter-spacing: 0; text-transform: none;
  color: var(--pat-ink); background: var(--pat-surface);
  border: 1px solid var(--pat-line-strong); border-radius: var(--pat-radius-sm);
  cursor: pointer; text-decoration: none; white-space: nowrap;
}
.tcb:hover, form button.tcb:hover { background: var(--pat-surface-muted);
                                    color: var(--pat-ink); }
.tcb:focus-visible, form button.tcb:focus-visible {
  outline: 2px solid var(--pat-green); outline-offset: 2px;
}
/* The one that goes somewhere. Yellow, because on these pages it is the
   action being asked for. */
.tcb--go, form button.tcb--go { background: var(--pat-yellow); color: var(--pat-on-yellow);
                                border-color: transparent; font-weight: 600; }
.tcb--go:hover, form button.tcb--go:hover { background: var(--yellow-dark); }
.tcb--tiny, form button.tcb--tiny { height: 28px; padding: 0 var(--pat-2);
                                    font-size: var(--pat-t-label); }

/* ------------------------------------------------------ challenges & play */
/* Live rooms and duels. These are game surfaces — big numbers, a countdown, a
   scoreboard — so they keep their own layout and take the product's palette,
   type and controls. */
.backlink { gap: var(--pat-2); padding: 5px var(--pat-3);
            border: 1px solid var(--pat-line-strong);
            border-radius: var(--pat-radius-pill);
            background: var(--pat-surface); color: var(--pat-ink-2);
            font-size: var(--pat-t-2); }
.backlink:hover { background: var(--pat-surface-muted);
                  border-color: var(--pat-line-strong); color: var(--pat-ink); }
.backlink svg { width: 16px; height: 16px; }

.field__label { font-size: var(--pat-t-label); font-weight: 500;
                color: var(--pat-ink); }
/* The big number on a scoreboard. Tabular, so a column of them lines up
   rather than jittering as the digits change. */
.num, .figures__n { font-variant-numeric: tabular-nums; }
.figures__label { font-size: var(--pat-t-label); color: var(--pat-ink-2); }

/* -------------------------------------------------- what needs attention */
/* One line at the top of a child's card, and only when there is something.
   Yellow-tinted rather than red: nothing here has gone wrong, somebody has
   simply not done something yet, and a parent opening this page to a red
   banner about their eleven-year-old is being told the wrong thing.

   The icon and the words carry it together — a tinted strip on its own is a
   colour, and colour is never the only thing saying something in this
   product. */
.fam__needs {
  display: flex; align-items: center; gap: var(--pat-2);
  margin: 0 0 var(--pat-4); padding: var(--pat-3) var(--pat-4);
  background: var(--pat-yellow-light); border-radius: var(--pat-radius);
  font-size: var(--pat-t-2); font-weight: 600; color: #4A3B00;
}
.fam__needs svg { width: 18px; height: 18px; flex: none; }

/* A jump from the top of a report to its recommendation. Quiet — it is a way
   past the reading, not a replacement for it. */
.report__jump { margin: var(--pat-6) 0 var(--pat-8); }
.report__jump a { display: inline-flex; align-items: center; gap: var(--pat-2);
                  font-size: var(--pat-t-2); font-weight: 600;
                  color: var(--pat-green-dark); text-decoration: none;
                  background-image: none; }
.report__jump a:hover { text-decoration: underline; }
.report__jump svg { width: 16px; height: 16px; }

/* --------------------------------------------------------------- the last
 * few utilities the audit turned up.
 *
 * Each of these replaces a value that was written into a `style=` attribute —
 * four different column widths on four pages that are the same kind of page,
 * two font sizes, a colour and a monospace stack. Named once, they are a
 * decision; in an attribute they were four decisions nobody made.
 */
/* A page that is mostly words: an application form, a confirmation, a
   decision. Wider than a login box, narrower than a catalogue. */
.reading { max-width: 38rem; }
.t-lead { font-size: 17px; line-height: 1.5; }
.t-small { font-size: var(--pat-t-label); }
/* The one warm red in the product, and it never appears without words. */
.t-wrong { color: #B3261E; }
.t-code { font-family: ui-monospace, "SF Mono", Consolas, monospace;
          font-variant-numeric: tabular-nums; }
.tci--wide { width: 10rem; }

/* A code typed off a board across a room. Monospace and tracked, so O and 0
   cannot be confused by somebody copying in a hurry — which is the whole job
   of the field. Defined here rather than in one app's sheet: the same code is
   entered on the play pages, the class join page and the family page, and it
   was a different size and family on each. */
.joincode {
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace;
  font-size: 22px; letter-spacing: .14em; text-transform: uppercase;
  font-variant-numeric: tabular-nums;
}
