/* ============================================================
   andrewryan.consulting — design system

   Same-origin only. Fonts are served from /assets/fonts/, images from
   /assets/demos/. Nothing is fetched from a third party, because the
   site's central claim is that nothing leaves your environment and a
   visitor with the network tab open has to see that hold.

   The palette is taken from the work: each dashboard already has a
   strong identity colour, and those seven colours are the site's colour
   system. Nothing else on the web has this palette, because nothing
   else has these seven dashboards.
   ============================================================ */

/* ---------- type ---------- */
@font-face{font-family:'Geist';font-style:normal;font-weight:400 700;font-display:swap;
  src:url(fonts/Geist-400.woff2) format('woff2')}
@font-face{font-family:'Instrument Serif';font-style:normal;font-weight:400;font-display:swap;
  src:url(fonts/Instrument-Serif-400.woff2) format('woff2')}
@font-face{font-family:'Instrument Serif';font-style:italic;font-weight:400;font-display:swap;
  src:url(fonts/Instrument-Serif-400-italic.woff2) format('woff2')}

:root{
  /* --- surfaces: warm off-white, so the light dashboards sit naturally --- */
  --paper:#fbfaf7;
  --paper-2:#f4f1ea;
  --card:#ffffff;
  --night:#14120f;
  --night-2:#1f1c18;

  /* --- ink --- */
  --ink:#141210;
  --ink-2:#544e46;
  --ink-3:#8a8279;
  --line:#e7e2d8;
  --line-2:#f0ece4;
  --on-night:#f7f5f1;
  --on-night-2:#a9a29a;

  /* --- the seven, straight from the dashboards ---
     `-fill` is the true brand colour. `-ink` is a contrast-safe variant for
     text on paper, needed because amber and mint fail on white. */
  --aviation:#e05d17;      --aviation-ink:#c04d10;
  --warehouse:#0d9488;     --warehouse-ink:#0b7a70;
  --fieldservice:#f2a413;  --fieldservice-ink:#9a6600;
  --ecom:#e11d74;          --ecom-ink:#c2185f;
  --proservices:#7b2d3b;   --proservices-ink:#7b2d3b;
  --construction:#c9820a;  --construction-ink:#996100;
  --aquaculture:#7fd4b8;   --aquaculture-ink:#0d7a63;

  /* accent hooks — a section sets these once and everything inside follows */
  --accent:var(--ink);
  --accent-ink:var(--ink);

  /* --- fluid type scale --- */
  --t-display:clamp(2.9rem,7.4vw,6.4rem);
  --t-h1:clamp(2.3rem,5vw,4rem);
  --t-h2:clamp(1.75rem,3.2vw,2.75rem);
  --t-h3:clamp(1.2rem,1.7vw,1.5rem);
  --t-lead:clamp(1.1rem,1.5vw,1.4rem);
  --t-body:1.0625rem;
  --t-small:0.9375rem;
  --t-label:0.75rem;

  /* --- rhythm --- */
  --s-1:.5rem;  --s-2:1rem;   --s-3:1.5rem; --s-4:2rem;
  --s-5:3rem;   --s-6:4.5rem; --s-7:7rem;
  --section:clamp(4.5rem,11vh,9rem);
  --page-max:1240px;
  --measure:66ch;

  --r-sm:8px; --r-md:14px; --r-lg:22px; --r-xl:30px;

  --shadow-sm:0 1px 2px rgba(20,18,16,.05),0 2px 8px -4px rgba(20,18,16,.08);
  --shadow-md:0 2px 6px rgba(20,18,16,.05),0 18px 40px -22px rgba(20,18,16,.35);
  --shadow-lg:0 4px 12px rgba(20,18,16,.06),0 40px 80px -40px rgba(20,18,16,.45);

  --dur:.6s; --dur-fast:.22s;
  --ease:cubic-bezier(.22,.61,.36,1);
  --ease-out:cubic-bezier(.16,1,.3,1);
}

/* ---------- reset ---------- */
*{box-sizing:border-box;margin:0;padding:0}
/* `clip` rather than `hidden`: the accent glow behind each screenshot extends
   past its box by design, and hidden on html/body would either leave a
   horizontal scrollbar or kill position:sticky on the nav. clip does neither. */
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth;overflow-x:clip;
  /* anchor targets clear the sticky nav instead of landing under it */
  scroll-padding-top:88px}
body{
  background:var(--paper);color:var(--ink);
  font-family:'Geist',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
  font-size:var(--t-body);line-height:1.6;
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;
  font-feature-settings:"cv11","ss01";
  overflow-x:clip;
}
img{max-width:100%;height:auto;display:block}
a{color:inherit}
::selection{background:var(--ink);color:var(--paper)}

/* native cross-document page transitions — ignored where unsupported */
@view-transition{navigation:auto}

/* ---------- layout ---------- */
.wrap{width:100%;max-width:var(--page-max);margin-inline:auto;padding-inline:clamp(1.25rem,4vw,2.5rem)}
.wrap-narrow{max-width:760px}
.section{padding-block:var(--section)}
.band{background:var(--paper-2)}
.band-dark{background:var(--night);color:var(--on-night)}
.band-dark h2,.band-dark h3{color:var(--on-night)}

.skip{position:absolute;left:-9999px;top:0;background:var(--ink);color:var(--paper);
  padding:.75rem 1.25rem;z-index:100;border-radius:0 0 var(--r-sm) 0}
.skip:focus{left:0}

:focus-visible{outline:2px solid var(--accent-ink);outline-offset:3px;border-radius:2px}

/* ---------- type ---------- */
h1,h2,h3,h4{line-height:1.05;letter-spacing:-.022em;font-weight:600;text-wrap:balance}
.display{font-size:var(--t-display);line-height:.98;letter-spacing:-.035em;font-weight:600}
h1{font-size:var(--t-h1)}
h2{font-size:var(--t-h2)}
h3{font-size:var(--t-h3);letter-spacing:-.015em}

/* the serif carries the human register a grotesk can't */
.serif{font-family:'Instrument Serif',Georgia,serif;font-weight:400;letter-spacing:-.01em}
.serif-i{font-family:'Instrument Serif',Georgia,serif;font-style:italic;font-weight:400}

.lead{font-size:var(--t-lead);line-height:1.5;color:var(--ink-2);max-width:52ch;text-wrap:pretty}
.label{font-size:var(--t-label);letter-spacing:.14em;text-transform:uppercase;
  font-weight:500;color:var(--ink-3)}
.muted{color:var(--ink-2)}
.tnum{font-variant-numeric:tabular-nums}

/* ---------- buttons ---------- */
.btn{display:inline-flex;align-items:center;gap:.55em;padding:.85em 1.5em;border-radius:100px;
  background:var(--ink);color:var(--paper);text-decoration:none;font-weight:500;font-size:var(--t-small);
  border:1px solid var(--ink);white-space:nowrap;
  transition:transform var(--dur-fast) var(--ease),box-shadow var(--dur-fast) var(--ease),
             background var(--dur-fast) var(--ease)}
.btn:hover{transform:translateY(-2px);box-shadow:0 10px 24px -10px rgba(20,18,16,.5)}
.btn:active{transform:translateY(0)}
.btn .arw{transition:transform var(--dur-fast) var(--ease)}
.btn:hover .arw{transform:translateX(3px)}
.btn-ghost{background:transparent;color:var(--ink);border-color:var(--line)}
.btn-ghost:hover{border-color:var(--ink);box-shadow:none}
/* Anything on a dark ground inverts the button, or it renders black-on-black. */
.band-dark .btn,.cta .btn,.proof .btn{background:var(--on-night);color:var(--night);
  border-color:var(--on-night)}
.band-dark .btn:hover,.cta .btn:hover,.proof .btn:hover{box-shadow:0 10px 26px -10px rgba(0,0,0,.7)}
.band-dark .btn-ghost,.cta .btn-ghost,.proof .btn-ghost{background:transparent;
  color:var(--on-night);border-color:#3a352e}
.band-dark .btn-ghost:hover,.cta .btn-ghost:hover,.proof .btn-ghost:hover{border-color:var(--on-night)}

/* a text link that reads as a link without shouting */
.tlink{text-decoration:none;background-image:linear-gradient(currentColor,currentColor);
  background-size:100% 1px;background-repeat:no-repeat;background-position:0 100%;
  padding-bottom:1px;transition:background-size var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease)}
.tlink:hover{color:var(--accent-ink);background-size:0% 1px}

/* ---------- nav ---------- */
.nav{position:sticky;top:0;z-index:50;background:color-mix(in srgb,var(--paper) 82%,transparent);
  backdrop-filter:saturate(1.4) blur(14px);-webkit-backdrop-filter:saturate(1.4) blur(14px);
  border-bottom:1px solid transparent;transition:border-color var(--dur-fast) var(--ease)}
.nav-in{display:flex;align-items:center;gap:var(--s-3);
  min-height:68px;padding-block:.75rem}
.brand{display:flex;align-items:center;gap:.6rem;text-decoration:none;font-weight:600;
  letter-spacing:-.02em;font-size:1rem;margin-right:auto;white-space:nowrap}
.brand .dot{width:11px;height:11px;border-radius:50%;background:var(--aviation);flex:none;
  transition:background var(--dur) var(--ease)}
.nav-links{display:flex;align-items:center;gap:clamp(1rem,2.4vw,2rem);
  font-size:var(--t-small);color:var(--ink-2);white-space:nowrap}
.nav-links a{text-decoration:none;transition:color var(--dur-fast) var(--ease)}
.nav-links a:hover,.nav-links a[aria-current="page"]{color:var(--ink)}

/* ---------- hero ---------- */
.hero{padding-block:clamp(3.5rem,9vh,7rem) clamp(2rem,5vh,3.5rem)}
.hero .display{max-width:15ch}
.hero .lead{margin-top:var(--s-3)}
.hero-actions{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s-2) var(--s-3);
  margin-top:var(--s-4)}
.hero-note{font-size:var(--t-small);color:var(--ink-3)}

/* ---------- inner-page header ----------
   Deliberately quieter than the homepage hero. These pages are read, not
   scrolled through, and /security/ is also the source for the PDF. */
.page-head{padding-block:clamp(2.5rem,7vh,4.5rem) clamp(1.5rem,4vh,2.25rem);
  border-bottom:1px solid var(--line);margin-bottom:var(--s-5)}
.page-head h1{margin:.7rem 0 .9rem;max-width:17ch}
.page-head .lead{max-width:56ch}

/* ---------- the showcase: one dashboard per section ---------- */
.shot{border-radius:var(--r-lg);overflow:hidden;background:var(--card);
  border:1px solid var(--line);box-shadow:var(--shadow-lg);
  transition:transform var(--dur) var(--ease-out),box-shadow var(--dur) var(--ease-out)}
.shot img{width:100%;display:block}

/* the hero image deliberately breaks the fold to invite the scroll */
.hero-shot{margin-top:clamp(2rem,5vh,3.5rem);max-height:min(62vh,620px);overflow:hidden;
  border-radius:var(--r-xl) var(--r-xl) 0 0;border-bottom:0}
.hero-shot img{object-fit:cover;object-position:top center}

.case{padding-block:clamp(3.5rem,8vh,6.5rem);position:relative}
.case + .case{border-top:1px solid var(--line-2)}
.case-in{display:grid;gap:clamp(1.75rem,4vw,3.5rem);align-items:center;
  grid-template-columns:minmax(0,1fr)}
@media(min-width:900px){
  /* Media gets the wider track. On alternating rows the *columns* have to swap
     too — reordering the content alone would drop the image into the narrow
     track and render every other screenshot smaller. */
  .case-in{grid-template-columns:minmax(0,.86fr) minmax(0,1.14fr)}
  .case:nth-of-type(even) .case-in{grid-template-columns:minmax(0,1.14fr) minmax(0,.86fr)}
  .case:nth-of-type(even) .case-copy{order:2}
  .case:nth-of-type(even) .case-media{order:1}
}
.case-copy{max-width:44ch}
.case-n{display:flex;align-items:baseline;gap:.7rem;margin-bottom:var(--s-2)}
.case-n b{font-size:var(--t-label);letter-spacing:.14em;font-weight:600;color:var(--accent-ink)}
.case-n span{font-size:var(--t-label);letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3)}
.case h2{margin-bottom:.6rem}
.case h2 em{font-family:'Instrument Serif',Georgia,serif;font-style:italic;font-weight:400;
  letter-spacing:-.01em;color:var(--accent-ink)}
.case p{color:var(--ink-2);max-width:42ch}
.case-metrics{margin-top:var(--s-3);display:flex;flex-wrap:wrap;gap:.4rem}
.chip{font-size:.8125rem;color:var(--ink-2);background:var(--card);border:1px solid var(--line);
  border-radius:100px;padding:.3rem .75rem;white-space:nowrap}
.case-cta{margin-top:var(--s-3);display:inline-flex;align-items:center;gap:.5em;
  text-decoration:none;font-weight:500;color:var(--accent-ink);font-size:var(--t-small)}
.case-cta .arw{transition:transform var(--dur-fast) var(--ease)}
.case-media{position:relative}
/* a soft wash of the demo's own colour behind its screenshot */
.case-media::before{content:"";position:absolute;inset:-10% -8% -14%;border-radius:50%;
  background:radial-gradient(closest-side,color-mix(in srgb,var(--accent) 42%,transparent),transparent 70%);
  filter:blur(52px);z-index:0;opacity:.9;pointer-events:none}
.case-media .shot{position:relative;z-index:1}
.case-media a:hover .shot{transform:translateY(-6px) scale(1.006);box-shadow:0 8px 20px rgba(20,18,16,.07),0 56px 100px -50px rgba(20,18,16,.5)}
.case-media a{display:block;text-decoration:none}

/* ---------- proof / dark moment ---------- */
.proof{background:var(--night);color:var(--on-night);border-radius:var(--r-xl);
  padding:clamp(2rem,5vw,4rem);margin-block:var(--s-4)}
.proof .lead{color:var(--on-night-2);max-width:46ch}
.proof-grid{display:grid;gap:var(--s-3);margin-top:var(--s-4);
  grid-template-columns:repeat(auto-fit,minmax(210px,1fr))}
.proof-item{border-top:1px solid #322d27;padding-top:var(--s-2)}
.proof-item b{display:block;font-weight:500;margin-bottom:.2rem}
.proof-item span{color:var(--on-night-2);font-size:var(--t-small)}
.testme{border:1px solid #322d27;border-radius:var(--r-md);padding:var(--s-3);
  margin-top:var(--s-4);background:var(--night-2)}
.testme .label{color:var(--aviation)}
/* Lighter than --on-night-2: on the security page this is a standalone dark
   card in a document people actually read, not a caption on a dark band. */
.testme p{color:#cbc4bb;margin-top:.5rem;max-width:60ch}
.testme b{color:#fff}

/* ---------- bio ---------- */
.bio{display:grid;gap:clamp(1.5rem,4vw,3rem);align-items:start;
  grid-template-columns:minmax(0,1fr)}
@media(min-width:820px){.bio{grid-template-columns:260px minmax(0,1fr)}}
.portrait{width:100%;max-width:260px;aspect-ratio:4/5;border-radius:var(--r-lg);
  object-fit:cover;background:var(--paper-2);border:1px solid var(--line)}
.bio p + p{margin-top:var(--s-2)}
.bio p{color:var(--ink-2);max-width:var(--measure)}

/* ---------- FAQ ---------- */
.faq{margin-top:var(--s-4);border-top:1px solid var(--line)}
.faq details{border-bottom:1px solid var(--line)}
.faq summary{cursor:pointer;list-style:none;padding:var(--s-3) 0;font-size:var(--t-h3);
  font-weight:500;letter-spacing:-.015em;display:flex;gap:var(--s-3);align-items:baseline;
  justify-content:space-between;transition:color var(--dur-fast) var(--ease)}
.faq summary::-webkit-details-marker{display:none}
.faq summary:hover{color:var(--aviation-ink)}
.faq summary .pm{flex:none;width:1em;text-align:center;color:var(--ink-3);font-weight:400}
.faq details[open] summary .pm{transform:rotate(45deg)}
.faq .pm{display:inline-block;transition:transform var(--dur-fast) var(--ease)}
.faq .a{padding-bottom:var(--s-3);max-width:var(--measure);color:var(--ink-2)}
.faq .a p + p{margin-top:var(--s-2)}
.faq .a ul{margin:var(--s-2) 0 0 1.1rem}
.faq .a li{margin:.35rem 0}

/* ---------- prose (inner pages stay document-like) ---------- */
.prose h2{font-size:clamp(1.5rem,2.4vw,2.1rem);margin:var(--s-6) 0 var(--s-2);
  padding-top:var(--s-3);border-top:1px solid var(--line)}
.prose h2:first-child{margin-top:0;padding-top:0;border-top:0}
.prose h3{margin:var(--s-4) 0 .4rem}
.prose p{margin:var(--s-2) 0;max-width:var(--measure);color:var(--ink-2)}
.prose > p:first-of-type{color:var(--ink)}
.prose ul,.prose ol{margin:var(--s-2) 0 var(--s-2) 1.2rem;max-width:var(--measure);color:var(--ink-2)}
.prose li{margin:.4rem 0}
.prose li::marker{color:var(--ink-3)}
.prose strong{font-weight:600;color:var(--ink)}
.prose a{color:var(--ink);text-decoration:underline;text-underline-offset:3px;
  text-decoration-color:var(--ink-3);transition:text-decoration-color var(--dur-fast) var(--ease)}
.prose a:hover{text-decoration-color:var(--ink)}
.prose code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.88em;
  background:var(--paper-2);border:1px solid var(--line);padding:.1em .4em;border-radius:5px}

.note{background:var(--card);border:1px solid var(--line);border-left:2px solid var(--accent);
  border-radius:0 var(--r-md) var(--r-md) 0;padding:var(--s-3);margin:var(--s-3) 0;max-width:var(--measure)}
.note .label{color:var(--accent-ink);margin-bottom:.4rem;display:block}
.note p{margin-top:0;color:var(--ink-2)}

table.spec{width:100%;border-collapse:collapse;margin:var(--s-3) 0;font-size:var(--t-small)}
table.spec th,table.spec td{text-align:left;vertical-align:top;padding:.7rem .8rem;
  border-bottom:1px solid var(--line)}
table.spec th{font-size:var(--t-label);letter-spacing:.1em;text-transform:uppercase;
  color:var(--ink-3);font-weight:600;background:var(--paper-2)}
table.spec td:first-child{font-weight:500;color:var(--ink);width:30%}
.scroll-x{overflow-x:auto;-webkit-overflow-scrolling:touch}

/* ---------- CTA + footer ---------- */
.cta{background:var(--night);color:var(--on-night);border-radius:var(--r-xl);
  padding:clamp(2rem,5vw,4rem);display:flex;flex-wrap:wrap;gap:var(--s-3) var(--s-5);
  align-items:center;justify-content:space-between}
.cta h2{max-width:18ch}
.cta p{color:var(--on-night-2);max-width:42ch;margin-top:.6rem}

.site-footer{border-top:1px solid var(--line);margin-top:var(--section);
  padding-block:var(--s-5) var(--s-4)}
.foot-grid{display:flex;flex-wrap:wrap;gap:var(--s-4) var(--s-5);justify-content:space-between}
.foot-col{display:flex;flex-direction:column;gap:.45rem;font-size:var(--t-small);color:var(--ink-2)}
.foot-col a{text-decoration:none}
.foot-col a:hover{color:var(--ink)}
.foot-col .label{margin-bottom:.3rem}
.foot-fine{margin-top:var(--s-4);padding-top:var(--s-3);border-top:1px solid var(--line-2);
  font-size:.8125rem;color:var(--ink-3);max-width:var(--measure)}

/* ---------- motion ----------
   Content is visible by default; JS only *adds* the pre-animation state, so a
   browser without IntersectionObserver — or with JS off — shows everything. */
.js-reveal .reveal{opacity:0;transform:translateY(22px)}
.js-reveal .reveal.in{opacity:1;transform:none;
  transition:opacity var(--dur) var(--ease-out),transform var(--dur) var(--ease-out)}
.js-reveal .reveal-d1.in{transition-delay:.08s}
.js-reveal .reveal-d2.in{transition-delay:.16s}
.js-reveal .reveal-d3.in{transition-delay:.24s}

@media(prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;
    transition-duration:.01ms!important;scroll-behavior:auto!important}
  .js-reveal .reveal{opacity:1;transform:none}
  @view-transition{navigation:none}
}

/* ---------- small screens ---------- */
@media(max-width:640px){
  :root{--section:3.5rem}
  .nav-in{min-height:58px;gap:.75rem}
  .brand{font-size:.9375rem}
  .brand .dot{width:9px;height:9px}
  .nav-links{gap:.9rem;font-size:.8125rem}
  /* The nav button is dropped rather than squeezed: at 390px it forces the
     links to wrap into an unusable stack, and the hero's own "Book a call"
     sits immediately below the fold anyway. */
  .nav-links .btn{display:none}
  .hero-shot{max-height:44vh;border-radius:var(--r-lg) var(--r-lg) 0 0}
  .case-copy,.case p{max-width:none}
  /* keep the glow inside the viewport on narrow screens rather than relying
     on the clip alone */
  .case-media::before{inset:-4% 0 -6%;filter:blur(38px)}
  .cta{flex-direction:column;align-items:flex-start;border-radius:var(--r-lg)}
  .proof,.cta{padding:var(--s-4) var(--s-3)}
  .faq summary{font-size:1.0625rem}
  table.spec td:first-child{width:auto}
  .foot-grid{gap:var(--s-3) var(--s-4)}
}

/* ---------- print: /security/ is also the forwardable PDF ---------- */
@media print{
  /* A4, not the Letter default — this PDF gets printed by European IT teams. */
  @page{size:A4;margin:16mm 15mm}
  html{scroll-behavior:auto}
  body{background:#fff;color:#000;font-size:10.5pt;line-height:1.45}
  .nav,.cta,.site-footer .foot-col,.skip,.no-print,.case-media::before{display:none!important}
  .wrap{max-width:none;padding:0}
  .section{padding-block:0}
  h1{font-size:20pt} h2{font-size:13.5pt} h3{font-size:11.5pt}
  .prose h2,.prose h3{page-break-after:avoid;break-after:avoid}
  .prose p,.prose li,.note,.lead{max-width:none}
  .note,.faq details,.testme{page-break-inside:avoid;break-inside:avoid}
  /* Tables may split across pages — forcing a tall one to stay whole pushes it
     to the next page and leaves half a page blank. Rows stay intact and the
     header repeats. */
  table.spec thead{display:table-header-group}
  table.spec tr{page-break-inside:avoid;break-inside:avoid}
  .note{border:1pt solid #999;border-left:3pt solid #000;background:#fafafa}
  .band-dark,.proof{background:#f2f2f2!important;color:#000!important;border:1pt solid #000}
  .proof .lead,.testme p{color:#000}
  .testme{background:#fff;border:1pt solid #666}
  table.spec th{background:#eee}
  .faq details{border:1pt solid #999}
  .faq .a{display:block!important}
  .reveal{opacity:1!important;transform:none!important}
  a{color:#000;text-decoration:none}
  .prose a[href^="http"]::after{content:" (" attr(href) ")";font-size:8.5pt;color:#555}
  .page-head{padding-block:0 8pt;margin-bottom:14pt;border-bottom:2pt solid #000}
}
