/* ==========================================================================
   Power Systems ARTS — site stylesheet
   Hand-written, no build step. Edit this file directly.

   The palette and type here deliberately carry over from the original psarts.gr:
   the deep teal ground, the coral accent and the Volkhov headline face were all
   chosen for the first version of this site, and they are what makes it
   recognisably PS ARTS. What has changed is the execution — readable body text
   in a clean face, one consistent layout across every page, and transmission
   towers added to the background artwork.

   Tokens are named after what they are in the brand, not after their colour, so
   they still read correctly if the colours are ever adjusted:
     tower     the near-black teal of the transmission towers in the logo
     dusk      the deep teal ground the original site used (#166262 / #004044)
     coral     the original accent (#FF7F50)
     mint      the pale highlight inside the logo's disc
     paper     the off-white the reading sections sit on
   ========================================================================== */

:root {
  /* --- brand, carried over from the original site ----------------------- */
  --tower:          #00262A;
  --dusk-deep:      #073A38;
  --dusk:           #0F4F4C;
  --dusk-raised:    #17605C;
  --dusk-rule:      #23706B;

  --coral:          #FF7F50;   /* the original accent, on dark grounds     */
  --coral-lift:     #FFA07A;   /* hover on dark                            */
  --coral-ink:      #A8461B;   /* deepened so it passes contrast on white  */

  --mint:           #90F0D8;
  --mint-lit:       #4FD8C0;
  --mint-wash:      #E4F2EF;

  /* --- neutrals, biased slightly teal so they sit with the brand -------- */
  --paper:          #F4F8F7;
  --card:           #FFFFFF;
  --rule:           #D3E0DD;
  --rule-soft:      #E6EEEC;
  --graphite:       #44605D;
  --graphite-faint: #6D8683;

  /* --- on dark grounds -------------------------------------------------- */
  --on-dark:        #FFFFFF;
  --on-dark-soft:   #C2DBD7;
  --on-dark-faint:  #8EB2AE;

  /* --- type -------------------------------------------------------------
     Volkhov is the headline face from the original site, kept for continuity.
     NOTE: Google serves Volkhov in Latin only — if a Greek version of the site
     is ever built, swap it for "Roboto Slab", which covers Greek and was also
     part of the original site's font set. */
  --display: "Volkhov", Georgia, "Times New Roman", serif;
  --sans:    "Fira Sans", "Segoe UI", system-ui, -apple-system, sans-serif;
  --mono:    "Fira Mono", ui-monospace, "SFMono-Regular", Menlo, monospace;

  /* --- measure ---------------------------------------------------------- */
  --page:    72rem;
  --measure: 40rem;
  --gutter:  1.5rem;
}

/* --------------------------------------------------------------------------
   Base
   -------------------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

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

body {
  margin: 0;
  background: var(--paper);
  color: var(--tower);
  font-family: var(--sans);
  font-size: 1.0625rem;
  line-height: 1.68;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3 {
  font-family: var(--display);
  font-weight: 700;
  letter-spacing: -.012em;
  line-height: 1.2;
  margin: 0;
  text-wrap: balance;
}
h4 { font-family: var(--sans); font-weight: 600; margin: 0; }

p { margin: 0; }

img { max-width: 100%; height: auto; display: block; }

a { color: var(--coral-ink); text-underline-offset: .2em; }
a:hover { color: var(--tower); }

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

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--coral);
  color: var(--tower);
  padding: .7rem 1.1rem;
  z-index: 100;
  font-family: var(--sans);
  font-weight: 600;
  text-decoration: none;
}
.skip:focus { left: 0; }

/* --------------------------------------------------------------------------
   Shared pieces
   -------------------------------------------------------------------------- */

.shell {
  width: 100%;
  max-width: var(--page);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.lede {
  font-size: 1.2rem;
  line-height: 1.62;
  color: var(--graphite);
  max-width: var(--measure);
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  font-family: var(--sans);
  font-size: .95rem;
  font-weight: 600;
  letter-spacing: .005em;
  padding: .74rem 1.4rem;
  border-radius: 2px;
  border: 1px solid transparent;
  text-decoration: none;
  cursor: pointer;
  transition: background-color .16s ease, border-color .16s ease, color .16s ease;
}

/* The primary action, in the original site's coral. */
.btn--solid {
  background: var(--coral);
  color: var(--tower);
  border-color: var(--coral);
}
.btn--solid:hover { background: var(--coral-lift); border-color: var(--coral-lift); color: var(--tower); }

/* Quiet action on a dark ground. */
.btn--ghost-dark {
  background: transparent;
  color: var(--on-dark);
  border-color: var(--dusk-rule);
}
.btn--ghost-dark:hover { border-color: var(--coral); color: var(--coral); }

/* Quiet action on a light ground. */
.btn--ghost {
  background: transparent;
  color: var(--tower);
  border-color: var(--rule);
}
.btn--ghost:hover { border-color: var(--coral-ink); color: var(--coral-ink); }

.btn .arrow { font-family: var(--sans); transition: transform .16s ease; }
.btn:hover .arrow { transform: translateX(3px); }

/* --------------------------------------------------------------------------
   Header — deep teal, as the original site's was
   -------------------------------------------------------------------------- */

.site-header {
  background: var(--dusk-deep);
  border-bottom: 1px solid var(--dusk-rule);
  position: sticky;
  top: 0;
  z-index: 50;
}

.site-header .shell {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  min-height: 5.6rem;
}

.brand { display: flex; align-items: center; text-decoration: none; }
/* Only the height is set and the width follows, so the lockup can never be
   squashed. It is a wide horizontal mark (about 2.74:1), so it needs less
   height than the old stacked logo did to carry the same visual weight. */
.brand img { height: 3.6rem; width: auto; }

.nav-toggle {
  display: none;
  background: none;
  border: 1px solid var(--dusk-rule);
  border-radius: 2px;
  padding: .5rem .8rem;
  font-family: var(--sans);
  font-size: .85rem;
  font-weight: 600;
  color: var(--on-dark);
  cursor: pointer;
  align-items: center;
  gap: .5rem;
}

.nav { display: flex; align-items: center; gap: .25rem; }

.nav a {
  font-family: var(--sans);
  font-size: .93rem;
  font-weight: 500;
  color: var(--on-dark-soft);
  text-decoration: none;
  padding: .5rem .72rem;
  border-radius: 2px;
  white-space: nowrap;
  transition: color .16s ease, background-color .16s ease;
}
.nav a:hover { color: var(--coral); background: rgba(255,127,80,.09); }
.nav a[aria-current="page"] {
  color: var(--on-dark);
  box-shadow: inset 0 -2px 0 var(--coral);
  border-radius: 0;
}
.nav .btn { margin-left: .7rem; }

@media (max-width: 64rem) {
  .nav-toggle { display: inline-flex; }
  .site-header .shell { flex-wrap: wrap; min-height: 4.5rem; }
  .brand img { height: 2.85rem; }
  .nav {
    display: none;
    flex-basis: 100%;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding-bottom: 1rem;
  }
  .nav.is-open { display: flex; }
  .nav a { padding: .85rem .2rem; border-bottom: 1px solid var(--dusk-raised); }
  .nav a[aria-current="page"] { box-shadow: inset 3px 0 0 var(--coral); padding-left: .8rem; }
  .nav .btn { margin: .9rem 0 0; justify-content: center; }
}

/* --------------------------------------------------------------------------
   Hero — deep teal, with the original site's energy silhouette (thermal
   plant, turbines, solar, plus transmission towers) along the bottom and a PV
   nose curve drawn over it.
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  overflow: hidden;
  background:
    linear-gradient(170deg, var(--dusk) 0%, var(--dusk-deep) 62%, var(--tower) 100%);
  color: var(--on-dark);
}

/* The silhouette sits along the bottom edge, well behind everything. On a
   phone it is the whole scene in one image, full width. */
.hero-skyline,
.hero-skyline-plant,
.hero-skyline-grid {
  position: absolute;
  bottom: -1px;
  /* Quiet enough that the turbine masts never fight the headline sitting
     over them, present enough to read as the original site's artwork. */
  opacity: .40;
  z-index: 1;
  pointer-events: none;
  user-select: none;
}
.hero-skyline {
  left: 0;
  right: 0;
  width: 100%;
  height: auto;
  /* Sunk by most of its ground strip (the bottom 12% of the image), leaving a
     thin strip of ground as a base. */
  transform: translateY(9%);
}
.hero-skyline-plant,
.hero-skyline-grid { display: none; }
@media (max-width: 48rem) { .hero-skyline { opacity: .28; } }
/* On a desktop screen the hero is short and wide. Stretched to full width the
   scene was three times taller than the hero and the turbines were cut off.
   So it comes in two pieces sized by the hero's height, with the whole picture
   in view: the thermal plant at the left edge, everything else at the right,
   behind the PV curve. The headline sits on clear ground between them at any
   width. The ground strip is sunk out of sight, as it would break in the gap. */
@media (min-width: 64rem) {
  .hero-skyline { display: none; }
  .hero-skyline-plant,
  .hero-skyline-grid {
    display: block;
    width: auto;
    max-width: none;
    height: 110%;
    transform: translateY(12.5%);
  }
  .hero-skyline-plant { left: 0; }
  .hero-skyline-grid { right: 0; }
}

.hero-curve {
  position: absolute;
  right: 2%;
  top: 46%;
  transform: translateY(-50%);
  width: min(38%, 27rem);
  z-index: 2;
  pointer-events: none;
  opacity: .85;
}
@media (max-width: 64rem) { .hero-curve { opacity: .2; right: -10%; width: 62%; } }
/* The transmission towers stand right behind the curve. A soft patch of the
   hero's own deep teal (--dusk-deep) under the plot quiets them there, so the
   curve reads cleanly while the towers stay visible around it. */
@media (min-width: 64rem) {
  .hero-curve {
    background: radial-gradient(closest-side, rgb(7 58 56 / .82) 55%, rgb(7 58 56 / 0));
  }
}

.hero .shell {
  position: relative;
  z-index: 3;
  padding-block: clamp(3.5rem, 8vw, 6.25rem) clamp(4.5rem, 10vw, 8rem);
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  align-items: flex-start;
}

/* The headline is the company's full name, with the four letters that spell
   ARTS picked out in coral — the device the original site used to explain
   where the name comes from. Setting it in the display face at full size makes
   the wordplay the first thing anyone reads, instead of a caption sitting
   above something else. */
.hero h1 {
  font-size: clamp(1.9rem, 4.4vw, 3.2rem);
  line-height: 1.14;
  color: var(--on-dark);
  max-width: 22ch;
}
.hero h1 b { color: var(--coral); font-weight: inherit; }

/* What the company actually does, in one line. Deliberately quiet: it is a
   subtitle to the name above it, not a second headline. */
.hero-tagline {
  max-width: 38ch;
  font-size: clamp(1rem, 1.6vw, 1.14rem);
  line-height: 1.55;
  color: var(--on-dark-soft);
}

.hero-actions { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: .5rem; }

/* --------------------------------------------------------------------------
   Proof strip
   -------------------------------------------------------------------------- */

.proof { background: var(--card); border-bottom: 1px solid var(--rule); }
.proof .shell {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 0;
}
.proof-item {
  padding: 1.9rem 2rem 2rem;
  border-left: 1px solid var(--rule-soft);
  display: flex;
  flex-direction: column;
  gap: .55rem;
}
.proof-item:first-child { border-left: 0; padding-left: 0; }
.proof-item p { font-size: .98rem; color: var(--graphite); }
.proof-item strong { color: var(--tower); font-weight: 600; }

@media (max-width: 48rem) {
  .proof-item { border-left: 0; border-top: 1px solid var(--rule-soft); padding: 1.4rem 0; }
  .proof-item:first-child { border-top: 0; }
}

/* --------------------------------------------------------------------------
   Bands
   -------------------------------------------------------------------------- */

.band { padding-block: clamp(3.5rem, 7vw, 5.5rem); }
.band--paper { background: var(--paper); }
.band--card  { background: var(--card); border-block: 1px solid var(--rule); }

.band--dark {
  background: var(--dusk-deep);
  color: var(--on-dark-soft);
  position: relative;
  overflow: hidden;
}
.band--dark h2, .band--dark h3, .band--dark strong { color: var(--on-dark); }
.band--dark p { color: var(--on-dark-soft); }
/* Text links only. A .btn carries its own foreground and background, and if
   this rule caught buttons too it would repaint a coral button's label coral —
   an invisible button on a coral ground. */
.band--dark a:not(.btn) { color: var(--coral); }
.band--dark a:not(.btn):hover { color: var(--coral-lift); }
.band--dark .shell { position: relative; z-index: 2; }

.band-head {
  display: flex;
  flex-direction: column;
  gap: .7rem;
  margin-bottom: 2.5rem;
  max-width: 48rem;
}
.band-head h2 { font-size: clamp(1.55rem, 3.2vw, 2.2rem); }
.band-head p  { color: var(--graphite); font-size: 1.06rem; }
.band--dark .band-head p { color: var(--on-dark-faint); }

/* A short coral rule under section headings — the original site used a
   coloured rule the same way. */
.band-head h2::after {
  content: "";
  display: block;
  width: 3rem;
  height: 3px;
  background: var(--coral);
  margin-top: .9rem;
}

/* --------------------------------------------------------------------------
   Solution cards
   -------------------------------------------------------------------------- */

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17.5rem, 1fr));
  gap: 1.25rem;
  align-items: stretch;
}

/* For a set of four. Auto-fit would put three on one row and leave the fourth
   sitting alone beside a gap; a fixed pair of columns fills both rows. */
.cards--2up { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 46rem) { .cards--2up { grid-template-columns: 1fr; } }

.card {
  display: flex;
  flex-direction: column;
  gap: .8rem;
  background: var(--card);
  border: 1px solid var(--rule);
  border-top: 3px solid var(--coral);
  border-radius: 2px;
  padding: 1.6rem 1.5rem 1.5rem;
  text-decoration: none;
  color: inherit;
  transition: border-color .16s ease, box-shadow .16s ease, transform .16s ease;
}
.card:hover {
  border-color: var(--coral);
  box-shadow: 0 12px 34px -24px rgba(0, 38, 42, .6);
  transform: translateY(-2px);
}
/* These two colours are stated explicitly rather than inherited. A card is a
   light object, and it is sometimes placed inside a .band--dark, whose heading
   and paragraph rules would otherwise paint white text onto the white card. */
.card h3 { font-size: 1.22rem; color: var(--tower); }
.card p { font-size: .98rem; color: var(--graphite); flex: 1; }
/* Only the description takes up the spare height. Without this the label
   stretched too, and in a shorter card it pushed the heading down out of line
   with its neighbours. */
.card p.label { flex: none; }
.card .more {
  font-family: var(--sans);
  font-size: .9rem;
  font-weight: 600;
  color: var(--coral-ink);
  display: inline-flex;
  gap: .4rem;
  align-items: center;
}
.card .arrow { transition: transform .16s ease; }
.card:hover .more .arrow { transform: translateX(3px); }

/* --------------------------------------------------------------------------
   Case study
   -------------------------------------------------------------------------- */

.case {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  gap: clamp(2rem, 5vw, 3.5rem);
  align-items: center;
}
@media (max-width: 58rem) { .case { grid-template-columns: 1fr; } }

.case-copy { display: flex; flex-direction: column; gap: 1.1rem; align-items: flex-start; }
.case-copy h2 { font-size: clamp(1.5rem, 3vw, 2.05rem); }

.case-figure {
  border: 1px solid var(--dusk-rule);
  border-radius: 2px;
  background: var(--dusk-raised);
  padding: .5rem;
}
.case-figure img { border-radius: 1px; }
.case-figure figcaption {
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--coral);
  padding: .75rem .4rem .3rem;
  line-height: 1.5;
}

/* A screenshot or plot on a LIGHT ground. .case-figure above is the same idea
   for the dark bands — the two differ only in which side of the palette they
   sit on. */
.shot {
  border: 1px solid var(--rule);
  border-radius: 2px;
  background: var(--card);
  padding: .5rem;
}
.shot img { border-radius: 1px; }
.shot figcaption {
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--coral-ink);
  padding: .75rem .4rem .3rem;
  line-height: 1.5;
}

/* Two figures side by side. The wider column takes the interface, which is
   dense with text and needs the room; the plot beside it reads fine small. */
.shots {
  display: grid;
  grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
  gap: clamp(1.5rem, 3vw, 2.25rem);
  align-items: start;
  margin-top: clamp(2.25rem, 5vw, 3.5rem);
}
/* Two figures of similar shape get equal columns. */
.shots--even { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.shots--tight { margin-top: 1.4rem; }

@media (max-width: 58rem) { .shots { grid-template-columns: 1fr; } }

.spec-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0;
  width: 100%;
}
.spec-list li {
  display: grid;
  grid-template-columns: 8.5rem 1fr;
  gap: 1rem;
  padding-block: .62rem;
  border-top: 1px solid var(--dusk-raised);
  font-size: .97rem;
}
.spec-list li:last-child { border-bottom: 1px solid var(--dusk-raised); }
.spec-list .k {
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--coral);
  padding-top: .3rem;
}
@media (max-width: 34rem) {
  .spec-list li { grid-template-columns: 1fr; gap: .2rem; }
}

/* --------------------------------------------------------------------------
   Publications
   -------------------------------------------------------------------------- */

.pubs { display: flex; flex-direction: column; gap: 0; }

.pub {
  display: grid;
  grid-template-columns: 8rem 1fr auto;
  gap: 1.5rem;
  align-items: baseline;
  padding-block: 1.45rem;
  border-top: 1px solid var(--rule);
  text-decoration: none;
  color: inherit;
  transition: background-color .16s ease;
}
.pub:last-child { border-bottom: 1px solid var(--rule); }
.pub:hover { background: var(--mint-wash); }
.pub h3 { font-size: 1.08rem; }
.pub p { font-size: .95rem; color: var(--graphite); margin-top: .3rem; }
.pub .venue {
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--coral-ink);
  padding-top: .3rem;
}
.pub .arrow { color: var(--coral-ink); }

@media (max-width: 46rem) {
  .pub { grid-template-columns: 1fr; gap: .35rem; }
  .pub .arrow { display: none; }
}

/* --------------------------------------------------------------------------
   Closing call to action
   -------------------------------------------------------------------------- */

.cta-band {
  background: var(--dusk);
  color: var(--on-dark);
  padding-block: clamp(3rem, 6vw, 4.5rem);
}
.cta-band .shell {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1.75rem;
}
.cta-copy { display: flex; flex-direction: column; gap: .6rem; max-width: 40rem; }
.cta-copy h2 { font-size: clamp(1.4rem, 2.8vw, 1.9rem); color: var(--on-dark); }
.cta-copy p { color: var(--on-dark-soft); }

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */

.site-footer {
  background: var(--tower);
  color: var(--on-dark-soft);
  padding-block: 3.25rem 2rem;
  font-size: .95rem;
}
.footer-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.3fr) repeat(2, minmax(0, 1fr));
  gap: 2.5rem;
  padding-bottom: 2.5rem;
  border-bottom: 1px solid var(--dusk-deep);
}
@media (max-width: 52rem) { .footer-grid { grid-template-columns: 1fr; gap: 2rem; } }

.footer-brand { display: flex; flex-direction: column; gap: 1rem; align-items: flex-start; }
.footer-brand img { height: 4.4rem; width: auto; }
.footer-brand p { color: var(--on-dark-faint); max-width: 26rem; font-size: .93rem; }

.footer-col h4 {
  font-family: var(--mono);
  font-size: .68rem;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--coral);
  margin-bottom: .9rem;
}
.footer-col ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .5rem; }
.footer-col a { color: var(--on-dark-soft); text-decoration: none; }
.footer-col a:hover { color: var(--coral); text-decoration: underline; }
.footer-col address { font-style: normal; color: var(--on-dark-faint); line-height: 1.6; }

.footer-base {
  padding-top: 1.5rem;
  display: flex;
  flex-wrap: wrap;
  gap: .6rem 1.75rem;
  justify-content: space-between;
  font-family: var(--mono);
  font-size: .7rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--on-dark-faint);
}
.footer-base a { color: var(--on-dark-faint); }
.footer-base a:hover { color: var(--coral); }

/* --------------------------------------------------------------------------
   Utility: the small mono label

   This sits at the END of the stylesheet on purpose.

   Labels are written as <p class="label">, and several components style their
   own paragraphs (.card p, .proof-item p, .band-head p, .band--dark p ...).
   Those selectors are just as specific as a bare .label, so whichever comes
   last in this file wins. Keeping the label here — and matching p.label rather
   than .label — means it always comes out right, including inside any new
   component you add later.
   -------------------------------------------------------------------------- */

p.label, span.label, div.label, .label {
  font-family: var(--mono);
  font-size: .68rem;
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--graphite-faint);
}

p.label--coral, .label--coral { color: var(--coral); }
p.label--ink,   .label--ink   { color: var(--coral-ink); }

/* ==========================================================================
   Interior pages
   Everything below is used by the pages other than the homepage.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Compact page header — the interior equivalent of the homepage hero
   -------------------------------------------------------------------------- */

.page-hero {
  position: relative;
  overflow: hidden;
  background: linear-gradient(165deg, var(--dusk) 0%, var(--dusk-deep) 100%);
  color: var(--on-dark);
}
.page-hero .shell {
  position: relative;
  z-index: 2;
  padding-block: clamp(2.75rem, 6vw, 4.25rem);
  display: flex;
  flex-direction: column;
  gap: 1rem;
  align-items: flex-start;
}
.page-hero h1 {
  font-size: clamp(1.85rem, 4vw, 2.85rem);
  color: var(--on-dark);
  max-width: 22ch;
}
.page-hero .lede { color: var(--on-dark-soft); max-width: 46rem; }
.page-hero p.label { color: var(--coral); }

/* A quiet trace of the same artwork, bottom right, so interior pages belong to
   the homepage without repeating the full silhouette. */
.page-hero-mark {
  position: absolute;
  right: -1%;
  bottom: -1px;
  width: min(40%, 30rem);
  /* Sunk by its ground strip only, so the whole scene shows above it. */
  transform: translateY(10%);
  opacity: .20;
  z-index: 1;
  pointer-events: none;
}
@media (max-width: 48rem) { .page-hero-mark { opacity: .12; } }

/* --------------------------------------------------------------------------
   Prose — a readable column for pages that are mostly words
   -------------------------------------------------------------------------- */

.prose { max-width: var(--measure); display: flex; flex-direction: column; gap: 1.15rem; }
.prose h2 { font-size: clamp(1.4rem, 2.8vw, 1.8rem); margin-top: 1rem; }
.prose h3 { font-size: 1.15rem; margin-top: .75rem; }
.prose p, .prose li { color: var(--graphite); }
.prose ul, .prose ol { margin: 0; padding-left: 1.25rem; display: flex; flex-direction: column; gap: .5rem; }
.prose strong { color: var(--tower); font-weight: 600; }
.prose--wide { max-width: 52rem; }

/* --------------------------------------------------------------------------
   Listed features — services, product capabilities
   -------------------------------------------------------------------------- */

.features { display: flex; flex-direction: column; gap: 0; }

.feature {
  display: grid;
  grid-template-columns: 3.25rem 1fr;
  gap: 0 1.5rem;
  padding-block: 1.6rem;
  border-top: 1px solid var(--rule);
  align-items: start;
}
.feature:last-child { border-bottom: 1px solid var(--rule); }
.feature-n {
  font-family: var(--mono);
  font-size: .95rem;
  font-weight: 500;
  color: var(--coral-ink);
  font-variant-numeric: tabular-nums;
  padding-top: .3rem;
}
.feature h3 { font-size: 1.14rem; margin-bottom: .4rem; }
.feature p { color: var(--graphite); font-size: .99rem; max-width: 54rem; }

@media (max-width: 34rem) {
  .feature { grid-template-columns: 1fr; gap: .3rem; }
}

/* Plain capability list, for bullets inside a card or band. */
.ticks { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .8rem; }
.ticks li {
  display: grid;
  grid-template-columns: 1.4rem 1fr;
  gap: .7rem;
  align-items: start;
  font-size: .99rem;
  color: var(--graphite);
}
.ticks li::before {
  content: "";
  width: .55rem;
  height: .55rem;
  margin-top: .5rem;
  background: var(--coral);
  border-radius: 1px;
}
.band--dark .ticks li { color: var(--on-dark-soft); }

/* --------------------------------------------------------------------------
   Figures on light grounds
   -------------------------------------------------------------------------- */

.figure {
  margin: 0;
  border: 1px solid var(--rule);
  border-radius: 2px;
  background: var(--card);
  padding: .75rem;
}
.figure img { border-radius: 1px; width: 100%; }
.figure figcaption {
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--graphite-faint);
  padding: .8rem .3rem .2rem;
  line-height: 1.55;
}

/* A clearly-marked gap where an asset is still needed. Deliberately obvious:
   it must never be mistaken for finished design. */
.placeholder {
  border: 2px dashed var(--coral);
  border-radius: 2px;
  background: repeating-linear-gradient(
    -45deg, var(--mint-wash), var(--mint-wash) 12px,
    var(--card) 12px, var(--card) 24px);
  padding: 2.75rem 1.75rem;
  display: flex;
  flex-direction: column;
  gap: .5rem;
  text-align: center;
  align-items: center;
}
.placeholder p { color: var(--graphite); font-size: .95rem; max-width: 34rem; }

/* --------------------------------------------------------------------------
   Two-column split — copy beside a figure
   -------------------------------------------------------------------------- */

.split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(2rem, 5vw, 3.5rem);
  align-items: center;
}
.split--copy-wide { grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); }
.split-copy { display: flex; flex-direction: column; gap: 1.1rem; align-items: flex-start; }
.split-copy h2 { font-size: clamp(1.45rem, 3vw, 2rem); }
.split-copy p { color: var(--graphite); }
.band--dark .split-copy p { color: var(--on-dark-soft); }
@media (max-width: 58rem) { .split, .split--copy-wide { grid-template-columns: 1fr; } }

/* --------------------------------------------------------------------------
   Team
   -------------------------------------------------------------------------- */

.team { display: flex; flex-direction: column; gap: 0; }

.person {
  display: grid;
  grid-template-columns: 8.25rem 1fr;
  gap: 0 2rem;
  padding-block: 2.25rem;
  border-top: 1px solid var(--rule);
  align-items: start;
}
.person:last-child { border-bottom: 1px solid var(--rule); }
/* Both dimensions are set here on purpose: the slot is a fixed square and the
   photo is cropped to fill it, so nothing is ever stretched. */
.person img {
  width: 8.25rem;
  height: 8.25rem;
  object-fit: cover;
  border-radius: 2px;
  border: 1px solid var(--rule);
  background: var(--mint-wash);
}
.person-body { display: flex; flex-direction: column; gap: .55rem; }
.person h2 { font-size: 1.32rem; }
.person .role {
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--coral-ink);
}
.person p { color: var(--graphite); font-size: .99rem; max-width: 54rem; }

@media (max-width: 40rem) {
  .person { grid-template-columns: 1fr; gap: 1.1rem; }
  .person img { width: 7rem; height: 7rem; }
}

/* --------------------------------------------------------------------------
   News entries
   -------------------------------------------------------------------------- */

.entries { display: flex; flex-direction: column; gap: 0; }

.entry {
  display: grid;
  grid-template-columns: 10rem 1fr;
  gap: 0 2rem;
  padding-block: 2rem;
  border-top: 1px solid var(--rule);
  align-items: start;
}
.entry:last-child { border-bottom: 1px solid var(--rule); }
.entry-meta { display: flex; flex-direction: column; gap: .35rem; padding-top: .3rem; }
.entry-meta .venue {
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--coral-ink);
}
.entry-body { display: flex; flex-direction: column; gap: .7rem; align-items: flex-start; }
.entry h2 { font-size: 1.22rem; }
.entry p { color: var(--graphite); font-size: .99rem; max-width: 54rem; }

@media (max-width: 44rem) {
  .entry { grid-template-columns: 1fr; gap: .6rem; }
}

/* --------------------------------------------------------------------------
   Sub-tabs under a page header — News has "Talks & news" and "Papers".
   Each tab is its own page, so they work as plain links with no script.
   -------------------------------------------------------------------------- */

.page-hero--tabs .shell { padding-bottom: 0; }

.subnav {
  align-self: stretch;
  display: flex;
  flex-wrap: wrap;
  gap: 0 1.75rem;
  margin-top: .9rem;
  border-bottom: 1px solid var(--dusk-rule);
}
.subnav a {
  color: var(--on-dark-soft);
  text-decoration: none;
  font-weight: 500;
  padding-block: .7rem;
  border-bottom: 3px solid transparent;
  margin-bottom: -1px;
  transition: color .16s ease, border-color .16s ease;
}
.subnav a:hover { color: var(--on-dark); }
.subnav a[aria-current="page"] { color: var(--on-dark); border-bottom-color: var(--coral); }

/* --------------------------------------------------------------------------
   Paper references — publications.html, written by make_publications.py
   -------------------------------------------------------------------------- */

.refs-note { color: var(--graphite); font-size: .95rem; margin-bottom: 1.5rem; }

.ref-year {
  display: grid;
  grid-template-columns: 8rem 1fr;
  gap: 0 2rem;
  padding-block: 1.6rem;
  border-top: 1px solid var(--rule);
}
.ref-year:last-child { border-bottom: 1px solid var(--rule); }
.ref-yr {
  font-family: var(--mono);
  font-size: .95rem;
  font-weight: 500;
  letter-spacing: .08em;
  color: var(--coral-ink);
  padding-top: .1rem;
}

.refs {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 1.2rem;
  min-width: 0;
}
.ref { display: flex; flex-direction: column; gap: .15rem; max-width: 54rem; }
.ref-title { font-weight: 600; line-height: 1.4; }
.ref-title a { color: var(--tower); text-decoration: none; }
.ref-title a:hover { color: var(--coral-ink); text-decoration: underline; }
.ref-authors { font-size: .95rem; color: var(--graphite); }
.ref-authors b { color: var(--tower); font-weight: 600; }
.ref-venue { font-size: .92rem; color: var(--graphite-faint); }

@media (max-width: 44rem) {
  .ref-year { grid-template-columns: 1fr; gap: .6rem; }
}

/* --------------------------------------------------------------------------
   Slide viewer — the conference decks on the news page

   The slides are pictures, rendered from the PDF ahead of time by
   assets/source/make_deck_slides.py; js/deck.js steps through them. The deck
   spans the whole width of a news entry rather than sitting in the text
   column, because a technical slide is unreadable at half a page wide.

   The two decks come off conference templates, one bright red and one bright
   green, so the frame around them is deliberately plain: a white stage and the
   site's own teal bar underneath. That reads as "a document we are showing
   you" rather than as part of the page, which is what keeps someone else's
   branding from fighting with ours.
   -------------------------------------------------------------------------- */

.deck {
  grid-column: 1 / -1;
  margin: 1.7rem 0 .3rem;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 2px;
  overflow: hidden;
}

.deck-stage {
  position: relative;
  aspect-ratio: 16 / 9;
  background: #FFFFFF;
}

.deck-slide {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}
.deck-slide.is-hidden { display: none; }

.deck-bar {
  display: flex;
  align-items: center;
  gap: .9rem;
  padding: .55rem .7rem;
  background: var(--dusk);
  border-top: 1px solid var(--dusk-rule);
  color: var(--on-dark);
}

.deck-nav { display: flex; align-items: center; gap: .35rem; flex: none; }

.deck-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  font-family: var(--sans);
  font-size: 1rem;
  line-height: 1;
  color: var(--on-dark);
  background: transparent;
  border: 1px solid var(--dusk-rule);
  border-radius: 2px;
  cursor: pointer;
  transition: border-color .16s ease, color .16s ease;
}
.deck-btn:hover:not(:disabled) { border-color: var(--coral); color: var(--coral); }
.deck-btn:disabled { opacity: .3; cursor: default; }
.deck-btn:focus-visible { outline: 2px solid var(--coral); outline-offset: 2px; }

.deck-count {
  flex: none;
  padding-left: .3rem;
  font-family: var(--mono);
  font-size: .72rem;
  letter-spacing: .06em;
  color: var(--on-dark-faint);
  white-space: nowrap;
}

.deck-title {
  flex: 1;
  min-width: 0;
  margin: 0;
  font-size: .88rem;
  color: var(--on-dark-soft);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.deck-tools { display: flex; align-items: center; gap: .5rem; flex: none; }

.deck-link {
  padding: .45rem .6rem;
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--on-dark);
  text-decoration: none;
  border: 1px solid var(--dusk-rule);
  border-radius: 2px;
  white-space: nowrap;
  transition: border-color .16s ease, color .16s ease;
}
.deck-link span { color: var(--on-dark-faint); }
.deck-link:hover { border-color: var(--coral); color: var(--coral); }
.deck-link:hover span { color: inherit; }
.deck-link:focus-visible { outline: 2px solid var(--coral); outline-offset: 2px; }

/* Full screen. The two spellings cannot share a rule — a browser that does not
   know one selector throws the whole list away. */
.deck:fullscreen { display: flex; flex-direction: column; border: 0; background: var(--tower); }
.deck:fullscreen .deck-stage { flex: 1; min-height: 0; aspect-ratio: auto; background: var(--tower); }
.deck:-webkit-full-screen { display: flex; flex-direction: column; border: 0; background: var(--tower); }
.deck:-webkit-full-screen .deck-stage { flex: 1; min-height: 0; aspect-ratio: auto; background: var(--tower); }

/* The keynote recording sits in the same frame as a deck. The stage holds a
   still we host ourselves; js/video.js builds the player only once somebody
   presses play, and says there why. */

.deck--video .deck-stage { background: var(--tower); }

.video-play { position: absolute; inset: 0; display: block; }
.video-play:focus-visible { outline: 2px solid var(--coral); outline-offset: -3px; }

.video-poster { width: 100%; height: 100%; object-fit: cover; display: block; }

.video-mark {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  display: grid;
  place-items: center;
  width: 4.4rem;
  height: 3rem;
  padding-left: .2rem;
  color: var(--on-dark);
  background: rgba(0, 38, 42, .72);
  border: 1px solid rgba(255, 255, 255, .38);
  border-radius: 3px;
  transition: background-color .16s ease, color .16s ease, border-color .16s ease;
}
.video-play:hover .video-mark,
.video-play:focus-visible .video-mark {
  background: var(--coral);
  color: var(--tower);
  border-color: var(--coral);
}

.video-frame { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* On a phone the bar has no room for the slide's title, and the counter says
   where you are anyway. The video has no counter, so its title stays and wraps
   onto its own line instead. */
@media (max-width: 34rem) {
  .deck { margin-top: 1.2rem; }
  .deck-title { display: none; }
  .deck-bar { gap: .5rem; justify-content: space-between; }
  .deck--video .deck-bar { flex-wrap: wrap; }
  .deck--video .deck-title {
    display: block;
    flex-basis: 100%;
    white-space: normal;
    font-size: .82rem;
  }
}

/* --------------------------------------------------------------------------
   Contact
   -------------------------------------------------------------------------- */

.contact-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  gap: clamp(2rem, 5vw, 4rem);
  align-items: start;
}
@media (max-width: 56rem) { .contact-grid { grid-template-columns: 1fr; } }

.form { display: flex; flex-direction: column; gap: 1.1rem; }
.field { display: flex; flex-direction: column; gap: .4rem; }
.field label {
  font-family: var(--sans);
  font-size: .88rem;
  font-weight: 600;
  color: var(--tower);
}
.field input, .field textarea {
  font-family: var(--sans);
  font-size: 1rem;
  color: var(--tower);
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 2px;
  padding: .7rem .85rem;
  width: 100%;
}
.field input:focus, .field textarea:focus {
  border-color: var(--coral);
  outline: none;
  box-shadow: 0 0 0 3px rgba(255, 127, 80, .18);
}
.field textarea { min-height: 8.5rem; resize: vertical; }
.field .hint { font-size: .85rem; color: var(--graphite-faint); }
.form .btn { align-self: flex-start; }

.form-note {
  border-left: 3px solid var(--coral);
  padding: .6rem 0 .6rem 1rem;
  font-size: .92rem;
  color: var(--graphite);
}

.contact-details { display: flex; flex-direction: column; gap: 1.6rem; }
.detail { display: flex; flex-direction: column; gap: .35rem; }
.detail a, .detail address {
  font-style: normal;
  font-size: 1.05rem;
  color: var(--tower);
  text-decoration: none;
  line-height: 1.6;
}
.detail a:hover { color: var(--coral-ink); text-decoration: underline; }

/* ==========================================================================
   Patent panel, project entries and status chips
   ========================================================================== */

/* --------------------------------------------------------------------------
   The patent

   GR 1009503 B is the single strongest credential the company has, so it gets
   its own object rather than a line of small print.
   -------------------------------------------------------------------------- */

.patent {
  border: 1px solid var(--coral);
  border-left-width: 4px;
  border-radius: 2px;
  background: rgba(255, 127, 80, .06);
  padding: 1.6rem 1.75rem 1.75rem;
  display: flex;
  flex-direction: column;
  gap: .85rem;
  align-items: flex-start;
}
.patent-no {
  font-family: var(--mono);
  font-size: clamp(1.5rem, 3.4vw, 2.1rem);
  font-weight: 500;
  letter-spacing: .02em;
  color: var(--coral);
  line-height: 1.1;
}
.patent h3 { font-size: 1.12rem; color: var(--on-dark); max-width: 40ch; }
.patent p { font-size: .97rem; color: var(--on-dark-soft); max-width: 54rem; }
.patent-meta {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem 1.5rem;
  font-family: var(--mono);
  font-size: .7rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--on-dark-faint);
}
.patent-actions { display: flex; flex-wrap: wrap; gap: .7rem; margin-top: .25rem; }

/* On a light ground the same panel needs light-ground colours. */
.band--paper .patent, .band--card .patent { background: rgba(255, 127, 80, .07); }
.band--paper .patent h3, .band--card .patent h3 { color: var(--tower); }
.band--paper .patent p, .band--card .patent p { color: var(--graphite); }
.band--paper .patent-no, .band--card .patent-no { color: var(--coral-ink); }
.band--paper .patent-meta, .band--card .patent-meta { color: var(--graphite-faint); }

/* --------------------------------------------------------------------------
   Status chips — a project is either finished or it is not
   -------------------------------------------------------------------------- */

.chip {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  font-family: var(--mono);
  font-size: .64rem;
  font-weight: 500;
  letter-spacing: .13em;
  text-transform: uppercase;
  padding: .25rem .55rem;
  border-radius: 2px;
  border: 1px solid currentColor;
  white-space: nowrap;
}
.chip::before {
  content: "";
  width: .4rem;
  height: .4rem;
  border-radius: 50%;
  background: currentColor;
}
.chip--live      { color: var(--coral-ink); }
.chip--done      { color: var(--graphite); }
.band--dark .chip--live { color: var(--coral); }
.band--dark .chip--done { color: var(--on-dark-faint); }

/* --------------------------------------------------------------------------
   Project entries
   -------------------------------------------------------------------------- */

.projects { display: flex; flex-direction: column; gap: 0; }

.project {
  display: grid;
  grid-template-columns: 11rem 1fr;
  gap: 0 2rem;
  padding-block: 2.1rem;
  border-top: 1px solid var(--rule);
  align-items: start;
}
.project:last-child { border-bottom: 1px solid var(--rule); }

.project-meta { display: flex; flex-direction: column; gap: .6rem; padding-top: .25rem; align-items: flex-start; }
.project-client {
  font-family: var(--sans);
  font-size: 1rem;
  font-weight: 600;
  color: var(--tower);
  line-height: 1.3;
}
.project-client span {
  display: block;
  font-family: var(--mono);
  font-size: .66rem;
  font-weight: 400;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--graphite-faint);
  margin-top: .2rem;
}

.project-body { display: flex; flex-direction: column; gap: .75rem; align-items: flex-start; }
.project h2 { font-size: 1.2rem; }
.project p { color: var(--graphite); font-size: .99rem; max-width: 54rem; }

@media (max-width: 46rem) {
  .project { grid-template-columns: 1fr; gap: .8rem; }
}

/* ==========================================================================
   The animated incident replay

   Three canvases driven by js/incident-replay.js. The plots are deliberately
   abstract — no axis values, no units, no identifiers — so the section shows
   the shape of an incident without publishing anything about a real network.
   ========================================================================== */

.replay {
  display: grid;
  grid-template-columns: minmax(0, 1.12fr) minmax(0, 1fr);
  gap: 1rem;
  align-items: stretch;
}
.replay-stack {
  display: grid;
  grid-template-rows: 1fr 1fr;
  gap: 1rem;
  min-width: 0;
}

@media (max-width: 56rem) {
  .replay { grid-template-columns: 1fr; }
  .replay-stack { grid-template-rows: auto auto; }
}

.replay-panel {
  margin: 0;
  min-width: 0;
  border: 1px solid var(--dusk-rule);
  border-radius: 2px;
  background: rgba(0, 38, 42, .45);
  padding: .85rem .9rem 1rem;
  display: flex;
  flex-direction: column;
  gap: .6rem;
}
.replay-panel figcaption {
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--on-dark-faint);
  line-height: 1.5;
}
.replay-panel figcaption b {
  display: block;
  color: var(--on-dark);
  font-weight: 500;
  letter-spacing: .1em;
}

/* The canvas draws itself to whatever box it is given; these ratios keep the
   PV panel roughly square and the time traces wide and short. */
.replay-panel canvas { display: block; width: 100%; }
.replay-panel--pv canvas { aspect-ratio: 4 / 3.4; }
.replay-panel--trace canvas { aspect-ratio: 5 / 2; }

@media (max-width: 56rem) {
  .replay-panel--pv canvas { aspect-ratio: 4 / 3; }
  .replay-panel--trace canvas { aspect-ratio: 5 / 2.2; }
}

.replay-bar {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-top: .35rem;
}

/* Reads "Stable", then flips when the index crosses its limit. The only live
   text in the figure, and it carries no quantity. */
.replay-state {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  font-family: var(--mono);
  font-size: .7rem;
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--mint-lit);
  border: 1px solid currentColor;
  border-radius: 2px;
  padding: .35rem .7rem;
  transition: color .2s ease;
}
.replay-state::before {
  content: "";
  width: .45rem;
  height: .45rem;
  border-radius: 50%;
  background: currentColor;
}
.replay-state.is-alarm { color: var(--coral); }

.replay-note {
  font-size: .88rem;
  color: var(--on-dark-faint);
  max-width: 46rem;
  flex: 1 1 22rem;
}

.replay-toggle {
  font-family: var(--sans);
  font-size: .85rem;
  font-weight: 600;
  color: var(--on-dark);
  background: transparent;
  border: 1px solid var(--dusk-rule);
  border-radius: 2px;
  padding: .45rem 1.1rem;
  cursor: pointer;
  transition: border-color .16s ease, color .16s ease;
}
.replay-toggle:hover { border-color: var(--coral); color: var(--coral); }
