/* ==========================================================================
 * visuals.css — iconography and drawn graphics.
 *
 * No photography anywhere on this site, on purpose: it sells verifiable
 * evidence, and stock imagery is the visual version of an unsupported claim.
 * Everything here is drawn — one stroke weight, one grid, the same hand as
 * the brand mark — and every piece is decorative, sitting beside copy that
 * already says what it means. Not one word of that copy changes.
 * ========================================================================== */

.ic { width: 24px; height: 24px; flex: none; color: var(--accent); }

/* The chip: a tinted plate behind the glyph, so a card leads with an image
   instead of a heading. */
.icon-chip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; margin-bottom: 14px;
  border-radius: 13px;
  background: linear-gradient(145deg,
              color-mix(in srgb, var(--accent) 14%, var(--bg-raised)),
              var(--accent-soft));
  border: 1px solid var(--accent-line);
  box-shadow: inset 0 1px 0 color-mix(in srgb, #fff 60%, transparent);
  color: var(--accent);
  transition: transform .35s cubic-bezier(.22,.61,.36,1), background-color .35s ease;
}
.cap:hover .icon-chip, .pillar:hover .icon-chip,
.principle:hover .icon-chip, .aud:hover .icon-chip { transform: translateY(-2px) rotate(-3deg); }

/* Kickers: a small mark at x-height, so the label reads as a signpost. */
/* `.hero .kicker` sets display:inline-block with more specificity than a
   single class, so the flex row never applied and the glyph sat against the
   first letter. Matched at the same depth rather than reached for with
   !important. */
.section-kicker.has-ic, .kicker.has-ic, .eyebrow.has-ic,
.hero .kicker.has-ic { display: inline-flex; align-items: center; gap: 8px; }
.ic-kicker { width: 17px; height: 17px; opacity: .85; }

/* Scope bullets: the glyph replaces the disc, aligned to the first line.
   Deliberately NOT a grid on the <li>: its content is a <strong> plus loose
   text, which grid would turn into separate cells -- one word per line. The
   icon is taken out of flow instead, so the sentence stays a sentence. */
.aside ul { padding-left: 0; }
.aside ul > li.has-ic { list-style: none; position: relative; padding-left: 30px; }
.ic-bullet {
  width: 19px; height: 19px; opacity: .9;
  position: absolute; left: 0; top: .18em;
}

/* An outlet with no logo gets a press glyph rather than an empty plate. */
.ic-outlet { width: 20px; height: 20px; opacity: .55; margin-right: 8px; }

/* ---- figures, drawn twice -----------------------------------------------
   The ring is a second reading of the number already printed: a percentage
   fills its share, anything else closes the circle. */
.stat.has-ring, .stat.has-glyph { position: relative; padding-right: 76px; }
/* A figure that is not a proportion gets a mark, never a ring: a full circle
   beside "2.1 years" would draw a share of nothing. */
.stat-glyph { position: absolute; top: 20px; right: 20px; width: 26px; height: 26px; opacity: .35; }
.stat-ring { position: absolute; top: 16px; right: 16px; width: 52px; height: 52px; transform: rotate(-90deg); }
.stat-ring circle { fill: none; stroke-width: 3; }
.ring-track { stroke: var(--border); }
.ring-fill {
  stroke: var(--accent); stroke-linecap: round;
  stroke-dasharray: 97.4;                      /* 2πr, r = 15.5 */
  stroke-dashoffset: 97.4;
}
.stat.is-in .ring-fill {
  animation: ring-draw 1.3s cubic-bezier(.22,.61,.36,1) .25s forwards;
}
@keyframes ring-draw { to { stroke-dashoffset: calc(97.4 - (97.4 * var(--pct) / 100)); } }

/* ---- the hero illustration ----------------------------------------------
   A claim being read and judged: lines of a document, one of them picked out,
   a beam passing over it, a verdict mark. It carries no words — the headline
   beside it is the message; this is what the product DOES. */
.hero .wrap { position: relative; }
.hero-figure { pointer-events: none; }

/* The figure shares the hero with the copy instead of floating over it.
   Absolute positioning put it on top of a paragraph that is allowed to run to
   46em, so on a wide screen the two collided. A grid gives the illustration a
   column of its own: the text can never grow into it, and the illustration
   can never cover a word. Below the breakpoint there is no room for a second
   column, so the figure stands down rather than shrinking into a smudge. */
@media (min-width: 1081px) {
  .hero .wrap {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 330px;
    column-gap: 56px;
    row-gap: 0;
    align-items: center;
  }
  .hero .wrap > *:not(.hero-figure) { grid-column: 1; }
  .hero-figure {
    grid-column: 2;
    /* `1 / -1` spans the EXPLICIT grid, and the rows here are implicit — so it
       covered row 1 only and the illustration sat level with the kicker
       instead of the block. Spanning past the last row costs nothing: empty
       implicit rows have no height, and row-gap is 0. */
    grid-row: 1 / span 50;
    align-self: center;
    width: 100%; height: auto;
    opacity: .95;
  }
  /* The measure is now the column's, not 46em of a wider page. */
  .hero p.sub { max-width: none; }
}
@media (max-width: 1080px) { .hero-figure { display: none; } }
.hf-card { fill: var(--bg-raised); stroke: var(--border); stroke-width: 1.5; }
.hf-line { stroke: var(--muted); stroke-width: 3.4; stroke-linecap: round; opacity: .35; }
.hf-line-hit { stroke: var(--accent); opacity: .9; }
.hf-beam { fill: url(#hf-beam-grad); }
.hf-badge { fill: var(--accent); }
.hf-badge-mark { stroke: var(--accent-contrast); stroke-width: 2; fill: none; stroke-linecap: round; stroke-linejoin: round; }
.hf-chip { fill: var(--accent-soft); stroke: var(--accent-line); stroke-width: 1.2; }

html.js-motion .hf-beam { animation: hf-sweep 4.4s cubic-bezier(.4,0,.2,1) .6s infinite; }
@keyframes hf-sweep { 0% { transform: translateY(0); opacity: 0; } 12% { opacity: 1; } 76% { opacity: 1; } 100% { transform: translateY(150px); opacity: 0; } }
html.js-motion .hf-badge, html.js-motion .hf-badge-mark { animation: hf-pop .7s cubic-bezier(.34,1.56,.64,1) 1.5s both; }
@keyframes hf-pop { from { opacity: 0; transform: scale(.6); } to { opacity: 1; transform: none; } }
.hf-badge, .hf-badge-mark { transform-box: fill-box; transform-origin: center; }

/* ---- bands ---------------------------------------------------------------
   The alternate sections carry a faint measured grid: the look of something
   being gridded and checked, at an opacity that never competes with text. */
section.alt { position: relative; isolation: isolate; }
section.alt::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background-image: radial-gradient(currentColor .9px, transparent .9px);
  background-size: 22px 22px;
  color: var(--accent);
  opacity: .05;
  mask-image: linear-gradient(to bottom, transparent, #000 18%, #000 82%, transparent);
}

/* Product cards: a soft aura in the brand colour, so a grid of them reads as
   a family rather than a table. */
.product, .hcard { position: relative; overflow: hidden; }
.product::after, .hcard::after {
  content: ""; position: absolute; z-index: -1;
  width: 190px; height: 190px; right: -70px; top: -70px; border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--accent) 22%, transparent), transparent 70%);
  opacity: .55; transition: transform .5s cubic-bezier(.22,.61,.36,1), opacity .5s ease;
}
.product:hover::after, .hcard:hover::after { transform: scale(1.25); opacity: .8; }

@media (prefers-reduced-motion: reduce) {
  .icon-chip, .product::after { transition: none !important; }
  .stat.is-in .ring-fill { animation: none; stroke-dashoffset: calc(97.4 - (97.4 * var(--pct) / 100)); }
  html.js-motion .hf-beam, html.js-motion .hf-badge, html.js-motion .hf-badge-mark { animation: none !important; }
  .hf-beam { opacity: .5; }
}
@media print {
  .hero-figure, .stat-ring, section.alt::before, .product::after { display: none !important; }
  .icon-chip { background: none; border-color: var(--border); }
}
