/* ==========================================================================
   thoughtz.com — site styles. CHANGE-017.
   --------------------------------------------------------------------------
   MOBILE FIRST. Every layout rule starts as a single column and widens at a
   breakpoint; nothing needs a breakpoint to work on a phone.

   ⚠️ NO BOOTSTRAP, deliberately (Glen asked for responsive "ie: bootstrap",
   and this delivers the responsive without the framework). The product retints
   Bootstrap and CHANGE-036 phase 3 records what that costs: .text-* reads
   --bs-<name>-rgb rather than --bs-<name>, .alert-* reads the 5.3 subtle
   triple, and eight further values are plain literals no family mapping
   reaches — so the retint has to win by source order from the end of the last
   stylesheet. A brochure site needs a grid and a collapsing nav, which is
   ~2KB of CSS Grid, so none of that tax is worth paying here.

   Class vocabulary is the product's own `thz-` convention (CHANGE-036 phase 2).
   Breakpoints: 560 (phone landscape) · 768 (tablet) · 1024 (desktop).
   ========================================================================== */

/* ⚠⚠ THE NOTE BELOW MUST STAY OUTSIDE THE HEADER COMMENT ABOVE. It was first
   written INSIDE it, and CSS HAS NO NESTED BLOCK COMMENTS: its closing
   delimiter ended the header early, the rest of the header parsed as a
   selector, and that selector swallowed the box-sizing reset that follows.
   Every .thz-container on every page then rendered 40px too wide (width:100%
   PLUS two 20px gutters) and every page scrolled sideways on a phone.
   ⚠️ Desktop looked perfect throughout, because --thz-measure caps the
   container long before the overflow shows - so screenshots did not reveal it
   and the contrast sweep had nothing to say about it. Only the responsive
   probe caught it. */
/* ⚠️ ONE CORRECTION THAT APPLIES TO EVERY "16px/600 floor" COMMENT BELOW.
   STYLE_GUIDE.md §3 rule 3 LOWERED that floor to 14px/600 on 2026-08-15 (Glen,
   looking at a rendered email). The comments in this file were written against
   the older 16px figure and each one names it.

   ✅ THE CODE IS STILL RIGHT AND MUST NOT BE "ALIGNED DOWN". The guide is
   explicit: "IT IS A FLOOR, NOT A TARGET, AND NOTHING WAS SHRUNK TO MEET IT...
   Do not align existing surfaces down to 14px" - the lower bound moved, the
   surfaces did not. Every accent-filled surface here is at 16px/600 and stays
   there. Only the stated RULE was a revision behind, which is recorded here
   once instead of being rewritten into ten places.

   ⚠️ AND CHECK THE STEP BEFORE REACHING FOR THE FLOOR AT ALL: an accent-700
   surface was never governed by it. 4.60:1 is AA body at any size, which is
   why .thz-appcta__note can sit at 0.84rem on the closing band. */

/* ---- reset ------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--thz-bg-page);
  color: var(--thz-text-body);
  font-family: var(--thz-font);
  font-weight: var(--thz-weight-body);
  font-size: 16px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}
img, svg, video { max-width: 100%; height: auto; display: block; }
h1, h2, h3, h4 {
  margin: 0;
  color: var(--thz-text-heading);
  font-weight: var(--thz-weight-heading);
  line-height: 1.15;
  letter-spacing: -0.015em;
}
p { margin: 0 0 1em; }
p:last-child { margin-bottom: 0; }
ul { margin: 0; padding-left: 1.15em; }
a { color: var(--thz-text-link); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--thz-text-link-hover); }

/* Everything focusable gets a visible ring — the site is keyboard-navigable. */
:focus-visible {
  outline: 3px solid var(--thz-action-700);
  outline-offset: 2px;
  border-radius: 3px;
}

/* ---- fluid type --------------------------------------------------------
   clamp() rather than breakpoint steps, so nothing jumps mid-resize.       */
.thz-h1 { font-size: clamp(2rem, 1.35rem + 2.9vw, 3.35rem); }
.thz-h2 { font-size: clamp(1.5rem, 1.15rem + 1.5vw, 2.15rem); }
.thz-h3 { font-size: clamp(1.15rem, 1.02rem + 0.55vw, 1.4rem); }
/* ⚠️ NO max-width (Glen, 2026-09-18, looking at it rendered). This carried `max-width: 62ch`,
   which is the classic measure for body copy - and on this site it made every section lede break
   three lines short of its own container while the bullets and figures beside it ran full width,
   so the sections read as ragged. A lede inside a .thz-split column is still capped by the column;
   only the full-width ones changed.
   ⚠️ THE TRADE IS REAL AND IS GLEN'S CALL: at the 1120px measure a full-width lede runs to
   roughly 120 characters a line against the 45-75 that reads most comfortably. It is two or three
   lines of intro under a heading, not an article, which is why the trade is worth taking here.
   Do not "restore" the cap - and do not copy this to a rule that sets long-form body copy. */
.thz-lede {
  font-size: clamp(1.02rem, 0.97rem + 0.25vw, 1.16rem);
}
.thz-eyebrow {
  font-size: 0.75rem;
  font-weight: var(--thz-weight-heading);
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--thz-text-action);
  margin-bottom: 0.5rem;
}
.thz-muted { color: var(--thz-text-muted); }
.thz-small { font-size: 0.875rem; }

/* ---- layout ------------------------------------------------------------
   ONE element owns the side gutter, so the page can never scroll sideways. */
.thz-container {
  width: 100%;
  max-width: var(--thz-measure);
  margin-inline: auto;
  padding-inline: var(--thz-gutter);
}
.thz-section { padding-block: clamp(2.5rem, 1.6rem + 4vw, 5rem); }
.thz-section--tight { padding-block: clamp(1.75rem, 1.2rem + 2.5vw, 3rem); }

/* Bands. Each states its own background AND its own text colour — a band that
   inherits one and not the other is how invisible text happens. */
.thz-band-ink    { background: var(--thz-bg-ink); color: var(--thz-text-on-ink); }
.thz-band-ink h1, .thz-band-ink h2, .thz-band-ink h3 { color: var(--thz-text-inverse); }
/* ⚠️ THE CTA BAND USES THE DEEP STEP, NOT accent-500, AND THAT IS DELIBERATE.
   STYLE_GUIDE.md §3 permits white on accent-500 only under a 16px/600 floor —
   which a whole lede SENTENCE does not meet. Measured: white on accent-500 is
   2.39–2.80:1, on accent-600 3.51:1, on accent-700 4.60:1. Only the deep step
   clears AA for body copy. §3's own rule says a fill carrying a sentence steps
   down the ramp; this is that rule applied to a band rather than a button.
   ⚠️ If this is ever reverted to the brighter orange, the sentence has to leave
   the band with it — do not move one without the other. */
.thz-band-action { background: var(--thz-bg-band-action); color: var(--thz-text-on-action); }
.thz-band-action h1, .thz-band-action h2 { color: var(--thz-text-inverse); }
.thz-band-wash   { background: var(--thz-bg-wash); color: var(--thz-text-body); }
.thz-band-card   { background: var(--thz-bg-card); color: var(--thz-text-body); }

/* ---- the grid ----------------------------------------------------------
   auto-fit + minmax does most of the work with no breakpoint at all: cards
   reflow to whatever fits. min() keeps it from overflowing a 320px screen. */
.thz-grid {
  display: grid;
  gap: clamp(0.85rem, 0.6rem + 1vw, 1.5rem);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
}
.thz-grid--wide { grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr)); }
.thz-grid--tight { grid-template-columns: repeat(auto-fit, minmax(min(100%, 165px), 1fr)); }

/* ---- the industry chips ------------------------------------------------
   Glen, 2026-09-18: "Add small icons to the left of each of these". These were an inline style
   on the element until then; a mark beside a label needs a flex row, which is more than an
   inline style should carry, and the border was a raw rgba sitting in the markup.

   ⚠️ INK-BAND VALUES. The class is named for the shape because it may get reused, but the
   white-alpha edge and the accent mark both assume a dark ground - put one of these on bone
   and the border disappears. The ONE use today is /ways-to-use-it's industry grid.
   ⚠️ 165px MINIMUM COLUMN, SET ABOVE, AND THE ICON EATS 1.5rem OF IT. "Concerts & events" and
   "Trades & services" are the longest labels and they wrap to two lines on a narrow column
   either way, which is why the chip is not `white-space: nowrap` - a nowrap chip would push
   the grid wider than the container instead. */
.thz-tag {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.6rem 0.85rem;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: var(--thz-radius-sm);
  font-size: 0.9rem;
}
/* ⚠️ THE MARK IS THE RAW ACCENT AND THAT IS THE PERMITTED DIRECTION: 6.21:1 on ink, the same
   pair STYLE_GUIDE.md §3 measures. Accent on a dark ground is sanctioned; accent on a light
   ground is the forbidden one, and --thz-text-action (#a8480a) is what a light ground gets. */
.thz-tag__icon {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  color: var(--thz-text-action-on-ink);
}
/* ⚠️ BOTH DIMENSIONS IN CSS, AND max-width: none. The reset at the top of this file sets
   `svg { max-width: 100%; height: auto }`, which overrides the height attribute every
   Bootstrap Icons file carries - so the icon's size stops being a property of the file and
   starts being whatever the box allows. State it here instead of inheriting an argument.
   Same reason .thz-aimodal__mark svg does it. */
.thz-tag__icon svg { width: 1rem; height: 1rem; max-width: none; }

/* (An earlier pass put the mark inside the h3 itself, as .thz-h3--icon on a white card, with
   the mark in --thz-text-action. Glen asked for a coloured header bar instead the same day,
   so the heading moved into .thz-card__head below and those two rules were deleted rather
   than left unused. The measurement is the part worth keeping: #a8480a is 5.84:1 on a white
   card, and it is what a mark on a LIGHT ground has to read - see .thz-tag__icon for the
   opposite case and why they differ.) */
/* ⚠️ `.thz-grid--start` IS GONE, AND SO IS THE PROBLEM IT WORKED AROUND
   (Glen, 2026-09-15: "Make these cards all the same size").
   Superseded reasoning, kept because it explains the shape of the fix: "Cards
   take their NATURAL height instead of stretching to match the tallest in the
   row. Grid's default `stretch` is right when the cards are comparable and
   wrong when they are not: on How it works, steps 2, 3 and 5 carry a screenshot
   and steps 1 and 4 carry a sentence, so the short ones grew to match and
   rendered as two large empty boxes. Ragged bottoms beat holes."
   That was true of the diagnosis and wrong about the remedy. The cards were
   uncomparable because two of six had no picture - so the answer was to give
   every card a picture, not to stop them lining up. Grid's default `stretch` is
   back (there is no modifier to remove), and `.thz-card` is a flex column with
   the image band pinned to its foot, which is what makes six unequal sentences
   end at one line. */

/* An explicit two-column split that stacks — for side-by-side prose + image. */
.thz-split { display: grid; gap: clamp(1.25rem, 0.8rem + 2vw, 2.75rem); align-items: center; }
@media (min-width: 768px) {
  .thz-split { grid-template-columns: 1fr 1fr; }
  .thz-split--wide-left { grid-template-columns: 1.25fr 1fr; }
  .thz-split--wide-right { grid-template-columns: 1fr 1.25fr; }
}
/* On a phone the image usually wants to come first regardless of source order. */
@media (max-width: 767px) {
  .thz-split--flip > :first-child { order: 2; }
}

/* ---- cards -------------------------------------------------------------- */
.thz-card {
  background: var(--thz-bg-card);
  border: 1px solid var(--thz-border-line);
  border-radius: var(--thz-radius);
  padding: clamp(1rem, 0.85rem + 0.7vw, 1.5rem);
}
/* ⚠️ A FLEX COLUMN SO THE IMAGE CAN BE PINNED TO THE FOOT. Nothing else
   about the card changes - block children lay out identically in a column flex
   container - but `.thz-shot { margin-top: auto }` needs a flex parent, and
   that one line is what stops six cards with sentences of different lengths
   putting their pictures at six different heights. */
.thz-card { display: flex; flex-direction: column; }
.thz-card h3 { margin-bottom: 0.35rem; }
.thz-card--sand { background: var(--thz-bg-sand); border-color: var(--thz-border-sand); }
.thz-card--sand h3 { color: var(--thz-text-on-sand); }
.thz-card--wash { background: var(--thz-bg-action-wash); border-color: #f3cfae; }

/* ---- a banded card: accent header, body, pinned footer -----------------
   Glen, 2026-09-18: "make them more colorful - header bar color and a footer on each, all the
   same size". One use today: /ways-to-use-it's three worked examples.

   ⚠️ IT MUST SIT AFTER .thz-card, NOT WITH THE GRID RULES ABOVE. Both selectors are (0,1,0), so
   `padding: 0` beats .thz-card's padding only on source order. Move this block up the file and
   the bands get an invisible ring of card padding around them, which reads as a rendering bug.
   ⚠️ `overflow: hidden` IS WHAT CLIPS THE HEADER TO THE RADIUS. Without it the accent fill keeps
   its square top corners and overhangs the rounded border by a pixel on each side.
   ⚠️ WHITE ON accent-500 IS 2.80:1 - the brand's reaffirmed trade, permitted by STYLE_GUIDE.md §3
   only above a 16px/600 floor. The title below is 1.05rem/700 and the mark is a FILLED icon at
   1.15rem (18.4px, clearing §3's separate ≥18px floor for icons on an accent fill). Do not shrink
   or lighten either: the size is what makes this readable, not the colour. */
.thz-card--banded { padding: 0; overflow: hidden; }
.thz-card__head {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.85rem 1rem;
  background: var(--thz-bg-action);
  color: var(--thz-text-on-action);
}
.thz-card__title {
  margin: 0;
  font-size: 1.05rem;
  font-weight: var(--thz-weight-heading);
  color: inherit;
  line-height: 1.3;
}
.thz-card__icon { flex: 0 0 auto; display: grid; place-items: center; }
.thz-card__icon svg { width: 1.15rem; height: 1.15rem; max-width: none; }

/* `flex: 1` is what leaves the slack for the footer's auto margin to take. */
.thz-card__body { flex: 1; padding: 1rem; }
.thz-card__body p:last-child { margin-bottom: 0; }

/* ⚠️ `margin-top: auto` IS THE HALF THAT ALIGNS THE FOOTERS, and the grid stretching the cards
   is the other half. Drop either one and three cards with bodies of different lengths put their
   footers at three different heights. Same mechanism as .thz-shot in a card. */
.thz-card__foot {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
  margin-top: auto;
  padding: 0.7rem 1rem;
  border-top: 1px solid var(--thz-border-line);
  background: var(--thz-bg-action-wash);
  color: var(--thz-text-body);
  font-size: 0.8rem;
}
/* The mark here is on the pale wash, not on the accent fill, so it takes the darkened
   website-only orange - #a8480a, 4.82:1 on wash. accent-500 would be 2.4:1 there. */
.thz-card__foot-icon { flex: 0 0 auto; display: grid; place-items: center; color: var(--thz-text-action); }
.thz-card__foot-icon svg { width: 0.95rem; height: 0.95rem; max-width: none; }

/* ---- buttons -----------------------------------------------------------
   ⚠️ STYLE_GUIDE.md §3: white on the accent fill is 2.80:1, which is the
   knowing trade. It is only safe because of the 16px/600 floor below — do
   not shrink or lighten a .thz-btn label. 44px min height is the touch
   target, which is why this matters on mobile specifically.               */
.thz-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: 44px;
  padding: 0.7rem 1.4rem;
  border-radius: var(--thz-radius-pill);
  font-size: 1rem;                        /* the 16px floor  */
  font-weight: var(--thz-weight-strong);  /* the 600 floor   */
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  border: 1px solid transparent;
  transition: background-color .15s ease, border-color .15s ease;
}
/* ⚠️ THE BORDER FOLLOWS THE FILL, IT IS NOT THE DEFINITION BORDER ANY MORE (Q-237).
   --thz-border-action is action-700, which is now also the FILL - so as a border it draws
   nothing on the default state and, worse, would have left a LIGHTER ring around the darker
   fill on hover and press. Every state sets both together. The definition border still does
   its job on ghost buttons and chips, which are light-filled. */
.thz-btn--primary {
  background: var(--thz-bg-action);
  color: var(--thz-text-on-action);
  border-color: var(--thz-bg-action);
}
.thz-btn--primary:hover {
  background: var(--thz-bg-action-hover);
  border-color: var(--thz-bg-action-hover);
  color: var(--thz-text-on-action);
}
.thz-btn--primary:active {
  background: var(--thz-bg-action-pressed);
  border-color: var(--thz-bg-action-pressed);
}

.thz-btn--ghost {
  background: transparent;
  color: var(--thz-text-action);
  border-color: var(--thz-border-action);
}
.thz-btn--ghost:hover { background: var(--thz-bg-action-wash); color: var(--thz-text-action); }

/* A ghost button inherits accent-700 lettering, which is correct on a light
   ground and WRONG on any dark or accent one. Both cases need stating.
   ⚠️ The accent band is the one that actually shipped broken: orange type on an
   orange fill, found in a render pass rather than by reading the CSS. If a new
   band colour is added, add its ghost rule at the same time. */
.thz-band-ink .thz-btn--ghost { color: var(--thz-text-inverse); border-color: rgba(255,255,255,.55); }
.thz-band-ink .thz-btn--ghost:hover { background: rgba(255,255,255,.1); color: var(--thz-text-inverse); }

/* White on the accent is the sanctioned 2.80:1 trade, and .thz-btn already
   carries the 16px/600 floor that STYLE_GUIDE.md §3 requires to permit it. */
.thz-band-action .thz-btn--ghost { color: var(--thz-text-on-action); border-color: rgba(255,255,255,.75); }
.thz-band-action .thz-btn--ghost:hover { background: rgba(255,255,255,.16); color: var(--thz-text-on-action); }
.thz-band-action .thz-btn--primary {
  background: var(--thz-white);
  color: var(--thz-action-700);
  border-color: var(--thz-white);
}
.thz-band-action .thz-btn--primary:hover { background: var(--thz-action-050); color: var(--thz-action-700); }

.thz-btn-row { display: flex; flex-wrap: wrap; gap: 0.75rem; }

/* ---- header / nav ------------------------------------------------------
   ⚠️ THE BAR IS ORANGE, AND THAT IS GLEN'S CALL MADE WITH THE MEASUREMENT IN
   FRONT OF HIM (2026-09-14): "the nav area should be orange as it is on every
   page and is our main color."

   ⚠️ THE HISTORY MATTERS BECAUSE THE OBJECTION WAS REAL AND IS NOW ANSWERED, NOT
   FORGOTTEN. Bone first (too quiet), then ink. Ink was chosen specifically
   because white nav links on accent-500 at 15px/400 are 2.80:1 and BREAK §3's
   16px/600 floor on the one piece of text every visitor must read. Glen's answer
   was that the brand colour belongs on every page — his decision to make, and
   made knowingly. **So the floor is what carries it now: the links are 16px/600,
   not 15px/400.** ⚠️ Shrinking or lightening them is what would actually ship
   unreadable text; the colour on its own is the same sanctioned trade every
   Thoughtz button already carries.

   ⚠️ AND THE BAR NO LONGER TOUCHES THE HERO — .thz-strip sits between them.
   Two orange fills stacked read as one undifferentiated mass; the ink strip is
   what gives the bar an edge. If the strip is ever removed, the bar needs a
   different way to end, or the top of the home page loses its structure.

   NO JAVASCRIPT. A hidden checkbox drives the phone menu; at 768px the toggle
   disappears and the list becomes a normal row.
   ⚠️ THE FIRST ATTEMPT USED <details> AND BROKE THE DESKTOP NAV. Chrome hides a
   closed <details>'s non-summary children through a UA slot rule that
   `display: flex !important` does not beat — the desktop header rendered as a
   logo and nothing else. The checkbox has no such rule: the <ul> is an ordinary
   element throughout, so the 768px override is an ordinary cascade win.       */
.thz-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--thz-bg-header);
  color: var(--thz-text-header);
  /* The hairline is the one place the accent touches the bar's edge — it stops
     the ink reading as a black void where it meets the orange banner below. */
  border-bottom: 3px solid var(--thz-border-header);
}
.thz-header__inner {
  display: flex;
  align-items: center;          /* vertical centring of everything in the bar */
  justify-content: space-between;
  gap: 1rem;
  min-height: 6rem;             /* Glen, 2026-09-14 */
}

/* ---- logo --------------------------------------------------------------- */
.thz-logo {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-weight: var(--thz-weight-heading);
  /* Glen, 2026-09-18: 1.3rem -> 2rem.
     The mark was scaled to match (Glen, same day) - see .thz-logo__mark below. The ®
     needed nothing: .thz-logo__tm is sized and offset in `em`, so it tracked this by
     itself, which is the argument for doing the mark the same way. */
  font-size: 2rem;
  color: var(--thz-text-header-active);
  text-decoration: none;
  letter-spacing: -0.025em;
  flex: 0 0 auto;
}
/* The mark is drawn in currentColor, so it is inlined rather than <img>-ed —
   an <img> cannot inherit colour. ⚠️ It is WHITE here: it was orange while the
   bar was ink, and orange-on-orange would erase it entirely. */
/* ⚠️ `em`, NOT px, AND THE RATIO IS THE OLD ONE PRESERVED. It was a fixed 32px against a
   1.3rem wordmark - 32/20.8 = 1.54 - so 1.54em reproduces exactly the proportion the mark
   had before the type grew, and cannot drift out of step again the next time the wordmark
   is resized. ⚠️ It also fixes something the px version got wrong quietly: this site sets
   no root font-size, so it honours the reader's browser default - and a fixed-px mark
   ignored that while every piece of type around it scaled. */
.thz-logo__mark { display: block; width: 1.54em; color: var(--thz-white); }
.thz-logo__mark svg { width: 100%; height: auto; display: block; }
.thz-logo:hover { color: var(--thz-text-header-active); }
.thz-logo:hover .thz-logo__mark { color: var(--thz-action-050); }

/* ---- the toggle --------------------------------------------------------- */
/* ⚠️ STRETCHED TO THE FULL BAR HEIGHT ON PURPOSE. The phone menu panel is
   positioned `top: 100%` against this element — and .thz-nav's natural height is
   the 44px toggle, not the bar. In a 6rem bar that put the panel's top edge
   ~26px ABOVE the header's bottom, overlapping it. Stretching makes 100% mean
   "below the header" again; the inner flex keeps the toggle itself centred. */
.thz-nav {
  position: relative;
  align-self: stretch;
  display: flex;
  align-items: center;
}
.thz-nav__cb { position: absolute; left: -9999px; width: 1px; height: 1px; }

.thz-nav__toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  min-height: 44px;
  padding: 0 0.85rem;
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: var(--thz-radius-pill);
  font-size: 0.95rem;
  font-weight: var(--thz-weight-strong);
  color: var(--thz-text-header);
  cursor: pointer;
  user-select: none;
}
.thz-nav__toggle:hover { background: var(--thz-bg-header-hover); color: var(--thz-text-header-active); }
/* The checkbox is off-canvas, so the ring has to be painted on the label. */
.thz-nav__cb:focus-visible + .thz-nav__toggle {
  outline: 3px solid var(--thz-action);
  outline-offset: 2px;
}
.thz-nav__cross { display: none; }
/* ⚠️ PRESSED, NOT THE ACTION FILL. This read --thz-bg-action, which was accent-500 against an
   accent-500 bar only because the BAR had its own token - and the moment both moved to
   action-700 the open toggle would have been the same colour as the bar it sits on, i.e.
   invisible but for a 30%-white border. action-900 reads as pressed against the darker bar. */
.thz-nav__cb:checked + .thz-nav__toggle { background: var(--thz-bg-action-pressed); border-color: var(--thz-bg-action-pressed); color: var(--thz-text-on-action); }
.thz-nav__cb:checked + .thz-nav__toggle .thz-nav__bars { display: none; }
.thz-nav__cb:checked + .thz-nav__toggle .thz-nav__cross { display: inline; }

/* ---- the list ----------------------------------------------------------- */
.thz-nav__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: none;
}
.thz-nav__cb:checked ~ .thz-nav__list { display: flex; }

.thz-nav__list a:not(.thz-btn) {
  display: block;
  min-height: 44px;
  line-height: 44px;
  padding-inline: 0.9rem;
  border-radius: var(--thz-radius-sm);
  color: var(--thz-text-header);
  text-decoration: none;
  /* ⚠️ 600, NOT 400 - STYLE_GUIDE §3 puts a 16px AND 600 floor on any text sitting on an
     accent fill, and these links had been 400 since the bar turned orange. It also serves the
     ask directly: a 400 stroke in white on a colour has less ink to hold its own edges, which
     is a real part of what reads as fuzzy. Reversible on its own if the bar looks too heavy. */
  font-weight: var(--thz-weight-strong);
  transition: color .15s ease, background-color .15s ease;
}
.thz-nav__list a:not(.thz-btn):hover {
  background: var(--thz-bg-header-hover);
  color: var(--thz-text-header-active);
}
.thz-nav__list a[aria-current="page"] {
  color: var(--thz-text-header-active);
  font-weight: var(--thz-weight-strong);
}

/* ---- phone and small tablet: the list drops out of the bar --------------
   ⚠️ THE BREAKPOINT IS 880px, NOT 768px, AND THAT IS A CONSEQUENCE OF THE ORANGE
   BAR. Going orange forced the links up to §3's 16px/600 floor, which made the
   row wider than 768 — at exactly 768 every label wrapped onto two lines ("How
   it / works"), including the button. Found by rendering at the breakpoint, not
   by reading the CSS. The collapsed menu simply starts earlier now.
   ⚠️ This value and the one on the row query below are a PAIR. Change both. */
@media (max-width: 879px) {
  .thz-nav__list {
    position: absolute;
    top: calc(100% + 0.5rem);
    right: 0;
    min-width: 15rem;
    flex-direction: column;
    gap: 0.15rem;
    padding: 0.6rem;
    /* Ink panel, matching the bar — a white panel hanging off a dark header
       reads as a different component rather than as the menu opening. */
    background: var(--thz-bg-header);
    border: 1px solid rgba(255, 255, 255, 0.16);
    border-top: 3px solid var(--thz-border-header);
    border-radius: var(--thz-radius);
    box-shadow: 0 18px 38px rgba(26, 26, 26, 0.35);
  }
  .thz-nav__list a[aria-current="page"] { box-shadow: inset 3px 0 0 var(--thz-white); }
  .thz-nav__cta { margin-top: 0.4rem; }
  .thz-nav__cta .thz-btn { width: 100%; }
}

/* ---- wide: a plain row -------------------------------------------------- */
/* ⚠️ Paired with the 879px query above — change both or a width band gets
   neither the toggle nor the row, which renders as a bar with no navigation. */
@media (min-width: 880px) {
  .thz-nav__toggle { display: none; }
  .thz-nav__list {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 0.2rem;
  }
  .thz-nav__list a:not(.thz-btn) {
    min-height: 0;
    line-height: 1.2;
    padding: 0.6rem 0.8rem;
    /* ⚠️ 16px/600 IS THE FLOOR, NOT A STYLE CHOICE. These were 0.95rem/400 while
       the bar was ink, where 13.6:1 made size irrelevant. On an accent fill §3
       permits white only at 16px/600 and above. Do not shrink them back. */
    font-size: 1rem;
    font-weight: var(--thz-weight-strong);
    /* A wrapped nav label is worse than a collapsed menu — belt and braces
       alongside the breakpoint above. */
    white-space: nowrap;
  }
  .thz-nav__list a[aria-current="page"] { box-shadow: inset 0 -3px 0 var(--thz-white); }
  .thz-nav__cta { margin-left: 0.6rem; }
  .thz-nav__cta .thz-btn { padding: 0.55rem 1.25rem; min-height: 42px; white-space: nowrap; }
}

/* ⚠️ THE HEADER CTA INVERTS — white fill, orange lettering. It was an orange
   pill while the bar was ink; on an orange bar that pill disappears. This is
   also the only text in the header that clears AA properly (4.60:1), which is
   the right place for the one thing you most want clicked. */
.thz-header .thz-btn--primary {
  background: var(--thz-white);
  color: var(--thz-action-700);
  border-color: var(--thz-white);
}
.thz-header .thz-btn--primary:hover {
  background: var(--thz-bg-action-wash);
  color: var(--thz-action-700);
  border-color: var(--thz-bg-action-wash);
}

/* ---- the strip ---------------------------------------------------------
   ⚠️ THIS BAND EXISTS TO SEPARATE TWO ORANGES (Glen, 2026-09-14): "if you add a
   section above the orange header ... it will break up the nav orange area from
   that area." An orange bar sitting directly on the orange hero reads as one
   undifferentiated block — the ink between them is what gives each an edge.

   ⚠️ It is on EVERY page, not just the home page. On the inner pages the hero is
   bone, so the strip is doing ordinary work there (a slim dark band under the
   bar); on the home page it is load-bearing. Removing it from the inner pages to
   "tidy up" would make the bar look different on the one page it matters most. */
.thz-strip {
  background: var(--thz-bg-strip);
  color: var(--thz-text-strip);
  font-size: 0.925rem;
}
.thz-strip__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.5rem 1.25rem;
  min-height: 52px;
  padding-block: 0.6rem;
  text-align: center;
}
.thz-strip__lead { font-weight: var(--thz-weight-strong); color: var(--thz-white); }
.thz-strip__list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 0.4rem 1.1rem;
  list-style: none;
  margin: 0;
  padding: 0;
}
.thz-strip__list li { display: inline-flex; align-items: center; gap: 0.45rem; }
/* A dot rather than a border, so wrapped rows never leave a dangling divider. */
.thz-strip__list li::before {
  content: '';
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--thz-action);
  flex: 0 0 auto;
}
.thz-strip__cta {
  color: var(--thz-white);
  font-weight: var(--thz-weight-strong);
  text-decoration: none;
  border-bottom: 2px solid var(--thz-action);
  padding-bottom: 1px;
  white-space: nowrap;
}
.thz-strip__cta:hover { color: var(--thz-action-050); border-color: var(--thz-action-600); }

/* ⚠️ ON A PHONE THE THREE BULLETS ARE DROPPED, and the reason is measured: with
   them the strip wrapped to FOUR lines and stood 173px tall. Stacked under a
   96px sticky bar that is ~270px of chrome before the hero starts — about a
   third of a 390x844 screen. The lead and the CTA alone are one line at ~52px
   and still do the band's structural job of separating the two oranges.
   ⚠️ Do not "restore" the bullets for consistency with desktop; they are the
   part that costs nothing to lose and everything to keep. */
@media (max-width: 879px) {
  .thz-strip__list { display: none; }
  .thz-strip__inner { gap: 0.35rem 0.85rem; }
}

/* ---- hero --------------------------------------------------------------- */
.thz-hero { padding-block: clamp(2.5rem, 1.5rem + 5vw, 5.5rem); }
.thz-hero h1 { margin-bottom: 0.75rem; }
.thz-hero .thz-lede { margin-bottom: 1.75rem; }

/* ---- hero BANNER — the bright orange front door -------------------------
   Glen, 2026-09-14: "I would like the banner to be more exciting - maybe
   bigger with a bright orange background so it stands out."

   ✅ IT IS accent-600 NOW, NOT accent-500 (Glen, 2026-09-18, Q-236). White on it is
   **3.51:1** measured on the glyph rows, which clears WCAG's 3:1 for large text - the
   first version of this banner that did. *(Superseded text, kept: "THIS IS accent-500,
   THE BRIGHT ONE, AND IT IS THE ONE HE ASKED FOR. White on it is 2.80:1 - the brand's
   known, reaffirmed sub-AA trade, the same one every Thoughtz button carries.")*
   ⚠️ THE 2.80:1 TRADE IS STILL LIVE EVERYWHERE ELSE - every Thoughtz BUTTON still
   carries it, and a contrast sweep still flags those. This banner is the exception,
   not a new rule, and nothing here licenses "fixing" the buttons.

   What IS managed here, because §3's floor still applies to everything sitting
   on an accent fill: the headline is enormous, the lede is lifted to 600 and
   never falls below 18px, and the eyebrow is 700 at 14px minimum. Nothing on
   this band is small, light text. If a new element is added to the banner, it
   has to clear the same bar.                                                */
.thz-hero--banner {
  position: relative;
  overflow: hidden;
  color: var(--thz-text-on-action);
  /* ✅✅ SUPERSEDED 2026-09-18 (Q-236) - THE GRADIENT IS GONE. Everything in this comment
     describes what USED to be here and is kept as the measurement record. The live rule is
     the flat fill below it.

     ⚠️ LIGHT AT THE TOP, FULL ORANGE AT THE BOTTOM (Glen, 2026-09-14).

     ⚠️⚠️ AN EARLIER VERSION OF THIS COMMENT CLAIMED "every word still sits on
     accent-500" BECAUSE THE LIGHT BAND WAS SPENT ON THE TOP PADDING. THAT WAS
     FALSE, and tools/_gradient.html is what disproved it — worth keeping as the
     record, because it is the kind of claim that reads as reasoning and is
     actually just an assumption. The hero is tall, so its top padding is only
     7–16% of its height: the eyebrow and headline land at 7–21% down, well
     inside the pale zone.

     WHAT IS ACTUALLY TRUE, measured at 390 / 768 / 1024 / 1440:
       eyebrow   2.01 – 2.19 : 1   (16px/700, 7–16% down)
       headline  2.18 – 2.30 : 1   (40–70px/700, 16–21% down)
       lede      2.58 – 2.80 : 1
       buttons   2.80 : 1          (full accent by then)
     Against the sanctioned baseline of 2.80:1 on flat accent-500.

     ⚠️ THE TENSION IS STRUCTURAL AND HAS NO CLEVER FIX: white on a LIGHTER
     orange is always worse than white on accent-500, so "lighter at the top"
     and "white text at the top" pull directly against each other. The stops
     below are the balance Glen was shown; tightening 46% → ~15% would put every
     word back on full accent but leaves the gradient a thin band at the very
     top rather than a top-to-bottom wash.

     ⚠️ Every element on this banner still clears §3's 16px/600 floor, which is
     what keeps it legible rather than merely low-contrast. Do not shrink any of
     it. Re-measure with tools/_gradient.html if these stops move. */
  /* ⚠️ FLAT accent-600, NOT THE GRADIENT (Glen, 2026-09-18, Q-236: "the white on orange
     looks a little fuzzy. Is there a way to make it crisp?").

     ⚠️⚠️ THE ANSWER WAS NOT A RENDERING SETTING, AND THAT IS THE POINT WORTH KEEPING.
     `-webkit-font-smoothing: antialiased` was already set at the top of this file and is a
     macOS-only property, so it was doing nothing on the machine the problem was reported
     from; `text-shadow` would have made it muddier. Measured on the actual glyph rows, the
     worst ground under the headline was **2.35:1** — the gradient was palest exactly where
     the largest type sat. "Fuzzy" was low luminance separation, not antialiasing.

     ⚠️ THE h1 IS 40–70px, WHICH IS "LARGE TEXT" TO WCAG AND WANTS 3:1. Three options were
     rendered and measured: as it was 2.35:1, gradient tightened 2.80:1, flat accent-600
     **3.51:1**. Only this one clears its own category, which is why it won.

     ⚠️ THIS IS A BRAND CHANGE, NOT ONLY A CONTRAST FIX, AND GLEN MADE IT KNOWINGLY. He
     asked for "a bright orange background so it stands out" on 2026-09-14 and this is one
     step deeper than that #f97316. Do not "restore" the brighter fill on the grounds that
     it is the brand colour — it was traded for legibility with the numbers in front of him.

     The gradient it replaced, and everything measured about it, is the block directly
     above - kept rather than deleted, because "put the wash back" is exactly the kind of
     thing that gets re-proposed by someone who has not seen the numbers. */
  background: var(--thz-action-600);
  padding-block: clamp(3rem, 1.8rem + 6.5vw, 7rem);
}
/* One deepening in the far corner, so the bottom half is not a flat slab.
   ⚠️ The white radial that used to sit here is GONE. It lightened the top,
   which is now the gradient's job — stacking both put text on a paler ground
   than the gradient alone accounts for, which is exactly the kind of thing the
   measurement below would then be wrong about. */
.thz-hero--banner::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(90% 80% at 100% 100%, rgba(194, 84, 11, 0.5), transparent 62%);
  pointer-events: none;
}
/* The brand mark, oversized and very quiet, bled off the right edge.
   ⚠️ Decorative only — aria-hidden in the markup. It must never be the only
   thing carrying meaning, and it is deliberately behind the text. */
.thz-hero__watermark {
  position: absolute;
  right: -4%;
  bottom: -28%;
  width: min(46%, 560px);
  color: rgba(255, 255, 255, 0.1);
  pointer-events: none;
  z-index: 0;
}
.thz-hero__watermark svg { width: 100%; height: auto; display: block; }
@media (max-width: 767px) {
  /* On a phone it would sit under the buttons and muddy them. */
  .thz-hero__watermark { display: none; }
}
.thz-hero--banner > .thz-container { position: relative; z-index: 1; }

.thz-hero--banner .thz-eyebrow {
  color: var(--thz-text-on-action);
  /* ⚠️ 16px MINIMUM, and this was WRONG until the sweep caught it. It sat at
     0.875rem (14px) with a comment claiming that met the floor — it does not.
     §3's floor is 16px AND 600 on an accent fill; extra weight does not buy
     back missing size. Weight comes from .thz-eyebrow at 700. */
  font-size: 1rem;
  opacity: 1;
}
.thz-hero--banner h1 {
  color: var(--thz-text-inverse);
  font-size: clamp(2.35rem, 1.5rem + 4.1vw, 4.4rem);
  letter-spacing: -0.03em;
  line-height: 1.03;
  margin-bottom: 1rem;
  text-wrap: balance;
}
.thz-hero--banner .thz-lede {
  color: var(--thz-text-on-action);
  font-size: clamp(1.13rem, 1rem + 0.85vw, 1.45rem);
  font-weight: var(--thz-weight-strong);   /* never light on an accent fill */
  max-width: 34ch;
  margin-bottom: 2rem;
}

/* On the banner the primary button inverts — white fill, orange lettering.
   It reads as the loudest thing on the page, which is the point, and it is the
   one piece of type up here that clears AA comfortably (4.60:1). */
.thz-hero--banner .thz-btn--primary {
  background: var(--thz-white);
  color: var(--thz-action-700);
  border-color: var(--thz-white);
}
.thz-hero--banner .thz-btn--primary:hover {
  background: var(--thz-bg-action-wash);
  color: var(--thz-action-700);
}
.thz-hero--banner .thz-btn--ghost {
  color: var(--thz-text-on-action);
  border-color: rgba(255, 255, 255, 0.8);
}
.thz-hero--banner .thz-btn--ghost:hover {
  background: rgba(255, 255, 255, 0.16);
  color: var(--thz-text-on-action);
}

/* The screenshot block lifts off the orange as a white card rather than
   dissolving into it — the generic peach placeholder measured 1.00:1 here. */
.thz-hero--banner .thz-placeholder {
  background: var(--thz-bg-card);
  border-color: var(--thz-bg-card);
  color: var(--thz-text-body);
  box-shadow: 0 24px 48px rgba(26, 26, 26, 0.22);
}
/* Taller here than the generic block: this slot holds a PHONE screenshot, and
   at the generic 180px it read as a small note floating on a big banner rather
   than as the product. Sized to roughly the aspect a portrait screen will want. */
.thz-hero--banner .thz-placeholder--shot { min-height: min(58vw, 400px); }
.thz-hero--banner .thz-placeholder__label { color: var(--thz-text-action); }
.thz-hero--banner .thz-placeholder__what { color: var(--thz-text-heading); }
.thz-hero--banner .thz-placeholder .thz-small { color: var(--thz-text-muted); }

/* ---- steps -------------------------------------------------------------- */
.thz-step { display: flex; gap: 0.9rem; margin-bottom: 1.1rem; }
.thz-step:last-child { margin-bottom: 0; }
.thz-step__num {
  flex: 0 0 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--thz-bg-action);
  color: var(--thz-text-on-action);
  /* ⚠️ 16px MINIMUM. This was 0.9rem (14.4px) and that BREAKS §3's floor: white
     on an accent fill is only sanctioned at 16px/600 or above. Caught by the
     contrast sweep, not by reading the rule. The brand-400 variant below
     inherits the size and is better for it. */
  font-size: 1rem;
  font-weight: var(--thz-weight-heading);
  display: grid;
  place-items: center;
  margin-top: 2px;
}
.thz-step--brand .thz-step__num { background: var(--thz-bg-brand-light); color: var(--thz-text-on-brand-light); }
.thz-step__title { font-weight: var(--thz-weight-strong); color: var(--thz-text-heading); }
.thz-step__body { font-size: 0.94rem; color: var(--thz-text-muted); }

/* ---- tick list ---------------------------------------------------------- */
/* ⚠️ THE TICK IS DRAWN IN CSS, NOT TYPED AS A CHARACTER. Same argument as the
   star in the product's bannerIcons.js: a glyph the font does not cover draws
   as tofu, and it fails silently on exactly the machines nobody here tests on.
   Two borders rotated 45deg cannot miss. It is decorative, so it is a
   pseudo-element and never reaches the accessibility tree. */
.thz-ticks { list-style: none; margin: 1.1rem 0 0; padding: 0; }
.thz-ticks li {
  position: relative;
  padding-left: 2rem;
  margin-bottom: 0.7rem;
  font-size: 0.97rem;
  color: var(--thz-text-body);
}
.thz-ticks li:last-child { margin-bottom: 0; }
.thz-ticks li::before {
  content: "";
  position: absolute;
  left: 0.35rem;
  top: 0.36em;
  width: 0.42rem;
  height: 0.76rem;
  border: solid var(--thz-text-action);
  border-width: 0 2px 2px 0;
  transform: rotate(42deg);
}
/* On the ink band the action ink is far too dark to read — use the light
   accent §STYLE_GUIDE.md sanctions for lettering on ink. */
.thz-band-ink .thz-ticks li { color: #cfcabf; }
.thz-band-ink .thz-ticks li::before { border-color: #ffb27a; }

/* ---- app store call to action ------------------------------------------ */
/* ⚠️ THIS IS NOT APPLE'S BADGE AND MUST NOT PRETEND TO BE. Apple's "Download
   on the App Store" lockup is a trademarked asset with its own guidelines, and
   a hand-rebuilt copy is a subtly-wrong version of somebody else's mark — the
   same reason the Thoughtz Code composites were not faked. The real SVG comes
   from Apple's marketing-tools page; drop it in and this block goes away. */
.thz-appcta { display: inline-flex; flex-direction: column; align-items: center; gap: 0.6rem; }
.thz-appcta__note { font-size: 0.84rem; color: var(--thz-text-on-action); opacity: 0.92; }

/* ---- placeholder (skeleton only — delete as real content lands) --------- */
.thz-placeholder {
  border: 2px dashed var(--thz-border-action);
  border-radius: var(--thz-radius);
  background: var(--thz-bg-action-wash);
  color: var(--thz-text-on-sand);
  padding: clamp(1.25rem, 1rem + 1vw, 2rem);
  text-align: center;
}
.thz-placeholder__label {
  font-size: 0.72rem;
  font-weight: var(--thz-weight-heading);
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--thz-text-action);
}
.thz-placeholder__what { font-weight: var(--thz-weight-strong); margin-top: 0.3rem; }
.thz-placeholder--shot { min-height: 180px; display: grid; place-content: center; }

/* ---- the uses strip ----------------------------------------------------
   ⚠️ A STRIP, NOT A CAROUSEL, AND THE REASON IS THE SECTION'S OWN ARGUMENT.
   The heading claims "a Code goes anywhere a picture goes" - breadth IS the
   point. A carousel shows one slide at a time and hides the other eight, so it
   argues against the very claim it sits under, and engagement past slide one is
   poor anyway. The problem it was meant to solve (nine uniform tiles reading as
   a sticker sheet) is caused by SIZE and SAMENESS, not by the count.

   So: everything stays visible, several at once, cut off at the right edge so
   it obviously continues. Native swipe on touch, scroll-snap on desktop.

   ⚠️ NO JAVASCRIPT, DELIBERATELY. overflow-x + scroll-snap is the whole
   mechanism. A JS carousel would need controls, focus management, an ARIA live
   region and a pause affordance to be accessible; a scroll container needs none
   of that because it IS a scroll container - keyboard, screen reader and
   trackpad all already understand it.

   ⚠️ The horizontal scroll lives on THIS element, never on the page. The
   responsive probe in tools/_harness.html checks documentElement.scrollWidth
   against clientWidth, so a contained overflow-x is invisible to it - which is
   correct, and is also why a stray `min-width` on a child would be a real bug
   the probe cannot see. Same pattern as .thz-tablewrap below. */
.thz-uses {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(230px, 1fr);
  gap: clamp(0.85rem, 0.5rem + 1vw, 1.4rem);
  overflow-x: auto;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
  padding-bottom: 0.9rem;           /* room for the scrollbar, not a gap */
  scrollbar-width: thin;
}
/* ~3.5 cards visible on a desktop container, ~1.6 on a phone - the half card is
   what tells the reader there is more without needing an arrow to say so. */
@media (min-width: 720px)  { .thz-uses { grid-auto-columns: minmax(262px, 1fr); } }
@media (min-width: 1100px) { .thz-uses { grid-auto-columns: minmax(286px, 1fr); } }

.thz-uses > * { scroll-snap-align: start; }

.thz-use {
  background: var(--thz-bg-card);
  border: 1px solid var(--thz-border-line);
  border-radius: var(--thz-radius);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
/* 3:4 portrait - the aspect the mockups come out of Placeit at. Reserving it
   here means no layout shift when the photographs land, and the placeholder
   occupies exactly the space the real image will. */
.thz-use__shot {
  aspect-ratio: 3 / 4;
  max-width: 100%;
  background: var(--thz-bg-wash);
  display: grid;
  place-items: center;
  border-bottom: 1px solid var(--thz-border-line);
}
.thz-use__shot img { width: 100%; height: 100%; object-fit: cover; display: block; }
.thz-use__body { padding: 0.9rem 1rem 1.1rem; }
.thz-use__name {
  font-weight: var(--thz-weight-heading);
  color: var(--thz-text-heading);
  font-size: 1rem;
}
.thz-use__line { font-size: 0.875rem; color: var(--thz-text-muted); margin-top: 0.3rem; }

/* The scroll hint. ⚠️ aria-hidden in the markup - it is a visual affordance
   and a screen reader announcing "scroll for more" on a natively scrollable
   region is noise. */
.thz-uses-hint {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.82rem;
  color: var(--thz-text-muted);
  margin-top: 0.15rem;
}
.thz-uses-hint::after {
  content: "";
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, var(--thz-border-line), transparent);
}

/* ---- product screenshots ------------------------------------------------ */
/* The border and radius are the frame: these are captures of a real screen, so
   they need an edge or they bleed into the card behind them. Wrapped in an <a>
   to the full-size file - a 680px-wide screenshot of a dense dashboard is not
   readable inline, and opening the original beats inventing a lightbox. */
/* ⚠️ `margin-top: auto` PUSHES THE BAND TO THE FOOT OF THE CARD, and the
   gap above it is the paragraph's own `margin: 0 0 1em` - auto only takes the
   space that is left over, so it never eats that. On the tallest card in a row
   there is no leftover and the 1em is all the separation there is, which is the
   correct floor rather than an accident. */
.thz-shot {
  display: block;
  margin-top: auto;
  border-radius: var(--thz-radius-sm);
  overflow: hidden;
  border: 1px solid var(--thz-border-line);
}
/* ⚠️ EVERY SOURCE IS ALREADY 680x470, SO `cover` CROPS NOTHING TODAY - it is
   here as the guarantee, not as the mechanism. A future image at another ratio
   is silently trimmed to fit rather than making one card taller than the five
   beside it, which is the failure this whole pass exists to remove. Cut a new
   one to 680x470 and it stays a no-op. */
.thz-shot img {
  display: block;
  width: 100%;
  aspect-ratio: 680 / 470;
  object-fit: cover;
  object-position: top center;
}
/* ⚠️ THERE IS NO :hover ON AN IMAGE ANY MORE (Glen, 2026-09-18) - do not put one back.
   What used to be here was `.thz-shot:hover { border-color: var(--thz-border-action); }`, and it
   had a fault that only showed on the pictures it was least wanted on. `.thz-shot--bare` (the
   transparent renders - the features hero, the brochures, the branding shot) turns the resting
   border off with `border-color: transparent`, but that is one class at (0,1,0) against a class
   plus a pseudo-class at (0,2,0). The hover rule outranked it no matter where either sat in the
   file, so a render meant to float on the page GREW a hard box the moment the pointer touched
   it - the one thing three rounds of edge feathering had just been spent removing.
   The affordance is not lost: every clickable shot is an <a>, so the pointer still changes. */

/* ---- tables scroll rather than widening the page ----------------------- */
.thz-tablewrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.thz-table { width: 100%; border-collapse: collapse; min-width: 480px; font-size: 0.94rem; }
.thz-table th {
  background: var(--thz-bg-ink);
  color: var(--thz-text-inverse);
  text-align: left;
  font-weight: var(--thz-weight-strong);
  padding: 0.7rem 0.9rem;
}
.thz-table td { padding: 0.7rem 0.9rem; border-top: 1px solid var(--thz-border-line); vertical-align: top; }
.thz-table tr:nth-child(even) td { background: #fbfaf7; }

/* ---- footer ------------------------------------------------------------- */
.thz-footer { background: var(--thz-bg-ink); color: #a9a49a; padding-block: 2.5rem; margin-top: 0; }
.thz-footer a { color: #d8d3c9; text-decoration: none; }
.thz-footer a:hover { color: var(--thz-text-inverse); text-decoration: underline; }
.thz-footer h4 { color: var(--thz-text-inverse); font-size: 0.85rem; letter-spacing: 0.06em;
  text-transform: uppercase; margin-bottom: 0.6rem; }
.thz-footer ul { list-style: none; padding: 0; display: flex; flex-direction: column; gap: 0.35rem; }
.thz-footer__base {
  margin-top: 2rem;
  padding-top: 1.25rem;
  border-top: 1px solid rgba(255,255,255,.12);
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 1.5rem;
  justify-content: space-between;
  font-size: 0.85rem;
}

/* ---- skip link ---------------------------------------------------------- */
.thz-skip {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--thz-bg-action);
  color: var(--thz-text-on-action);
  padding: 0.75rem 1.25rem;
  font-weight: var(--thz-weight-strong);
  z-index: 100;
}
.thz-skip:focus { left: 0; color: var(--thz-text-on-action); }

/* ---- motion ------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}

/* ---- forms --------------------------------------------------------------
   ⚠️ 16px MINIMUM on every input. Below 16px, iOS Safari zooms the page on
   focus and does not zoom back out — the single most common way a responsive
   form breaks on a phone. 44px min-height is the touch target.             */
.thz-form { max-width: 34rem; }
.thz-field { margin-bottom: 1.1rem; }
.thz-field label {
  display: block;
  font-size: 0.92rem;
  font-weight: var(--thz-weight-strong);
  color: var(--thz-text-heading);
  margin-bottom: 0.35rem;
}
.thz-field label span[aria-hidden] { color: var(--thz-text-action); }
.thz-field input,
.thz-field textarea {
  width: 100%;
  min-height: 44px;
  padding: 0.65rem 0.85rem;
  font-family: inherit;
  font-size: 1rem;                 /* the 16px iOS floor — do not shrink */
  font-weight: var(--thz-weight-body);
  color: var(--thz-text-body);
  background: var(--thz-bg-card);
  border: 1px solid var(--thz-border-line);
  border-radius: var(--thz-radius-sm);
}
.thz-field textarea { min-height: 8rem; resize: vertical; line-height: 1.6; }
.thz-field input:focus,
.thz-field textarea:focus { border-color: var(--thz-action-700); outline-offset: 1px; }

/* The honeypot must be invisible to people but NOT display:none — some bots
   skip hidden fields, and some screen readers announce them. Off-canvas plus
   aria-hidden and tabindex="-1" is the arrangement that actually works. */
.thz-honeypot {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ---- contact-form result banners --------------------------------------- */
/* The Worker answers every submission with a 303 back to /support/#<outcome>, and
   `:target` is what makes the matching banner appear. No JavaScript at all, which is
   deliberate twice over: this site ships almost none, and a static site cannot mint the
   CSP nonce TMS uses — so a scripted banner would be the first thing to break the day a
   Content-Security-Policy is added. See the note in support.ejs.

   ⚠️ NOT display:none ON THE CONTAINER + :target OVERRIDE ALONE. `tabindex="-1"` on each
   banner is what lets the browser move FOCUS to it on the fragment navigation, so a
   screen-reader user lands on the outcome instead of at the top of the page with nothing
   announced. `role="status"` does not cover this case: the banner is present at first
   paint rather than changing afterwards, and a live region only announces a CHANGE. */
.thz-result { display: none; }
.thz-result:target {
  display: block;
  margin-bottom: 1.5rem;
  padding: 0.9rem 1.1rem;
  background: var(--thz-bg-card);
  border: 1px solid var(--thz-sand-edge);
  border-left: 4px solid var(--thz-caption);
  border-radius: 0.4rem;
  max-width: 34rem;      /* matches .thz-form, so it reads as part of it */
}
.thz-result:focus { outline: none; }   /* the border-left is the affordance */
.thz-result strong { display: block; color: var(--thz-text-heading); }
.thz-result span { color: var(--thz-text-body); font-size: 0.95rem; }
/* ⚠️ COLOUR IS ON THE EDGE, NOT BEHIND THE TEXT. A success-green or danger-red FILL
   would need white lettering and land straight in the white-on-colour trade STYLE_GUIDE.md
   §3 governs; a 4px edge carries the same meaning at full body contrast. */
.thz-result--bad:target { border-left-color: var(--thz-danger); }

/* ---- the success state, which REPLACES the form ------------------------- */
/* Glen, 2026-09-18: "replace the form and button with a large email sent icon".
   ⚠️ SUCCESS IS THE ONLY OUTCOME THAT REMOVES THE FORM, and the asymmetry is deliberate:
   a failure needs the form still there to retry, a success needs it gone so nobody sends
   the same message twice wondering whether the first one landed.
   ⚠️ THE `~` IS A GENERAL SIBLING SELECTOR, SO ORDER IS LOAD-BEARING. #sent must appear
   BEFORE the <form> in support.ejs; move it after and this rule stops matching silently,
   leaving an empty form sitting under the confirmation. */
#sent:target ~ .thz-form { display: none; }

.thz-sent { display: none; }
.thz-sent:target {
  display: block;
  text-align: center;
  padding: 3rem 1.5rem 3.25rem;
  background: var(--thz-bg-card);
  border: 1px solid var(--thz-sand-edge);
  border-radius: 0.6rem;
  max-width: 34rem;       /* the width the form occupied, so the column does not jump */
}
.thz-sent:focus { outline: none; }
/* ⚠️ BOTH DIMENSIONS, ALWAYS. The reset's `svg { max-width: 100%; height: auto }` throws
   away the height="16" every Bootstrap Icons file carries, so stating width alone gives a
   84px-wide, 84px-tall-by-accident icon on some engines and a collapsed one on others. */
.thz-sent__icon svg {
  width: 84px;
  height: 84px;
  color: var(--thz-success);   /* 5.36:1 - a filled mark, well over §3's 18px floor */
}
.thz-sent__title {
  margin: 1.25rem 0 0.4rem;
  font-size: 1.5rem;
  font-weight: 600;
  color: var(--thz-text-heading);
}
.thz-sent__sub { margin: 0; color: var(--thz-text-muted); }

/* ---- the legal documents ------------------------------------------------
   /privacy and /terms render text generated by tools/importLegal.py from the App's
   copies. These rules style a document that was written in Word and converted, so they
   have to cope with four heading levels and no lists.

   ⚠️ scroll-margin-top IS NOT OPTIONAL HERE. .thz-header is `position: sticky; top: 0`
   with a 6rem inner height, so a jump to #acceptable-use lands the heading UNDERNEATH the
   bar - the page looks like it scrolled to the wrong place. This is the only page on the
   site with in-page anchors, which is why the problem appears here and nowhere else. */
.thz-legal :is(h2, h3, h4) { scroll-margin-top: 7rem; }
.thz-legal p { margin-bottom: 0.9rem; }
.thz-legal h4 { margin: 1.1rem 0 0.35rem; font-size: 1rem; color: var(--thz-text-heading); }
/* Word numbers its own headings ("1 Collection of personal information"), so the heading
   text already carries the ordinal - no counters here, or every section gets two numbers. */
.thz-legal h2 { margin-top: 2rem; }
.thz-legal h2:first-child { margin-top: 0; }
.thz-legal__rule {
  max-width: 68ch;
  margin: 3rem 0;
  border: 0;
  border-top: 1px solid var(--thz-border-line);
}

/* ---- prose (legal pages, long copy) ------------------------------------ */
.thz-prose { max-width: 68ch; }
.thz-prose h2 { margin: 1.75rem 0 0.5rem; }
.thz-prose h3 { margin: 1.4rem 0 0.4rem; }
.thz-prose ul { margin-bottom: 1em; }
.thz-prose li { margin-bottom: 0.35rem; }

/* ---- print --------------------------------------------------------------
   Legal pages get printed. Drop the chrome and the ink-heavy bands.        */
@media print {
  .thz-header, .thz-footer, .thz-skip, .thz-btn { display: none !important; }
  body { background: #fff; color: #000; font-size: 11pt; }
  .thz-band-ink, .thz-band-action { background: #fff !important; color: #000 !important; }
  .thz-band-ink h1, .thz-band-ink h2, .thz-band-action h2 { color: #000 !important; }
  .thz-section { padding-block: 1rem; }
}

/* ---- placeholder on an accent band --------------------------------------
   ⚠️ The generic .thz-placeholder is peach-on-peach by design, which on an
   accent band measured 1.00:1 — invisible. Skeleton-only styling, but a
   screenshot of an invisible block reads as a broken page. */
.thz-band-action .thz-placeholder {
  background: var(--thz-white);
  border-color: var(--thz-white);
  color: var(--thz-text-body);
}
.thz-band-action .thz-placeholder__label { color: var(--thz-text-action); }
.thz-band-action .thz-placeholder__what { color: var(--thz-text-heading); }
.thz-band-action .thz-placeholder .thz-small { color: var(--thz-text-muted); }

/* ---- phone ---------------------------------------------------------------
   A device frame around a real App screenshot. The screens are cropped out of
   the CHANGE-099 App Store panels — see tools/ in CHANGE-099-store-images for
   how those were shot, and scratchpad crop for how they were extracted.

   ⚠️ THE FRAME IS CSS, NOT PART OF THE IMAGE. The crops are the bare screen, so
   the bezel can be restyled, and a re-shoot drops straight in without anyone
   having to match a frame that was baked into a PNG.

   ⚠️ THE IMAGE CARRIES ITS OWN aspect-ratio. Without it the frame collapses to
   nothing before the PNG loads and every band jumps on first paint. */
.thz-phone {
  position: relative;
  width: 100%;
  max-width: 260px;
  margin-inline: auto;
  padding: 10px;
  background: var(--thz-accent-700);
  border-radius: 34px;
  box-shadow:
    0 0 0 2px rgba(255, 255, 255, 0.18) inset,
    0 26px 52px rgba(26, 26, 26, 0.28);
}
.thz-phone img {
  display: block;
  width: 100%;
  aspect-ratio: 520 / 1138;
  object-fit: cover;
  object-position: top center;
  border-radius: 25px;
  background: var(--thz-white);
}
/* The speaker notch. Decorative only — the frame carries no meaning. */
.thz-phone::before {
  content: '';
  position: absolute;
  top: 19px;
  left: 50%;
  transform: translateX(-50%);
  width: 58px;
  height: 5px;
  border-radius: 3px;
  background: rgba(255, 255, 255, 0.28);
  z-index: 1;
}
.thz-phone--lg { max-width: 300px; }
.thz-phone--sm { max-width: 190px; }

/* A row of phones that overlaps slightly, so three screens read as one story
   rather than three unrelated pictures. Falls back to a plain grid on a phone,
   where overlapping would cost width the screens cannot spare. */
.thz-phone-row {
  display: grid;
  gap: clamp(0.85rem, 0.5rem + 1.4vw, 1.75rem);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 150px), 1fr));
  align-items: start;
}
/* ⚠️ THE STAGGER IS GONE AND MUST NOT COME BACK (Glen, 2026-09-15): "line
   these up evenly". It translateY()d every even child by 1.75rem, which threw
   the middle phone down AND left the three captions on three different
   baselines - so the row read as misaligned rather than as designed. Even
   beats clever here: the phones are the same 520x1138 and line up exactly. */
.thz-phone-caption {
  margin-top: 0.85rem;
  text-align: center;
  font-size: 0.85rem;
  font-weight: var(--thz-weight-strong);
  color: var(--thz-text-muted);
}
.thz-band-ink .thz-phone-caption,
.thz-hero--banner .thz-phone-caption { color: rgba(255, 255, 255, 0.88); }

/* ---- the uses strip's arrows -------------------------------------------
   ⚠️ THEY ARE `hidden` IN THE MARKUP AND REVEALED BY /js/uses-strip.js. With
   JavaScript off there are no dead controls, which is what keeps Q-190's
   "nothing to break" true while still giving Glen the arrows he asked for.
   The script also re-hides them when everything fits and there is nothing to
   scroll to - an arrow that does nothing is worse than no arrow. */
.thz-uses-wrap { position: relative; }

.thz-uses-nav {
  position: absolute;
  top: 38%;                        /* on the picture, not on the caption below it */
  transform: translateY(-50%);
  z-index: 2;
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 1px solid var(--thz-border-line);
  border-radius: 50%;
  background: var(--thz-bg-card);
  color: var(--thz-text-heading);
  box-shadow: 0 2px 10px rgba(26, 26, 26, 0.16);
  cursor: pointer;
}
.thz-uses-nav svg { width: 20px; height: 20px; }
.thz-uses-nav:hover { border-color: var(--thz-border-action); color: var(--thz-text-action); }
/* ⚠️ DISABLED IS DIMMED, NOT HIDDEN. A control that disappears at each end makes
   the strip jump sideways as it is used; one that fades keeps the layout still
   and still says "there is nothing further this way". */
.thz-uses-nav[disabled] { opacity: 0.35; cursor: default; box-shadow: none; }
.thz-uses-nav[disabled]:hover { border-color: var(--thz-border-line); color: var(--thz-text-heading); }
.thz-uses-nav--prev { left: 4px; }
.thz-uses-nav--next { right: 4px; }
@media (min-width: 1100px) {
  .thz-uses-nav { width: 44px; height: 44px; }
  .thz-uses-nav--prev { left: -12px; }
  .thz-uses-nav--next { right: -12px; }
}

/* ---- the registered mark on the wordmark --------------------------------
   ⚠️ NOT font-size: smaller + vertical-align: super. That combination shifts the
   line box and nudges the whole header bar, because .thz-logo is an inline-flex
   row aligned on its centre. A fixed size with a translate moves the glyph
   without telling the layout about it. */
.thz-logo__tm {
  font-size: 0.5em;
  font-weight: 600;
  letter-spacing: 0;
  display: inline-block;
  transform: translateY(-0.62em);
  margin-left: 0.08em;
}

/* ---- features page ------------------------------------------------------
   The share card is 1200x630 (1.91:1), not the 680:470 .thz-shot box, and
   cover-cropping it would cut off the very thing the section is about. Its own
   container keeps the native ratio and just draws the same border. */
.thz-cardshot {
  border: 1px solid var(--thz-border-line);
  border-radius: var(--thz-radius-sm);
  overflow: hidden;
  align-self: start;
}
.thz-cardshot img { display: block; width: 100%; height: auto; }

/* A grade badge, as the AI report itself uses: Quick win / High impact and so on.
   ⚠️ --thz-bg-sand carries --thz-text-on-sand; do not pair it with body ink. */
.thz-chip {
  display: inline-block;
  background: var(--thz-bg-sand);
  color: var(--thz-text-on-sand);
  border: 1px solid var(--thz-border-sand);
  border-radius: 999px;
  padding: 0.05em 0.6em;
  margin: 0.15em 0.2em 0.15em 0;
  font-size: 0.82em;
  font-weight: var(--thz-weight-heading);
  white-space: nowrap;
}

/* ---- a render, not a screenshot ----------------------------------------
   ⚠️ .thz-shot's border exists because a SCREENSHOT needs an edge - a white UI
   on a bone band has no silhouette of its own. A product render with a
   TRANSPARENT surround is the opposite case: the border stops outlining the
   picture and starts drawing a box around empty space, which is what Glen saw
   on the Features hero (2026-09-17: "remove the border from this image").
   ⚠️ The rule is mechanical, not a judgement call: `writeByContent` in the crop
   scripts emits PNG only when the crop actually contains transparency, so
   "the file is a .png" IS "the render floats". The templates key off that. */
.thz-shot--bare {
  border-color: transparent;
  border-radius: 0;
  background: none;
}

/* ---- the share-card column: the card, then where it gets pasted -------------------------
   ⚠️ `align-self: start` IS INHERITED WORK, NOT DECORATION. .thz-cardshot carried it as the
   grid child; wrapping it moved that job here. Drop it and .thz-split's `align-items: center`
   floats the whole column down the page, away from the heading. */
/* ⚠️ STRETCH, NOT START - and the card is what holds the top now. `align-self: start` sized
   this column to its content, which pinned the channel strip directly under the card and left
   the slack in one lump at the bottom. Stretching it to the row height and giving the strip
   `margin-block: auto` centres the strip in whatever slack there is (Glen, 2026-09-18). The
   card still sits at the top because it is the first flex child with no auto margin above it. */
.thz-sharecol {
  align-self: stretch;
  display: flex;
  flex-direction: column;
}

/* ---- /support's right-hand column --------------------------------------
   Glen, 2026-09-18: "center the right hand cards vertically". The cards sit as one centred
   group against the form beside them, with `gap` as the only space between them.

   ⚠️ SUPERSEDED THE SAME DAY, KEPT BECAUSE THE MECHANISM IS THE PART WORTH KNOWING. This read
   `justify-content: space-between`, which answered the earlier "so both sides are the same
   height" by pinning one card to the top of the column and one to the bottom. It did end the
   two columns level, and with only two cards left it also left a large hole in the middle,
   which is what Glen is removing here. If a future change wants the columns ending level
   again, `space-between` is the one word that does it - the stretch below is what makes it
   possible, not what does it.
   ⚠️ `align-self: stretch` STAYS AND IS NOT DEAD. .thz-split sets `align-items: center`, which
   would size this column to its own content; stretching it to the ROW's height is what gives
   `justify-content` a height to centre WITHIN. Without it the two rules agree by coincidence
   today and diverge the moment anything else changes. Same pair as .thz-sharecol above. */
.thz-contactcol {
  align-self: stretch;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1rem;
}
.thz-address { font-style: normal; margin-top: 0.4rem; line-height: 1.65; }
.thz-nowrap { white-space: nowrap; }

/* The widget is 65px tall and `flexible` makes it span the form column. Reserving the height
   stops the Send button jumping down the page when the iframe finishes loading - the form is
   the last thing on the page, so that shift is right under the pointer. */
/* ⚠️ NO min-height ANY MORE. It reserved 65px so the widget could not shift the layout as it
   loaded — correct while the widget always rendered. With `data-appearance="interaction-only"`
   it usually renders nothing, so that 65px became a permanent empty gap between the message
   box and the Send button, which reads as a missing element. The margin is kept: when a
   challenge IS shown it needs separating from the button, and when it is not, 1rem of space
   above a button is unremarkable. A challenge appearing now shifts the button down — accepted,
   because it happens rarely and the alternative is a hole on every visit. */
.thz-turnstile { margin-bottom: 1rem; }
.thz-channels {
  /* auto top AND bottom, so the block centres in the leftover height rather than hugging the
     card.
     ⚠️ `max(1.15rem, auto)` WAS WRITTEN HERE FIRST AND IS NOT VALID CSS - max() takes lengths,
     never the `auto` keyword, so the whole declaration is dropped silently and the only sign is
     the spacing being wrong on one breakpoint. Below 768px the column is not stretched, auto
     resolves to 0, and the gap has to be stated as a real length - which the media query at the
     end of this block does. */
  margin-block: auto;
  padding-top: 1.1rem;
  border-top: 1px solid var(--thz-border-line);
}
.thz-channels__row {
  list-style: none;
  margin: 1rem 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.6rem;
}
.thz-channels__row li {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  text-align: center;
  /* ⚠️ 0.72rem is 11.5px, and that is FINE HERE because it is not accent-on-fill: this is
     --thz-text-muted on the card band, which is AA at any size. §3's 14px/600 floor governs
     white on an accent fill, nothing else - see the correction at the top of this file. */
  font-size: 0.72rem;
  font-weight: var(--thz-weight-heading);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--thz-text-muted);
}
/* ⚠️ `color`, NOT `fill` - the inlined marks are drawn in currentColor, which is the whole
   reason they are inlined rather than referenced as <img>. An <img> cannot inherit colour, the
   same argument the 11ty config makes for the Thoughtz mark. Messenger is the exception: its
   brand is a gradient, which currentColor cannot express, so that one mark carries its own
   <linearGradient> and paints itself. */
.thz-channels__row svg {
  width: 30px;
  height: 30px;
}
.thz-channels__row li:nth-child(1) svg { color: var(--thz-vendor-facebook); }
.thz-channels__row li:nth-child(2) svg { color: var(--thz-vendor-whatsapp); }
/* 3 = Messenger, painted by its own gradient */
/* ⚠️ A `color` MUST NOT POINT AT A --thz-bg-* TOKEN - same tier rule the product carries.
   This read --thz-bg-action, so it silently followed the fill down the ramp today. It is a
   MARK ON A LIGHT GROUND, which is exactly what --thz-text-action is for. Same value it now
   resolves to; correct tier, and it no longer moves when a button fill does. */
.thz-channels__row li:nth-child(4) svg { color: var(--thz-text-action); }
/* Below the split's own 768px breakpoint there is no second column and so no slack to centre in. */
@media (max-width: 767px) {
  .thz-channels { margin-top: 1.15rem; }
}
@media (max-width: 400px) {
  .thz-channels__row { gap: 0.4rem; }
  .thz-channels__row svg { width: 26px; height: 26px; }
  .thz-channels__row li { font-size: 0.66rem; letter-spacing: 0.03em; }
}

/* ---- the AI assistant, drawn rather than screenshotted -----------------------------------
   Three panels recreating the assistant modal. See the long note in features.ejs for why they
   are HTML: the captures they replace were 524, 664 and 1216px tall, and every layout problem
   this section has had came from that. Equal height is free here and was never free there.

   ⚠️ SUPERSEDED, KEPT BECAUSE IT NAMES WHAT NOT TO REBUILD. This block held `.thz-steps`
   (a two-column stack), `.thz-stepshot` (the figure that carried a capture), `.thz-stepflow`
   (the chevrons bridging them) and `.thz-assistcard` (a summary card filling the right column).
   All four existed to manage three pictures of wildly different heights. None is needed now.
   The one piece of that work worth remembering is the trap inside it: an `svg` inherits
   `max-width: 100%` from the reset at the top of this file, and 100% of a shrink-to-fit
   absolutely positioned parent is circular - it resolves to ZERO and the mark vanishes while
   every measurement still reads as correct. */
.thz-aisteps {
  display: grid;
  gap: clamp(1rem, 0.6rem + 1.6vw, 1.75rem);
  margin-top: clamp(1.75rem, 1.2rem + 2vw, 2.75rem);
  align-items: stretch;
}
@media (min-width: 768px) {
  .thz-aisteps { grid-template-columns: repeat(3, 1fr); }
}
/* The three notes under the rule. Plain text, no card - the panels above are the boxes, and a
   second set of boxes would read as six things rather than three. */
.thz-aisteps--notes {
  margin-top: clamp(1.75rem, 1.2rem + 2vw, 2.5rem);
  padding-top: clamp(1.5rem, 1rem + 2vw, 2.25rem);
  border-top: 1px solid var(--thz-border-line);
}
.thz-aisteps--notes .thz-h3 { margin-bottom: 0.4rem; }

.thz-aistep { display: flex; flex-direction: column; }
.thz-aistep__label {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 0 0 0.7rem;
  font-size: 0.9rem;
  font-weight: var(--thz-weight-heading);
  color: var(--thz-text-heading);
}
/* .thz-step__num is sized for the stacked step lists it was written for. Smaller here, and the
   2px top nudge it carries for aligning with a title block reads as a wobble on one line. */
.thz-aistep__label .thz-step__num {
  flex: 0 0 1.55rem;
  height: 1.55rem;
  font-size: 0.8rem;
  margin-top: 0;
}

/* ⚠️ `flex: 1` ON THE PANEL IS WHAT MAKES THE THREE EQUAL. The grid stretches each column to
   the row height; the panel then fills its column whatever the label above it wrapped to. Without
   it the panels are as tall as their own content and the row is ragged again - which is the whole
   fault this rebuild exists to remove. */
.thz-aimodal {
  flex: 1;
  display: flex;
  flex-direction: column;
  background: var(--thz-bg-card);
  border: 1px solid var(--thz-border-line);
  border-radius: var(--thz-radius-sm);
}
.thz-aimodal__head {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.7rem 0.85rem;
  border-bottom: 1px solid var(--thz-border-line);
}
.thz-aimodal__mark { display: grid; place-items: center; color: var(--thz-text-heading); }
.thz-aimodal__mark svg { width: 0.95rem; height: 0.95rem; max-width: none; }
.thz-aimodal__title {
  flex: 1;
  font-weight: var(--thz-weight-strong);
  font-size: 0.92rem;
  color: var(--thz-text-heading);
}
.thz-aimodal__close { color: var(--thz-text-muted); font-size: 1.1rem; line-height: 1; }

.thz-aimodal__body {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  padding: 0.9rem 0.85rem;
  font-size: 0.82rem;
  line-height: 1.5;
}
.thz-aimodal__body p { margin: 0; }
.thz-aimodal__hint { font-style: italic; color: var(--thz-text-muted); }
.thz-aimodal__label { color: var(--thz-text-muted); }
/* The closing action line. Centred and in the action colour so it reads as the three choices the
   modal offers rather than as a caption - it is the only part of this panel that was not obviously
   a control.
   ⚠️ --thz-text-action IS THE SANCTIONED ACCENT-AS-TYPE STEP on a light ground (#a8480a, 5.84:1
   on the card). Do NOT reach for --thz-bg-action here: accent-500 as lettering is 2.80:1 and
   forbidden on light, which is the single rule this palette is most often broken against. */
.thz-aimodal__more {
  margin-top: 0.25rem;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.15rem 0.45rem;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: var(--thz-weight-heading);
}
.thz-aimodal__act { color: var(--thz-text-action); }
/* Muted, so the dots read as punctuation and the words read as the choices. */
.thz-aimodal__sep { color: var(--thz-text-muted); }

/* The two form fields in panel 2 - a box with the answer already in it. */
.thz-aifield {
  border: 1px solid var(--thz-border-line);
  border-radius: 6px;
  padding: 0.5rem 0.6rem;
  background: var(--thz-bg-card);
}
.thz-aifield--area { min-height: 3.4rem; }

/* The drafted questions in panel 3. */
.thz-aiq + .thz-aiq { margin-top: 0.15rem; }
.thz-aiq__q { font-weight: var(--thz-weight-strong); color: var(--thz-text-heading); }
.thz-aiq__t { font-style: italic; color: var(--thz-text-muted); }
.thz-aiq__o { color: var(--thz-text-muted); }
/* ⚠️ BOTH SPELLINGS. Safari still wants -webkit-mask-image, and without it the last question
   simply renders solid there - a fade that silently does not fade. */
.thz-aiq--fade {
  -webkit-mask-image: linear-gradient(to bottom, #000 35%, rgba(0, 0, 0, 0.3) 100%);
  mask-image: linear-gradient(to bottom, #000 35%, rgba(0, 0, 0, 0.3) 100%);
}

/* The buttons. Not <button>s - nothing here is operable, it is a picture of a modal drawn in
   text, so they are spans and reach no tab stop.
   ⚠️ 0.875rem/600 IS A FLOOR, NOT A PREFERENCE. White on an accent fill is sanctioned only at
   14px/600 and above (STYLE_GUIDE §3); the panel body around it is 0.82rem and these must NOT be
   shrunk to match it. */
.thz-aimodal__actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: auto; padding-top: 0.5rem; }
.thz-aibtn {
  display: inline-block;
  padding: 0.42rem 0.9rem;
  border-radius: 999px;
  border: 1px solid var(--thz-border-line);
  background: var(--thz-bg-card);
  color: var(--thz-text-body);
  font-size: 0.875rem;
  font-weight: var(--thz-weight-heading);
  line-height: 1.25;
}
.thz-aibtn--primary {
  background: var(--thz-bg-action);
  border-color: var(--thz-bg-action);
  color: var(--thz-text-on-action);
}
