/* ==========================================================================
   tt-core.css - the Tomasetti Tech business design system (tomasettitech.com)

   Copyright (c) 2026 Tomasetti Tech LLC. All rights reserved.

   One stylesheet owns the nav, hero, sections, rate card, catalog, directory
   rows, forms and footer for tomasettitech.com and the four product pages under
   tomasettitech.com/<product>. Those pages carry no structural CSS of their own,
   so a change here moves all five together and none of them can drift. That is
   the whole point of the file and the reason to keep every class name in it.

   HISTORY, because this file has been rewritten twice and the second rewrite is
   easy to misread as a revert:

   1. 2026-07 "Soft Dark" (assets/tomasetti-tokens.css + tomasetti-site.css) had
      the purple but wrapped it in rainbow .t-pride bars, glow orbs, a .t-grid-bg
      overlay, gradient CTAs and glass cards. Tj retired that on 2026-09-12:
      "looks kind of AI made". Those tells stay dead. Do not load those two files
      here and do not rebuild their effects.

   2. 2026-09-14 morning: a de-SaaS pass fixed the neon but also threw out the
      color, landing on --accent #4a2a86. That is a desaturated aubergine that
      reads nearly black at button size, and dark mode fell back to a washed
      lilac. Tj, same day: "I don't know where my purple went."

   3. THIS FILE restores the violet. --accent is #6d28d9, which is the old
      --t-violet family, not a new invention. The distinction that matters: the
      2026-07 problem was the TREATMENT (gradients, glow, glass, chips), never
      the hue. Color is back. Every effect that made it look generated stays
      gone.

   4. 2026-09-14 evening, same day: dark mode is PURPLE, not black. The dark
      palette had been #0e0a15 (a black page with violet trim), which is not
      what the rest of the fleet looks like. It is now the same purple dark the
      forum and Ascend use. See the note above the dark token blocks for the
      mapping and for which two files the values were copied from.

      docs/AI-SPEAK-DETECTION.md is the rule of record here and it is narrower
      than "no purple": item 8 bans the purple-to-pink GRADIENT, item 12 bans
      gradients everywhere, and both say use color sparingly. A flat violet on
      paper is not the tell. A violet-to-pink gradient would be.

   What this file is: violet as a flat signal color, hairline rules, mono for
   anything tabular, square markers instead of rounded chips, and three distinct
   section treatments so the page is not one hairline list repeated. No
   gradients, no glow, no blur, no shadows, no emoji-as-icons, no pill chips.
   Corner radius stays at 4px; the "12-20px on everything" look is item 10.

   Theme: light and dark, both purple. :root is the light palette and is what a
   visitor with no JavaScript and no OS preference gets. Dark arrives two ways,
   the same two ways the rest of the fleet does it: the OS preference, and the
   toggle in the nav. Both routes land on the same purple, never on black. See
   the note above the dark token blocks.

   Copy rules live in docs/AI-SPEAK-DETECTION.md. Naming and the two-class
   attribution model live in BRAND.md.
   ========================================================================== */

/* ==========================================================================
   1. TOKENS
   ========================================================================== */
:root {
  /* Bench paper: near-white with a faint violet cast, not the warm cream the
     de-SaaS pass used. The old paper read like a bakery; this reads like a
     spec sheet, which is closer to what the company actually is. */
  --paper:      #fbfaff;
  --paper-2:    #f1edfa;
  --ink:        #140f1c;
  --ink-2:      #4a4059;
  /* ink-3 is the quiet tier: dates, hostnames, footer legal. The old value
     #7b7190 sat at 4.39:1 on paper, a hair under the 4.5:1 small text needs;
     #6c6484 is the same muted hue a step darker, 5.3:1 on paper and 4.8:1 on
     paper-2 (2026-09-30 audit). The dark value below already clears at 7.3:1. */
  --ink-3:      #6c6484;
  --rule:       rgba(20, 15, 28, .13);
  --rule-hard:  rgba(20, 15, 28, .30);

  /* The violet, restored. #6d28d9 carries text and buttons; #a855f7 is the
     signal color and is deliberately NOT used for body-size text, because it
     does not hold contrast on paper. */
  --accent:     #6d28d9;
  --accent-2:   #7c3aed;
  --accent-ink: #ffffff;
  --accent-soft:rgba(124, 58, 237, .07);
  --signal:     #a855f7;
  --alert:      #b3261e;

  --sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;

  --wrap: min(1140px, calc(100% - 44px));
  --r: 4px;
}
/* DARK IS PURPLE, NOT BLACK. Tj, 2026-09-14: "I don't want dark mode to be a
   black theme, I like it to be purple like our other sites."

   What went wrong before: the dark palette here was paper #0e0a15 with violet
   only as an accent, so the site read as a black page with purple trim. That is
   not what the rest of the fleet looks like. The forum (apps/crm/forum) and
   Ascend (apps/ascend) share a genuinely purple dark, and these values are
   copied from it rather than invented:

     apps/crm/forum/static/forum.css   [data-theme="dark"]
     apps/ascend/static/css/style.css  html[data-theme="dark"]

     their token        ->  here         value
     --canvas           ->  --paper      #140d20   purple-black, not black
     --surface          ->  --paper-2    #211632   lifted violet panel
     --ink              ->  --ink        #f1ecf7
     --ink-soft         ->  --ink-2      #ddd2ea
     --muted            ->  --ink-3      #aa9bb8
     --line             ->  --rule       rgba(205,183,232,.16)  lavender hairline
     --line-strong      ->  --rule-hard  rgba(205,183,232,.30)
     --purple-mid       ->  --accent     #b49bf2
     --purple           ->  --accent-2   #9b7be8
     --purple-soft      ->  --accent-soft rgba(155,123,232,.14)

   Note the hairlines are lavender, not white at low alpha. That single choice
   is most of why the fleet's dark reads purple: every rule on the page carries
   the hue, so the whole surface does, instead of the color sitting in the
   accents while the page underneath stays grey.

   Both application routes are back, so dark works for a visitor whose OS asks
   for it and for one who picks it in the toggle. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper:      #140d20;
    --paper-2:    #211632;
    --ink:        #f1ecf7;
    --ink-2:      #ddd2ea;
    --ink-3:      #aa9bb8;
    --rule:       rgba(205, 183, 232, .16);
    --rule-hard:  rgba(205, 183, 232, .30);
    --accent:     #b49bf2;
    --accent-2:   #9b7be8;
    --accent-ink: #140d20;
    --accent-soft:rgba(155, 123, 232, .14);
    --signal:     #b49bf2;
    --alert:      #ef7a92;
  }
}
[data-theme="dark"] {
  --paper:      #140d20;
  --paper-2:    #211632;
  --ink:        #f1ecf7;
  --ink-2:      #ddd2ea;
  --ink-3:      #aa9bb8;
  --rule:       rgba(205, 183, 232, .16);
  --rule-hard:  rgba(205, 183, 232, .30);
  --accent:     #b49bf2;
  --accent-2:   #9b7be8;
  --accent-ink: #140d20;
  --accent-soft:rgba(155, 123, 232, .14);
  --signal:     #b49bf2;
  --alert:      #ef7a92;
}

/* ==========================================================================
   2. BASE
   ========================================================================== */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 400 17px/1.62 var(--sans);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
h1, h2, h3 { margin: 0; font-weight: 700; letter-spacing: -.028em; line-height: 1.08; text-wrap: balance; }
p { margin: 0; text-wrap: pretty; }
ul, ol, dl, dd { margin: 0; padding: 0; }
li { list-style: none; }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 3px; }
/* In-text links (2026-09-30 audit, axe link-in-text-block / WCAG 1.4.1): a
   link inside prose is told apart from the words around it by color alone,
   and accent-on-body-text does not clear the 3:1 that takes in either theme
   (about 1.4:1 light, 1.6:1 dark). Links inside prose get the underline;
   standalone links (nav items, footer link list, cards, buttons) keep the
   quiet no-underline. */
p a, li a, dd a, dt a {
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: color-mix(in srgb, currentColor 45%, transparent);
}
.nav-links a { text-decoration: none; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 2px; }
hr { border: 0; border-top: 1px solid var(--rule); margin: 0; }

.wrap { width: var(--wrap); margin-inline: auto; }
.mono { font-family: var(--mono); font-size: .78rem; letter-spacing: .08em; text-transform: uppercase; }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--ink); color: var(--paper); padding: 10px 16px;
}
.skip:focus { left: 12px; top: 12px; }

/* ==========================================================================
   3. NAV
   Solid, hairline, no blur and no translucency. A translucent blurred bar is
   one of the tells this pass removes.
   ========================================================================== */
.nav {
  position: sticky; top: 0; z-index: 100;
  background: var(--paper);
  border-bottom: 1px solid var(--rule-hard);
}
.nav-in { display: flex; align-items: center; justify-content: space-between; gap: 20px; padding: 15px 0; flex-wrap: wrap; }
.brand { color: var(--ink); font-weight: 700; font-size: 1.04rem; letter-spacing: -.03em; }
.brand:hover { text-decoration: none; color: var(--accent); }
.brand .dot { color: var(--accent); }
.nav-links { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.nav-links a, .tt {
  font: 500 .92rem/1 var(--sans);
  color: var(--ink-2); background: none; border: 0;
  padding: 8px 10px; cursor: pointer;
}
.nav-links a:hover { color: var(--accent); text-decoration: none; }
.tt {
  font-family: var(--mono); font-size: .72rem; letter-spacing: .1em; text-transform: uppercase;
  border: 1px solid var(--rule-hard); border-radius: var(--r); color: var(--ink-2);
}
.tt:hover { border-color: var(--accent); color: var(--accent); }
/* Narrow screens: the links wrap to a second row rather than disappear, so every
   destination stays reachable with no JS and no hamburger. The bar also stops
   being sticky here, because two rows of chrome pinned to a phone screen taxes
   every scroll for very little. */
@media (max-width: 760px) {
  .nav { position: static; }
  .nav-in { gap: 6px 14px; padding: 12px 0; }
  .nav-links { gap: 0; }
  .nav-links a, .tt { padding: 7px 9px; font-size: .88rem; }
}

/* ==========================================================================
   4. TYPE HELPERS AND CONTROLS
   ========================================================================== */
/* The only color in the top of the page. A short violet rule instead of a
   gradient, a badge or a chip. It is the whole "signal" gesture. */
.kicker {
  display: inline-flex; align-items: center; gap: 11px;
  font-family: var(--mono); font-size: .76rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-3);
}
.kicker::before { content: ""; width: 24px; height: 2px; background: var(--accent); flex: none; }

.btn {
  display: inline-block; padding: 14px 24px;
  background: var(--accent); color: var(--accent-ink);
  font: 600 .95rem/1 var(--sans); border-radius: var(--r);
}
.btn:hover { background: var(--accent-2); text-decoration: none; }
.link-quiet { font-size: .95rem; color: var(--ink-2); }
.link-quiet:hover { color: var(--accent); }

/* At-a-glance spec list. Mono labels, hairline separated, no chips. */
.spec { border-top: 1px solid var(--rule-hard); }
.spec div { display: grid; grid-template-columns: 5.6rem 1fr; gap: 14px; padding: 12px 0; border-bottom: 1px solid var(--rule); }
.spec dt { font-family: var(--mono); font-size: .72rem; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3); padding-top: 3px; }
.spec dd { color: var(--ink); font-size: .95rem; }
/* The one violet mark in the spec list, on the row that answers "what do I
   actually get". Square, not a dot, not a chip. */
.spec .keep dd { color: var(--accent); font-weight: 600; }

/* --- Form: the clarity-review intake -------------------------------------
   Lives on the .com front door. It was the only form on the business domain
   and it lived in the page; it lives here now so the product pages can reuse
   the field styling instead of each growing its own.

   Hairline fields on paper, mono labels, one accent. No floating labels, no
   rounded pills, no glow on focus: focus is the accent border plus the global
   :focus-visible ring, which is why nothing here touches `outline`. */
.form { margin-top: 30px; display: grid; gap: 17px; max-width: 46rem; }
.form-row { display: grid; gap: 7px; }
.form-row label {
  font-family: var(--mono); font-size: .72rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-3);
}
.form-row label .opt { text-transform: none; letter-spacing: .04em; }
.form-row input, .form-row textarea {
  width: 100%; padding: 12px 13px; border-radius: var(--r);
  font: inherit; font-size: .97rem; color: var(--ink);
  background: var(--paper); border: 1px solid var(--rule-hard);
}
.form-row textarea { resize: vertical; min-height: 4.4em; }
.form-row input::placeholder, .form-row textarea::placeholder { color: var(--ink-3); }
.form-row input:focus, .form-row textarea:focus { border-color: var(--accent); }
/* Honeypot. Off-screen rather than display:none, because some bots skip what
   cannot be laid out at all, and the point of the trap is that they fill it. */
.form-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.form-actions { margin-top: 6px; display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
/* .btn is written for anchors; it needs the two resets a real button does not
   inherit, plus a disabled state for the in-flight submit. */
button.btn { border: 0; cursor: pointer; }
button.btn:disabled { background: var(--accent); opacity: .55; cursor: default; }
.form-status { margin: 0; font-size: .93rem; color: var(--ink-2); }
.form-status.err { color: var(--alert); }
/* The success path sets form.hidden, and .form's own `display: grid` above would
   beat the user agent's [hidden] rule (any author declaration outranks the UA
   sheet). Without this line the form stays on screen after a successful send,
   which is exactly what happened on the tomasetti.online apex for as long as the
   form lived there. Do not remove it. */
.form[hidden] { display: none; }
.form-done { margin-top: 30px; padding-top: 22px; border-top: 1px solid var(--rule-hard); max-width: 46rem; }
.form-done h3 { font-size: 1.16rem; letter-spacing: -.02em; }
.form-done p { margin-top: 10px; color: var(--ink-2); }

/* ==========================================================================
   5. HERO
   Promoted out of the page-local blocks on 2026-09-14 so the front door and the
   four product pages share one hero instead of five copies that drift. The
   product pages keep their own <h1> copy and .byline; they no longer restate
   padding, grid ratio or type scale.
   ========================================================================== */
.hero { padding: 82px 0 60px; }
.hero-grid { display: grid; grid-template-columns: minmax(0, 1.38fr) minmax(0, .62fr); gap: 62px; align-items: start; }
@media (max-width: 940px) { .hero-grid { grid-template-columns: 1fr; gap: 42px; } }
.hero h1 { font-size: clamp(2.5rem, 6vw, 4.2rem); margin: 20px 0 0; letter-spacing: -.038em; max-width: 19ch; }
.hero .lede { margin-top: 24px; font-size: 1.13rem; line-height: 1.62; color: var(--ink-2); max-width: 58ch; }
.hero .actions { margin-top: 32px; display: flex; align-items: center; gap: 20px; flex-wrap: wrap; }
/* Product pages: the mono line that says what the thing is. */
.byline {
  margin-top: 14px; font-family: var(--mono); font-size: .74rem;
  letter-spacing: .1em; text-transform: uppercase; color: var(--accent);
}
.status { margin-top: 20px; color: var(--ink-3); font-size: .93rem; max-width: 56ch; }

/* ==========================================================================
   6. SECTIONS
   Three treatments, not one. A page built only from top-ruled sections reads as
   a single grey list no matter how good the type is, which is what the previous
   pass looked like.
     .sec    top-ruled block        (default rhythm)
     .band   tinted strip           (breaks the page, for the shop roofs)
     .close  tinted closing panel   (the ask, with the form)
   ========================================================================== */
.sec { padding: 72px 0; border-top: 1px solid var(--rule); }
.sec-lead { border-top: 0; padding-top: 22px; }
.sec-head { max-width: 62ch; }
.sec-head h2 { font-size: clamp(1.7rem, 3.4vw, 2.3rem); }
.sec-head p { margin-top: 15px; color: var(--ink-2); }

/* --- Catalog: the product index -----------------------------------------
   The lead section, so it gets a treatment of its own rather than the .dir rows
   used further down. Two columns split by a vertical hairline, square state
   markers, no cards and no rounded corners. The square marker is doing the job
   a pill chip would normally do, and a chip is item 17 on the tell list. */
.catalog {
  margin-top: 46px; border-top: 1px solid var(--rule-hard);
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
}
.cat {
  display: block; padding: 32px 0 30px; color: var(--ink);
  border-bottom: 1px solid var(--rule);
}
.cat:nth-child(odd) { padding-right: 44px; border-right: 1px solid var(--rule); }
.cat:nth-child(even) { padding-left: 44px; }
.cat:hover { text-decoration: none; }
.cat:hover .cat-name { color: var(--accent); }
.cat:hover .cat-state.is-live { color: var(--accent-2); }
.cat-name { font-size: 1.5rem; font-weight: 700; letter-spacing: -.028em; }
.cat-what { margin-top: 11px; color: var(--ink-2); font-size: .97rem; max-width: 44ch; }
.cat-foot { margin-top: 20px; display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.cat-state {
  display: inline-flex; align-items: center; gap: 9px;
  font-family: var(--mono); font-size: .72rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-3);
}
.cat-state::before { content: ""; width: 7px; height: 7px; background: var(--rule-hard); flex: none; }
.cat-state.is-live { color: var(--accent); }
.cat-state.is-live::before { background: var(--accent); }
.cat-get { font-family: var(--mono); font-size: .72rem; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3); }
.cat:hover .cat-get { color: var(--accent); }
@media (max-width: 760px) {
  .catalog { grid-template-columns: 1fr; }
  .cat:nth-child(odd) { padding-right: 0; border-right: 0; }
  .cat:nth-child(even) { padding-left: 0; }
}

/* --- Rate card: a printed price list, not three floating cards --- */
.rate { margin-top: 40px; border-top: 1px solid var(--rule-hard); }
.rate-row {
  display: grid; grid-template-columns: 13rem minmax(0, 1fr); gap: 34px;
  padding: 26px 0; border-bottom: 1px solid var(--rule);
}
@media (max-width: 760px) { .rate-row { grid-template-columns: 1fr; gap: 14px; } }
.rate-name { font-size: 1.2rem; font-weight: 700; letter-spacing: -.025em; }
.rate-price { font-family: var(--mono); font-size: 1.55rem; margin-top: 8px; display: block; }
.rate-unit { font-family: var(--mono); font-size: .72rem; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3); display: block; margin-top: 6px; }
.rate-pick { font-family: var(--mono); font-size: .72rem; letter-spacing: .1em; text-transform: uppercase; color: var(--accent); display: block; margin-top: 10px; }
.rate-inc li { padding: 6px 0; color: var(--ink-2); font-size: .97rem; }
.rate-inc li + li { border-top: 1px solid var(--rule); }
.rate-foot { margin-top: 26px; color: var(--ink-3); font-size: .93rem; max-width: 72ch; }

/* --- Included list --- */
.cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 26px 44px; margin-top: 36px; }
@media (max-width: 760px) { .cols { grid-template-columns: 1fr; } }
.cols .item { padding: 15px 0; border-top: 1px solid var(--rule); }
.cols .item h3 { font-size: 1rem; }
.cols .item p { margin-top: 6px; color: var(--ink-2); font-size: .94rem; }

/* --- Steps, set as a numbered track rather than four equal cards --- */
.steps {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0; margin-top: 38px; border-top: 1px solid var(--rule-hard);
}
.step { padding: 20px 26px 4px 0; border-right: 1px solid var(--rule); }
.step:last-child { border-right: 0; }
.step + .step { padding-left: 26px; }
@media (max-width: 900px) {
  .steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .step:nth-child(2n) { border-right: 0; padding-right: 0; }
  .step:nth-child(2n+1) { padding-left: 0; }
  .step:nth-child(n+3) { border-top: 1px solid var(--rule); }
}
@media (max-width: 520px) {
  .steps { grid-template-columns: 1fr; }
  .step { border-right: 0; padding: 18px 0 4px; }
  .step + .step { padding-left: 0; }
  .step:nth-child(n+2) { border-top: 1px solid var(--rule); }
}
.step .n { font-family: var(--mono); font-size: .76rem; color: var(--accent); letter-spacing: .1em; }
.step h3 { margin-top: 10px; font-size: 1rem; }
.step p { margin-top: 7px; color: var(--ink-2); font-size: .93rem; }

/* --- Directory rows: hosted fronts --- */
.dir { margin-top: 30px; border-top: 1px solid var(--rule-hard); }
.dir a {
  display: grid; grid-template-columns: 12.5rem minmax(0, 1fr) auto; gap: 26px; align-items: baseline;
  padding: 16px 0; border-bottom: 1px solid var(--rule); color: var(--ink);
}
.dir a:hover { text-decoration: none; }
.dir a:hover .dir-name { color: var(--accent); }
.dir-name { font-weight: 700; letter-spacing: -.02em; }
.dir-what { color: var(--ink-2); font-size: .94rem; }
.dir-host { font-family: var(--mono); font-size: .72rem; color: var(--ink-3); white-space: nowrap; }
/* Right-column tag for a directory row that has no host to show. On the products
   directory it carries the product's real status, which is why it is a plain mono
   word and not a rounded pill: this pass removed chips. The wording has to match
   what the product actually does today, not what it is meant to do eventually. */
.dir-tag {
  font-family: var(--mono); font-size: .72rem; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink-3); white-space: nowrap;
}
.dir a:hover .dir-tag { color: var(--accent); }
@media (max-width: 760px) {
  .dir a { grid-template-columns: 1fr; gap: 6px; }
  .dir-host, .dir-tag { white-space: normal; }
}
.dir-note { margin-top: 22px; color: var(--ink-3); font-size: .93rem; }

/* --- Two-up: receipt / refusal, and any paired argument --- */
.two { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 52px; margin-top: 36px; }
@media (max-width: 860px) { .two { grid-template-columns: 1fr; gap: 42px; } }
.two h3 { font-size: 1.35rem; letter-spacing: -.025em; }
.two .sub { margin-top: 12px; color: var(--ink-2); font-size: .97rem; }
.tick { margin-top: 22px; border-top: 1px solid var(--rule-hard); }
.tick li { padding: 12px 0; border-bottom: 1px solid var(--rule); font-size: .95rem; color: var(--ink-2); }
.tick li strong { color: var(--ink); font-weight: 600; }

/* --- Band: a tinted strip that breaks the page rhythm --- */
.band {
  background: var(--paper-2);
  border-top: 1px solid var(--rule-hard); border-bottom: 1px solid var(--rule-hard);
  padding: 64px 0;
}
.band h2 { font-size: clamp(1.65rem, 3.4vw, 2.25rem); }
.band p { margin-top: 15px; color: var(--ink-2); max-width: 62ch; }
.band .dir a:hover .dir-name { color: var(--accent); }

/* --- Close: the ask, and the only other tinted panel on the page --- */
.close { padding: 72px 0; background: var(--paper-2); border-top: 1px solid var(--rule-hard); }
.close h2 { font-size: clamp(1.75rem, 3.6vw, 2.45rem); }
.close p { margin-top: 15px; color: var(--ink-2); max-width: 60ch; }
.close .actions { margin-top: 28px; }

/* ==========================================================================
   7. FOOTER
   Every page carries the attribution line. "by Tomasetti Tech" is for what we
   own; "Hosted by Tomasetti Tech" is for what we host and do not own. Never
   mix them. See BRAND.md.
   ========================================================================== */
.foot { border-top: 1px solid var(--rule-hard); padding: 48px 0 58px; }
.foot-top { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 40px; align-items: start; }
@media (max-width: 760px) { .foot-top { grid-template-columns: 1fr; gap: 26px; } }
.foot-nav { display: flex; flex-wrap: wrap; gap: 6px 22px; }
.foot-nav a { color: var(--ink-2); font-size: .93rem; }
.foot-nav a:hover { color: var(--accent); }
.foot-legal { margin-top: 32px; padding-top: 22px; border-top: 1px solid var(--rule); }
.foot-legal p { color: var(--ink-3); font-size: .88rem; }
.foot-legal p + p { margin-top: 7px; }
.attrib { color: var(--ink-2); font-size: .88rem; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}
