/* ==========================================================================
   ai-visibility.css - the AI Visibility Check page, and nothing else loads it.

   WHAT THIS PAGE IS. tools.html sells the check in a card whose leaderboard is
   entirely redacted, because a card that invented one would be fabricating the
   proof the tool exists to go and find. This page runs the check against a
   domain the visitor types and hands back the report, before an address is
   asked for. It is the second page on this site whose main content is generated
   at runtime, and the reasoning is daily-brief.css's own: the pitch, the "what
   the real check returns" section and the closer are all real markup and are
   what a crawler reads. What JavaScript builds is the SPECIMEN.

   WHITE LABEL. Same rule as tools.html and daily-brief.css. The provider is
   named in docs/brief.md and appears nowhere in this sheet, in
   ai-visibility.html, in js/ai-visibility.js, or in a comment in any of them.

   TOKENS, NOT VALUES. Everything here is base.css's own scale. This sheet
   declares one thing of its own - the four band colours - and every one of them
   is an existing token rather than a new hex, so a brand change carries them.

   IT BORROWS RATHER THAN REDECLARES. The header comes from insights.css, the
   two form rows and the error line from brief-form.css, and .tl-select - the
   market field - from tools.css. It borrowed .tl-route as well, for the member
   agency named in the closer, until that block was removed on client
   direction.

   THE STRUCTURE DELIBERATELY RHYMES WITH daily-brief.css. Both are a three-stage
   demo on the same site reached from the same wall: ask, working, result. The
   stage machinery, the log, the 920 measure on the result and the reduced-motion
   contract are the same answers to the same questions, and two different answers
   would be the drift, not the repetition. What differs is section 03, because a
   report is not a brief.
   ========================================================================== */

.av{
  /* THE FOUR BANDS, and every one is an existing token. Poor and Strong are
     base.css's own semantic pair; the two in between are borrowed from the
     discipline hues, which base.css allows on the stated condition that a
     second use earns the rhyme rather than the palette - here the four are a
     ladder, not six meanings, and no discipline is being claimed.

     The -ink variants are the same four darkened for text on their own tint,
     because --d-media at 12px on a pale ground does not clear 4.5:1. */
  --band-poor:var(--red);
  --band-work:var(--d-media);
  --band-good:var(--d-digital);
  --band-strong:var(--green);

  --band-poor-ink:#A32424;
  --band-work-ink:#8A5E06;
  --band-good-ink:#2453B8;
  --band-strong-ink:#2C7A45;

  /* TWO TIERS OF TINT, AND THE RULE IS AREA, NOT IMPORTANCE.

     --tint-* is the PILL tier, 12-16%. A pill is 60px of colour carrying
     uppercase 11px type, and below about 12% it stops reading as a state at
     all - the percentage is buying legibility at small size, not emphasis.

     --fill-* is the CARD tier, 5-7%. The same hues over a 900px panel, where
     12% stops being a tint and becomes a coloured box: three of those stacked
     is a warning label, not a report. The card says its severity in the fill
     and again in the pill, and the fill is the quieter of the two on purpose.

     The percentages differ per hue because the hues do not weigh the same.
     --d-media is a yellow and disappears a step earlier than --red does, so it
     takes 8 where red takes 6. Matching numbers would have been consistency
     with the token and inconsistency on the screen.

     NEITHER TIER IS EVER THE ONLY SIGNAL. Every card carrying a fill also
     carries the word - CRITICAL, WARNING, NOTICE, "Never named" - because
     colour alone is not a state a screen reader or a colourblind reader can
     read. */
  --tint-poor:color-mix(in srgb,var(--red) 12%,var(--white));
  --tint-work:color-mix(in srgb,var(--d-media) 16%,var(--white));
  --tint-good:color-mix(in srgb,var(--d-digital) 12%,var(--white));
  --tint-strong:color-mix(in srgb,var(--green) 14%,var(--white));

  --fill-poor:color-mix(in srgb,var(--red) 6%,var(--white));
  --fill-work:color-mix(in srgb,var(--d-media) 8%,var(--white));
  --fill-strong:color-mix(in srgb,var(--green) 7%,var(--white));

  /* ONE DURATION FOR EVERY HOVER ON THIS PAGE. base.css has --dur-line at
     260ms and it belongs to a different gesture - the underline wipe, which
     draws a shape and wants to be seen doing it. A pointer state is not drawing
     anything; it has to have landed before the eye moves on, and 260ms on a
     card you are sweeping past reads as lag. 160 is the shortest step that
     still reads as a transition rather than a jump. */
  --hover-t:160ms;
}

.av-main{padding-bottom:var(--s14)}

/* A stage is a step of the demo, not a section of the page. Only one is ever
   shown, and the ask stage is the one that ships open - so with scripting off
   the page is its own pitch and its own form, and nothing below it is a hole
   where content should have been. */
.av-stage{display:none}
.av-stage[data-on="true"]{display:block}

/* Declared here rather than in base.css, because this is the only page that
   needs one and a utility introduced for one caller belongs to that caller.
   newsletter.css declares its own for the same reason. */
.av-sr{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0;
}


/* ==========================================================================
   01. Ask
   THE FOLD IS tech-audit.html's FOLD. Two open tool pages reached from one wall
   of cards, arriving at two different shapes, is what makes a network of eleven
   agencies look like a network of eleven websites - so this section is
   tech-audit.css section 01 with this page's own words in it, and where the two
   differ it is because the content differs, never because the layout was
   decided twice.

   WHAT WENT, and it is recorded in ai-visibility.html at length because it was
   the fold's argument rather than its decoration: the two-column grid, and the
   redacted leaderboard that filled the second column. The market select went
   with them, down to the closer, where tech-audit.html also asks it.
   ========================================================================== */
/* The one tinted ground on the page, and it is the fold's, so the field has
   something to sit in front of. --pale and --lavender, and nothing new: both
   are brand purples, so the fold is tinted with a colour the site already means
   something by rather than with a grey that reads as a page that loaded wrong.
   Copied from .ta-ask, deliberately - see the section note above.

   IT BLEEDS UP BEHIND THE HEADER, and this is the correction of a fault that
   was copied across with the rule (2026-08-28, client direction). Painted as a
   background on .av-ask the wash began at the section's own top edge, which is
   below the header - so the page opened with a white band, a hard horizontal
   line, and then the tint. A ::before pinned 240px above the section paints the
   header band and the cut is gone.

   240px is the header plus its air, rounded up. Above 901px insights.css makes
   .ins .site-header transparent with a white pill inside, so the wash runs
   behind the pill and the pill floats on it; below 901 the header is a solid
   white bar that covers the bleed, and there is no cut to fix there.

   z-index:-1 AND NO STACKING CONTEXT ON .av-ask. The section is position
   relative with no z-index, so the pseudo-element drops behind the section's
   content while the header - which does open one - stays above it. Adding a
   z-index here would trap the wash in the section and put the cut back. */
.av-ask,
.av-working{padding:var(--sec) 0;position:relative;background:transparent}
/* ONE GROUND FOR BOTH STAGES, and it is the same shared selector tech-audit.css
   uses for the same reason. The ask and the working stage are the SAME PLACE at
   two moments - one swaps out for the other under a header that does not move -
   so a tinted fold handing over to a flat white pane reads as a second page
   loading rather than as the button having worked. */
.av-ask::before,
.av-working::before{
  content:"";position:absolute;z-index:-1;pointer-events:none;
  left:0;right:0;bottom:0;top:-240px;
  background:
    radial-gradient(84% 58% at 50% 0%, var(--pale) 0%, transparent 66%),
    radial-gradient(46% 34% at 86% 4%, color-mix(in srgb,var(--lavender) 34%,transparent) 0%, transparent 74%),
    var(--surface);
}

.av-hero{max-width:760px;margin:0 auto;text-align:center}
.av-hero .eyebrow{justify-content:center}
.av-hero h1{text-wrap:balance}
.av-lede{
  max-width:62ch;margin:var(--s5) auto 0;
  color:var(--gray);font-size:19px;line-height:31px;text-wrap:pretty;
}

/* ---- the address field -------------------------------------------------
   ONE COMPOSITE CONTROL: a prefix, a field and a submit sharing one rounded
   outline. Its parts are all base.css - --r-pill, --line, --white, and
   .btn.btn-fill.btn-neutral on the button - and what earns it a component is
   the ARRANGEMENT: the page's whole action is one address, and a labelled box
   with a button underneath reads as a form to be filled in.

   The focus ring goes on the WRAPPER, not the input. A ring around a
   borderless input inside a pill draws a second rectangle inside the first.

   THIS IS A SECOND COPY OF .ta-url AND IT IS KNOWN DRIFT, stated rather than
   hidden, which is this project's own rule for a value it cannot yet share.
   The component belongs in one sheet both pages load - tools.css already plays
   exactly that role for .tl-select - and moving it there is a deliberate pass
   over two files rather than a side effect of this one. Until then: any change
   here belongs in tech-audit.css too.
   ------------------------------------------------------------------------- */
.av-form{margin-top:var(--sec-sm);text-align:center}
.av-form-h{
  display:block;font-family:inherit;
  font-size:30px;font-weight:500;line-height:37.5px;letter-spacing:-.01em;color:var(--black);
}
.av-url{
  display:flex;align-items:center;gap:var(--s2);
  max-width:640px;margin:var(--s5) auto 0;
  background:var(--white);border:1px solid var(--line);border-radius:var(--r-pill);
  padding:6px 6px 6px var(--s5);
  transition:border-color 200ms var(--ease),box-shadow 200ms var(--ease);
}
.av-url:focus-within{border-color:var(--purple);box-shadow:0 0 0 3px var(--pale)}
.av-url-proto{flex:none;color:var(--ash);font-size:16px;letter-spacing:.02em}
.av-url input{
  flex:1;min-width:0;border:0;outline:0;background:none;
  font:inherit;font-size:17px;color:var(--slate);padding:12px 0;
  font-variant-numeric:tabular-nums;
}
.av-url input::placeholder{color:var(--ash)}
.av-url-go{flex:none;white-space:nowrap}

/* Ranged left inside a centred column, and 12px clear of the field. An error
   is read, not admired, and it belongs to the control above it - see the note
   this sheet carried when the field was a two-column row. */
.av-err{max-width:640px;margin:var(--s3) auto 0;text-align:left}

/* The chip row. .tag .tag-btn is base.css's own pill and carries the colour,
   radius and hover; this is a layout and a label. The label sits IN the flex
   row rather than above it, so the names wrap around it instead of being
   stranded on a line of their own.

   FOUR CHIPS, SO IT IS A PLAIN CENTRED WRAP AGAIN - the same three lines as
   .ta-try. Everything below is why four is the ceiling and why the row that
   scrolled had to exist while there were nine.

   860, NOT tech-audit's 780 AND NOT THE FIELD'S 640. This page's chips are
   domains where that page's are brand names, so the same four pills are about
   eighty pixels wider here; at 780 the fourth name wrapped alone, which reads
   as a chip that did not fit rather than as a set of four. A row that runs a
   little past the control it belongs to is the lesser of the two.

   WHAT THIS REPLACED, AND WHY IT CANNOT COME BACK WITH NINE IN IT. Nine names
   do not fit on one line at any width this site is read at - measured, they
   want 1426px against the wrap's 1352 - so wrapping broke 5/4 on desktop and
   into FIVE lines on a phone, where it pushed the note and the way-out below
   the fold. The fix was a nowrap row with overflow-x:auto, width:max-content
   and a right-edge mask for the affordance. Three findings from it are worth
   keeping, because any future row longer than four meets them again:

     - .tag-sm would have fitted 1309px and made nine static at 1440, and it
       would have taken the touch target from 35px to 24px on the one control a
       thumb is most likely to reach for. Scrolling is cheaper than a chip that
       cannot be pressed.
     - width:max-content + margin-inline:auto, never justify-content:center. A
       centred flex row whose content overflows clips its own FIRST item, and
       the first item here is the label.
     - the mask goes on the right edge only. The row rests at scroll-0, where
       there is nothing behind the left edge to fade, so a matching left fade
       only washes out the first letter of the label. */
.av-try{
  display:flex;flex-wrap:wrap;align-items:center;justify-content:center;
  gap:var(--s2);max-width:860px;margin:var(--s5) auto 0;
}
.av-try .tag-btn{font-variant-numeric:tabular-nums}
.av-try-h{color:var(--ash);font-size:14px;line-height:22px;margin-right:var(--s1)}
/* 64ch, not 60. The sentence is 118 characters and at 60ch it broke 3 lines
   with four words on the last; 64 splits it evenly in two. Still inside the
   60-75 character band this project holds body copy to. */
.av-form-note{
  max-width:64ch;margin:var(--s5) auto 0;
  font-size:14px;line-height:22px;color:var(--ash);
}

.av-ask-out{margin-top:var(--s8);text-align:center}


/* ==========================================================================
   02. Working
   Six lines that arrive one at a time. Same component as daily-brief.css and
   the same 920 measure, because it is the same eight seconds doing the same job
   on the same site - see the note there for why the wrap needs an explicit
   width inside a column flex container.
   ========================================================================== */
/* padding and the ground are declared with .av-ask in section 01. */
.av-working{min-height:56vh}
.av-working[data-on="true"]{display:flex;flex-direction:column;justify-content:center}
.av-working > .wrap{max-width:920px;width:100%}

/* ---- the target ---------------------------------------------------------
   A pill, on --haze, with a live dot. It is the address echoed back, which is
   the first thing the page owes somebody who has just typed one - and on a
   sample it is the site the chip opened. Same component as .ta-target. */
.av-target{
  display:inline-flex;align-items:center;gap:var(--s3);
  margin:var(--s5) 0 0;padding:8px var(--s5);
  background:var(--haze);border-radius:var(--r-pill);
  font-size:15px;line-height:23px;color:var(--slate);
  font-variant-numeric:tabular-nums;
}
.av-target-dot{
  flex:none;width:8px;height:8px;border-radius:50%;background:var(--purple);
}
/* The only thing on this stage that says "live" rather than "still". It rests
   opaque, so with reduced motion or no animation support the dot is simply a
   dot rather than a missing one. */
@media (prefers-reduced-motion:no-preference){
  @keyframes av-pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.35;transform:scale(.82)}}
  .av-target-dot{animation:av-pulse 1.4s var(--ease) infinite}
}

/* Heading left, counter right, rail spanning under both - a progress header
   rather than a bar with a caption under it. Baseline-aligned so the 30px
   heading and the 13px counter sit on one line rather than on two centres. */
.av-work-top{
  display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;
  gap:var(--s4);margin:var(--s5) 0 var(--s4);
}
.av-work-top h2{margin:0}

/* ---- the rail -----------------------------------------------------------
   THE ONE THING THE LOG CANNOT SAY: how much is left. It is driven off the
   log's own index in js/ai-visibility.js rather than off a clock of its own,
   so it can never show a step the list has not reached.

   The fill TRANSITIONS rather than animating, because its width is set six
   times from the script and CSS should carry it between those points - an
   animation here would be a second timeline racing the first.

   PLUM, NOT --ramp. tech-audit.css states the reason and it holds here: --ramp
   is the longitude gradient and this site has already decided it means the
   working day from Karachi to Auckland. A progress bar is not a map. */
.av-rail{height:4px;border-radius:2px;background:var(--mist);overflow:hidden}
.av-rail i{
  display:block;height:100%;width:0;border-radius:2px;
  background:var(--plum);
  transition:width 520ms var(--ease);
}
.av-step{
  margin:0;font-size:13px;line-height:20px;color:var(--ash);
  font-variant-numeric:tabular-nums;
}

.av-log{list-style:none;padding:0;margin:var(--s8) 0 0;font-size:16px;line-height:2;font-variant-numeric:tabular-nums}
.av-log li{
  display:flex;gap:var(--s3);color:var(--ash);
  opacity:0;transform:translateY(4px);
  transition:opacity 280ms ease,transform 280ms ease,color 280ms ease;
}
.av-log li[data-shown="true"]{opacity:1;transform:none}
.av-log li[data-done="true"]{color:var(--gray)}
.av-log .av-mark{flex:none;width:14px;color:var(--purple)}
.av-log b{color:var(--plum);font-weight:600;font-variant-numeric:tabular-nums}

@keyframes av-blink{0%,55%{opacity:1}56%,100%{opacity:.2}}
.av-log li[data-shown="true"]:not([data-done="true"]) .av-mark{animation:av-blink 1s steps(1) infinite}


/* ==========================================================================
   03. The report
   A document, not a dashboard. White ground, hairline rules, tabular figures,
   and the only colour that moves is the band. The 920 measure is the brief
   page's, so the two results on this site sit on one left edge.
   ========================================================================== */
.av-report{padding:var(--sec) 0;background:var(--surface)}
.av-report > .wrap{max-width:920px}

.av-report-top{
  display:flex;flex-wrap:wrap;justify-content:space-between;
  align-items:baseline;gap:var(--s4);
  padding-bottom:var(--s4);border-bottom:2px solid var(--plum);
}
.av-meta{margin:0;font-size:13px;line-height:20px;color:var(--gray);font-variant-numeric:tabular-nums}
.av-meta b{color:var(--plum);font-weight:600}

/* ---- the disclosure -----------------------------------------------------
   ABOVE THE SCORE, NOT UNDER IT. The report carries invented numbers about a
   domain the visitor may well own, and a disclosure below the gauge is a
   disclosure read second. It is a plain band rather than a warning colour: this
   is a statement of what the page is, not an error, and painting it red would
   make the honest sentence look like the thing that went wrong.

   A FILL, NOT A RULE. This carried a 3px purple edge and the report below it
   carried coloured edges on every card, which made the whole document a column
   of left-hand stripes - the one device doing four different jobs, none of them
   loudly enough to be worth the repetition. The panel is --haze on --surface,
   which is base.css's own stated inversion rather than a value picked here, and
   --r-md rather than --r-sm because it is now a panel rather than a flagged
   line.
   ------------------------------------------------------------------------- */
/* CENTRED, BLOCK AND TEXT, AND IT IS THE ONE THING ON THE REPORT THAT SHOULD BE.
   Everything else here is a document and starts on the column's left edge. This
   is not part of that document - it is a label ON it, in the same register as
   the note at the foot of the page, and the centring is what says so before the
   sentence does.

   The block was flush left at 70ch inside a 920 column, which left a third of
   the row empty on the right and read as a panel that had failed to fill rather
   than one that had been placed. Centring the box alone would have been worse:
   it would sit off the left edge every other element on the page shares, which
   is a misalignment rather than a composition. Both, or neither.

   66ch rather than 70, so the two lines break at a similar length - a centred
   block whose second line is a quarter of the first reads as a mistake. */
.av-demo{
  margin:var(--s5) auto 0;padding:var(--s4) var(--s6);
  background:var(--haze);border-radius:var(--r-md);
  color:var(--gray);font-size:15px;line-height:24px;
  max-width:66ch;text-align:center;
}
.av-demo b{color:var(--plum);font-weight:600}

/* ---- the score ---------------------------------------------------------- */
.av-score{
  display:grid;grid-template-columns:168px minmax(0,1fr);
  gap:var(--s10);align-items:center;
  margin-top:var(--s10);
}

/* THE BAND SETS `color` AND EVERYTHING INHERITS IT. The arc is drawn with
   stroke="currentColor" in js/ai-visibility.js, so the four band colours are
   declared here with every other colour on the site rather than half in a
   stylesheet and half in a script. */
.av-gauge{position:relative;width:168px;height:168px}
.av-gauge[data-band="Poor"]{color:var(--band-poor)}
.av-gauge[data-band="Needs work"]{color:var(--band-work)}
.av-gauge[data-band="Good"]{color:var(--band-good)}
.av-gauge[data-band="Strong"]{color:var(--band-strong)}
.av-gauge svg{display:block;width:100%;height:100%;transform:rotate(-90deg)}
.av-arc-track{stroke:var(--mist)}
.av-gauge-n{
  position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  font-size:46px;line-height:1;font-weight:500;letter-spacing:-.02em;
  color:var(--plum);font-variant-numeric:tabular-nums;
}
.av-gauge-of{
  position:absolute;left:0;right:0;bottom:30px;text-align:center;
  font-size:11px;line-height:16px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--ash);
}

/* The arc draws itself from empty. 1000 is not a magic number pulled out of
   the air: stroke-dashoffset at or above the circumference is a fully hidden
   ring, and the largest circle on this page - the 168px gauge - has a
   circumference of about 487. Anything past that reads as empty, so one
   constant serves both the gauge and the three rings.

   900ms IS THE COUNT'S OWN DURATION - AV_COUNT_MS in js/ai-visibility.js and
   COUNT_MS in js/daily-brief.js before it. The needle and the number are one
   movement or they are two, and two is the version where the ring finishes
   while the figure is still climbing.

   THE THREE RINGS DRAW ONE AFTER ANOTHER, 110ms apart, on top of their
   section's own 200ms. Three arcs sweeping in unison read as one animation
   playing three times; staggered, they read as three scores being taken. */
@media (prefers-reduced-motion:no-preference){
  @keyframes av-arc-in{from{stroke-dashoffset:1000}}
  .av-arc-fill{animation:av-arc-in 900ms var(--ease) both}
  .av-gauge .av-arc-fill{animation-delay:120ms}
  .av-ring:nth-child(1) .av-arc-fill{animation-delay:200ms}
  .av-ring:nth-child(2) .av-arc-fill{animation-delay:310ms}
  .av-ring:nth-child(3) .av-arc-fill{animation-delay:420ms}
}

.av-band{
  display:inline-flex;align-items:center;
  padding:6px 13px;border-radius:var(--r-pill);
  font-size:12px;line-height:18px;font-weight:600;
  letter-spacing:.14em;text-transform:uppercase;
}
.av-band[data-band="Poor"]{background:var(--tint-poor);color:var(--band-poor-ink)}
.av-band[data-band="Needs work"]{background:var(--tint-work);color:var(--band-work-ink)}
.av-band[data-band="Good"]{background:var(--tint-good);color:var(--band-good-ink)}
.av-band[data-band="Strong"]{background:var(--tint-strong);color:var(--band-strong-ink)}

.av-score h2{margin-top:var(--s4);max-width:34ch}

/* Four figures, and the fourth keeps the other three honest: a report that only
   counted failures would read as a list of reasons to panic rather than as a
   reading of a site. The dot is the only colour, because four tinted tiles
   would make the counts the loudest thing under a gauge that is already the
   loudest thing on the page. */
.av-counts{display:flex;flex-wrap:wrap;gap:var(--s6);margin-top:var(--s6)}
.av-count{display:flex;align-items:baseline;gap:var(--s2)}
.av-count b{
  font-size:24px;line-height:30px;font-weight:600;color:var(--plum);
  font-variant-numeric:tabular-nums;
}
.av-count span{font-size:14px;line-height:21px;color:var(--gray)}
.av-count::before{
  content:"";width:8px;height:8px;border-radius:50%;flex:none;
  align-self:center;margin-right:2px;
}
.av-count[data-tone="crit"]::before{background:var(--band-poor)}
.av-count[data-tone="warn"]::before{background:var(--band-work)}
.av-count[data-tone="note"]::before{background:var(--ash)}
.av-count[data-tone="pass"]::before{background:var(--band-strong)}

/* ---- sections ----------------------------------------------------------- */
.av-sect{margin-top:var(--s14)}
.av-sect > .eyebrow{margin-bottom:var(--s6)}

/* The gap drops a step because each cell now carries --s5 of its own padding,
   and 32 + 20 + 20 between two rings is a gutter wider than the ring. */
.av-rings{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--s4)}
.av-ring[data-band="Poor"]{color:var(--band-poor)}
.av-ring[data-band="Needs work"]{color:var(--band-work)}
.av-ring[data-band="Good"]{color:var(--band-good)}
.av-ring[data-band="Strong"]{color:var(--band-strong)}
/* THE RINGS ARE CARDS NOW, and the padding is what the hover ground needs to
   sit on rather than a decision about spacing: a background appearing tight
   against three sides of a text block reads as a rendering fault. Transparent
   at rest, so nothing changes about how the section looks until a pointer is
   over one. */
.av-ring{
  padding:var(--s5);border-radius:var(--r-md);
  background:transparent;
}
.av-ring-arc{position:relative;width:112px;height:112px}
.av-ring-arc svg{display:block;width:100%;height:100%;transform:rotate(-90deg)}
.av-ring-n{
  position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  font-size:26px;line-height:1;font-weight:600;color:var(--plum);
  font-variant-numeric:tabular-nums;
}
.av-ring h3{font-size:19px;line-height:27px;margin:var(--s4) 0 var(--s2)}
.av-ring p{margin:0;color:var(--gray);font-size:15px;line-height:24px}

/* ---- the engines --------------------------------------------------------
   THE ONE THING A BUYER CANNOT COUNT FOR THEMSELVES, because there is no click
   to count in an AI answer. It gets a card each and the page's only repeated
   bar, and it sits directly under the score rather than after the findings: the
   findings are the explanation of this table, not the other way round.

   A ROW THAT WAS NEVER NAMED IS NOT GREYED OUT. It is the finding. Fading it
   would be the design deciding the empty rows matter less than the full ones,
   which is the reverse of what the page is arguing.
   ------------------------------------------------------------------------- */
.av-engines{display:grid;gap:var(--s3)}
.av-engine{
  display:grid;
  grid-template-columns:9rem minmax(0,1fr) 7rem 5.5rem;
  grid-template-areas:"name note share pill" "name bar share pill";
  gap:var(--s2) var(--s5);align-items:center;
  padding:var(--s5);
  /* --haze on --surface, base.css's own inversion rule. The 1px --line that
     used to draw this row is gone with every other border on the report: four
     bordered rows above three bordered cards is seven boxes competing for the
     same attention, and a fill separates a row from the page just as well
     without adding an edge to the count. */
  background:var(--haze);border-radius:var(--r-md);
}
.av-en-name{grid-area:name;font-size:17px;line-height:24px;font-weight:600;color:var(--plum)}
.av-en-note{grid-area:note;font-size:14px;line-height:21px;color:var(--gray)}
/* THE RAIL IS --line, NOT --mist, and that is a consequence of the row taking a
   ground. --mist on --white was a visible track; --mist on --haze is a five per
   cent difference and the rail disappeared - which matters most on exactly the
   rows where it is the whole of the bar, the ones at nought per cent. --line is
   the site's hairline colour and is the darkest neutral that still recedes,
   and it holds on --haze and on --fill-poor alike. */
.av-en-bar{grid-area:bar;display:block;height:6px;border-radius:var(--r-sm);background:var(--line);overflow:hidden}
.av-en-bar i{display:block;height:100%;border-radius:var(--r-sm);background:var(--purple)}
.av-en-share{grid-area:share;display:grid;gap:1px;text-align:right}
.av-en-share b{font-size:22px;line-height:28px;font-weight:600;color:var(--plum);font-variant-numeric:tabular-nums}
.av-en-share span{font-size:11px;line-height:16px;letter-spacing:.1em;text-transform:uppercase;color:var(--ash)}
.av-en-pill{
  grid-area:pill;justify-self:end;
  padding:5px 12px;border-radius:var(--r-pill);
  font-size:12px;line-height:18px;font-weight:600;white-space:nowrap;
}
.av-engine[data-cited="true"] .av-en-pill{background:var(--tint-strong);color:var(--band-strong-ink)}
.av-engine[data-cited="false"] .av-en-pill{background:var(--tint-poor);color:var(--band-poor-ink)}
/* The zero row keeps its rail and loses its fill, so the row still reads as a
   measurement that came back empty rather than as a row that failed to render. */
.av-engine[data-cited="false"] .av-en-bar i{background:transparent}
/* THE STATE IS THE FILL. This was a 3px red left rule, which was already the
   second correction on this row - it began as a full red border, became an
   edge, and is now the ground itself at --fill-poor. Six per cent of red over
   a whole row is quieter than three pixels of it down one side, and it marks
   the row rather than annotating it.

   A NAMED ROW IS NOT TINTED GREEN. Being cited is the expected state and the
   expected state is the neutral one; tinting both would make the section a
   traffic light and leave a reader deciding which of two colours is the
   default. */
.av-engine[data-cited="false"]{background:var(--fill-poor)}

/* The four bars fill in the order the engines are listed, starting with their
   own section at AV_IN.engines - 260ms - rather than at zero, which had them
   finishing before the panel they sit in had arrived. 90ms apart, so four bars
   read as four measurements taken in turn. */
@media (prefers-reduced-motion:no-preference){
  @keyframes av-fill-in{from{transform:scaleX(0)}to{transform:none}}
  .av-en-bar i{transform-origin:left center;animation:av-fill-in 700ms var(--ease) both}
  .av-engine:nth-child(1) .av-en-bar i{animation-delay:260ms}
  .av-engine:nth-child(2) .av-en-bar i{animation-delay:350ms}
  .av-engine:nth-child(3) .av-en-bar i{animation-delay:440ms}
  .av-engine:nth-child(4) .av-en-bar i{animation-delay:530ms}
}

.av-engines-note{
  margin-top:var(--s5);max-width:66ch;
  color:var(--slate);font-size:17px;line-height:28px;
}

/* ---- the three findings ------------------------------------------------- */
.av-finds{display:grid;gap:var(--s5)}
.av-find{
  padding:var(--s6);
  /* THE SEVERITY IS THE GROUND, not a stripe down the edge of it. Three cards
     each wearing a 3px coloured rule read as a list that has been annotated
     after the fact; three cards on three grounds read as three things of
     different weight, which is what they are. --fill-* is the card tier of the
     tint scale - see the token block at the top of this sheet for why it is a
     third of the pill's percentage.

     THE GROUND IS SET AS A VARIABLE, NOT AS A BACKGROUND, and that is the whole
     reason this reads the way it does: the evidence panel inside the card is
     derived from --card-fill rather than picked, so it is always a shade of
     whatever card it happens to be sitting in. Three severities, one rule, and
     no fourth colour to keep in step by hand. */
  --card-fill:var(--haze);
  background:var(--card-fill);border-radius:var(--r-md);
}
.av-find[data-sev="critical"]{--card-fill:var(--fill-poor)}
.av-find[data-sev="warning"]{--card-fill:var(--fill-work)}
/* Notice keeps the neutral panel. A third hue for the least important row is a
   colour spent on the thing that needed it least. */
.av-find[data-sev="notice"]{--card-fill:var(--haze)}
.av-find-head{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s3);margin-bottom:var(--s3)}
.av-sev{
  padding:3px 10px;border-radius:var(--r-pill);
  font-size:11px;line-height:16px;font-weight:600;
  letter-spacing:.12em;text-transform:uppercase;
}
[data-sev="critical"] .av-sev{background:var(--tint-poor);color:var(--band-poor-ink)}
[data-sev="warning"] .av-sev{background:var(--tint-work);color:var(--band-work-ink)}
[data-sev="notice"] .av-sev{background:var(--mist);color:var(--gray)}
/* --mist on --haze is a two per cent difference and disappears. Inside a card
   the neutral pill inverts to white, exactly as the evidence block does; in the
   list below, which is still on white, --mist above is correct and stands. */
.av-find[data-sev="notice"] .av-sev{background:var(--white)}
.av-find-sect{font-size:12px;line-height:18px;letter-spacing:.14em;text-transform:uppercase;color:var(--ash)}
.av-find h3{font-size:21px;line-height:30px;margin-bottom:var(--s3);max-width:44ch}
/* The evidence is the line a reader checks against their own site, so it is set
   apart from the argument above and below it rather than run into either.

   IT RECEDES, IT DOES NOT ADVANCE, and that is the correction. This was
   --white, on base.css's inversion rule - a panel inside a panel inverts - and
   the rule was applied without checking what it produced. White is the
   brightest value on the page, so a white block inside a tinted card does not
   read as an inset, it reads as a hole punched through it. Evidence is the
   quietest thing in a finding: it is the raw line, quoted, for a reader to
   check against their own site. It should sit BELOW the card, not on top of it.

   SO IT IS THE CARD'S OWN GROUND, DARKENED 7% TOWARD --ink, rather than a
   colour of its own. Three consequences, and each is why this is the version
   that survives: it stays in the card's hue family, so nothing goes muddy the
   way a cool grey does over a warm tint; it recedes rather than advances,
   because it is genuinely darker than what surrounds it; and it needs no
   per-severity value, because --card-fill is set on the card and this reads it.
   Add a fourth severity tomorrow and this follows without being edited.

   --ink and not black. base.css makes the same call for --e-panel and gives the
   reason: pure black over a tinted ground goes muddy grey, and the site's near
   black keeps the hue. */
.av-find-ev{
  margin:0;padding:var(--s3) var(--s4);
  background:color-mix(in srgb,var(--card-fill) 93%,var(--ink));
  border-radius:var(--r-sm);
  color:var(--gray);font-size:14px;line-height:23px;
  font-variant-numeric:tabular-nums;
}
.av-find-why{margin:var(--s4) 0 0;max-width:66ch;color:var(--slate);font-size:16px;line-height:27px}

/* ---- everything else -----------------------------------------------------
   TITLES ONLY, and no blur, no lock icon and no fade. The reason those are
   absent is written in the markup: what is missing from these rows is the
   sentence explaining why the finding matters on this particular site, and that
   sentence is written by a person rather than withheld by a paywall. A blurred
   panel would be pretending there is text under it.
   ------------------------------------------------------------------------- */
.av-more{display:grid;border-top:1px solid var(--line)}
.av-more-row{
  display:grid;grid-template-columns:6.5rem minmax(0,1fr) auto;
  gap:var(--s4);align-items:baseline;
  padding:var(--s4) 0;border-bottom:1px solid var(--line);
  font-size:16px;line-height:25px;color:var(--slate);
}
.av-more-row > .av-sev{justify-self:start}
.av-more-sect{font-size:12px;line-height:18px;letter-spacing:.14em;text-transform:uppercase;color:var(--ash);white-space:nowrap}


/* ==========================================================================
   03b. Hover
   ONE RULE, AND IT IS THE REASON THIS SECTION IS SHORT: hover may help you READ
   the report and may never CARRY any of it. Nothing here reveals a figure, a
   label or a sentence that is not already on screen - because none of these
   elements is focusable, and a card that only tells a pointer something has
   simply hidden it from every keyboard and every phone.

   So what hover does is separate the thing under the pointer from the fifteen
   things around it, which on a document of stacked panels is a genuine reading
   aid and is all it is for.

   ONE DEVICE, NOT FOUR. Every card takes the same 1px lift and the same
   --e-card, and no card changes colour. A ground that deepened on hover would
   need a second tint tier for the neutral cards and a third for the tinted
   ones, and the severity fills would then be saying two things at once - the
   severity, and whether a pointer happens to be nearby. The list rows are the
   one exception and they earn it: a row 24px tall in a stack of six cannot lift
   without shifting its neighbours, so it takes a ground instead.

   -1px AND --e-card ARE BOTH BORROWED. The lift is base.css's own .btn-fill
   hover, so a card and a button move by the same amount on this site.

   --e-card, NOT --e-subtle, and that is the second answer to this question.
   The ladder's usual reading is elevation-1 resting, elevation-2 on hover - but
   these panels rest at ZERO, on a ground of their own rather than a shadow, so
   --e-subtle put the hovered card one imperceptible step above nothing at all.
   --e-card is the shadow this site gives an actual card, which is the right
   sentence: on hover the panel becomes one.

   @media (hover:hover) and (pointer:fine), because a touch device fires hover
   on tap and then holds it: without the guard, every card a thumb touched would
   stay lifted until something else was touched.
   ========================================================================== */
@media (hover:hover) and (pointer:fine){
  .av-engine,
  .av-find,
  .av-ring{
    transition:transform var(--hover-t) var(--ease),
               box-shadow var(--hover-t) var(--ease),
               background-color var(--hover-t) var(--ease);
  }
  .av-engine:hover,
  .av-find:hover{transform:translateY(-1px);box-shadow:var(--e-card)}

  /* The ring is the one card with no ground at rest, so it gets one on hover -
     which is the same separation the others get from their shadow, drawn the
     only way a transparent cell can draw it. */
  .av-ring:hover{transform:translateY(-1px);background:var(--haze);box-shadow:var(--e-card)}

  /* The list. A ground, no lift, and no shadow: these are rows inside one
     ruled block, and lifting one out of a stack of hairlines breaks the two
     rules above and below it. */
  .av-more-row{transition:background-color var(--hover-t) var(--ease)}
  .av-more-row:hover{background:var(--haze)}

  .av-arc-fill{transition:stroke-width var(--hover-t) var(--ease)}
  .av-arc-track{transition:stroke var(--hover-t) var(--ease)}
  .av-en-bar i{transition:background-color var(--hover-t) var(--ease)}

  /* THE CHARTS ANSWER TOO, and this is the second half of the hover pass. A
     card that lifts while the chart inside it sits still says the CARD is the
     thing under the pointer; the chart is the thing under the pointer. So the
     arc thickens by two and its track steps from --mist to --line, which is the
     same gesture at both sizes - the gauge rests at 13 and the rings at 9, so
     the values differ and the change does not.

     THE GAUGE IS NO LONGER INERT. It was, on the argument that one element with
     nothing beside it has nothing to be separated from. That argument was about
     LIFT, and it still holds - the gauge does not move. What it now does is
     respond, which is a different thing and is worth having on the single
     figure this whole page is built to deliver. */
  .av-gauge:hover .av-arc-fill{stroke-width:15}
  .av-ring:hover .av-arc-fill{stroke-width:11}
  .av-gauge:hover .av-arc-track,
  .av-ring:hover .av-arc-track{stroke:var(--line)}

  /* The bar deepens rather than grows. Height is a grid row on this row and a
     2px change in it moves the name and the pill beside it; --purple-deep is
     the site's own hover purple and moves nothing. */
  .av-engine:hover .av-en-bar i{background:var(--purple-deep)}

  /* THE LEADERBOARD ON THE ASK STAGE STAYS INERT. It is entirely redacted, and
     a hover state on six blank bars is motion with nothing under it. */
}

@media (prefers-reduced-motion:reduce){
  /* The state still lands; it just stops travelling. A hover that helps you
     read is worth keeping when motion is not - so the shadow and the ground
     remain and only the 1px and the timing go. */
  .av-engine,.av-find,.av-ring,.av-more-row,
  .av-arc-fill,.av-arc-track,.av-en-bar i{transition:none}
  .av-engine:hover,.av-find:hover,.av-ring:hover{transform:none}
}


/* ==========================================================================
   04. The handoff
   base.css's .closer inside the report stage, the same placement
   daily-brief.css uses. No gate drawing here, and that is deliberate: the brief
   page withholds TOMORROW'S mail, which exists in shape and can honestly be
   blurred. What this page withholds is a person's reading of a real site, and
   there is no shape of that to draw.

   NO ROUTE LINE EITHER, as of the same pass - see the note at .av-gate-face.
   The closer is four elements now, and its spacing is the section tier rather
   than anything this sheet has to compose.
   ========================================================================== */
.av-hand{margin-top:var(--s14)}
/* The closer is a full-bleed section everywhere else on the site; here it is
   inside a 920 column, so it takes its own edge rather than the page's. */
.av-hand.closer{
  padding:var(--sec-sm) var(--s8);
  background:var(--surface-alt);border-radius:var(--r-lg);
}
/* The closer is now a heading, a paragraph and two buttons. The .tl-route
   block that sat between the paragraph and the buttons - the member agency,
   its mark and its local clock - was removed on client direction, and its one
   rule went with it rather than being left behind as a selector matching
   nothing. */
.av-gate-face{
  max-width:56ch;margin-inline:auto;text-align:center;
  display:grid;gap:var(--s5);justify-items:center;
}
.av-gate-face .eyebrow{margin:0;color:var(--plum)}
.av-gate-face h2{max-width:26ch;margin:0}
.av-gate-face .closer-p{margin:0}

/* The market question, in the closer, which is where tech-audit.css puts its
   own and for the reason recorded there: it is one optional field inside a
   closing argument, not a form, and at full width it reads as the thing being
   asked for rather than as a refinement of the button under it. The label
   centres with the field - two axes in a centred box is drift. */
/* .av-hand-market IS GONE. It centred the closer's market select at 300px. The
   field was removed on 2026-08-28 (client direction) and contact.html asks the
   question instead; these two rules went with it rather than being left as
   selectors matching nothing. The page also stopped loading css/tools.css,
   which it had been pulling in whole for that select's .tl-select. */

.av-hand-acts{
  display:flex;flex-wrap:wrap;justify-content:center;
  gap:var(--s3);
}

.av-note{
  margin-top:var(--s10);padding-top:var(--s5);border-top:1px solid var(--line);
  max-width:70ch;color:var(--ash);font-size:14px;line-height:23px;
}
.av-note b{color:var(--gray);font-weight:600}


/* ==========================================================================
   05. What the real check returns
   The tinted half of the alternation, and the only part of the report half of
   this page a crawler can read. Same measure and same grid as daily-brief.css's
   own closing section, so the two pages share one left edge down the page.

   NO EMAIL FIELD ANYWHERE ON THIS PAGE. tools.html owns the one form that asks
   for a tool, and a page reached from that page collecting an address of its
   own is two captures for one action. The closer above hands the visitor back
   with both answers already in the query.
   ========================================================================== */
.av-inside{padding:var(--sec) 0;background:var(--surface-alt)}
.av-inside-box{max-width:1180px;margin-inline:auto}
.av-inside-deck{margin-top:var(--s3);color:var(--gray);font-size:18px;line-height:27px;max-width:66ch}
.av-inside-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--s8);margin-top:var(--s8)}
/* 66ch on the answers, as .bp-faq p and .disclaimer. Three columns give these
   a measure for free; the single-column arrangement below 1023 does not, and
   measured at 834 they ran to 98 characters. */
.av-inside-grid p{max-width:66ch}
.av-inside h3{font-size:20px;line-height:28px;margin-bottom:var(--s2)}
.av-inside p{margin:0;color:var(--gray);font-size:16px;line-height:25px}


/* ==========================================================================
   06. The report's entrance
   One rise, staggered down the document, and it is armed by js/ai-visibility.js
   adding .is-in rather than left on the element - the visitor can run the demo
   more than once and a CSS animation only plays when the class arrives. The
   whole sequence lives inside the no-preference query, so with reduced motion
   the report simply exists.
   ========================================================================== */
/* THE FOUR SECTIONS USED TO SHARE ONE DELAY, which meant the document did not
   assemble, it appeared in two pieces. Each has its own now and they are 60ms
   apart - close enough to read as one movement, far enough that the eye is led
   down the page rather than handed all of it. */
@media (prefers-reduced-motion:no-preference){
  @keyframes av-rise{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
  .av-report.is-in > .wrap > *{animation:av-rise 480ms var(--ease) both}
  .av-report.is-in .av-report-top{animation-delay:0ms}
  .av-report.is-in .av-demo{animation-delay:60ms}
  /* 120 and 200 are AV_IN.score and AV_IN.rings in js/ai-visibility.js. The
     panel rises and the figure inside it starts counting on the same frame;
     changing one without the other puts a needle ahead of its own number. */
  .av-report.is-in .av-score{animation-delay:120ms}
  .av-report.is-in .av-sect:nth-of-type(1){animation-delay:200ms}
  .av-report.is-in .av-sect:nth-of-type(2){animation-delay:260ms}
  .av-report.is-in .av-sect:nth-of-type(3){animation-delay:320ms}
  .av-report.is-in .av-sect:nth-of-type(4){animation-delay:380ms}
  /* The handoff and the note do NOT rise. They are the foot of a document the
     reader has not scrolled to yet, and animating them means they have already
     played by the time anyone arrives. */
  .av-report.is-in .av-hand,
  .av-report.is-in .av-note{animation:none}
}


/* ==========================================================================
   07. Responsive
   ========================================================================== */
/* THE FOLD COLLAPSES AT 1024, NOT AT THE SITE'S 900, the same call
   daily-brief.css makes and for the same measured reason: held to 900, the copy
   column loses width to a drawing that keeps all of its own. */
/* 1023, not 1024, to land on base.css's own tablet boundary. Both were
   max-width, so at exactly 1024px - iPad landscape, and the single most common
   tablet width there is - base.css had already switched this page to its
   DESKTOP layout while this sheet was still serving its tablet one. A 1px band
   of half-collapsed page, on a real device width. */
@media (max-width:1023px){
  .av-score{grid-template-columns:1fr;gap:var(--s6);justify-items:start}
}
@media (max-width:900px){
  .av-inside-grid{grid-template-columns:1fr;gap:var(--s6)}
  .av-lede{font-size:18px;line-height:28px}
  /* The submit leaves the pill and goes under it. At 600 the field is about
     300px wide with a button inside it, which leaves the address six
     characters to be typed into. */
  .av-form-h{font-size:24px;line-height:32px}
  .av-rings{grid-template-columns:1fr;gap:var(--s6)}
  /* The ring goes beside its own text rather than above it, because three
     stacked 112px discs down a phone is three screens of chart. */
  .av-ring{display:grid;grid-template-columns:112px minmax(0,1fr);gap:var(--s5);align-items:center;padding:var(--s3)}
  .av-ring h3{margin-top:0}
  /* The engine row loses its two right-hand columns to a second line. The share
     stays with the name, because the number is the row's whole content. */
  .av-engine{
    grid-template-columns:minmax(0,1fr) auto;
    grid-template-areas:"name share" "note pill" "bar bar";
    gap:var(--s3) var(--s4);
  }
  .av-en-pill{justify-self:end}
}
@media (max-width:600px){
  /* The pill unstacks: prefix and field on one line, the submit full width
     under them. A button inside a 300px field leaves the address six characters
     of room, which is the one thing this fold cannot afford. */
  .av-url{flex-wrap:wrap;border-radius:var(--r-lg);padding:var(--s3) var(--s4)}
  .av-url input{padding:6px 0}
  .av-url-go{width:100%;justify-content:center;margin-top:var(--s2)}

  /* THE NOTICE GOES BACK TO LEFT-ALIGNED, and the block stays where it is - it
     already fills the column here, so there is nothing left to centre. What is
     dropped is the TEXT alignment: 66ch is wider than the viewport, so the two
     balanced lines become five, and five centred lines of body copy give the
     eye a different start point on every one. Centring is worth it at two lines
     and costs more than it returns at five. */
  .av-demo{text-align:left}
  .av-hand.closer{padding:var(--sec-sm) var(--s5)}
  .av-find{padding:var(--s5)}
  .av-counts{gap:var(--s4) var(--s5)}
  .av-more-row{grid-template-columns:minmax(0,1fr);gap:var(--s2)}
  .av-more-sect{display:none}
  .av-gauge{width:140px;height:140px}
  .av-gauge-n{font-size:38px}
}


/* ==========================================================================
   08. Reduced motion
   The site's standing contract. Nothing here reveals content, so removing the
   motion removes nothing: the log still lands, it just lands at once, and the
   leaderboard was always drawn.
   ========================================================================== */
@media (prefers-reduced-motion:reduce){
  .av-log li{transition:none}
  .av-log .av-mark{animation:none!important}
  /* The rail still fills - it is information - it just stops sliding there. */
  .av-rail i{transition:none}
}
