/* ============================================================
   saarthm.com home - the rules that belong to this one page

   Everything the homepage draws that no other site draws: the hero command
   bar, the portrait, the winding career path, the Sensify demo, the creed,
   the hobby tiles and the connect strip, plus their phone layouts. The shell
   (topbar, nav, monogram, footer, theme behaviour) lives in tokens.css,
   base.css and components.css, which every saarthm site shares.

   This used to be a 68 KB <style> block inside index.html. It moved out so
   the shared files can become the single source of truth for the shell: as
   long as the homepage kept private shell rules, every other site had to
   guess at them (the gallery publisher restated the topbar for exactly that
   reason). Nothing here changed on the way out; the computed styles of every
   element were dumped before and after and diffed at three widths in both
   themes.

   Loaded after tokens, base and components, so a rule here wins any tie.
   ============================================================ */

/* Email links copy instead of launching a mail client. Hover reveals the
   address itself (there is no point hiding it behind the word "email"), and
   the tooltip is CSS-only so it appears instantly rather than after the ~1s
   the browser waits before showing a native title. .email already shows the
   address, so only the hero one needs it. */
.hero .meta .copy-mail { position: relative; }
.hero .meta .copy-mail::after {
  content: attr(data-copy); position: absolute; top: calc(100% + 8px); right: 0;
  padding: 5px 9px; border-radius: 8px; white-space: nowrap;
  font-family: var(--font-mono); font-size: 11px; letter-spacing: 0; text-transform: none;
  color: var(--ink); background: var(--card-solid, var(--bg));
  border: 1px solid var(--trim); box-shadow: 0 6px 18px var(--shadow);
  opacity: 0; visibility: hidden; transform: translateY(-3px);
  transition: opacity .16s ease, transform .16s ease, visibility .16s;
  pointer-events: none; z-index: 60;
}
.hero .meta .copy-mail:hover::after,
.hero .meta .copy-mail:focus-visible::after { opacity: 1; visibility: visible; transform: translateY(0); }
/* On a desktop the click answers in that same box: the address becomes
   "… copied!" and stays up a moment even if the pointer moves away. */
.hero .meta .copy-mail.is-copied::after {
  content: attr(data-copy) " copied!"; color: var(--head); font-weight: 700;
  opacity: 1; visibility: visible; transform: translateY(0);
}
@media (hover: none) { .hero .meta .copy-mail::after { display: none; } }

/* Copy confirmation. Fixed to the viewport so it reads the same whether you
   clicked the hero link or the one down in Connect. */
.copy-toast {
  position: fixed; left: 50%; bottom: 24px; transform: translate(-50%, 10px);
  z-index: 200; max-width: min(92vw, 460px); text-align: center;
  padding: 11px 16px; border-radius: 12px;
  font-family: var(--font-mono); font-size: 12px; line-height: 1.45;
  color: var(--ink); background: var(--bg);
  border: 1px solid var(--trim); box-shadow: 0 10px 30px var(--shadow);
  opacity: 0; visibility: hidden;
  transition: opacity .2s ease, transform .2s ease, visibility .2s;
}
.copy-toast.show { opacity: 1; visibility: visible; transform: translate(-50%, 0); }
/* On a phone the hero's toast sits just under the contact block it came from
   (the script sets top), centred on the page, instead of at the screen's foot. */
.hero { position: relative; }
.copy-toast.pinned { position: absolute; bottom: auto; width: max-content; transform: translate(-50%, -6px); z-index: 60; }
.copy-toast.pinned.show { transform: translate(-50%, 0); }
.copy-toast b { color: var(--head); font-weight: 700; }
@media (prefers-reduced-motion: reduce) { .copy-toast { transition: opacity .01s; } }
/* When the hover box already said it, the toast is only for screen readers:
   still announced, never drawn. */
.copy-toast.quiet { clip-path: inset(50%); width: 1px; height: 1px; overflow: hidden; padding: 0; border: 0; box-shadow: none; }
/* A phone has no hover box, so the toast is the whole answer: a heavier
   copper frame and a little more room so it is hard to miss. */
@media (hover: none) {
  .copy-toast { border-width: 3px; padding: 14px 20px; font-size: 13px; }
}

/* The homepage runs a little wider than the shared 920px measure: the two
   column hero and the career path want the room. */
.wrap { max-width: 980px; }

/* hero - command bar */
.hero {
  /* The meta block centres against the statement rather than sharing its first
     baseline. The h1 keeps margin:0 and the extra 10px it used to carry moves
     into the section padding, so the headline sits exactly where it did and
     the two columns share a true centre line. */
  display: flex; align-items: center; justify-content: space-between;
  gap: 24px; padding: 62px 0 26px; flex-wrap: wrap;
}
.hero .kicker { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .16em; text-transform: uppercase; color: var(--head); }
/* The size is the kit's --fs-hero now. What is left is this page's own
   measure and rhythm, which the homepage has always set for itself. */
.hero h1 { font-weight: 800; letter-spacing: -.02em; line-height: 1.1; margin: 0; max-width: 24ch; }
/* Two-column grid: labels right-aligned against the gutter, values left-aligned
   off it. Right-aligning the whole block left BOTH inner edges ragged - the
   label→value boundary zigzagged because the labels are different lengths -
   which is what read as off-centre. Now that boundary and the start of every
   value each sit on a straight line, and the block still sits flush right. */
.hero .meta { display: grid; grid-template-columns: auto auto; column-gap: 10px;
              justify-content: end; align-items: baseline; margin: 0;
              font-family: var(--font-mono); font-size: 11px; color: var(--tag); line-height: 2; }
.hero .meta dt { color: var(--head); font-weight: 700; text-align: right; }
.hero .meta dd { margin: 0; text-align: left; }
/* Meta links take the same mint-on-copper-underline treatment as the rest of
   the mono labels: readable text colour, copper kept to the rule beneath it. */
.hero .meta a { color: inherit; text-decoration: underline;
                text-decoration-color: var(--trim); text-decoration-thickness: 2px;
                text-underline-offset: 3px; transition: color .2s ease; }
.hero .meta a:hover, .hero .meta a:focus-visible { color: var(--head); }

/* about - portrait beside the bio */
.about { display: grid; grid-template-columns: 250px 1fr; gap: 30px; align-items: end; }
/* the fade lives on the wrapper so it takes the outline with it */
.portrait { position: relative; display: block;
            -webkit-mask-image: linear-gradient(to bottom, #000 76%, transparent 99%);
                    mask-image: linear-gradient(to bottom, #000 76%, transparent 99%); }
.portrait img { position: relative; width: 100%; height: auto; display: block; }
/* offset silhouette: a pre-rendered alpha ring, tinted live so it follows the theme */
.portrait .ring { position: absolute; inset: 0; pointer-events: none; background: var(--trim);
                  -webkit-mask: url(portrait-ring.png) center / 100% 100% no-repeat;
                          mask: url(portrait-ring.png) center / 100% 100% no-repeat;
                  transition: background-color var(--transition); }
.about-text { padding-bottom: 4px; }
.bio { font-size: 15px; color: var(--tag); line-height: 1.72; max-width: 58ch;
       transition: color var(--transition); }
.bio strong { color: var(--ink); font-weight: 600; }
.stats3 { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 20px;
          align-items: stretch; }
.stat-stack { display: flex; flex-direction: column; gap: 10px; }
.stat-stack .stat { flex: 1; justify-content: center; }

/* Every grant linked individually, plus the Justia inventor page, which lists
   all five under the correct spelling. Google Patents' own inventor search is
   incomplete (one assignment record misspells the surname), so a reader who
   wants to check the number gets a direct route rather than a bad search. */
/* Five numbers on their own said nothing, and the plain-English titles lived
   in `title=` attributes, which a phone never shows. The grants are grouped
   under what they actually cover instead: three subjects, five numbers, newest
   first. */
.patlinks { display: grid; gap: 9px; margin-top: 13px; }
.patgrp-name { font-size: 11.5px; line-height: 1.4; color: var(--head); font-weight: 600; }
.patgrp-ids { display: flex; flex-wrap: wrap; justify-content: center; gap: 4px; margin-top: 4px; }
.patlinks a { display: inline-flex; align-items: center; gap: 3px;
              font-family: var(--font-mono); font-size: 9.5px; letter-spacing: .02em;
              color: var(--pill-fg); background: var(--pill-bg);
              border: 1px solid var(--pill-b); border-radius: 999px;
              padding: 4px 7px; text-decoration: none; white-space: nowrap;
              transition: color .2s ease, border-color .2s ease, background-color var(--transition); }
.patlinks a:hover, .patlinks a:focus-visible { color: var(--head); border-color: var(--head); }
.patlinks .yr-tag { color: var(--tag); }
.patlinks a:hover .yr-tag, .patlinks a:focus-visible .yr-tag { color: inherit; }
.patlinks .ext { opacity: .6; font-size: 9px; }
/* The count itself links to the Justia inventor page: one destination showing
   all five under the correct spelling, instead of a sixth chip that read like
   a sixth patent. */
.stat-pat .pat-label { color: var(--head); text-decoration: underline;
                       text-decoration-color: var(--trim); text-decoration-thickness: 2px;
                       text-underline-offset: 2px; transition: color .2s ease; }
.stat-pat .pat-label:hover, .stat-pat .pat-label:focus-visible { color: var(--ink); }
/* Dim the arrow with COLOUR, not opacity. `opacity` on a child fades that
   child's whole painted box - including the stretch of the link's underline
   that runs beneath it - which left the tail of the rule visibly lighter than
   the rest. Setting colour only touches the glyph; the rule stays solid. */
.stat-pat .pat-label .ext { color: var(--tag); font-size: 9px; }
.stat-pat .more { color: var(--head); }
.stat { display: flex; flex-direction: column; justify-content: flex-start;
        background: var(--card); border: 1px solid var(--card-edge);
        border-top: 2px solid var(--card-top); border-radius: 12px; padding: 14px; text-align: center; }
.stat b { display: block; font-size: 19px; color: var(--head); }
.stat span { font-family: var(--font-mono); font-size: 9.5px; text-transform: uppercase; letter-spacing: .08em; color: var(--tag); }

/* work hard - the winding path, drawn from the story's own geometry */
.journey { position: relative; padding-left: 424px; margin-top: 8px; }
.journey-rail { position: absolute; left: 0; top: 0; width: 384px; height: 100%; pointer-events: none;
                opacity: 0; transition: opacity .3s ease; }
.journey-rail.ready { opacity: 1; }
.journey-rail svg { width: 100%; height: 100%; display: block; overflow: visible; }

.jp-track { fill: none; stroke: var(--rule); stroke-width: 5; stroke-linecap: round;
            stroke-linejoin: round; shape-rendering: geometricPrecision; }
.jp-ink   { fill: none; stroke: var(--trim); stroke-width: 5; stroke-linecap: round;
            stroke-linejoin: round; shape-rendering: geometricPrecision;
            transition: stroke-dashoffset .6s var(--ease); }
.jp-head  { fill: none; stroke: var(--trim); stroke-width: 5;
            stroke-linecap: round; stroke-linejoin: round; }
.jp-lead circle { fill: var(--rule); }

.jp-node circle { fill: var(--rule); transition: fill .4s ease, r .4s var(--ease); }
.jp-node text { font-family: var(--font-mono); font-size: 12.5px; font-weight: 700;
                fill: var(--tag); transition: fill .4s ease; }
.jp-node.done circle { fill: var(--trim); }
.jp-node.done text { fill: var(--head); }
.jp-node.on circle { fill: var(--trim); }
.jp-node.on text { fill: var(--head); }

/* the story column - no dimming; the node beside it does the pointing */
.chapter { padding: 24px 0; }
/* the factual line leads at display size; the thematic line is the mono kicker */
/* The same size as a creed heading (15px). It used to be a 24 to 32px display
   line, which made the timeline the loudest section on the page and the years
   read like billboards beside the principles' modest headings. */
/* The copper underline marks the year line, the one thing every chapter has;
   the tagline under it is plain mono. */
.chapter .yr { display: block; margin: 0; font-family: var(--font); font-size: 15px;
               font-weight: 700; color: var(--head); letter-spacing: 0; line-height: 1.35;
               text-transform: none;
               text-decoration: underline; text-decoration-color: var(--trim);
               text-decoration-thickness: 2px; text-underline-offset: 3px; }
.chapter .tagline { font-family: var(--font-mono); font-size: 12px; font-weight: 700;
              letter-spacing: .12em; text-transform: uppercase; color: var(--head);
              margin: 6px 0 12px; line-height: 1.4; }
.chapter p { font-size: 14px; color: var(--tag); line-height: 1.72; max-width: 54ch; }
.chapter p + p { margin-top: 12px; }
/* a chapter whose heading says it all carries no tagline; the story still
   needs the air the tagline used to give it */
.chapter .yr + p { margin-top: 6px; }
/* the 2025 entry points back up at the demo, which now sits above the timeline */
.chapter .jump a { font-family: var(--font-mono); font-size: 11px; letter-spacing: .06em;
                   text-transform: uppercase; color: var(--head); text-decoration: underline;
                   text-decoration-color: var(--trim); text-decoration-thickness: 2px;
                   text-underline-offset: 3px; transition: color .2s ease; }
.chapter .jump a:hover, .chapter .jump a:focus-visible { color: var(--ink); }
.chapter p strong { color: var(--ink); font-weight: 600; }
.chapter ul { list-style: none; margin-top: 13px; max-width: 54ch; }
.chapter li { position: relative; font-size: 13.5px; color: var(--tag); line-height: 1.62;
              padding-left: 17px; margin-top: 8px; }
.chapter li::before { content: ""; position: absolute; left: 0; top: 10px;
                      width: 7px; height: 2px; background: var(--trim); }
.chapter li strong { color: var(--head); font-weight: 700; }

@media (prefers-reduced-motion: reduce) {
  .jp-ink, .jp-node circle, .jp-node text, .journey-rail { transition: none; }
}


/* ---- sensify demo ------------------------------------------------- */
.sensify { max-width: 54ch; }
/* As its own section on a wide screen, a 54ch column left the right-hand 40%
   of the page empty. The copy and the demo sit side by side instead, centred
   on each other; below 760px they stack as before. */
@media (min-width: 761px) {
  .sensify { max-width: none; display: grid; grid-template-columns: 1fr 1fr; gap: 36px; align-items: center; }
  .sensify .demo { margin-top: 0; }
}
.sf-lede { font-size: 14px; color: var(--tag); line-height: 1.72; }
.sf-lede + .sf-lede { margin-top: 11px; }
.sf-lede strong { color: var(--ink); font-weight: 600; }

.demo { position: relative; margin-top: 20px; border: 1px solid var(--card-edge);
        border-radius: var(--radius); background: var(--card); overflow: hidden;
        transition: background-color var(--transition), border-color var(--transition); }
.demo svg { display: block; width: 100%; height: auto; touch-action: pan-y; }
.tm { position: relative; }
.tm::after { content: "\2122"; font-size: .58em; vertical-align: .55em; margin-left: .5px; }
.sf-claim { margin-top: 13px; font-size: 14px; font-weight: 600; color: var(--head);
            line-height: 1.6; transition: color var(--transition); }

/* two hints, cross-faded - the second narrates the detection */
.sf-hint { position: absolute; left: 14px; right: 14px; bottom: 14px; margin: 0;
           text-align: center; font-family: var(--font-mono); font-size: 10px;
           letter-spacing: .07em; line-height: 1.55; text-transform: uppercase;
           pointer-events: none; transition: opacity .45s ease; }
.sf-hint.idle { color: var(--tag); opacity: .75; }
.sf-hint.live { color: var(--head); opacity: 0; font-weight: 700;
               text-decoration: underline; text-decoration-color: var(--trim);
               text-decoration-thickness: 2px; text-underline-offset: 2px; }
/* a finger has no cursor: the hint asks for a tap instead. The demo script
   sets is-touch from the pointer actually in use. */
.sf-touch { display: none; }
.demo.is-touch .sf-mouse { display: none; }
.demo.is-touch .sf-touch { display: inline; }
/* The "detected" line follows the traffic (.hot), not the lights (.awake).
   The lights hold for a few seconds after someone leaves; the line used to
   hold with them, claiming a detection over traffic that had already gone
   quiet. */
.demo.hot .sf-hint.idle { opacity: 0; }
.demo.hot .sf-hint.live { opacity: 1; }

/* the signal marks - one unit arc, scaled and rotated per packet */
.sig { fill: none; stroke: var(--tag); stroke-linecap: round; stroke-linejoin: round;
       vector-effect: non-scaling-stroke; transition: stroke .45s ease; }
.demo.hot .sig { stroke: var(--trim); }

.bulb { color: var(--tag); --fil: var(--rule);
        transition: color .55s ease; }
.bulb.on { color: var(--head); --fil: var(--trim); }
.bulb .b-glow { opacity: 0; transition: opacity .7s ease; }
.bulb.on .b-glow { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .sig { transition: none; }
}

/* how i manage - the creed */
.work-sub { font-size: 20px; font-weight: 700; color: var(--head); margin: 6px 0 2px 0; }
.creed { list-style: none; margin-top: 8px; }
.creed li { display: grid; grid-template-columns: 30px 1fr; gap: 12px; padding: 18px 0; border-bottom: 1px solid var(--rule); }
.creed .n { font-family: var(--font-mono); font-size: 11px; color: var(--head); padding-top: 5px; letter-spacing: .08em;
            text-decoration: underline; text-decoration-color: var(--trim);
            text-decoration-thickness: 2px; text-underline-offset: 2px; }
.creed h3 { font-size: 15px; font-weight: 700; color: var(--head); margin-bottom: 5px; }
/* The same measure as the timeline and the sensify copy (14px on 1.72). The
   creed used to run at 12.5px on 1.55, which read as a tighter, smaller page
   inside the page. */
.creed p { font-size: 14px; color: var(--tag); line-height: 1.72; }
/* one line per principle, in the same ink the bio uses for its own */
.creed p strong { color: var(--ink); font-weight: 600; }

/* play hard - tiles */
.tiles { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; align-items: stretch; }
.tile { display: flex; flex-direction: column; align-items: center; text-align: center; background: var(--card); border: 1px solid var(--card-edge); border-top: 3px solid var(--card-top); border-radius: 14px; padding: 20px; text-decoration: none; transition: transform .12s ease, box-shadow .2s ease; }
a.tile:hover { transform: translateY(-2px); box-shadow: 0 8px 20px var(--shadow); }
.tile .name { margin: 0; font-size: 16px; font-weight: 700; color: var(--head); }
/* A tile with nowhere to go yet (the galleries the panel has not published):
   no lift on hover, and its foot says so. */
.tile-still { cursor: default; }
.tile-still:hover { transform: none; box-shadow: none; }
.tile .tile-head { display: flex; flex-direction: column; align-items: center; gap: 8px; margin-bottom: 4px; }
.tile .tile-icon { color: var(--trim); flex: none; pointer-events: none; }
.tile-icon svg, .tile-icon { width: 48px; height: 48px; display: block; }
.tile p { font-size: 12.5px; color: var(--tag); margin-top: 6px; line-height: 1.55;
           text-align: left; align-self: stretch; }
.tile .tile-link { font-family: var(--font-mono); font-size: 11px; color: var(--head); margin-top: auto; padding-top: 14px; text-align: center;
                   text-decoration: underline; text-decoration-color: var(--trim);
                   text-decoration-thickness: 2px; text-underline-offset: 2px; }

/* connect - strip */
.connect { display: flex; align-items: center; justify-content: space-between; gap: 16px; border: 1px solid var(--card-edge); border-radius: 14px; background: var(--card); padding: 20px 22px; flex-wrap: wrap; }
.connect .email { font-size: clamp(15px, 2.1vw, 20px); font-weight: 800; color: var(--head); text-decoration: none; }
.connect .note { font-family: var(--font-mono); font-size: 10.5px; color: var(--tag); }
.socials { display: flex; gap: 8px; flex-wrap: wrap; }
.socials a { font-family: var(--font-mono); font-size: 10.5px; border: 1px solid var(--card-edge); background: var(--bg); color: var(--tag); border-radius: 999px; padding: 6px 13px; text-decoration: none; }
.socials a:hover { color: var(--head); border-color: var(--head); }

@media (max-width: 1040px) {
  .journey { padding-left: 300px; }
  .journey-rail { width: 268px; }
}
@media (max-width: 900px) {
  .tiles { grid-template-columns: 1fr 1fr; }
  .about { grid-template-columns: 200px 1fr; gap: 22px; }
}

/* mobile - the serpentine straightens into a simple left rail */
@media (max-width: 760px) {
  .about { grid-template-columns: 1fr; gap: 16px; align-items: start; }
  .portrait { max-width: 215px; margin-inline: auto; }
  .stats3 { grid-template-columns: 1fr; }
  .stat-stack { flex-direction: row; }
  .tiles { grid-template-columns: 1fr; }
  /* one column on a phone, so the statement, the meta block and the portrait
     all sit on the centre line rather than hugging the left edge */
  .hero { justify-content: center; }
  .hero h1 { text-align: center; }
  .hero .meta { justify-content: center; }

  .journey { padding-left: 0; }
  .journey-rail { display: none; }
  .chapter { padding: 0 0 0 26px; margin-bottom: 30px; position: relative;
             border-left: 2px solid var(--rule); }
  .chapter::before { content: ""; position: absolute; left: -7px; top: 4px; width: 12px; height: 12px;
                     border-radius: 50%; background: var(--trim); }
  .chapter:last-child { border-left-color: transparent; }

  /* sensify demo - extra bottom space so the hint text clears the bulbs */
  .demo { padding-bottom: 56px; }
}
