/* stefanpressconsulting.com - the home page's release board ("mission board"), "How it's built" and the contact
   section's width. Loaded after home.css, which holds the tokens (:root) and the base look. Served as a file: the
   CSP allows no inline style. */

  :root {
    --live:  #4af0ff;   /* cyan lamp: live in production */
    --beta:  #ffc857;   /* amber lamp: in beta */
    --inuse: #a06bff;   /* violet lamp: an internal tool in daily use */
    --row:   rgba(10, 14, 26, 0.72);
    --rowhi: rgba(16, 22, 40, 0.86);
  }

  .hero { max-width: none; }   /* the headline is ~11em wide: the intro under it may use that width (owner: "wrapped funny" at 640 px) */

  /* ---- the headline v3 (owner 2026-10-24: "I need something amazing"). Line 1: a COIN that spins in place - one
     face "AI", the other "SI" - then a row of signal packets. Line 2: another row of packets and, only once the walking
     eye has reached the last of them, "engineered!" pops up with the eye dotting its i. 30 packets on line 1 and 20 on
     line 2 (owner: "make the top line have 30 dots"); 7 a row on a phone, where they cannot fit. assets/hero.js runs the sequence and staggers the landing; without it the word
     simply shows. Reduced motion: home.css stops every animation - the coin rests on "SI", the word shows, no eye.
     Screen readers hear "SI ... engineered!" (.vh copies; the drawn parts are aria-hidden). */
  .hero-title {
    margin: 22px 0 16px;
    font-size: clamp(40px, 7.4vw, 76px);          /* line 2 (25 packets + the word, ~11.8em) still fits 960 px */
    line-height: 1.02;
    letter-spacing: -0.035em;
    font-weight: 850;
    background: none;
    -webkit-background-clip: border-box;
    background-clip: border-box;
    color: #fff;
    filter: none;
  }
  /* .hrow, not .row: home.css's .row stacks into a column on a phone (MEASURED 2026-10-24 at 375 px) */
  .hero-title .hrow { display: flex; flex-direction: row; align-items: center; white-space: nowrap; }
  .hero-title .hrow + .hrow { margin-top: 0.04em; }

  /* the coin: "AI" and "SI" stacked; assets/hero.js changes one into the other through a different mechanism each
     time (owner 2026-10-24: "rotate as a circle ... mixed up several mechanisms") - a coin flip, a full circle spin, a
     dissolve, a tumble, a glitch. Only the face with .is-on shows. Without the script: AI. Reduced motion: SI. */
  .hero-title .coin { display: inline-block; perspective: 3.2em; }
  .hero-title .coin-in { display: inline-grid; transform-style: preserve-3d; }
  .hero-title .face {
    grid-area: 1 / 1; text-align: center; opacity: 0;
    color: #fff;
    /* a HUD read-out: a cyan edge left, a violet edge right, a soft glow */
    text-shadow: -0.035em 0.012em 0 rgba(74, 240, 255, 0.85), 0.035em -0.012em 0 rgba(160, 107, 255, 0.85),
      0 0 34px rgba(74, 240, 255, 0.35);
  }
  .hero-title .face.is-on { opacity: 1; }
  @media (prefers-reduced-motion: reduce) {
    .hero-title .face-ai.is-on { opacity: 0; }
    .hero-title .face-si { opacity: 1; }
  }

  /* the signal packets on their wire */
  .hero-title .dots { position: relative; display: inline-flex; align-items: center; gap: 0.12em; margin-left: 0.24em; padding: 0 0.04em; }
  .hero-title .hrow2 .dots { margin-left: 0; margin-right: 0.24em; }
  .hero-title .dots::before {                      /* the wire: a faint line the packets ride on */
    content: ""; position: absolute; left: -0.12em; right: -0.12em; top: 50%; height: 0.02em; margin-top: -0.01em;
    background: linear-gradient(90deg, transparent, rgba(74, 240, 255, 0.5) 12%, rgba(160, 107, 255, 0.5) 88%, transparent);
    opacity: 0; animation: wire-in .8s ease-out .6s both;
  }
  .hero-title .dots i {
    position: relative; display: block; flex: none;
    width: 0.13em; height: 0.13em; border-radius: 50%;
    background: var(--cyan); box-shadow: 0 0 0.22em rgba(74, 240, 255, 0.9);
    animation: packet-in .6s cubic-bezier(.2, .9, .3, 1.2) both;
    transition: width .3s ease, height .3s ease, margin .3s ease, border-radius .3s ease, background-color .3s ease;
  }
  /* with scripts on (assets/js-on.js sets .js in the <head>), the packets wait unseen until hero.js has set their
     landing delays (.landing) - before, they drew at once and some re-landed (owner 2026-10-26: "after a clear it starts
     with some of the bottom line drawn") */
  .js .hero-title:not(.landing) .dots i { animation: none; opacity: 0; }
  .hero-title .dots i:nth-child(3n) { background: #b9a3ff; box-shadow: 0 0 0.22em rgba(160, 107, 255, 0.9); }
  .hero-title.settled .dots i { animation: signal 2.6s ease-in-out infinite; }
  .hero-title:hover .dots i { animation-duration: .6s; }
  @media (max-width: 560px) {
    .hero-title .dots i:nth-child(n+8) { display: none; }
  }

  /* THE WALKING EYE (owner 2026-10-24 "make the ones that walk on the dots be 50% smaller"; 2026-10-25 "make the eyes
     on the dots 50% bigger": 0.21em -> 0.315em; then "make all the eyes that travel along the dots to be 33% larger.
     Leave the last one alone": 0.42em while it walks (then "larger" again: 0.525em), 0.315em on the last packet (.is-last, where it waits while the
     word types). assets/hero.js moves .is-eye along every visible packet; the eye grows into the gaps with negative
     margins, so the row never shifts (it overlaps the next packets' edges while it walks). */
  .hero-title .dots i::before {                     /* the pupil, only on the eye */
    content: ""; position: absolute; left: 50%; top: 50%; width: 0.175em; height: 0.175em; margin: -0.0875em 0 0 -0.0875em;
    border-radius: 50%; background: #04111a; opacity: 0; transition: opacity .15s ease .1s;
  }
  .hero-title .dots i.is-eye {
    /* full size AT ONCE: the eye moves on every ~80 ms, so the packets' .3s grow never finished and the walking eye
       stayed packet-sized (MEASURED 2026-10-25 in WebKit: 0.13-0.19em, owner "need to be 50% larger"). The packet
       it leaves still shrinks back over .3s (its own transition). */
    transition: none;
    width: 0.525em; height: 0.3125em; margin: 0 -0.1975em; border-radius: 0.525em / 0.3125em; z-index: 2;
    background: #e9fdff; box-shadow: 0 0 0.5em rgba(74, 240, 255, 0.9), inset 0 0 0 0.03em var(--cyan);
    animation: none;
  }
  .hero-title .dots i.is-eye.is-last {             /* the last packet: left at 0.315em (owner "leave the last one alone") */
    width: 0.315em; height: 0.1875em; margin: 0 -0.0925em; border-radius: 0.315em / 0.1875em;
    box-shadow: 0 0 0.3em rgba(74, 240, 255, 0.9), inset 0 0 0 0.018em var(--cyan);
  }
  .hero-title .dots i.is-last::before { width: 0.105em; height: 0.105em; margin: -0.0525em 0 0 -0.0525em; }
  .hero-title .dots i.is-eye.is-last::before { animation-name: eye-look-last; }
  @keyframes eye-look-last { 0%, 20% { transform: translateX(0); } 40%, 55% { transform: translateX(-0.075em); }
    70%, 85% { transform: translateX(0.075em); } 100% { transform: translateX(0); } }
  .hero-title .dots i.is-eye::before { opacity: 1; animation: eye-look-s 1.2s ease-in-out infinite; }
  @keyframes eye-look-s { 0%, 20% { transform: translateX(0); } 40%, 55% { transform: translateX(-0.125em); }
    70%, 85% { transform: translateX(0.125em); } 100% { transform: translateX(0); } }
  /* EYELASHES on every eye while the headline has .lashed (assets/hero.js copies it from the LANai eye, so
     SPC_EYE_LASHES in includes/apps.php is the ONE switch - owner "All lashes") */
  .hero-title.lashed .dots i.is-eye::after, .hero-title.lashed .i-eye::before {
    content: ""; position: absolute; left: 50%; background:
      linear-gradient(118deg, transparent 44%, #c9fbff 44% 60%, transparent 60%) left center / 34% 100% no-repeat,
      linear-gradient(90deg, transparent 40%, #c9fbff 40% 60%, transparent 60%) center center / 34% 100% no-repeat,
      linear-gradient(62deg, transparent 40%, #c9fbff 40% 56%, transparent 56%) right center / 34% 100% no-repeat;
    filter: drop-shadow(0 0 0.04em var(--cyan));
  }
  .hero-title.lashed .dots i.is-eye::after { top: -0.125em; width: 0.45em; height: 0.1375em; margin-left: -0.225em; }
  .hero-title.lashed .dots i.is-eye.is-last::after { top: -0.075em; width: 0.27em; height: 0.0825em; margin-left: -0.135em; }
  .hero-title.lashed .i-eye::before { top: -0.1em; width: 0.36em; height: 0.11em; margin-left: -0.18em; }

  /* "engineered!": hidden until the walk reaches the end of line 2 (.pre, set by the script), then it pops up */
  .hero-title .eng {
    /* room below for the g's descender: the gradient paints only inside this box (Windows cross-test 2026-10-24) */
    padding-bottom: 0.16em;
    margin-bottom: -0.16em;
    background: linear-gradient(100deg, var(--cyan) 0%, #b6f6ff 24%, #ffffff 33%, #c9b6ff 44%, var(--violet) 56%, var(--violet) 100%);
    background-size: 180% 100%;
    background-position: 0% 0;
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
  /* it TYPES in, one letter every 0.25 s from the e; once all are there and the eye has perched on the i, it FLASHES
     and disappears, and the next lap types it again (owner 2026-10-24). No filter and no transform on the word: those
     made the gradient text render soft ("why is engineered blurred?"). hero.js sets .typing (letters hidden until
     .on) and .flash; without the script, or under reduced motion, the word simply shows. */
  .hero-title.typing .eng .ltr { visibility: hidden; }
  .hero-title.typing .eng .ltr.on { visibility: visible; }
  .hero-title.flash .eng { animation: eng-flash .9s steps(1, end) both; }
  @keyframes eng-flash { 0% { opacity: 1; } 16% { opacity: 0; } 33% { opacity: 1; } 50% { opacity: 0; } 66% { opacity: 1; }
    83%, 100% { opacity: 0; } }

  /* the i of "engineered!": while the eye perches above it, the i is hidden and a drawn STEM stands in its place - the
     i without its dot (owner 2026-10-24: "leave it hiding and draw a line (rect) on top of it for the lower part of
     the i"; the dotless glyph looked odd). hero.js measures the real i's stem (canvas) and sets the stem's box and its
     colour from the word's gradient at that spot. */
  .hero-title .i-host { position: relative; }
  .hero-title .i-stem { position: absolute; display: none; border-radius: 0.02em; }
  /* NEVER a dot on the i (owner 2026-10-24: "do not have a dot on top of the letter i"): once hero.js has measured the
     stem it sets .stemmed - the real i is then always invisible (it only keeps its width) and the stem is the letter,
     typed in with the others (shown once the i is .on) and flashing out with them. Without the script: the plain i. */
  .hero-title.stemmed .eng .i-dot.ltr, .hero-title.stemmed.typing .eng .i-dot.ltr.on { visibility: hidden; }
  .hero-title.stemmed .i-stem { display: block; }
  .hero-title.stemmed.typing .i-dot:not(.on) ~ .i-stem { display: none; }
  .hero-title .i-eye {
    /* top 0.165em -> 0.105em (owner 2026-10-25 "have it land a little higher ... more space under it before the bottom
       of the i"): the gap over the stem grows from ~0.006em to ~0.066em */
    position: absolute; left: 50%; top: 0.105em; width: 0.42em; height: 0.25em; margin-left: -0.21em;
    border-radius: 0.42em / 0.25em; background: #e9fdff; box-shadow: 0 0 0.35em rgba(74, 240, 255, 0.9), inset 0 0 0 0.02em var(--cyan);
    opacity: 0; transform: translateY(-0.45em) scale(.3); transition: opacity .3s ease, transform .45s cubic-bezier(.2, 1.4, .4, 1);
  }
  .hero-title .i-eye::after {
    content: ""; position: absolute; left: 50%; top: 50%; width: 0.14em; height: 0.14em; margin: -0.07em 0 0 -0.07em;
    border-radius: 50%; background: #04111a; box-shadow: 0 0 0 0.03em var(--violet); animation: eye-look 3s ease-in-out infinite;
  }
  .hero-title .i-eye.on { opacity: 1; transform: none; animation: eye-blink 3s infinite; }

  @keyframes packet-in {
    0%   { opacity: 0; transform: translate(-0.6em, -0.5em) scale(.4); }
    70%  { opacity: 1; transform: translate(0.03em, 0.02em) scale(1.3); }
    100% { opacity: 1; transform: none; }
  }
  @keyframes wire-in { from { opacity: 0; transform: scaleX(.2); } to { opacity: 1; transform: none; } }
  @keyframes signal {
    0%, 30%, 100% { opacity: .6; transform: scale(1); }
    12%           { opacity: 1;  transform: scale(1.4); }
  }

  .vh { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  /* the full width of the page (owner 2026-10-25 "Reflow the text ... It looks jammed to the left": 64ch left a third
     of the 960 px page empty) */
  .hero .tag { max-width: none; font-size: clamp(15px, 1.25vw, 18px); line-height: 1.6; text-wrap: pretty; }

  /* ---- the board ------------------------------------------------------------------------------------------- */
  .board { margin: 34px 0 0; animation: rise .6s ease .15s both; }
  .board-bar {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    padding: 0 4px 10px;
    border-bottom: 1px solid var(--line);
  }
  .board h2, .how h2 {
    margin: 0;
    font-size: 22px;
    font-weight: 750;
    letter-spacing: -0.01em;
    color: #fff;
  }
  .board-legend { margin: 0; font-size: 12.5px; color: var(--muted); display: flex; align-items: center; gap: 6px 10px; flex-wrap: wrap; }
  .board-legend .lamp { margin-left: 6px; }

  .board-group { margin-top: 18px; }
  .board-head {
    margin: 0 0 8px 4px;
    font-size: 13px;
    font-weight: 600;
    color: var(--muted);
    letter-spacing: 0.01em;
  }
  #group-platform .release { border-style: dashed; }

  .release {
    background: var(--row);
    border: 1px solid var(--line);
    border-radius: 12px;
    margin: 0 0 8px;
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    transition: border-color .18s, background .18s;
  }
  .release[open] { background: var(--rowhi); border-color: rgba(74, 240, 255, 0.38); }
  .release summary, .release.preview .summary {
    list-style: none;
    cursor: pointer;
    display: grid;
    grid-template-columns: 14px minmax(160px, 15rem) 1fr auto;
    align-items: center;
    gap: 14px;
    padding: 14px 18px;
    border-radius: 12px;
  }
  .release summary::-webkit-details-marker { display: none; }
  /* a visitor's locked preview row: it does not open - no pointer, no open/close hint */
  .release.preview .summary { cursor: default; }
  .release.preview .rstatus::after { content: none; }
  .release.preview + .locked, .board-group + .locked { margin-top: 16px; }
  .release summary:hover .rname { color: var(--cyan); }
  .release summary:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }
  .rname { font-size: 16.5px; font-weight: 700; color: #fff; transition: color .15s; }
  /* a brand name's styled part (LANai: the "ai", owner 2026-10-24 "go with A") - on the board, in the theatre's reel
     and marquee */
  .ai { color: var(--cyan); text-shadow: 0 0 10px rgba(74, 240, 255, 0.55); }
  /* the looking eye: the last i's dot is an eye whose pupil glances left and right and now and then blinks */
  .eye-i { position: relative; display: inline-block; }
  .eye { position: absolute; left: 50%; top: -0.08em; width: 0.5em; height: 0.3em; margin-left: -0.25em;
    border-radius: 0.5em / 0.3em; background: #e9fdff; box-shadow: 0 0 8px rgba(74, 240, 255, 0.8), inset 0 0 0 1px var(--cyan);
    animation: eye-blink 6s infinite; }
  /* its lashes (SPC_EYE_LASHES in includes/apps.php adds .lashed): the same three strokes as the headline's eye */
  .eye.lashed::before { content: ""; position: absolute; left: 50%; top: -0.12em; width: 0.42em; height: 0.12em;
    margin-left: -0.21em;
    background:
      linear-gradient(118deg, transparent 44%, #c9fbff 44% 62%, transparent 62%) left center / 34% 100% no-repeat,
      linear-gradient(90deg, transparent 38%, #c9fbff 38% 62%, transparent 62%) center center / 34% 100% no-repeat,
      linear-gradient(62deg, transparent 38%, #c9fbff 38% 56%, transparent 56%) right center / 34% 100% no-repeat;
    filter: drop-shadow(0 0 0.04em var(--cyan)); }
  .eye::after { content: ""; position: absolute; left: 50%; top: 50%; width: 0.17em; height: 0.17em; margin: -0.085em 0 0 -0.085em;
    border-radius: 50%; background: #04111a; box-shadow: 0 0 0 0.03em var(--violet); animation: eye-look 6s ease-in-out infinite; }
  @keyframes eye-look { 0%, 18% { transform: translateX(0); } 28%, 42% { transform: translateX(-0.12em); }
    52%, 66% { transform: translateX(0.12em); } 76%, 100% { transform: translateX(0); } }
  @keyframes eye-blink { 0%, 88%, 94%, 100% { transform: scaleY(1); } 91% { transform: scaleY(0.1); } }
  @media (prefers-reduced-motion: reduce) { .eye, .eye::after, .i-eye::after { animation: none; } }
  .rdomain { margin-left: 4px; font: 600 11px/1 ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace; letter-spacing: .06em;
    color: var(--muted); }
  .rtag { font-size: 14px; color: var(--muted); }
  .rstatus {
    font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
    font-size: 12px;
    color: var(--text);
    opacity: 0.8;
    white-space: nowrap;
  }
  .rstatus::after {             /* the open/close hint, turns when the row opens */
    content: "";
    display: inline-block;
    width: 7px; height: 7px;
    margin-left: 12px;
    border-right: 1.5px solid var(--muted);
    border-bottom: 1.5px solid var(--muted);
    transform: translateY(-2px) rotate(45deg);
    transition: transform .2s ease;
  }
  .release[open] .rstatus::after { transform: translateY(1px) rotate(225deg); }

  .lamp {
    display: inline-block;
    width: 9px; height: 9px;
    border-radius: 50%;
    flex: 0 0 auto;
  }
  .lamp-live  { background: var(--live);  box-shadow: 0 0 10px var(--live); }
  .lamp-beta  { background: var(--beta);  box-shadow: 0 0 10px rgba(255, 200, 87, 0.7); }
  .lamp-inuse { background: var(--inuse); box-shadow: 0 0 10px var(--inuse); }
  .board .release .lamp-live { animation: pulse 2.4s ease-in-out infinite; }

  .rbody {
    padding: 0 18px 18px calc(18px + 14px + 14px);   /* lines up under the name */
    animation: open .22s ease both;
  }
  @keyframes open { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
  .rbody p { margin: 0 0 12px; max-width: 68ch; font-size: 14.5px; line-height: 1.6; color: var(--text); }

  .chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 14px; padding: 0; list-style: none; }
  .chips li {
    font-size: 12px;
    color: var(--cyan);
    background: rgba(74, 240, 255, 0.07);
    border: 1px solid var(--line);
    border-radius: 6px;
    padding: 3px 8px;
  }

  .actions { display: flex; gap: 10px; flex-wrap: wrap; }
  .btn {
    display: inline-block;
    padding: 10px 16px;
    border-radius: 10px;
    font-size: 13.5px;
    font-weight: 650;
    text-decoration: none;
    white-space: nowrap;
    transition: transform .12s, filter .18s, border-color .18s, color .18s;
  }
  .btn.primary { color: #04111a; background: linear-gradient(100deg, var(--cyan), var(--violet)); }
  .btn.primary:hover { transform: translateY(-1px); filter: brightness(1.07); }
  .btn.ghost { color: var(--text); background: rgba(4, 7, 16, 0.65); border: 1px solid var(--line); }
  .btn.ghost:hover { border-color: var(--cyan); color: var(--cyan); }
  .btn:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }

  /* ---- How it's built ---------------------------------------------------------------------------------------- */
  .how { margin: 48px 0 0; padding-top: 16px; border-top: 1px solid var(--line); }
  .how-cols { display: grid; grid-template-columns: repeat(3, 1fr); gap: 26px; margin-top: 16px; }
  .how h3 { margin: 0 0 6px; font-size: 15.5px; font-weight: 700; color: #fff; }
  .how p { margin: 0; font-size: 14px; line-height: 1.6; color: var(--muted); }
  /* "How the apps are tested" (owner 2026-10-27): a full-width part under the three columns */
  .how-tested { margin-top: 28px; }
  .how-tested p { margin-bottom: 10px; }
  .how-tested ul { margin: 0; padding: 0 0 0 18px; display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px 28px; }
  .how-tested li { font-size: 14px; line-height: 1.55; color: var(--muted); }
  .how-tested li b { color: #fff; font-weight: 600; }

  /* ---- Contact: the form keeps its narrow card -------------------------------------------------------------- */
  #contact { max-width: 640px; margin: 52px auto 0; scroll-margin-top: 24px; }
  #releases, #how { scroll-margin-top: 24px; }
  .contact-title { margin: 0 0 16px; font-size: 19px; font-weight: 700; color: #fff; text-align: center; }   /* owner 2026-10-25: centred */

  @media (max-width: 760px) {
    /* line 2 (25 packets + "engineered!") is ~11.8em wide: the type follows the width so it always fits (566 px
       overflowed at a fixed 60 px - MEASURED 2026-10-24) */
    .hero-title { font-size: clamp(30px, calc((100vw - 56px) / 12.1), 60px); }
    .how-cols { grid-template-columns: 1fr; gap: 18px; }
    .how-tested ul { grid-template-columns: 1fr; }
    .release summary, .release.preview .summary { grid-template-columns: 12px 1fr auto; gap: 4px 12px; }
    .rtag { grid-column: 2 / 4; grid-row: 2; font-size: 13.5px; }
    .rbody { padding: 0 16px 16px; }
  }
  @media (max-width: 560px) {
    /* 7 packets a row (above): line 2 (7 packets + "engineered!") is now the wider one, ~7.4em */
    .hero-title { font-size: clamp(30px, calc((100vw - 44px) / 7.6), 52px); }
    .nav { gap: 14px; }
    .top { flex-wrap: wrap; row-gap: 12px; }
    .board-legend { display: none; }
  }
  @media (prefers-reduced-motion: reduce) {
    .board, .rbody, .board .release .lamp-live { animation: none; }
    .release, .rstatus::after, .btn { transition: none; }
  }
