/*
 * Teacher's Cart design system
 * ============================
 * Extracted verbatim from the design canvas
 * (artifact e9840760-c302-4f94-96c0-743733488c6b): every colour, type step,
 * radius, shadow and control height below is a measured value from that
 * component library, not an approximation of it.
 *
 * The canvas is a component library rather than a screen design, so this is
 * the shape it wants to be reused in: tokens plus the components built on
 * them. Anything the canvas did not define is absent here on purpose — a
 * value invented to fill a gap is how a design system stops matching itself.
 *
 * Structure mirrors the canvas sections:
 *   tokens · typography · buttons · inputs · chips & pills · badges · cards
 *   segmented / tab bars · toggles · elevation
 */

/* ==========================================================================
   The hidden attribute
   ==========================================================================
   The UA stylesheet gives [hidden] `display:none`, and ANY class here that
   sets a display beats it — .tc-btn-icon is display:grid, .tc-btn is
   inline-flex. So el.hidden = true on a button hid nothing, silently: the
   "Got it" on the viewer's first-run hint looked like a dead button, and the
   open-page link stayed visible on the reference, which has no page to open.

   Declared once, with !important, because the whole point is to outrank a
   component's own display. */
[hidden] { display: none !important; }

/* ==========================================================================
   Manrope — the canvas ships weights 500-800
   ========================================================================== */

@import url('https://fonts.googleapis.com/css2?family=Manrope:wght@500;600;700;800&display=swap');

/* ==========================================================================
   Tokens
   ========================================================================== */

:root {
  /* Brand */
  --tc-coral:        #FF5B39;   /* primary action */
  --tc-indigo:       #6C5DD3;   /* secondary action */

  /* Ink ramp */
  --tc-ink:          #14141A;   /* headings */
  --tc-body:         #5B5F6B;   /* paragraphs */
  --tc-meta:         #8B8D97;   /* timestamps, secondary */
  --tc-disabled:     #B7B9C2;
  --tc-disabled-alt: #C4C6CC;

  /* Surfaces */
  --tc-white:        #ffffff;
  --tc-surface:      #F4F4F6;   /* sunk fields, segmented track */
  --tc-border:       #ECECEF;

  /* Tints — each pairs a wash with the ink that sits on it */
  --tc-coral-tint:   #FFF1EC;
  /* Coral TEXT on that tint. The brand coral is a fill colour: at #FF5B39 on
     #FFF1EC it measures 2.71:1, and the place that pairing is used most is the
     active navigation tab — so the one word telling you which page you are on
     was the least readable text in the app. Same hue, taken down to 5.3:1. */
  --tc-coral-ink:    #B23A16;
  --tc-coral-soft:   #FFDCD2;
  --tc-indigo-tint:  #EFECFC;
  /* READY's own blue. It could not be indigo: that is BUILDING's, and the
     finished state and the in-flight one sharing a colour is worse than the
     green READY had. */
  --tc-blue:         #2563C9;
  --tc-blue-tint:    #E8EFFC;
  --tc-amber-tint:   #FFF8E6;
  --tc-amber-ink:    #8A6A00;
  --tc-green-tint:   #E9F8EF;
  --tc-green-ink:    #1E8A5B;

  /* Spacing — the canvas shows exactly these seven steps */
  --tc-s1:  4px;
  --tc-s2:  8px;
  --tc-s3: 12px;
  --tc-s4: 16px;
  --tc-s5: 20px;
  --tc-s6: 24px;
  --tc-s7: 32px;

  /* Radii */
  --tc-r-xs:   2px;   /* spacing ticks, hairline marks */
  --tc-r-sm:   6px;
  --tc-r-md:  10px;
  --tc-r-lg:  12px;   /* inputs */
  --tc-r-xl:  16px;   /* small cards, swatches */
  --tc-r-2xl: 20px;   /* cards */
  --tc-r-3xl: 24px;
  /* Every button, chip, badge, icon button and avatar. NOT a pill: the design
     has no 999px and no 50% anywhere in it — buttons, 38px icon squares and
     the READY badge are all 10px, and rounding them fully was the single thing
     that made the app look unlike its own spec. Renamed from --tc-r-pill so
     the name cannot go on claiming otherwise. */
  --tc-r-control: 10px;

  /* The page column. The header row and every wide page are held to this, so
     the brand lines up with the heading under it — they were two numbers and
     drifted apart the moment one of them changed. */
  --tc-page: 1440px;

  /* Elevation */
  --tc-shadow-sm:    0 2px 8px rgba(20, 20, 30, .04);
  --tc-shadow-card:  0 2px 10px rgba(20, 20, 30, .05);
  /* Overlays sit far above the page — a menu or a dialog, never a panel. */
  --tc-shadow-over:  0 14px 36px rgba(20, 20, 30, .16);
  --tc-shadow-coral:    0 8px 20px rgba(255, 91, 57, .3);  /* 52px primary CTA */
  --tc-shadow-coral-44: 0 6px 16px rgba(255, 91, 57, .3);  /* 44px compact */
  --tc-shadow-coral-40: 0 6px 14px rgba(255, 91, 57, .3);  /* 40px icon circle */

  --tc-font: 'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}

/* ==========================================================================
   Typography — ten steps, each with its stated role
   ========================================================================== */

.tc-display     { font: 700 32px/1.1 var(--tc-font); letter-spacing: -.02em; color: var(--tc-ink); }
.tc-h1          { font: 700 24px/1.2 var(--tc-font); letter-spacing: -.02em; color: var(--tc-ink); }
.tc-h2          { font: 700 20px/1.2 var(--tc-font); letter-spacing: -.02em; color: var(--tc-ink); }
.tc-h3          { font: 700 16px/1.3 var(--tc-font); color: var(--tc-ink); }
.tc-card-title  { font: 700 14px/1.3 var(--tc-font); color: var(--tc-ink); }
.tc-body-bold   { font: 500 14px/1.4 var(--tc-font); color: var(--tc-ink); }
.tc-body        { font: 400 14px/1.4 var(--tc-font); color: var(--tc-body); }
.tc-caption     { font: 500 14px/1.3 var(--tc-font); color: var(--tc-body); }
.tc-meta        { font: 400 14px/1.3 var(--tc-font); color: var(--tc-meta); }
.tc-micro       { font: 500 14px/1.2 var(--tc-font); color: var(--tc-meta);
                  text-transform: uppercase; letter-spacing: .06em; }

/* Emphasis, at the scale's own emphasis weight.
   <strong> and <b> are unstyled otherwise, which means the browser's bold —
   700 — and after the weights came down that made a stressed word inside a
   sentence heavier than the heading above it. The element still means what it
   means; it just stops shouting a step louder than everything else. */
strong, b { font-weight: 500; }

/* The canvas labels every group with this step — it is the section eyebrow. */
.tc-eyebrow {
  font: 500 14px/1.2 var(--tc-font); color: var(--tc-meta);
  text-transform: uppercase; letter-spacing: .06em;
}

/* ==========================================================================
   Buttons — four heights, all fully pilled
   ========================================================================== */

.tc-btn {
  font-family: var(--tc-font);
  border-radius: var(--tc-r-control);
  display: inline-flex; align-items: center; justify-content: center; gap: var(--tc-s2);
  cursor: pointer; white-space: nowrap;
  transition: transform .12s ease, box-shadow .12s ease, background .12s ease, border-color .12s ease;
}
.tc-btn:active  { transform: translateY(1px); }
.tc-btn:disabled { opacity: .5; cursor: not-allowed; transform: none; }
.tc-btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--tc-coral-tint), 0 0 0 4.5px var(--tc-coral);
}

/* Primary CTA · 46px. Measured off the design: every primary in it is 46 or
   48 at 14/800, never 52 at 15 — ours stood a fifth taller than the field it
   sat beside, which is what made the toolbars look loose. */
.tc-btn-primary {
  border: none; height: 46px; padding-inline: var(--tc-s5);
  background: var(--tc-coral); color: var(--tc-white);
  font: 700 14px/1 var(--tc-font);
  box-shadow: var(--tc-shadow-coral);
}
.tc-btn-primary:hover:not(:disabled) { filter: brightness(1.05); }

/* Secondary outline — the same 46px as the primary it stands beside.
   It was 44, "a hair under", which is a real idea and the wrong one here:
   these two are a PAIR on every toolbar and in every dialog, and two pills of
   almost the same height side by side do not read as a hierarchy, they read
   as a mistake. The weight of the fill carries the hierarchy. */
.tc-btn-secondary {
  border: 1px solid var(--tc-border); background: var(--tc-white); color: var(--tc-ink);
  height: 46px; padding-inline: var(--tc-s5);
  font: 700 14px/1 var(--tc-font);
}
.tc-btn-secondary:hover:not(:disabled) { border-color: var(--tc-meta); }

/* Compact action · 44px — coral carries a glow, indigo is flat */
.tc-btn-compact {
  border: none; height: 44px; padding-inline: var(--tc-s5);
  background: var(--tc-coral); color: var(--tc-white);
  font: 700 14px/1 var(--tc-font);
  box-shadow: var(--tc-shadow-coral-44);
}
.tc-btn-compact-indigo {
  background: var(--tc-indigo); box-shadow: none;
}
.tc-btn-compact:hover:not(:disabled) { filter: brightness(1.06); }

/* Inline action · 40px — outlined, in coral or indigo; "Download" is the quiet one */
.tc-btn-inline {
  border: 1.5px solid var(--tc-coral); background: var(--tc-white); color: var(--tc-coral);
  height: 40px; padding-inline: var(--tc-s4);
  font: 700 14px/1 var(--tc-font);
}
.tc-btn-inline:hover:not(:disabled) { background: var(--tc-coral-tint); }

.tc-btn-inline-indigo { border-color: var(--tc-indigo); color: var(--tc-indigo); }
.tc-btn-inline-indigo:hover:not(:disabled) { background: var(--tc-indigo-tint); }

.tc-btn-quiet {
  border: 1.5px solid var(--tc-border); background: var(--tc-white); color: var(--tc-ink);
  height: 40px; padding-inline: 14px;
  font: 700 14px/1 var(--tc-font);
}
.tc-btn-quiet:hover:not(:disabled) { background: var(--tc-surface); }

/* Icon circles · 36px, and the 40px coral send button from the input row */
/* An icon button standing beside a full-height .tc-input. The default 36px one
   bottom-aligns against a 48px field, which puts 12px of nothing above it and
   reads as a padding bug. Matching the field's height makes the two a pair. */
.tc-btn-icon.tc-btn-icon-field { width: 48px; height: 48px; }

.tc-btn-icon {
  border: none; width: 36px; height: 36px; padding: 0;
  border-radius: var(--tc-r-control);
  background: var(--tc-surface); color: var(--tc-ink);
  display: grid; place-items: center; flex: none;
}
.tc-btn-icon-coral {
  width: 40px; height: 40px; background: var(--tc-coral); color: var(--tc-white);
  box-shadow: var(--tc-shadow-coral-40);
}

/* ==========================================================================
   Inputs
   ========================================================================== */

.tc-field { display: flex; flex-direction: column; gap: var(--tc-s2); }

.tc-label {
  font: 500 14px/1.3 var(--tc-font); color: var(--tc-body);
}

.tc-input, .tc-textarea {
  width: 100%; box-sizing: border-box;
  border: 1px solid var(--tc-border); border-radius: var(--tc-r-lg);
  background: var(--tc-white); color: var(--tc-ink);
  font-family: var(--tc-font); font-size: 14px;
  transition: border-color .12s ease, box-shadow .12s ease;
}
.tc-input    { height: 48px; padding: 0 var(--tc-s4); }

/* A number field with no stepper. The arrows are worth having on a dial you
   nudge — two workers to three — and are noise on a figure you know and type,
   like a plan size of 2,500. Typing and the arrow keys both still work; only
   the little control goes. */
.tc-input.tc-nospin { appearance: textfield; -moz-appearance: textfield; }
.tc-input.tc-nospin::-webkit-outer-spin-button,
.tc-input.tc-nospin::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.tc-textarea { height: 96px; padding: var(--tc-s3) var(--tc-s4); line-height: 1.5; resize: vertical; }

.tc-input::placeholder, .tc-textarea::placeholder { color: var(--tc-meta); }

/* A <select> keeps its NATIVE chrome until appearance is cleared — on macOS a
   grey gradient, a squarer radius and a stepper glyph, which is a different
   design system sitting inside this one. AGENT.md already requires exactly this
   of every theme the agent generates; the app that ships that rule was the one
   place not following it.

   The chevron is an inline SVG data URI rather than a pseudo-element because a
   replaced element cannot carry ::after, and rather than a file because one
   more request for 200 bytes is not worth it. */
select.tc-input {
  appearance: none; -webkit-appearance: none;
  padding-right: calc(var(--tc-s4) + 18px);
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1.5 1.75 6 6.25l4.5-4.5' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--tc-s4) center;
  cursor: pointer;
}
select.tc-input:disabled { cursor: default; opacity: .55; }

/* iOS zooms the whole page when a field under 16px takes focus, which on a
   form means the layout jumping on every tap. */
@media (max-width: 640px) { select.tc-input, .tc-input { font-size: 16px; } }

.tc-input:focus, .tc-textarea:focus {
  outline: none;
  border-color: var(--tc-coral);
  box-shadow: 0 0 0 3px var(--tc-coral-tint);
}

/* Pill field — the sunk variant used in search and composer rows */
.tc-input-pill {
  flex: 1; box-sizing: border-box; height: 44px;
  border: 1px solid var(--tc-border); border-radius: var(--tc-r-control);
  background: var(--tc-surface); color: var(--tc-ink);
  padding: 0 var(--tc-s4);
  font-family: var(--tc-font); font-size: 14px;
}
.tc-input-pill:focus { outline: none; border-color: var(--tc-coral); background: var(--tc-white); }

/* Search row — sunk container that holds an icon plus a bare input */
.tc-search {
  display: flex; align-items: center; gap: var(--tc-s2);
  background: var(--tc-surface); border-radius: var(--tc-r-control);
  padding: var(--tc-s3) var(--tc-s4);
  border: 1.5px solid transparent;
}
.tc-search:focus-within { border-color: var(--tc-coral); }
.tc-search input {
  flex: 1; border: none; background: none; outline: none;
  font-family: var(--tc-font); font-size: 14px; font-weight: 400; color: var(--tc-ink);
}

/* ==========================================================================
   Chips & pills
   ========================================================================== */

.tc-chip {
  display: inline-flex; align-items: center; gap: var(--tc-s1);
  padding: var(--tc-s2) var(--tc-s4);
  border-radius: var(--tc-r-control);
  border: 1px solid var(--tc-border); background: var(--tc-white); color: var(--tc-ink);
  font-family: var(--tc-font); font-weight: 400; font-size: 14px;
  cursor: pointer; transition: background .12s ease, border-color .12s ease, color .12s ease;
}
.tc-chip:hover { border-color: var(--tc-meta); }
.tc-chip-active,
.tc-chip[aria-pressed="true"] {
  border-color: var(--tc-coral); background: var(--tc-coral); color: var(--tc-white);
}
.tc-chip-active:hover { border-color: var(--tc-coral); }

/* ==========================================================================
   Badges — a wash plus the ink that belongs on it
   ========================================================================== */

.tc-badge {
  display: inline-flex; align-items: center; gap: var(--tc-s1);
  font-family: var(--tc-font); font-size: 14px; font-weight: 500;
  padding: var(--tc-s1) var(--tc-s3);
  border-radius: var(--tc-r-control);
  width: fit-content;
}
.tc-badge-green  { background: var(--tc-green-tint);  color: var(--tc-green-ink); }
.tc-badge-coral  { background: var(--tc-coral-tint);  color: var(--tc-coral); font: 700 14px/1 var(--tc-font); padding: var(--tc-s2) 14px; }
.tc-badge-amber  { background: var(--tc-amber-tint);  color: var(--tc-amber-ink); font-size: 14px; padding: var(--tc-s2) 14px; }
.tc-badge-indigo {
  background: var(--tc-indigo-tint); color: var(--tc-indigo);
  text-transform: uppercase; letter-spacing: .06em;
  padding: 6px var(--tc-s3);
}

/* ==========================================================================
   Cards
   ========================================================================== */

.tc-card {
  background: var(--tc-white);
  border-radius: var(--tc-r-2xl);
  padding: var(--tc-s6);
  box-shadow: var(--tc-shadow-card);
}
.tc-card-sm { border-radius: var(--tc-r-xl); box-shadow: var(--tc-shadow-sm); padding: var(--tc-s4); }

/* Visually hidden, still read aloud. Lived in sites.css AND inline in the Mac's
   providers page; a label for a screen reader is not a property of one page. */
.vh {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Grid-or-list toggle. THE FOURTH COPY WOULD HAVE BEEN THE POINT: sites.css had
   one, the SaaS the same one, and the Mac's providers page a third — same class
   name, its own padding, its own tap target, so the identical control was a
   different size depending on which page you were looking at. Its own comment
   said the fix was to move it to a shared sheet, so here it is, once.

   The 8px/10px padding is the sites.css version, kept because it is the one
   that clears a comfortable tap target rather than sitting a pixel under it. */
.layoutbtns {
  display: inline-flex; gap: 4px; background: var(--tc-surface);
  padding: 3px; border-radius: var(--tc-r-control);
}
.layoutbtns button {
  border: 0; background: none; cursor: pointer; padding: 8px 10px;
  border-radius: var(--tc-r-control); color: var(--tc-meta); display: grid;
  place-items: center; min-height: 28px;
}
.layoutbtns button.on {
  background: var(--tc-white); color: var(--tc-ink);
  box-shadow: var(--tc-shadow-sm, 0 1px 2px rgba(0, 0, 0, .08));
}
/* On a phone the toggle has nothing to choose between — the list is always the
   grid down there, because a wide table in a narrow window is scrolling
   sideways to read one row. AFTER the rules above: a media query carries no
   extra specificity, so placed before them this lost to `display:inline-flex`
   and the buttons stayed on screen. */
@media (max-width: 700px) { .layoutbtns { display: none; } }

/* Something is wrong enough that the page cannot do what it normally does.
   Put it on a .tc-card.

   WHY THIS IS A CLASS AND NOT A STYLE ATTRIBUTE. Five pages each wrote
   `style="border-color: var(--tc-amber-ink)"` on a card, and every one of them
   drew nothing at all: .tc-card sets no `border`, so border-STYLE was still
   `none`, and a colour on an absent border is invisible. Five copies of one
   idea, all silently wrong, is the argument for naming it once.

   The colour is carried by the border, not the fill: the tint is 1.10:1
   against a white page — a wash you cannot rely on anyone noticing — while the
   coral edge is 3.08:1, and the heading on the tint is 5.43:1. */
.tc-alarm {
  background: var(--tc-coral-tint);
  border: 1px solid var(--tc-coral);
  box-shadow: none;
}
.tc-alarm > .tc-h3,
.tc-alarm > strong { color: var(--tc-coral-ink); }
.tc-alarm .tc-body { color: var(--tc-ink); }

/* Interactive card — the list/tile shape that navigates somewhere */
.tc-card-link {
  display: block; text-decoration: none; color: inherit;
  border: 1px solid transparent;
  transition: transform .12s ease, box-shadow .12s ease, border-color .12s ease;
}
.tc-card-link:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 20px rgba(20, 20, 30, .08);
  border-color: var(--tc-coral-soft);
}
.tc-card-link[aria-pressed="true"],
.tc-card-selected {
  border-color: var(--tc-coral);
  box-shadow: 0 0 0 3px var(--tc-coral-tint);
}

/* ==========================================================================
   Segmented control / tab bar — variant A, "pill highlight"
   The track is --tc-surface, so it only reads as sunk on white. The canvas
   always places it inside a card; on a grey ground it disappears.
   ========================================================================== */

.tc-segmented {
  display: flex; gap: var(--tc-s2);
  background: var(--tc-surface);
  border-radius: var(--tc-r-control);
  padding: var(--tc-s1);
  width: fit-content; max-width: 100%;
  overflow-x: auto; scrollbar-width: none;
}
.tc-segmented::-webkit-scrollbar { display: none; }

/* Scroll affordance. The track scrolls fine with any number of tabs, but with
   nothing fading at the edge there is no sign that more exist — so a site with
   a dozen page types looks like it has however many happen to fit. The classes
   are toggled from JS against real scroll position, so a track that is not
   actually overflowing is never dimmed. */
.tc-segmented.can-left  { mask-image: linear-gradient(to right, transparent, #000 28px); }
.tc-segmented.can-right { mask-image: linear-gradient(to left,  transparent, #000 28px); }
.tc-segmented.can-left.can-right {
  mask-image: linear-gradient(to right, transparent, #000 28px,
                              #000 calc(100% - 28px), transparent);
}

.tc-segmented button {
  flex: 1 0 auto; text-align: center;
  padding: var(--tc-s2) var(--tc-s3);
  border: none; background: none; color: var(--tc-body);
  border-radius: var(--tc-r-control);
  font-family: var(--tc-font); font-weight: 500; font-size: 14px;
  cursor: pointer; white-space: nowrap;
  transition: background .12s ease, color .12s ease;
}
.tc-segmented button:hover { color: var(--tc-ink); }
.tc-segmented button.tc-on { background: var(--tc-coral); color: var(--tc-white); }

/* ==========================================================================
   Toggle
   ========================================================================== */

.tc-toggle {
  appearance: none; -webkit-appearance: none;
  width: 44px; height: 26px; flex: none;
  border-radius: var(--tc-r-control);
  background: var(--tc-border);
  position: relative; cursor: pointer;
  transition: background .16s ease;
}
.tc-toggle::after {
  content: ""; position: absolute; top: 3px; left: 3px;
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--tc-white);
  box-shadow: 0 1px 3px rgba(20, 20, 30, .2);
  transition: transform .16s ease;
}
.tc-toggle:checked { background: var(--tc-coral); }
.tc-toggle:checked::after { transform: translateX(18px); }

/* ==========================================================================
   Page scaffolding
   ========================================================================== */

.tc-page {
  font-family: var(--tc-font);
  color: var(--tc-ink);
  background: var(--tc-surface);
}
.tc-stack   { display: flex; flex-direction: column; gap: var(--tc-s5); }
/* ==========================================================================
   Grid
   ==========================================================================
   Twelve columns, because a settings page of full-width cards wastes most of a
   1,240px row on a control that is a number box and a Save. Cards say how much
   of the row they want; below 900px they all take the whole of it, since a
   half-width card on a phone is not half a card, it is a squeezed one. */
/* align-items:start, so a card is as tall as its contents.
   A grid row stretches its items by default, which pulled a card holding one
   number box and a Save to the full height of the list beside it — a small
   control with a hand's width of empty card under it. */
.tc-grid {
  display: grid; grid-template-columns: repeat(12, 1fr);
  gap: var(--tc-s5); align-items: start;
}
.tc-grid > .col-4  { grid-column: span 4; }
.tc-grid > .col-6  { grid-column: span 6; }
.tc-grid > .col-8  { grid-column: span 8; }
.tc-grid > .col-12 { grid-column: span 12; }
@media (max-width: 900px) {
  .tc-grid > [class*="col-"] { grid-column: span 12; }
}

/* ── Masonry ─────────────────────────────────────────────────────────────
   Cards of unequal height, packed. A grid row is only as tall as its tallest
   card, so a four-line card beside a hundred-line one leaves most of a column
   empty; two fixed stacks fix that only when the stacks happen to balance.
   Each card goes to whichever column is currently shortest — the script in
   base.html does the placing, because CSS cannot yet. Before it runs, the cards
   are ordinary grid items, so the page is readable and the jump is small.

   Gaps are the grid's own token, in both directions, so a masonry page has the
   same rhythm as a grid page. */
.tc-masonry {
  display: grid; grid-template-columns: repeat(var(--tc-cols, 2), 1fr);
  gap: var(--tc-s5);
  /* start, not stretch. Stretching made the columns equal by growing the last
     card of the short one, on the reasoning that a tall card is ordinary and a
     short column is the gap people notice. It does not hold when the last card
     is small: Provider capacity with two accounts was 386px tall around 200px
     of content, so half the card was empty white and it read as broken rather
     than as spacing. Cards are their own height now, and the leftover sits
     below the short column as page background, where nobody reads it as part
     of a card. */
  align-items: start;
}
.tc-masonry > .tc-masonry-col {
  display: flex; flex-direction: column; gap: var(--tc-s5); min-width: 0;
}
/* No card grows to fill. See the note on align-items above. */
.tc-masonry > .tc-masonry-col > .tc-card:last-child { flex: 0 0 auto; }
@media (max-width: 900px) { .tc-masonry { --tc-cols: 1; } }

.tc-row     { display: flex; align-items: center; gap: var(--tc-s3); }
/* A page's header row: a back link, the title, and whatever is pushed right.
   It was defined in two templates and in neither of the others, so every page
   added since stacked its back button on top of its heading. One definition. */
.head {
  display: flex; align-items: center; gap: var(--tc-s3);
  flex-wrap: wrap; margin-bottom: var(--tc-s6);
}

/* ── Select ──────────────────────────────────────────────────────────────
   A native select draws its own list, and that list is the operating
   system's — grey, square-cornered, and nothing like the rest of this. The
   markup stays a <select> so the form still submits and a keyboard still
   works; the script in base.html hides it behind a button and a menu that
   look like everything else. */
.tc-select-wrap { position: relative; }
.tc-select-wrap > select { position: absolute; opacity: 0; pointer-events: none;
                           width: 100%; height: 100%; left: 0; top: 0; }
.tc-select-btn {
  width: 100%; box-sizing: border-box; height: 48px;
  display: flex; align-items: center; gap: var(--tc-s2);
  padding: 0 var(--tc-s4); cursor: pointer; text-align: left;
  border: 1px solid var(--tc-border); border-radius: var(--tc-r-lg);
  background: var(--tc-white); color: var(--tc-ink);
  font-family: var(--tc-font); font-size: 14px; font-weight: 400;
}
.tc-select-btn:hover { border-color: var(--tc-disabled-alt); }
.tc-select-btn[aria-expanded="true"] { border-color: var(--tc-coral); }
.tc-select-btn .chev { margin-left: auto; color: var(--tc-meta); flex: none; }
.tc-select-menu {
  position: absolute; left: 0; right: 0; top: calc(100% + 6px); z-index: 55;
  padding: var(--tc-s2);
  background: var(--tc-white); border: 1px solid var(--tc-border);
  border-radius: var(--tc-r-xl); box-shadow: var(--tc-shadow-card);
}
/* The height belongs to the LIST, not to the menu: with it here the search
   box scrolled away with the options it was filtering. */
.tc-select-opt {
  display: flex; align-items: center; gap: var(--tc-s2);
  padding: var(--tc-s2) var(--tc-s3); border-radius: var(--tc-r-md);
  font: 400 14px/1.4 var(--tc-font); color: var(--tc-ink); cursor: pointer;
}
.tc-select-opt:hover, .tc-select-opt.here { background: var(--tc-surface); }
.tc-select-opt.on { color: var(--tc-coral); }
.tc-select-opt .tick { margin-left: auto; opacity: 0; flex: none; }
.tc-select-opt.on .tick { opacity: 1; }

/* Searching a long list, and saying so while it loads. */
.tc-select-find {
  width: 100%; box-sizing: border-box; height: 34px; margin-bottom: var(--tc-s2);
  padding: 0 var(--tc-s3); border: 1px solid var(--tc-border);
  border-radius: var(--tc-r-md); background: var(--tc-white); color: var(--tc-ink);
  font-family: var(--tc-font); font-size: 14px;
}
.tc-select-find:focus { outline: none; border-color: var(--tc-coral); }
/* The list scrolls; the search box does not go with it. */
.tc-select-list { max-height: 232px; overflow-y: auto; }
.tc-select-wait {
  display: flex; align-items: center; gap: var(--tc-s2);
  padding: var(--tc-s3); color: var(--tc-meta);
  font: 400 14px/1.4 var(--tc-font);
}
.tc-spin {
  width: 13px; height: 13px; flex: none; border-radius: 50%;
  border: 2px solid var(--tc-border); border-top-color: var(--tc-coral);
  animation: tc-spin 0.7s linear infinite;
}
@keyframes tc-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .tc-spin { animation: none; border-top-color: var(--tc-border); }
}

/* A button that is waiting on the server.
   Added to the pressed submitter by the submit guard in base.html, which
   already disables it — disabled says "not now" and a spinner says "working",
   and the second is the one somebody needs while a plugin downloads or a site
   is created. The label stays: replacing it with "Adding…" would move the
   button's width mid-press and lose what it was going to do.
   A pseudo-element, so it is a flex item of .tc-btn and picks up its gap. */
.tc-btn.tc-busy::before {
  content: ""; width: 13px; height: 13px; flex: none; border-radius: 50%;
  border: 2px solid currentColor; border-top-color: transparent;
  animation: tc-spin 0.7s linear infinite;
}
/* An icon button has no room beside its icon, so it dims instead. */
.tc-btn-icon.tc-busy::before { display: none; }
.tc-btn.tc-busy { opacity: .85; }
@media (prefers-reduced-motion: reduce) {
  .tc-btn.tc-busy::before { animation: none; border-top-color: currentColor;
                            opacity: .4; }
}
/* The provider's logo, when an option says which kind it is. It collapses
   when there is none, or every select in the app would carry the gap of an
   icon it does not have. */
.tc-select-btn .selmark:empty { display: none; }
.tc-select-btn .selmark { display: flex; flex: none; }
.markbank { display: none; }

/* ── A row of icon-only actions ──────────────────────────────────────────
   Repeat actions on a list row: the label is the same on every row, so after
   the first one it is noise. The icon carries it and the tooltip says it in
   words. Lived in index.html's own <style> as .rowacts .act, so the Serper key
   rows could not reach it and shipped four word-buttons instead.

   Anything destructive takes .danger, which only shows on hover: a row of red
   never lets the eye rest, and the colour is worth more at the moment of
   pressing than as decoration. */
.tc-actions { display: flex; align-items: center; gap: 6px; flex: none; }
.tc-actions .tc-btn-icon { color: var(--tc-meta); }
.tc-actions .tc-btn-icon:hover { background: var(--tc-surface); color: var(--tc-ink); }
.tc-actions .tc-btn-icon.danger:hover {
  background: var(--tc-coral-tint); color: var(--tc-coral);
}
/* A form is a layout box the buttons should not be nested inside visually. */
.tc-actions form { display: contents; }

/* ── A secret you can look at ────────────────────────────────────────────
   A password field with a reveal button inside its right edge. Masked by
   default, because these fields sit on screens that get screenshotted; the eye
   is there because a password you cannot read is a password you cannot check
   before saving it. */
.tc-secret { position: relative; display: block; }
/* The generate button sits under the field, not in it: the reveal eye already
   owns the inset space on the right, and two controls in one box is a box you
   have to aim at. */
.tc-gen { margin-top: var(--tc-s2); font-size: 14px; padding: 6px 10px; }
.tc-secret > .tc-input { padding-right: 46px; }
/* Centred on the FIELD, not on the block. It was top:50% of .tc-secret —
   which contains the input AND the Generate button under it, so the eye sat
   halfway down the pair, below the box it belongs to and overlapping the gap.
   Invisible until this form had no Save button beside it to disguise the
   offset. 5px from the top of a 48px input centres a 38px button in it. */
.tc-secret-eye {
  position: absolute; right: 5px; top: 5px;
  width: 38px; height: 38px; padding: 0; border: none; background: none;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--tc-r-md); color: var(--tc-meta); cursor: pointer;
  transition: background .12s ease, color .12s ease;
}
.tc-secret-eye:hover { background: var(--tc-surface); color: var(--tc-ink); }
.tc-secret-eye svg { display: block; }
/* Only one of the two is ever in the document flow. */
.tc-secret-eye .off { display: none; }
.tc-secret.shown .tc-secret-eye .on  { display: none; }
.tc-secret.shown .tc-secret-eye .off { display: block; }

/* ── Modal ───────────────────────────────────────────────────────────────
   One dialog, one definition. It lived in index.html's own <style>, so the
   second modal on another page had to reinvent it and got a different width, a
   different scrim and its buttons on the wrong side. Anything that dims the page
   and asks a question uses these two classes.

   Shown by adding .open rather than by clearing [hidden], because the base state
   is display:none and this file makes [hidden] !important — the two would
   fight. */
.tc-modal {
  position: fixed; inset: 0; z-index: 60; display: none;
  background: rgba(20, 18, 17, .45);
  align-items: center; justify-content: center;
  padding: var(--tc-s5);
  overflow: auto;
}
.tc-modal.open { display: flex; }
.tc-modal-card {
  background: var(--tc-white); border-radius: var(--tc-r-2xl);
  padding: var(--tc-s6); max-width: 520px; width: 100%;
  box-shadow: var(--tc-shadow-over);
  margin: auto;                    /* centres it, and lets a tall one scroll */
}
/* The footer of a dialog: quiet on the left, the committing action last, both
   pushed right. Every dialog in the app puts them in that order. */
.tc-modal-actions {
  display: flex; align-items: center; gap: var(--tc-s3);
  margin-top: var(--tc-s5); justify-content: flex-end;
}

/* A card's own title row. 16px/1.3 puts about 5px of half-leading and ascent
   above the cap, so a 24px card pad reads as ~29px on top against exactly 24px
   on the left — the gap that kept being reported as "top and left do not
   match". Killing the leading and trimming the ascent makes the two optically
   equal, and one class means every card on every page sits the same. */
/* A card's header row: a title, whatever sits beside it, and an action pushed
   to the right. It had only a margin, so a title and a close button stacked
   instead of sitting on one line. */
/* A card's header row AND the rule under it. In the design a panel is always
   title, then a 1px line, then the content — the line is what makes a card
   read as a thing with a header rather than a box of stacked paragraphs, and
   it was the piece ours was missing. Drawn here so no card has to remember it.

   .cardhead-bare opts out, for the few headers that sit directly on a page
   rather than at the top of a panel. */
.cardhead   { display: flex; align-items: center; gap: var(--tc-s3);
              margin-bottom: 18px; padding-bottom: 18px;
              border-bottom: 1px solid var(--tc-surface); }
.cardhead-bare { border-bottom: none; padding-bottom: 0;
                 margin-bottom: var(--tc-s3); }
.cardhead .tc-h3 { line-height: 1; margin-top: -3px; }
.tc-grow    { flex: 1; min-width: 0; }

/* ── A card's own title ──────────────────────────────────────────────────
   Every card names itself, with a rule under the name. Cards whose name
   floated above their contents read, stacked, as one long column of things —
   the rule is what makes each one a card rather than a section.

   .cardhead's own 18px is built for an .tc-h3; an eyebrow is smaller and
   sits closer. Here rather than in site.css, because the SERP page and the
   credential page need it and link neither. */
.sidehead { margin-bottom: var(--tc-s3); padding-bottom: var(--tc-s3); }
.sidehead .tc-eyebrow { margin: 0; }

.tc-divider { height: 1px; background: var(--tc-border); border: none; margin: 0; }

/* A row of something that happened: a dot, what it was, when.
 *
 * It lived in dashboard.css, which is why the SaaS site page linked that whole
 * sheet for ten lines — and inherited its `.head` override with it, so the one
 * page meant to match the Mac app's exactly had a header 4px wider-gapped than
 * the Mac's. A component used by three pages across two apps belongs in the
 * design system.
 */
.actrow { display: flex; align-items: flex-start; gap: var(--tc-s3);
          padding: var(--tc-s3) 0; }
.actrow + .actrow { border-top: 1px solid var(--tc-surface); }
.actrow .dot { width: 7px; height: 7px; border-radius: 50%; flex: none;
               background: var(--tc-coral); margin-top: 6px; }
.actrow .what { display: block; font: 500 14px/1.4 var(--tc-font);
                color: var(--tc-ink); }
.actrow .when { display: block; font: 400 14px/1.4 var(--tc-font);
                color: var(--tc-meta); margin-top: 2px; }

/* A link inside a sentence is underlined.
 *
 * Coral on white is 2.81:1 — below the threshold at which colour alone can
 * carry meaning — so "Accounts live on Providers" was a link identifiable only
 * by a colour somebody may not be able to distinguish. The underline says it
 * without touching the palette, and only inside prose: nav items, row actions
 * and cards are links too, and underlining those would be noise.
 */
.tc-body a,
main p a {
  /* The palette's own darker coral, not a new colour. #FF5B39 is 3.08:1 on
     white and this is 5.4:1 — the difference between a link somebody can read
     and one they can guess at. The underline stays: colour alone should not
     be what says "this is a link". */
  color: var(--tc-coral-ink);
  text-decoration: underline; text-underline-offset: 2px;
}
